diff --git a/BigInteger.js b/BigInteger.js index bc15bb7..c1d6a26 100644 --- a/BigInteger.js +++ b/BigInteger.js @@ -1345,6 +1345,1069 @@ var bigInt = BigInteger = (function (undefined) { return randBigInt; } + BigInteger.prototype.checkCoPrime = function (another) { + var g = gcd(this, another); //test gcd + return ( (g.bitLength().value === 1) && (g.value == 1) ) //if 1, optionally, g.bitLength == 1 - true + } + SmallInteger.prototype.checkCoPrime = BigInteger.prototype.checkCoPrime; + // Usage: + // new BigInteger('100500').checkCoPrime(new BigInteger('121')) // true + // (new BigInteger('100500')).checkCoPrime(new BigInteger('119')) // true + + BigInteger.prototype.genCoPrime = function ( + bits //number of bits to generate co-prime, or strings ('prev', 'previous') or 'next' - to get previous or next co-prime from number + , number //string or bigInteger with start number, from which need to generate co-prime. + //This is optional parameter, and if not specified, first must be a number of bits, not a string. + , cur2 //check current number too, or not? default - false, and do not return the number if number is co-prime with "this". + ) + { + cur2 = ( ( ( typeof cur2 === 'undefined' ) || (cur2 == false) ) ? false : true ); //return current number if co-prime with "this"? + if(typeof number !== 'undefined'){ + if(['previous', 'prev'].indexOf(bits) !== -1){ + bits = 'previous'; + }else{ + bits = 'next'; + } + }else{ + bits = bits || 256; + } + var RandCoPrimeResult = (typeof number !== 'undefined') //when number is defined + ? bigInt().from(number) //use this number, as start value + : get_random_k_bits(bits) //or generate random number, with specified bitlength, or default. + ; + while((!cur2) ? (cur2=true, true) : !this.checkCoPrime(RandCoPrimeResult)){ //while it not co-prime with this + RandCoPrimeResult = RandCoPrimeResult.next( ((bits === 'next')? 1 : -1 ) ); //when number is defined, then bits can be a strings, use 'next' or 'prev' number. + } + return RandCoPrimeResult; + } + SmallInteger.prototype.genCoPrime = BigInteger.prototype.genCoPrime; + // Usage: + // (new BigInteger('100500')).genCoPrime('prev', new BigInteger('121'), true).toString() //"121" + // new BigInteger('100500').genCoPrime('prev', new BigInteger('121'), false).toString() //"119" + + var from = BigInteger.prototype.from = function(number) //fast way to return bigInteger as is, or from decimal string, or from hexadecimal string. + { + var bigNumber = undefined; + var number = number || this; + + if( + (number instanceof bigInt) + || (typeof number === 'undefined') + || (typeof number === 'number') + || (typeof number === 'bigint') //or if bigint in form 123n + || ( + (typeof number === 'string') + && ( /^[+-\d]+$/ .test(number) === true ) + ) + ) + { + return new bigInt(number); + } + else if( + (typeof number === 'string') + && ( /^[0-9a-fA-F]+$/ .test(number) === true ) + ) + { + bigNumber = new bigInt(number, 16); + } + + return new bigInt(bigNumber); + } + SmallInteger.prototype.from = BigInteger.prototype.from; + // Usage: + // new bigInt().from(new BigInteger('100500')); + // new bigInt().from('HexOrDecString') + //or new bigInt('HexOrDecString').from() + + BigInteger.prototype.isSafePrime = function (MRrounds) //is the prime, value of (p-1)/2, where p = this? (true/false) + { + MRrounds = MRrounds || getSetMRrounds(); //default MillerRabin rounds + return ( + this.MillerRabin(MRrounds) + && ( + ( + this + .subtract( + bigInt('1') + ) + ) + .divide( + bigInt('2') + ) + ) + .MillerRabin(MRrounds) + ); + } + SmallInteger.prototype.isSafePrime = BigInteger.prototype.isSafePrime; + // Usage: + // new BigInteger(83).isSafePrime(); //true + + //Generate and return the Safe Prime p, for which (p-1)/2 is a prime too. + function generateSafePrime( + x, //string or BigInteger - safe-prime, or start-number from which need to generate a safe-prime, + //or number - bitlength to generate random safePrime with specified bitlength, if "x" not a string or BigInteger + mode //'previous', or 'next', or 'doubled-previous', or 'doubled_next'; + , MRrounds + ){ + /* + Proof of the validity of the representation a Safe-Prime number, in form: p = 12*k - 1: + + Let q = 12*x+r; where x - natural number, r = q%12 - remainder by modulo x, and number with value from 0 up to (x-1) (0,1,2,3,4,5,6,7,8,9,10,11). + In this form can be represented each natural number. + + Now, let us prove that the representation of any Safe-Prime (which are not excepted), in form q = 12*x+11 is valid: + + 1. When r is even, y - natural number, r = 2*y; q = 12*x + r = 12*x + 2y; q = 2*(6x+y) - so q have divisor 2, and this is even number, not an odd prime number. + So, y = 0,1,2,3,4,5, and even values of r = 0,2,4,6,8,10 - are excluded. + + 2. Now, exclude an odd values of r: + When r = 1; q = 12*x + 1; (q-1)/2 = 12*x/2 = 6*x = 2*3x - have divisor 2, and this is even number, not an odd Sophie-Germen prime number. + When r = 3; q = 12*x + 3; q = 3*(4x+1) - have divisor 3, and this is not a prime, because this have no divisors besides 1 and itself. + When r = 5; q = 12*x + 5; (q-1)/2 = (12*x+4)/2 = 2*(6x+2)/2 = (6x+2) = 2*(3x+1) - have divisor 2, and this is even number, not an odd Sophie-Germen prime number. + Exception: x = 0; q = 12*0 + 5 = 5; (q-1)/2 = (5-1)/2 = 4/2 = 2, is even, but this is a Sophie-Germen prime-number, and this have divisor 1 and itself. + When r = 7; q = 12*x + 7; (q-1)/2 = (12*x+6)/2 = 2*(6x+3)/2 = (6x+3) = 3*(2x+1) - have divisor 3, and this is not a prime, because this have no divisors besides 1 and itself. + Exception: x = 0; q = 12*0 + 7 = 7; (q-1)/2 = (7-1)/2 = 6/2 = 3, have divisor 3, but this is a Sophie-Germen prime-number, and this have divisor 1 and itself. + When r = 9; q = 12*x + 9; (q-1)/2 = (12*x+8)/2 = 2*(6*x+4)/2 = (6x+4) = 2*(3x+2) - have divisor 2, and this is even number, not an odd Sophie-Germen prime number. + + After this all, from all possible values of r = q%12, from the numbers 0,1,2,3,4,5,6,7,8,9,10,11, + was been excluded (two exceptions) the values r = 0,2,4,6,8,10,1,3,5,7,9 (sorted: 0,1,2,3,4,5,6,7,8,9,10), and only one option remains - value 11. + Consequently, r = 11, and any Safe-Prime nubmer (except for 5, 7), can be represented in form q = 12*x + 11; + Now, let, k = (x+1); q = 12*(x+1) - 1 = 12k - 1; Consequently, q = 12k - 1. + + Original statement is proven. + */ + + MRrounds = MRrounds || getSetMRrounds(); //default MillerRabin rounds + + if((typeof x !== 'number') && bigInt().from(x).isSafePrime()){return bigInt().from(x);} //if x not number but string or bigint, and if this already safe prime - return it + + // Or start generate the Safe-Prime: + //by "bitlength" - prime with specified bitlength in number "x", or by specified BigInteger "x" - the start number, with "mode" - 'previos'(default), 'next', + //(also, 'doubled[_- +.]previous', 'doubled[_- +.]next' - means generate previous or next Sofi-Germen prime, and return doubled safePrime 2p+1). + + // sp - Safe Prime, sgp - Sofi-Germen's prime, corresponding for sp. + //sgp = (sp-1)/2 - must be a prime, when sp is Safe Prime. | * 2 + //2*sgp = sp-1 | + 1 + //2*sgp + 1 = sp |revert this + //sp = 2sgp + 1; |if sgp, is a prime -> return sp. + + mode = mode || 'previous'; + + // console.log( + // 'Generating "safe prime" number, as ' + + // mode + + // ' prime from x ' + + // ( ( mode.indexOf('doubled') !== -1 ) ? ', means as next 2x' : '' ) + + // ((typeof x === 'number')?'from random '+x+' bits BigInteger': x.toString()) + + // ', for which (p-1)/2 is prime number too... ' + // ); + + var p, prime = (typeof x === 'number') ? bigInt.randbits(x) : bigInt().from(x); //just got rand bits or nubmer. + prime = ( + (prime.MillerRabin(MRrounds)) //if already prime + ? prime //use it + : prime.prevprime() + ) + ; + if(prime.isSafePrime()){return prime;} + prime = ( //find next or previous prime, (12k - 1) + (mode.indexOf('previous')!==-1) + ? (prime.subtract(prime.mod(bigInt('12'))).add(bigInt('12')).prev()) // ((p - (p%12) + 12) - 1) -> next number (12k - 1) + : (prime.subtract(prime.mod(bigInt('12'))).prev()) // (p - (p%12) - 1) -> previous number (12k - 1) + ) + ; + if(prime.isSafePrime()){return prime;} + do{ + // console.log('p', p, 'prime', prime.toString()); + prime = ( (mode.indexOf('previous')!==-1) ? prime.subtract(bigInt('12')) : prime.add(bigInt('12')) ); //next or previous nubmer (12k-1) + //find next prime p, by rolling, using MillerRabin() primality check + p = ( + ( mode.indexOf('doubled') !== -1 ) + ? (prime.multiply(bigInt('2'))).next() //make p*2+1 + : (prime.prev()).divide(bigInt('2')) //or (p-1)/2 + ) + ; + // console.log('p.toString()', p.toString()); + }while( + !prime.isNegative() + && ( + !prime.MillerRabin(MRrounds) + || !p.MillerRabin(MRrounds) //check (p*2)+1 primality of + ) + ) + p = ( ( mode.indexOf( 'doubled' ) !== -1 ) ? p : prime ); //return safe prime, if next or previous was been Sofi-Germen prime, and need to return doubled Safe-prime. + + // console.log('Done! p = ', p.toString()); + return p; //maybe this fuction return a safe prime + } + //Usage: + // BigInteger.GenSafePrime(10).toString(2).length //10 bits, when number on input + // BigInteger.GenSafePrime('10').toString() //7 - when string + // BigInteger.GenSafePrime(new BigInteger('10')).toString() //7 - when bigInteger + + function isStrongPrime(p, s, r, t, MRrounds) + { + MRrounds = MRrounds || getSetMRrounds(); //default MillerRabin rounds + p = bigInt().from(p); //bigInt from string if string, or bigInt from bigInt + s = bigInt().from(s); + r = bigInt().from(r); + t = bigInt().from(t); + return ( //true when + ( + p.MillerRabin(MRrounds) //p - is prime + && s.MillerRabin(MRrounds) //s - is prime + && r.MillerRabin(MRrounds) //r - is prime + && t.MillerRabin(MRrounds) //t - is prime + ) + && //and + (//criteries for a Strong prime: + p.next().mod(s).eq(0) //(p+1) have divisor s + && p.prev().mod(r).eq(0) //(p-1) have divisor r + && r.prev().mod(t).eq(0) //(r-1) have divisor t + ) + ) // when this all is true - return true, else - false. + ; + } + + function genStrongPrime( //Gordon's Algorithm, to generate Strong Prime (cryptography). + bits + , maxIter + , strings + , MRrounds + ) + { + bits = bits || 20; + MRrounds = MRrounds || getSetMRrounds(); //default MillerRabin rounds + var s = get_random_k_bits(bits).prevprime(); + var t = get_random_k_bits(bits).prevprime(); + var r = Integer.one.next(3); //start - 4, first not prime. + for( + var l = Integer.one; //from l = 1 + ( //while + l.leq(t.bitLength()) //l<=t.bitlength() + && !r.MillerRabin(MRrounds) //and r not a prime + ); + l = l.next() //compute r, and increment l while contition is true + ){ + r = Integer.one.add(l.multiply(t)); // r = 1+l*t + } + var p0 = ( //p0 = ( (2*(s^(r-2) mod r)*s) - 1 ) + ( + (Integer.one.next()) + .multiply( + s.modPow(r.subtract(Integer.one.next()), r) + ) + .multiply(s) + ) + .subtract( + Integer.one + ) + ) + ; + + var p = Integer.one.next(3); //start - 4, first not a prime. + var limit = maxIter || 1000; //up to limit iterations in cycle, (1000 by default, if undefined). + for( + var j = Integer.one; //from start j = 1 + ( //while + !isStrongPrime(p, s, r, t) //or p is not a strong-prime + && (limit > 0) //or number of iterations is reached + ); + j = j.next() //compute p, and then increment j, and continue + ){ + p = p0.add((((Integer.one.next()).multiply(j)).multiply(r)).multiply(s)); //p = p0 + 2*j*r*s + limit--; //decrease limit-value + } + + // Proof, that prime p, generated with Gordon's algorithm, is a strong-prime: + // 1. s^(r-1) === 1 (mod r) ; -> this is a corollary of Fermat's theorem. + // Consequently, p0 = 1 (mod r); p0 = -1 (mod s); + // 2. After all: + // p-1 = p0 + 2jrs - 1 = 0 (mod r); and (p-1) have divisor r + // p+1 = p0 + 2jrs + 1 = 0 (mod s); and (p+1) have divisor s + // r-1 = 2it = 0 (mod t); and (r-1) have divisor t + + var strings = (((typeof strings !== 'undefined') && (strings !== false)) ? true : false); + var object = { + //return as strings or as BigIntegers. + 'p': ((strings)?p.toString():p), + 'r': ((strings)?r.toString():r), + 's': ((strings)?s.toString():s), + 't': ((strings)?t.toString():t) + } + ; + return ( + (isStrongPrime(p, s, r, t)) //if p is a strong prime + ? object //return object with results + : genStrongPrime(bits, undefined, strings) //else one more try, with default limit. + ) + ; + }//test: var SP = BigInteger.genStrongPrime(20); BigInteger.isStrongPrime(SP.p, SP.s, SP.r, SP.t); //true + + var Factorize = + BigInteger.prototype.Factorize = + SmallInteger.prototype.Factorize = + function FactorizePollardRhoBrent( + NumberToFactorize + , MRrounds + ) { + // input - bigInteger, + // output - array with prime factors... + + NumberToFactorize = this || bigInt().from(NumberToFactorize); + MRrounds = MRrounds || getSetMRrounds(); //default MillerRabin rounds + + function PollardRho(n_){ //return divisor from n_ + if ( + ['0', '1', '2'].indexOf(n_.toString()) !== -1 //if 0, 1 or 2 + || n_.MillerRabin() //or prime + ){ + return n_; //return n, as divisor. + } + + //# even number means one of the divisors is 2 + else if (n_.mod(2).eq(0)){ //if even + return bigInt(2); //divisor is 2 + } + function f(_x){return ( ( ( ( _x.modPow(2, n_) ).add(c_) ).add(n_) ).mod(n_) ); } //modPow is faster, than square and mod: f(x) = ( ( (x^2 mod n) + c + n ) mod n ); + var x_, y_, d_ = n_, c_ = n_; //define this variables, on start; + while(d_.eq(n_)){ //while failure - repeat again + x_ = bigInt(1); //test x = 1; + y_ = x_; //y_ = x_ + + d_ = bigInt(1); //start d_ = 1 + //# until the prime factor isn't obtained. + //# If n_ is prime, return n_ + while (d_.eq(1)){ //while d_ != 1 + x_ = f(x_); //# Tortoise Move: x_(i+1) = f(x_(i)); + y_ = f(f(y_)); //# Hare Move: y_(i+1) = f(f(y_(i))); + d_ = gcd((x_.subtract(y_).abs()), n_); //# check gcd of |x_-y_| and n_ + } + if(d_.neq(n_)){ //if d_ !== n_ + return d_; //return divisor + }else{ //else + c_ = c_.next(); //increment c_ after each failure, and continue with this c_. + } + } + } + + var factors = []; //define array with prime factors + var currentNumber = NumberToFactorize; //save current number + var divisor, primeIs; //define variables for divisor and primeIs + do{ //and begin to + divisor = PollardRho(currentNumber); //get divisor. It can be a component (2*2*2 = 8, for example. Or 2*3*5 = 30) + if(divisor.eq(0) || divisor.eq(1)){ //if this 0 or 1 + break; //break from cycle + } + while(!(primeIs = divisor.MillerRabin(MRrounds), primeIs)){ //while divisor not a prime (save result into variable primeIs) + divisor = PollardRho(divisor); //try to factorize divisor + } + if(primeIs){ //if divisor is a prime (use saved variable, to do not check primality again) + factors.push(divisor.toString()); //push this divisor as string + currentNumber = currentNumber.divide(divisor); //and divide current number on this + } + }while(currentNumber.neq(1)) //and try again, with the quotient, up to the end + return factors; //After all, return array with consecutive prime-factors. + } + + /* + //test: + var start = new bigInt(1); + for(var iter=start; iter to BigInteger (this can be a number or string) + var p = n; //p = n; + n = bigInt.from(Exp); //n = Exp -> to BigInteger (this can be a number or string) + var phi_p_n = (p.pow(n)).subtract(p.pow(n.prev())); //phi(p^n) = p^n - p^(n-1) + return phi_p_n; //return phi(p^n) for nubmer n^Exp, where n is a prime. + //number = p^n; phi(1*p^n) = phi(1) * phi(p^n) = 1*phi(p^n) + //number = 2*p^n; phi(2*p^n) = phi(2) * phi(p^n) = 1*phi(p^n) too. + //So, number = n^Exp or number = 2*n^Exp; and phi(number) = phi_p_n; + } + else if(n.isOdd()) //if n is odd + { + if(n.MillerRabin(MRrounds)){ //and prime + return n.subtract(bigInt('1')); //phi(n) = phi(1*n) = phi(1) * phi(n) = 1*(n-1) = (n-1), if n is prime. All numbers before n is co-prime with n. + } + }else if(n.isEven()){ //if n is Even + var n2 = n.divide(Integer[2]); //(n/2) + if(n2.MillerRabin(MRrounds)){ //and if n/2 is a prime + return n2.subtract(bigInt('1')); //phi(2n) = phi(2) * phi(n) = 1*(n-1) = (n-1), if n is prime. All numbers before n is co-prime with n. + } + } + + //else if n not a prime + var n_factors = n.Factorize(); //factorize n to array with prime factors; + //console.log('n_factors', n_factors); + // + // //now, compute euler phi: + // phi(ab) = phi(a) * phi(b); //ab + // phi(p^a) = p^a - p^(a-1); //p^a + // phi(p^1) = p^1 - p^(1-1) = p - p^0 = p-1; //p is prime; + // + // n = p1^a * p2^b * p3^c * ... * pN^n; //canonical note of n, using factors. + // phi(n) = phi(p1^a) * phi(p2^b) * phi(p3^c) * ... * phi(pN^n) = + // (p1^a - p1^(a-1)) * (p2^b - p2^(b-1)) * ... * (pN^n - pN^(n-1)) ; //phi_n from canonical n-factors + var result = bigInt(1); + //var factors = n.Factorize(); //factors + var factor = bigInt(1); + var curFactor; + var exp = bigInt(0); + for(var ifact = 0; ifact2, phi(p) always have divisor 2 (prime number), + //so g^(phi(p)/2) mod p !== 1 mod p, for primitive root by modulo p; + for(var factor = 0; factor=1; + BigInteger.prototype.GetPrimitiveRoot = function ( //return primitive root, for prime or SafePrime, or any number + g_mode //start number to generate g; + , MRrounds + , prev //true if need 'previous' or false, or undefined if need 'next' + , Exp //a=Exp, if number = p^a or number = 2*p^a; + ) + { + // Get first or random primitive root, by module of prime p. + + //This function fast finding a primitive root g, by module of prime p, + //For the numbers: + // p is prime, + // or p = p^Exp, + // or p = 2*p^Exp, + // or sfp = (sp-1)/2 is a prime too (sfp - Sophie-Germain prime, sp - SafePrime). + // phi(sp) = (sp-1); phi(sp) / 2 = (sp-1)/2 = sgp; factors(phi(sp)) = [2, sgp]; phi(phi(sp)) = phi(sgp) = (sgp-1); - easy to compute this all; + + var p = this; + MRrounds = MRrounds || getSetMRrounds(); //default MillerRabin rounds + prev = ( ( (typeof prev === 'undefined') || (prev === false) ) ? false : true ); + var exp = (typeof Exp !== 'undefined'); //if exponent defined, that means n = n^exp; + + var is_p_prime = p.MillerRabin(MRrounds); //is p prime? if p = p^a or p = 2p^a, this can be not a prime. + var phi_p = EulerPhi(p, MRrounds, Exp); //if p is prime, phi(p) = p-1, phi(p^a) = phi(2p^a) = p^a - p^(a-1); without factorization of p. + + var phi_p_factors = phi_p.Factorize(); //factorize phi_p into array of prime-factors. phi(m) - always even, for any m > 2; so at least 2 is a prime factor for this; + //console.log('phi_p_factors', phi_p_factors); //show this factors + + var phi_phi_p = EulerPhi(phi_p, MRrounds); //phi(phi(m)) - number of primitive roots, by modulo m; + //for Safe-Prime p = sgp * 2 + 1; phi(p) = p-1 = 2sgp; phi(phi(p)) = phi(2sgp) = phi(2) * phi(sgp) = 1 * (sgp-1) = (sgp-1); + + if (typeof g_mode === 'undefined'){ g_mode = bigInt('1'); } //use 1 if undefined; + else if ( + ( g_mode === 'random' ) + || ( g_mode === '0' ) + || ( g_mode === 0 ) + || ( bigInt.from(g_mode).eq(0) ) + ) + { + g_mode = ( ( bigInt.randBetween(bigInt('0'), p) ).mod( phi_p ) ); //or generate randomly + } + else{ + g_mode = bigInt.from(g_mode); //or use specified number + } + + //Now, just return first finded primitive root + var last_g = g_mode.prev( ( ( prev ) ? -1 : 1 ) ).mod(p); //save previous or next g + for( + var g = g_mode; //from g_mode + true; //while g not found + g = ( //rolling g from g_mode, by modulo p + g.next( + ( ( prev ) ? -1 : 1 ) //by increment or decrement g + ) + ).mod(p) //in circle, by modulo p + ){ + if( g.eq(last_g) ){break;} //if all cycle was been checked - break; + if( g.isPrimitiveRoot(p, MRrounds, is_p_prime, phi_p, phi_p_factors)){ //if current g is a valid primitive root + return g; //stop finding and return it + } + } + }; + SmallInteger.prototype.GetPrimitiveRoot = BigInteger.prototype.GetPrimitiveRoot; + + //Blum-Blum Shub (BBS) PRNG, allow to get n-th number, without rotate PRNG, and generate all previous numbers, to skip it. + //seed is (x0, M, lambdaM), n - N-th value from PRNG, bits need to specify number of bits, to generate seed, if this was been undefined. + function BBSBigInteger( + bits, //(string, number, or BigInteger) - If need to generate random p, and q with specified bitlength + n, //(string, number, or BigInteger) - N-th number + seed //JSON-object with PRNG-seed: - {'x0': x0, 'M': M, 'lambdaM': lambdaM} + ) + { //n-th number from BBS PRNG, without calculating previous. + seed = ( + (typeof seed !== 'undefined') + ?(typeof seed === 'string') + ? (typeof JSON.parse(seed) === 'object') + ? JSON.parse(seed) + : undefined + : (typeof seed === 'object') + ? seed + : undefined + : undefined + ) + ; + + var x0; + if( + (typeof seed !== 'undefined') + &&( + ( + ( + (seed.x0 instanceof bigInt ) + && (seed.M instanceof bigInt ) + && (seed.lambdaM instanceof bigInt ) + ) + && ( + (typeof seed.x0 !== 'undefined') + && (typeof seed.M !== 'undefined') + && (typeof seed.lambdaM !== 'undefined') + ) + ) + || + ( + (typeof seed.x0 === 'string') + && (typeof seed.M === 'string') + && (typeof seed.lambdaM === 'string') + ) + ) + && (new bigInt().from(seed.x0)).checkCoPrime(new bigInt().from(seed.M)) + ){ + x0 = new bigInt().from(seed.x0); + M = new bigInt().from(seed.M); + lambdaM = new bigInt().from(seed.lambdaM); + } + else{ //generate new p, q, M, lambdaM and x0, with bitlength of bits. + bits = ( + bits + || ( + (typeof bits === 'string') + && (/^\d+$/.test(bits) === true) + ) + ? parseInt(bits, 10) + : 256 //256 bits, by default. + ) + ; + + var p = get_random_k_bits(bits).nextprime(); // p + console.log('p', p.toString(), p.isPrime()); + + var q = get_random_k_bits(bits).nextprime(); // q + console.log('q', q.toString(), q.isPrime()); + + var M = p.multiply(q); // M = p * q + console.log('M = p*q = ', M.toString()); + + //compute lambdaM + var BigPrevP = p.subtract(bigInt('1')); //(p-1) + var BigPrevQ = q.subtract(bigInt('1')); //(q-1) + var lambdaM = lcm(BigPrevP, BigPrevQ); //lambdaM = lcm((p-1), (q-1)) + + //generate x0 + var coPrime = M.genCoPrime(bits); + console.log('coPrime = ', coPrime.toString(), 'is CoPrime: ', coPrime.checkCoPrime(M)); + + if(coPrime.checkCoPrime(M) === true){ + x0 = coPrime; + console.log('x0 is coPrime with M: ', x0.toString(), x0.checkCoPrime(M)); + } + + //combine this all to seed + seed = {'M': M.toString(), 'lambdaM': lambdaM.toString(), 'x0': x0.toString()}; + console.log('new seed was been generated!'); + console.log( + 'JSON.stringify(seed)\n'+ + '\''+JSON.stringify(seed)+'\'' + ); + } + + if(typeof n === 'undefined' || !(n instanceof bigInt)){ + n = new bigInt().from(n); //0 index, by default, if undefined, or return bigInt as is or from (hexa)decimal-string + } + //now, compute N-th value, from PRNG; + + //prepare computing 2^n mod lambdaM + var twoBig = Integer[2]; //2 + var nBig = n; //n + //do it + var expBig = twoBig.modPow(nBig, lambdaM); //2^n mod lambdaM + //compute pseudorand result Nth-value + var result = x0.modPow(expBig, M); //and finaly: result = x0 ^ (2 ^ n mod lambdaM ) mod M; + + //and return this all. + return {'n': n.toString(), 'NthValue': result.toString(), 'seed': JSON.stringify(seed)}; + } + // Usage: + // First run: + // var bits = 128; BigInteger.BBSBigInteger(bits); //-> return JSON-string with seed. + // Random Access PRNG, with seed: + // BigInteger.BBSBigInteger( + // undefined, //number, bigInt, or (hexa)decimal-string (bitlength for p and q, but optional, and default 256) + // n, //number, bigInt, or (hexa)decimal-string (optional, for generation) + // '{"M":"M_value","lambdaM":"lamdaM_value","x0":"x0_value"}' //(optional) - seed, returned as string, after generation of this + // ); //return object {"n":"n","NthValue":"pseudo-rand","seed":{seedObjectString}} + // //.NthValue.toString() //N-th value as string + + /* + BRAPRNG - Bijective Random Access Pseudo-Random Number Generator (Bijective Random Access PRNG, BRAPRNG). + + The main formula of this generator, is a simply formula, from Diffie-Helman Key-Exchange Protocol: + pubKey = g ^ privKey mod p + which allow to generate pseudorand-values, + when result - prand, privKey - Index, p - safe prime (prime for which ((p/2)-1) is Sophie-Germain prime): + prand = g ^ Index mod p; where p is Safe-Prime (for which (p/2)-1 is prime too), g is primitive root by modulo p, + Index - some index in range (1, ... phi(p)), prand - pseudorand-value in the same range. + + Because g is a primitive root by modulo p, + the main property of ransfrom "Index" to "prand" - this is a bijective-transform. + This means, for each unique "Index", in range (1, ... phi(p)), corresponding one, and only one "prand"-value, in the same range, + where phi(p) = (p-1), when p is prime nubmer. + For each unique "index" in this range, only one "prand" is corresponding, and this is unique too, wihtout any repeations of "prand", in this range. + + This transfrom is not reversible, because to "Index", by known "prand", and moreover "g", "p", need to resolve "discrette-logarithm"-problem. + Because of this, this transorm seems, like a hash, but this is not a hash, because bitlength of data is not changing, + and, as result - no any collisions, so, this is just - a bijective transform "Index" into "prand". + + Random-Access PRNG, means, any "prand", can be extracted directly by "Index", and "Index", can be a random-values for each "prand". + No need to compute N values, ans skip it then, to extract N-th value. + So, this PRNG, seems like Blum-Blum-Shub Algorithm too, but there need to specify N, and the seed with three numbers: x0, M, and lamdaM. + Here, "Index", and seed (g, p, shift_value) + + In Diffie-Hellman Key-Exchange protocol, g and p - this is a public values. + Here, this can be customized, and this can be a private. + p, can be selected, as any safe-prime, from the some start_number: + p = BigInteger.GenSafePrime(new BigInteger().from('some seed, with a hexa(decimal)-value to compute this p')); + + g - this is primitive root, by modulo p. + The number of primitive roots by modulo p, is phi(phi(p)), + and when p is a safe-prime, then phi(phi(p)) = ( ( p-1 )/2 ) - 1 -> big number of primitive roots. + So, there is possible to use any primitive root, by modulo p. + For example, this can be depended from Index: + g = p.GetPrimitiveRoot(Index); + + Index, can be a private value too. + This can have unique values in range (1, ... phi(p)), where 0 = phi(p) (mod phi(p)), + and by modulo p, we have a circle, and finite field, with (p-1) elements (excluding 0-th element). + + Also, a big table of unique values can be generated, when: + Index = (i * floor(sqrt(p)) + j), where i and j, the number of i-th row, and j-th column in this table. + This i and j numbers can have value from 0 up to floor(sqrt(p)). + + After all, all this circle, can be rotated on "shift_value" indexes (shift_value mod phi(p) indexes): + Index = (i * floor(sqrt(p)) + j) + or Index = (i * floor(sqrt(p)) + j) mod phi(p) + or Index = (i * floor(sqrt(p)) + j + 0) mod phi(p) + or Index = (i * floor(sqrt(p)) + j + 0) mod (p-1) + or Index = (i * floor(sqrt(p)) + j + shift_value) mod (p-1) -> where shift_value = 0 + or Index = (i * floor(sqrt(p)) + j + shift_value) mod (p-1) -> where shift_value = any + or Index = (i * floor(sqrt(p)) + j + (shift_value mod phi(p)) ) mod (p-1) -> this is the same, by modulo phi(p) = (p-1), when p is prime. + + And shift_value can be private value too, which can be used to generate "Index", locally. + + All, this, allow to extract an unique pseudo-rand values, + from large table floor(sqrt(p)) * floor(sqrt(p)), + and extract it, just by indexes (i and j), + and extract this directly, like in Blum-Blum-Shub algorithm, by index, after compute that "Index". + + Any "prand", contains in range (1, (p-1)), + and can have bitlength up to (p.prev()).bitLength; + or bytelength up to ( ( (p.prev()).bitLength - (p.prev()).bitLength % 8 ) / 8 + (((p.prev()).bitLength%8 > 0) ? 1 : 0) ); + So, any "prand", can have a static bitlength, or bytelength of specified bits, + when p is a SafePrime, lesser than ((new BigInteger('2').pow(new BigInteger(bits))).subtract(1)); + + Seed values, can be specified on start, with index 'seed', + then, any "prand"-value can be extracted by index or [i, j], as BigIntegers, or as (hexa)decimals-strings. + */ + + //define this valuest to cache it, after seed, and do not re-compute this again and again, on each iteration. + var BRAPRNG_p = undefined; + var BRAPRNG_phi_p = undefined; + var BRAPRNG_FloorSqrtP = undefined; + var BRAPRNG_bits = undefined; + var BRAPRNG_g = undefined; + var BRAPRNG_shift_value = undefined; + + function BRAPRNG( + IndexOrObject_ij //Index (need to specify it) - string, or BigInteger, or array with strings ['0', '1'], or object with i and j: {'i':'1', 'j':'3'}, or 'seed' if seed specified on first start. + , set_p //(optional, seed or 'hex') - string or BigInteger with P, or start value of p, or number with bits, or 'hex', if need to return hex; + , set_g //(optional, seed) - string or BigInteger with g, or start number to generate g, or 'dynamic', to get g from Index. + , set_shiftValue //(optional, seed) - set shift-value, to generate Index from (i,j)-values. + ) + { + //console.log('start Bijective PRNG...'); + + if( + typeof BRAPRNG_p === 'undefined' + || ( + (typeof set_p !== 'undefined') + && (set_p !== 'hex') + ) + ){ + console.log('BRAPRNG_p - is undefined or must to be changed. Try to set it...'); + var gen_p = ( + ( + (set_p !== 'hex') + ? set_p + : undefined + ) + || prompt( + 'Enter the (hexa)decimal-string with safe-prime p\n' + + 'or with number from which previous safe-prime will be generated\n' + + 'or type nothing and cancel this prompt, to set default bitlength 256 bits.' + ) + || 256 + ) + ; + + if( + (typeof gen_p === 'number') + && (gen_p === 256) + ){ + gen_p = new bigInt('115792089237316195423570985008687907853269984665640564039457584007913129603823'); //first safe prime before 2^256 (to do not recalculate it for bitlength of 256 bits of input value "Index", and output value "prand") + } + else{ + gen_p = new bigInt().from(gen_p); + } + + BRAPRNG_p = bigInt.GenSafePrime(gen_p); + console.log('now BRAPRNG_p = ', BRAPRNG_p.toString()); + + BRAPRNG_phi_p = BRAPRNG_p.prev(); //phi(p) = (p-1), when p is prime, and moreover safe-prime. Save this value, to do not recalculate this. + + BRAPRNG_FloorSqrtP = BRAPRNG_p.sqrt('floor')[0]; //save this value to do not recalculate this. + + BRAPRNG_bits = BRAPRNG_p.bitLength().value; //save this value to get formatted hex-values, with fixed bitlength, in future; + } + if( + (typeof BRAPRNG_g === 'undefined') + || (typeof set_g !== 'undefined') + ){ + var gen_g = set_g + || prompt( + 'Enter (hexa)decimal-string to specify g\n' + + 'or the first number from which g will be generated, (default = 1, means first primitive root, from \'1\')\n' + + 'or type nothing and cancel prompt, to set default value of g as \'dynamic\', and depended from \'Index\'', '1' + ) + || 'dynamic' + ; + if(gen_g === 'dynamic'){ + BRAPRNG_g = gen_g; + }else{ + BRAPRNG_g = (BRAPRNG_p).GetPrimitiveRoot(new bigInt().from(gen_g)); + } + console.log('BRAPRNG_g', BRAPRNG_g.toString()); + + } + if( + (typeof BRAPRNG_shift_value === 'undefined') + || (typeof set_shiftValue !== 'undefined') + ){ + console.log('Set \'shift_value\' to rotate circle.'); + var use_shift_value = set_shiftValue + || prompt( + 'To rotate cicle on some number of indexes, specify the \'shift_value\'\n' + + 'as a (hexa)decimal-string (default = 0)\n' + + 'or type nothing and cancel prompt, to set default value as 0', '0' + ) + || '0' + ; + + BRAPRNG_shift_value = bigInt().from(use_shift_value); + console.log('BRAPRNG_shift_value', BRAPRNG_shift_value.toString()); + } + if(IndexOrObject_ij === 'seed'){console.log("seed accepted"); return;} + + if( + (typeof IndexOrObject_ij === 'object') + && ( + (typeof IndexOrObject_ij.i !== 'undefined') + || (typeof IndexOrObject_ij[0] !== 'undefined') + ) + && + ( + (typeof IndexOrObject_ij.j !== 'undefined') + || (typeof IndexOrObject_ij[1] !== 'undefined') + ) + ){ + var i = IndexOrObject_ij.i || IndexOrObject_ij[0]; + var j = IndexOrObject_ij.j || IndexOrObject_ij[1]; + + //console.log('i', i, 'j', j); + + var Index = ( + ( // ( + ( + ( + ( + new BigInteger().from(i) // i + ) + .multiply( // * + BRAPRNG_FloorSqrtP // floor(sqrt(p)) + ) + ) + .add( + new BigInteger().from(j) // +j + ) + ) + .add( + new BigInteger().from( + BRAPRNG_shift_value // +shift_value + ).mod( // mod + BRAPRNG_phi_p // phi(p) + ) + ) // ) + ) + .mod( // mod + BRAPRNG_phi_p // phi(p) + ) + ) + ; + } + else{ + // console.log('this...') + var Index = bigInt().from(IndexOrObject_ij) + .add( + BRAPRNG_shift_value + .mod( // mod + BRAPRNG_phi_p // phi(p) + ) + ) + ; + } + + // console.log( + // '\n' + 'BRAPRNG_p', BRAPRNG_p.toString(), + // '\n' + 'BRAPRNG_phi_p', BRAPRNG_phi_p.toString(), + // '\n' + 'BRAPRNG_FloorSqrtP', BRAPRNG_FloorSqrtP.toString(), + // '\n' + 'BRAPRNG_bits', BRAPRNG_bits.toString(), + // '\n' + 'BRAPRNG_g', BRAPRNG_g.toString() + // ); + + + //console.log('Index', Index.toString()); + + var use_g = ( + (BRAPRNG_g === 'dynamic') + ? (BRAPRNG_p).GetPrimitiveRoot(Index) + : BRAPRNG_g + ) + ; + + var prand = use_g.modPow(Index, BRAPRNG_p); //prand = g^Index mod p + prand = + (set_p !== 'hex') + ? prand + : prand + .toString(16) + .padStart( + ( + ( ( BRAPRNG_p.bitLength().value - BRAPRNG_p.bitLength().value % 8 ) / 8 ) + + ( ( BRAPRNG_p.bitLength().value % 8 > 0 ) ? 1 : 0 ) + ) + *2 + , '0' + ) + ; + return prand; //as BigInteger + } + //Usage: + // BigInteger.BRAPRNG( + // Index //Index, as string or BigInteger, or array with indexes, with string or with bigIntegers [i, j], or object {'i': i, 'j', j} + // , p //(optional) string or BigInteger - p, or the number from which need to find previous safe prime p, or string 'hex', if need to return hex with bytelength of p + // , g //(optional) string or Biginteger - g, or first value from which need to find g. Or string 'dynamic', to compute g from Index + // , shift_value //(optional) string or BigInteger - shift_value to rotate circle on shift_value mod phi(p) indexes. + // ).toString() + + // optional parameters, can be specified at first start of generator, + // then just Index, as string with Index, or array/object with i, j + 'hex', as second parameter 'p' + // Example: + // console.log( + // BigInteger.BRAPRNG('seed',256,'1','0') //set seed for generator (any value can bee undefined, to set it, using prompt) + // , BigInteger.BRAPRNG('1') //generate without seet + // , BigInteger.BRAPRNG('2') + // , BigInteger.BRAPRNG(['1', '1']) + // , BigInteger.BRAPRNG(['1', '2'], 'hex') //b4870a125e963a78979dcd0222fb973c12e6f1adcdd7167fb511cfd4ee8f5315 + // ); + + + //When p, g, and shift_value already defined, after set the BRAPRNG-seed + //there is possible to find unknown indexes (i, j) by hexadecimal value, with this function, + //by searching this, in growing square of the table: + function BRAPRNG_FindIJ(value){ + + // i 1 2 1 2 3 1 3 2 3 4 1 4 2 ... + // j 1 1 2 2 1 3 2 3 3 1 4 2 4 ... + // 1 2 3 + // 1*1 2*2 3*3 + // Square side is growing... + if(typeof BRAPRNG_FloorSqrtP === 'undefined'){console.log('set seed, at first'); return false;} + for (var i = new BigInteger('1'); i.leq(BRAPRNG_FloorSqrtP); i = i.next()){ + for (var j = new BigInteger('1'); j.leq(i); j = j.next()){ + // console.log('i', i.toString(), 'j', j.toString(), BRAPRNG([j, i], 'hex')); + if(BRAPRNG([i.toString(), j.toString()], 'hex') === value){ // compare (i, j) too + break; + } + else if(i.neq(j)){ //if i not equal of j, compare (j, i) too + // console.log('i', j.toString(), 'j', i.toString(), BRAPRNG([j, i], 'hex')); + if(BRAPRNG([j.toString(), i.toString()], 'hex') === value){ + var temp = i; // and change indexes + i = j; // i to j + j = temp; // j to i + break; + } + } + } + if(BRAPRNG([i.toString(), j.toString()], 'hex') === value){ + break; + } + } + return { 'i': (i.toString()), 'j': (j.toString()) }; + //BRAPRNG([i, j], 'hex') - element, after set seed. + } + //For example, indexes i, j, is not known, but seed (p, g, and shift_value) is known: + //and also, known some value: b4870a125e963a78979dcd0222fb973c12e6f1adcdd7167fb511cfd4ee8f5315 + //let's find this indexes: + // BigInteger.BRAPRNG('seed',256,'1','0') //seed generator (any value can bee undefined, to set it, using prompt) + // console.log( + // BigInteger.BRAPRNG_FindIJ('b4870a125e963a78979dcd0222fb973c12e6f1adcdd7167fb511cfd4ee8f5315') //{i: "1", j: "2"} + // , BigInteger.BRAPRNG(['1', '2'], 'hex') //b4870a125e963a78979dcd0222fb973c12e6f1adcdd7167fb511cfd4ee8f5315 + // ) + + + + + // Encoding/decoding bigIntegers <-> Strings var alphabet_36; //to cache generated alphabet for base up to 36 var alphabet_32768; //to cache generated alphabet for base up to 32768 @@ -1805,9 +2868,18 @@ var bigInt = BigInteger = (function (undefined) { Integer.gcd = gcd; Integer.lcm = lcm; Integer.isInstance = function (x) { return x instanceof BigInteger || x instanceof SmallInteger; }; - Integer.randBetween = randBetween; //randBetween(a, b, rng) + Integer.randBetween = randBetween; //randBetween(a, b, rng) Integer.randbits = get_random_k_bits; - Integer.getSetMRrounds = getSetMRrounds; //getSetMRrounds() or getSetMRrounds(rounds) - get or set the value of rounds MillerRabin, to check primality for prime numbers. + Integer.getSetMRrounds = getSetMRrounds; //getSetMRrounds() or getSetMRrounds(rounds) - get or set the value of rounds MillerRabin, to check primality for prime numbers. + Integer.from = from; //from(value), value - (hexa)decimal string, number, or bigInteger; + Integer.BBSBigInteger = BBSBigInteger; + Integer.GenSafePrime = generateSafePrime; //generateSafePrime(bitlength) + Integer.genStrongPrime = genStrongPrime; //genStrongPrime(bits, maxIter, strings) + Integer.isStrongPrime = isStrongPrime; //isStrongPrime(p, s, r, t) + Integer.EulerPhi = EulerPhi; //EulerPhi(n) + Integer.Factorize = Factorize; //factorize number, using Pollard-rho algorithm, with Richard Brent optimization. + Integer.BRAPRNG = BRAPRNG; //Bijective PRNG. + Integer.BRAPRNG_FindIJ = BRAPRNG_FindIJ; //Find (i and j), by value, in the square table, by grow the sqaure in this table. Integer.isBasicPrime = isBasicPrime; Integer.alphabet = //Access to alphabet ans show it, or set it, or generate it by base: BigInteger.alphabet(base) function(baseOrAlphabet){ @@ -1851,3 +2923,1293 @@ if (typeof define === "function" && define.amd) { return bigInt; }); } + +//RSABigInteger object with functions: +var RSABigInteger = (function (undefined) { + "use strict"; + + /* + This code allow to RSA-encrypt/RSA-decrypt, and RSA-sign/RSA-verify of bytearrays, with arbitrary bytelengths, using BigIntegers. + + Describe an RSA-operations: + m - message, c - encrypted message (cipher), e - public exponent, d - secret exponent, n - modulus, + (e, n) - public key, (d, n) - private key, m_ - decrypted message, s - signature; + + RSA Encrypt-decrypt: + (e, n) -> from owner for someone + c = m ^ e % n; - RSA-encrypt by owner's public key (someone) + c -> to owner of privkey + m_ = c ^ d % n; - RSA-decrypt by owner's private key (owner) + m_ === m - true, the main property. + + RSA Sign-Verify: + s = m ^ d % n; - RSA-sign by private key (owner) + (m, s, (e, n)) -> to someone; + m_ = s ^ e % n; - RSA-decrypt by public key (someone) + m_ === m - true, the main property. + + All this is working, using bigInt.modPow() + when m, e, d, n - is bigInegers, + and when m have value from 0 up to n-1, + then c and s have value from 0 up to n-1 too; + + For data with arbitrary bytelengths, + data can be readed by blocks, + blocks -> to hex, + hex -> to bigIntegers, + bigIntegers -> to cipher, and back. + + (e, n) - pubkey, (d, n) - privkey. + + c = m^e % n - encrypt by pub; + m_ = m^d % n - decrypt by priv; + + s = m^d % n - sign by priv; + m_ = m^e % n - extract by pub; + + When "m" is BigInteger in (0, ..., (n-1)), "c" and "s" is BigIntegers in (0, ..., (n-1)) too. + And m.modPow(exp, modulus), can be used. + + When "m" have arbitrary length, it must to be splitted by blocks with values in (0, ..., (n-1)); + When "m_block" have bitlength (n.bitLength()-1), or bytelength ( ( n.bitLength() - ( n.bitLength()%8 ) / 8 ) - ( ( n.bitLength()%8 > 0 ) ? 1 : 0 ) ), + any block can be encoded in bigitnegers with value in range (0, ..., (n-1)), and return cipher in the same range, with value up to (n-1) + with bitlength (n.bitLength()) and bytelength (n.bitLength() - (n.bitLength() % 8) / 8); + Different block-lengths make encryption/decrypion and sign/verify the different-function, dispite one function (modPow), to do this - RSA-operations. + + The following functions allow to do this: + RSABigInteger.EncryptBytes(key, src, byPriv) // Encrypt bytearray with arbitrary length by Pub (default), or byPriv (sign it). + RSABigInteger.DecryptBytes(key, src, byPub) // Decrypt bytearray with arbitrary length by Priv (default), or byPub (extract it from signature). + */ + + // Additional functions. + function hexToBase64(hstr) // Hex to Base64 + { + hstr = ((hstr.length%2 == 1)? '0'+hstr : hstr); //add one null, at beginning, if string length is odd. + return btoa( + String.fromCharCode.apply(null, + hstr.replace(/\r|\n/g, "").replace(/([\da-fA-F]{2}) ?/g, "0x$1 ").replace(/ +$/, "").split(" ") + ) + ); + } + RSABigInteger.hexToBase64 = hexToBase64; //hexToBase64(hstr) // Hex to Base64 + + function base64ToHex(b64str) // Base64 to Hex + { + for (var i = 0, bin = atob(b64str.replace(/[ \r\n]+$/, "")), hex = []; i < bin.length; ++i) { + var tmp = bin.charCodeAt(i).toString(16); + if (tmp.length === 1) tmp = "0" + tmp; + hex[hex.length] = tmp; + } + return hex.join(""); + } + RSABigInteger.base64ToHex = base64ToHex; //base64ToHex(b64str) // Base64 to Hex + + function B64ToBi ( b64 ) // Base64-string -> to BigInteger. + { + return new BigInteger(base64ToHex(b64), 16); + } + RSABigInteger.B64ToBi = B64ToBi; //B64ToBi ( b64 ) // Base64-string -> to BigInteger. + + function Bi2Base64 ( bi ) // BigInteger -> to Base64-string. + { + return hexToBase64(bi.toString(16)); + } + RSABigInteger.Bi2Base64 = Bi2Base64; //Bi2Base64 ( bi ) // BigInteger -> to Base64-string. + + function Combine (first, second) // Combine, and concatenate two arrays. + { + return first.concat(second); + } + RSABigInteger.Combine = Combine; //Combine(first, second) // Combine, and concatenate two arrays. + + // Methods to work with with ByteArrays. + function CombineUint8(first, second) // Combine, and concatenate two bytearrays(Uint8Arrays). + { + // 1. + var combined; + if(first.length === 0 || second.length === 0){ + combined = ((first.length > 0) ? first : second); + }else{ + combined = new Uint8Array(first.length + second.length); + combined.set(first, 0); + combined.set(second, first.length); + } + + // or 2. + // var first_str = first.join(','); var second_str = second.join(','); + // var combined_str = first_str + (((second_str !== '') && (first_str !== '')) ? ',' : '') + second_str; + // //console.log('first_str', first_str, 'second_str', second_str, 'combined_str', combined_str); + // var combined = new Uint8Array(combined_str.split(',')); //or by this way + + // or 3. + // var combined = new Uint8Array( (Array.from( first )).concat(Array.from( second ))); //or by this way + + return combined; + } + RSABigInteger.CombineUint8 = CombineUint8; //CombineUint8(first, second) // Combine, and concatenate two bytearrays. + + function CompareBytes(one, two) // Compare two bytearrays (Uint8Arrays) + { + return (one.toString() === two.toString()); + } + RSABigInteger.CompareBytes = CompareBytes; //CompareBytes(one, two) // Compare two bytearrays + + function diffarrays(arr1, arr2){ // Show differences between two arrays. + var maxlength = ( (arr1.length>arr2.length) ? arr1.length : arr2.length); + var res = ''; + for(var i = 0; i to JSON-string. + + var ready = false; //need to stop script, when keys loading or save. Default - false; true, when ready. + + //Generate RSA-key, and save in RSA_key-variable. + function GenerateRSAKeys( //Generate, and save RSA-keys + bitlength //bitlength can be specified, default value = 512, just for test (this is faster) + ) + { + ready = false; + bitlength = bitlength || 512; //default value = 512 bits, if undefined. + bitlength = (bitlength < 128 ? 128 : bitlength); //minimum is 128 bits, else, sometimes errors, in RSABigInteger.TEST()... + + /* + Crypto Strength of p and q. + + The values p and q must be a safe-primes, or strong primes, + and (p-1) with (q-1) must to have no common divisors (composition of common factors of this), + becides at least one common divisor beetween this - number 2, + just because since p and q is prime, this is odd, so (p-1) and (q-1) is even numbers, and 2 is a common divisor for this even numbers. + + Since n = pq, (n-1) = (pq-1) = (p−1)(q−1)+(p−1)+(q−1), + so any common divisors, and a greatest common divisor (as composition of all commmon factors) of secret values (p-1), (q-1), + contains in factorization order of public value (n-1), since n is public. + Moreover, g = gcd((p-1), (q-1)) is a divisor for secret value phi(n): + φ(n) / g = λ(n) - Carmichael's totient function. + + Proof: + Since n = pq, λ(n) = lcm(λ(p),λ(q)), and since p and q - primes, λ(p) = φ(p) = (p − 1), and λ(q) = φ(p) = (q − 1), + therefore, λ(n) = lcm((p − 1), (q − 1)), and since lcm(a,b) = |ab|/gcd(a,b), + then λ(n) = lcm((p-1), (q-1)) = |(p-1)(q-1)|/gcd((p-1), (q-1)). + What is "(p-1)(q-1)" ? this is φ(n), since p and q - is a primes. Moreover, this is natural number, and |φ(n)| = φ(n). + So: λ(n) = φ(n) / gcd((p-1), (q-1)), where gcd((p-1), (q-1)) = g, + This means: λ(n) = φ(n) / g, or φ(n) / g = λ(n) + + Also, this means g * λ(n) = φ(n), where g - this is a number privkeys, which are cryptoeqivalent privkeys for secret key d. + Because φ(n) always divisible on λ(n), and φ(n) / λ(n) = g, when e*d = 1 mod φ(n) is true, then e*d = 1 mod λ(n) is true too. + And for each d, can be finded some privkey d', which is cryptoequivalently for that secret privkey d: + (d' = d mod λ(n) === d' mod λ(n)), but look: (d' mod φ(n) !== d mod phi(n)); + For this conditions, is corresponding all keys, in this row: (d', d'+λ(n), d'+2λ(n), d'+3λ(n), ..., d'+(g-1)λ(n)), + and all this keys are privkeys, which are cryptoequivalently for privkey d. + + The number of this cryptoequivalently keys is growing, when g is growing, and since g = gcd((p-1), (q-1)), + this value is growing, when (p-1) and (q-1), have large greatest common divisors, + or many common-factors, as result of factorization private values (p-1), (q-1), + or just a public value (n-1), since n is public value. When g is large number, + then any d'+x*λ(n) is more easy to brute and force, just in range [0, ..., λ(n)]; + __________________ + 1. But, when p and q is a safe-prime numbers, then p' = (p-1)/2, q' = (p-1)/2 - Sophie-Germen prime-numbers, + and (p-1) = 2p', (q-1) = 2q', this numbers have only one common divisor - number 2, and another divisors are not common, this is a primes. + + 2. Also, when p and q is a strong-prime numbers, then (p-1) and (q-1) have large prime divisors and some another divisors, + which can be not a common divisors for both this numbers, together. + */ + + //use Safe-Primes for p and q: + var bi_p = BigInteger.GenSafePrime(BigInteger.randbits(bitlength/2), 'previous'); //generate p as random safe-prime, with half-bitlength of n. + var bi_q = bi_p; //q is p, on start. + while(bi_q.eq(bi_p)){ //while q == p + bi_q = BigInteger.GenSafePrime(BigInteger.randbits(bitlength/2), 'previous'); //generate safe prime q != p, with half-bitlength of n. + } + + // Also, can be used a strong-primes for p and q, but need to fix bitlength there, on genertion of this... + // var SP = BigInteger.genStrongPrime(20); + // console.log( + // 'StongPrime object: ', SP, + // 'Strong Prime value:', SP.p.toString(), + // 'isStrongPrime: ', BigInteger.isStrongPrime(SP.p, SP.s, SP.r, SP.t), + // 'bitlength: ', SP.p.bitLength().value + // ); + + var bi_n = bi_p.multiply(bi_q); //n = p*q + var lambdaN = BigInteger.lcm(bi_p.prev(), bi_q.prev()); + var bi_e = lambdaN.genCoPrime(lambdaN.bitLength().value); //lambdaN + + //continue generate values... + var bi_d = bi_e.modInv(lambdaN); //lambdaN - d = ( e^(−1) mod phi_n ) - is working, because (phi_n % λ(n) === 0), and for when (d*e ≡ 1 (mod λ(n))), (d*e ≡ 1 (mod λ(n))) too. But (d > λ(n)) can be true. + + // if(bi_e.geq(bi_d)){ //if e lesser or equals d + // var temp = bi_d; bi_d = bi_e; bi_e = temp; //swap bi_e <-> bi_d + // } //to return e, lesser than d, to keep secret a longer d. + + var bi_dp = bi_d.mod(bi_p.prev()); //dp = ( d mod (p−1) ) + var bi_dq = bi_d.mod(bi_q.prev()); //dq = ( d mod (q−1) ) + + var bi_InverseQ = bi_q.modInv(bi_p); //inverseQ = ( q^(−1) mod p ) + + //save pub (e,n) and priv (d, n); + RSA_key.e = bi_e; + RSA_key.d = bi_d; + RSA_key.n = bi_n; + + //save another values. + RSA_key.p = bi_p; + RSA_key.q = bi_q; + //additional values for accelleration + RSA_key.dp = bi_dp; + RSA_key.dq = bi_dq; + RSA_key.InverseQ = bi_InverseQ; + + //Try to save this generated values into xml-string. + // + // XML RSA-keys format (like in C# RSA.ToXmlString(Boolean), RSA.FromXmlString(Boolean)): + // + // Base64-encoded-number + // Base64-encoded-number + //

Base64-encoded-number

+ // Base64-encoded-number + // Base64-encoded-number + // Base64-encoded-number + // Base64-encoded-number + // Base64-encoded-number + //
+ // + // n - Modulus + // e - Exponent + // p - P + // q - Q + // d - D + // + // dp - DP, this is ( d mod (p−1) ), + // dq - DQ, this is ( d mod (q−1) ), + // InverseQ - this is ( q^(−1) mod p ). + // + // These are used in applying the Chinese Remainder Theorem to RSA decryption, which is an optimization technique. + // + + //Generate xml-string with RSA-privKey + RSA_key.xml_privKey = "" + // + "" + + "" + + "" + ( Bi2Base64( bi_n ) ) + "" + + "" + ( Bi2Base64( bi_e ) ) + "" + + "

" + ( Bi2Base64( bi_p ) ) + "

" + + "" + ( Bi2Base64( bi_q ) ) + "" + + "" + ( Bi2Base64( bi_dp ) ) + "" + + "" + ( Bi2Base64( bi_dq ) ) + "" + + "" + ( Bi2Base64( bi_InverseQ ) ) + "" + + "" + ( Bi2Base64( bi_d ) ) + "" + // + "
" + + "" + ; + //Format this as a multistring. + RSA_key.xml_privKey = RSA_key.xml_privKey + .replace(//g,">\n\t\t") + .replace(/\t\t\n/g,"") + // .replace(/\t<\/RSAKeyValue>\n\t\t/g,"") + .replace(/\t<\/RSAKeyValueBigInteger>\n\t\t/g,"") + .replace(/\n\t" + + "" + + "" + ( Bi2Base64( bi_n ) ) + "" + + "" + ( Bi2Base64( bi_e ) ) + "" + // + "" + + "" + ; + + RSA_key.xml_pubKey = RSA_key.xml_pubKey + .replace(//g,">\n\t\t") + .replace(/\t\t\n/g,"") + // .replace(/\t<\/RSAKeyValue>\n\t\t/g,"") + .replace(/\t<\/RSAKeyValueBigInteger>\n\t\t/g,"") + .replace(/\n\t") !== -1){ //if this was been a privKey, and this contains -value + //decode values from base64 fields of XML - and import this into BigIntegers + RSA_key.n = B64ToBi(xmlDoc.getElementsByTagName ("Modulus") [0].childNodes[0].nodeValue); // n + RSA_key.e = B64ToBi(xmlDoc.getElementsByTagName ("Exponent") [0].childNodes[0].nodeValue); // e + RSA_key.p = B64ToBi(xmlDoc.getElementsByTagName ("P") [0].childNodes[0].nodeValue); // p + RSA_key.q = B64ToBi(xmlDoc.getElementsByTagName ("Q") [0].childNodes[0].nodeValue); // q + RSA_key.dp = B64ToBi(xmlDoc.getElementsByTagName ("DP") [0].childNodes[0].nodeValue); // dp + RSA_key.dq = B64ToBi(xmlDoc.getElementsByTagName ("DQ") [0].childNodes[0].nodeValue); // dq + RSA_key.InverseQ = B64ToBi(xmlDoc.getElementsByTagName ("InverseQ") [0].childNodes[0].nodeValue); // InverseQ + RSA_key.d = B64ToBi(xmlDoc.getElementsByTagName ("D") [0].childNodes[0].nodeValue); // d + + RSA_key.xml_privKey = "" + // + "" + + "" + + "" + ( Bi2Base64( RSA_key.n ) ) + "" + + "" + ( Bi2Base64( RSA_key.e ) ) + "" + + "

" + ( Bi2Base64( RSA_key.p ) ) + "

" + + "" + ( Bi2Base64( RSA_key.q ) ) + "" + + "" + ( Bi2Base64( RSA_key.dp ) ) + "" + + "" + ( Bi2Base64( RSA_key.dq ) ) + "" + + "" + ( Bi2Base64( RSA_key.InverseQ ) ) + "" + + "" + ( Bi2Base64( RSA_key.d ) ) + "" + // + "
" + + "" + ; + //Format this as a multistring. + RSA_key.xml_privKey = RSA_key.xml_privKey + .replace(//g,">\n\t\t") + .replace(/\t\t\n/g,"") + // .replace(/\t<\/RSAKeyValue>\n\t\t/g,"") + .replace(/\t<\/RSAKeyValueBigInteger>\n\t\t/g,"") + .replace(/\n\t" + + "" + + "" + ( Bi2Base64( RSA_key.n ) ) + "" + + "" + ( Bi2Base64( RSA_key.e ) ) + "" + // + "" + + "" + ; + + RSA_key.xml_pubKey = RSA_key.xml_pubKey + .replace(//g,">\n\t\t") + .replace(/\t\t\n/g,"") + // .replace(/\t<\/RSAKeyValue>\n\t\t/g,"") + .replace(/\t<\/RSAKeyValueBigInteger>\n\t\t/g,"") + .replace(/\n\t 0)?1:0) ); +// ByteArray with source data, will be splitted by blocks with (BlockSiseToRead = ( BlockSizeToWrite - SubtractBytes )) bytes. +// This blocks will be encrypted by pubkey from "key", or pubkey which is extracted from prikey "key" (if no need to sign by privKey). +// Pubkey - is (e, n), where n, this is a modulus - a big number with specified "n_bitlength". +// The result ciphertext have "n_bitlength" bits, or "BlockSizeToWrite" bytes, and will be writted by blocks in encrypted bytearray. +// +// Last block will be encrypted as is, but after encrypting this block will be added a ulong-value (8 bytes) with "LastBlockLength". +// + + //Save length for blocks, to read-write data with arbitrary bytelenths. + + // Define this variables, to save the values of blocks to read openedText and cipher data. + var SubtractBytes, //how many bytes need to subtract from "result-block-length", to read "src-data", by blocks with "BlockSizeToWrite" + BlockSizeToWrite, //bytesize of block to write "dest-data". + BlockSiseToRead; //bytesize of block to read "src-data" + + //Set this values, by value of bitlength of modulus n. + function set_lengths( // Set lengths of blocks to read-write + n_bitlength //bitlength of modulus n from KeyFile + ) + { + //set this values: + SubtractBytes = 1; //select how many bytes need to subtract from each block. Default - 1 byte. + + BlockSizeToWrite = ( //BlockSizeToWrite for destination cipherData = n_bytelength (+ 1, when n_bitlength%8 > 0). + ( //n_bytelength + ( //= + n_bitlength //n_bitlength + - //- + ( n_bitlength % 8 ) //rest by modulo 8 (8 bits in byte) + ) + / //and divide + 8 //to 8 + ) + + //block-size will be + ( + ( + ( ( n_bitlength % 8 ) > 0 ) //if rest is over null + ) + ? 1 //is larger + : 0 //or the same + ) + ) + ; + + BlockSiseToRead = BlockSizeToWrite - SubtractBytes; //block length to read source openText data + // console.log('n_bitlength', n_bitlength, 'SubtractBytes', SubtractBytes, 'BlockSiseToRead', BlockSiseToRead); + return; //and return, then. + } + RSABigInteger.set_lengths = set_lengths; //set_lengths(n_bitlength) // Set lengths of blocks to read-write + //Usage: + //RSABigInteger.set_lengths(n_bitlength); //set length for read-write blocks, by n_bitlength, before read-write the data with arbitrary length. + + // Additional functions (need to encode-decode bytes): + function buf2hex(buffer) // ArrayBuffer to hex. buffer is an ArrayBuffer (Uint8Array.buffer) + { + return Array.prototype.map.call( new Uint8Array(buffer), function(x){ return (('00' + x.toString(16)).slice(-2));} ).join(''); + } + RSABigInteger.buf2hex = buf2hex; //buf2hex(buffer) // ArrayBuffer to hex. buffer is an ArrayBuffer (Uint8Array.buffer) + + function hex2buf(hex) // Hex to ArrayBuffer + { + hex = hex.padStart(2, '0'); + var typedArray = new Uint8Array( + hex.match(/[\da-fA-F]{2}/gi) + .map( + function (h) { + return parseInt(h, 16) + } + ) + ); + return typedArray.buffer; + } + RSABigInteger.hex2buf = hex2buf; //hex2buf(hex) // Hex to ArrayBuffer + + function hexToUint8( // Hex to Uint8Array + hexString + , padZeroBytes //null padding on start + ){ + hexString = hexString + .padStart( + ( + (typeof padZeroBytes !== 'undefined') + ? padZeroBytes*2 //number of hexadecimal characters if double bytes + : ( hexString.length + (hexString.length % 2) ) //or if hex string-length is odd, add 1 null at beginning. + ), + '0' + ) + ; + + return (new Uint8Array(hex2buf(hexString))); + } + RSABigInteger.hexToUint8 = hexToUint8; //hexToUint8(hexString, padZeroBytes) // Hex to Uint8Array + padding on start + + function Uint8ToHex(byteArray, padZeroBytes) // Uint8Array to Hex + { + return Array.prototype.map + .call( + byteArray, + function(byte) { + return ('0' + (byte & 0xFF).toString(16)).slice(-2); + } + ) + .join('') + .padStart( ( ( typeof padZeroBytes !== 'undefined' ) ? ( padZeroBytes*2 ) : 0 ), '0' ) + ; + } + RSABigInteger.Uint8ToHex = Uint8ToHex; //Uint8ToHex(byteArray, padZeroBytes) // Uint8Array to Hex + padding on start + //End additional functions. + + //function to write data in specified offset of block. + function WriteBlock( // Write src in the end of dest. + dest //here, in empty block, with fixed length + , src //write this data + ) + { + for( + var o = dest.length - src.length, j=0; //from offset "o", of dest array, and from offset "j" of src array + o to Hex -> to BigInteger + .modPow ( //by using modPow + ed, //to encrypt this buffer, into BigInteger, by e or d + n //and modulus n + ) + ) + ) + .toString(16) //convert BigInteger -> to Hex + , BlockSizeToWrite //and add Padding + ) + ; + encbuffer = WriteBlock(encbuffer, encryptedBuffer); //Write block in the end of encbuffer. + } + else //else if last block, and readed bytes not equals of BlockSiseToRead. + { + var buffer2 = new Uint8Array(c); + + for (var i = 0; i < c; i++){ + buffer2[i] = buffer[i]; + } + var encryptedBuffer; //define new encrypted buffer for result, this can have different length + encryptedBuffer = hexToUint8( //and encrypt + ( + (ed === 'chinese-remainder-theorem') + ? CRTAcceleration( + new BigInteger ( + ( (buffer.length === 0) ? '00' : Uint8ToHex(buffer2) ) + , 16 + ) + ) + : ( + ( + new BigInteger ( + ( (buffer.length === 0) ? '00' : Uint8ToHex(buffer2) ) + , 16 + ) + ) + .modPow (ed, n) //by using BigInteger modPow method + ) + ) + .toString(16) + , + BlockSizeToWrite + ) + ; + encbuffer = WriteBlock(encbuffer, encryptedBuffer); + var LastBlockLength = new Uint8Array(8); + LastBlockLength = hexToUint8(c.toString(16), 8); + encbuffer = CombineUint8(encbuffer, LastBlockLength); + } + + return encbuffer; + } + + //encrypt "src"-bytes with arbitrary bytelength. + function EncryptBytes( //Encrypt bytearray from src to dest, by using pubkey in key; + key //key - pub, for encrypt, or priv, to get pub from it, and encrypt then, if byPriv == false. This can be xml-string with key too. + , src //reference to bytearray with source data + , byPriv //encrypt by privKey to sing the message, and decrypt by pubKey, then. + , disableCRT + ) + { + byPriv = ( ( ( typeof byPriv === 'undefined' ) || (byPriv === false ) ) ? false : true ); //false, by default, or true; + disableCRT = ((typeof disableCRT === 'undefined') || (disableCRT === false)) ? false : true; + LoadXMLKey(key); //extract public key from "key"-file with xml. + var n_bitlength = 0; + n_bitlength = (RSA_key.n).bitLength().value; + set_lengths(n_bitlength); + + var buffer = new Uint8Array( BlockSiseToRead ); + var encbuffer = new Uint8Array ( BlockSizeToWrite ); + var c = 0; + + var ed = null; + var n = null; + ed = ed || ( + (byPriv === true) //if byPriv == true + ? + (disableCRT === false) + ? 'chinese-remainder-theorem' //then, use accelleration with chinese-remainder-theorem + : RSA_key.d //or use, d -> to BigInteger + : RSA_key.e //else, e -> to BigInteger + ); + n = RSA_key.n; //n -> to BigInteger + + var dest = new Uint8Array(0); + var i = 0; + while(i<=src.length){ + buffer = src.subarray(i, (i+=BlockSiseToRead)); + c = buffer.length; + encbuffer = EncryptFullBlockOrLastBlock(buffer, BlockSizeToWrite, BlockSiseToRead, c, ed, n); + dest = CombineUint8(dest, encbuffer); + } + return dest; + } + + //Decrypt one block of readed cipher. + //RSA decrypt + function DecryptFullBlockOrLastBlock( //Decrypt full block or last block inside the cycle. + buffer //readed buffer from the source file + , BlockSizeToWrite //already defined BlockSizeToWrite, as reference + , c //number of readed bytes, as reference + , isNextUlong //is next value ulong or not? true/false + , dataLength //Length of data + , de //de - d or e. d (secret exponent) - if decrypt by priv (d, n), (by default); or e (pubic exponent) - if decrypt by pub (verify signature) + , n //n - modulus + , current_block //number of the current block + , max_blocks //number of the max block to decrypt + , length__ //length of last block + ) + { + dataLength = dataLength || 0 ; + de = de || null ; + n = n || null ; + current_block = current_block || 0 ; + max_blocks = max_blocks || 0 ; + length__ = length__ || 0 ; + + var BufferLength = ( ( current_block == max_blocks-1 ) ? length__ : ( BlockSizeToWrite - SubtractBytes ) ); //length__ ! + + var decryptedBuffer = new Uint8Array( BlockSizeToWrite ); + var decbuffer = new Uint8Array( (((isNextUlong === true)) ? length__ : BlockSiseToRead ) ); + + decryptedBuffer = hexToUint8( //and encrypt + ( + (de === 'chinese-remainder-theorem') + ? CRTAcceleration(new BigInteger (Uint8ToHex(buffer), 16)) + : ( + (new BigInteger (Uint8ToHex(buffer), 16)) //buffer2 + .modPow (de, n) //by using BigInteger modPow method + ) + ) + .toString(16) + , + BufferLength + ) + ; + + decbuffer = WriteBlock(decbuffer, decryptedBuffer); + return decbuffer; + } + + + // + // Decrypt encrypted bytearray with cipher, by priv. + // (d, n) - privkey, where n have n_bitlength size, and n_bytelength. + // encrypted file readed by blocks with n_bytelength, + // this block will be decrypted, then result will writted to blocks with bytelength (n_bytelenght - 1). + // Last 8 bytes of encrypted file, this is ulong value with bytelength of last block. + // This value will be readed at beginning, and then this value need to skip, and slice the bytes of last block, then. + // + + //Decrypt cipher with arbitrary bytelength. + function DecryptBytes( + key //file with priv or pub + , src //reference on src-bytes + , byPub //default - false (decrypt by Priv); + , disableCRT + ) + { + byPub = ( ( ( typeof byPub === 'undefined' ) || (byPub === false) ) ? false : true ); + disableCRT = ((typeof disableCRT === 'undefined') || (disableCRT === false)) ? false : true; + + var length__ = 0; + var LastBlockLength = src.subarray(src.length-8, src.length); //read last 8 bytes with LastBlockLength + length__ = parseInt((new BigInteger (Uint8ToHex(LastBlockLength), 16)).toString(), 10); + + var dataLength = src.length; //get length of src. + + LoadXMLKey(key); //extract public key from "key"-file with xml. + + var n_bitlength = 0; + n_bitlength = (RSA_key.n).bitLength().value; + set_lengths(n_bitlength); + + var buffer = new Uint8Array(BlockSizeToWrite); + var decbuffer = new Uint8Array(BlockSiseToRead); + + var de = null; + var n = null; + de = de || ( + (byPub === true) + ? RSA_key.e + : + (disableCRT === false) + ? 'chinese-remainder-theorem' //then, use accelleration with chinese-remainder-theorem + : RSA_key.d //or use privKey to decrypt, by default + ) + ; + n = RSA_key.n; + + var max_blocks = Math.floor(src.length / BlockSizeToWrite); + var current_block = 0; + + var c = 0; + + var isNextUlong = false; + + var dest = new Uint8Array(0); + var i = 0; + while(i= (max_blocks-1) ){ + isNextUlong = true; + } + decbuffer = DecryptFullBlockOrLastBlock( + buffer + , BlockSizeToWrite + , c + , isNextUlong + , dataLength + , de + , n + , current_block + , max_blocks + , length__ + ) + ; + dest = CombineUint8(dest, decbuffer); + current_block += 1; + } + return dest; + } + + RSABigInteger.EncryptBytes = EncryptBytes; //EncryptBytes(key, src, byPriv) // Encrypt bytearray with arbitrary length by Pub (default), or byPriv (sign it). + RSABigInteger.DecryptBytes = DecryptBytes; //DecryptBytes(key, src, byPub) // Decrypt bytearray with arbitrary length by Priv (default), or byPub (extract it from signature). + //RSABigInteger.EncryptBytes(key, src, byPriv) + //RSABigInteger.DecryptBytes(key, src, byPub) + + //This functions can be used for encrypt-decrypt or sign-verify, with different keys. + // c = m^e mod n - encrypt by pub + // m_ = m^d mod n - decrypt by priv + // s = m^d mod n - sing by priv + // e = s^e mod n - extract message from signature, to verify it. + + function TEST(){ + // TEST: + var rand_byte = (window.crypto.getRandomValues(new Uint8Array(1))[0]) + 8; + console.log('rand_byte', rand_byte); + + RSABigInteger.GenerateRSAKeys(rand_byte); //generate keys + //console.log('RSABigInteger.RSA_key', RSABigInteger.RSA_key); + + var rand_message = window.crypto.getRandomValues(new Uint8Array(window.crypto.getRandomValues(new Uint8Array(1))[0])); + //console.log('rand_message', rand_message.toString()); + + var readyInterval = setInterval( //wait some time to write key. + function(){ + if(ready===false){return;} //if not ready, return and repeat, by interval + else{clearInterval(readyInterval)}; //else clearInterval, and continue with this code. + + var encdec = false; //test encrypt-decrypt + console.log( + 'RSA encrypt by pub, decrypt by priv:\t', + ( + encdec = + RSABigInteger.CompareBytes( + rand_message, + RSABigInteger.DecryptBytes( + RSABigInteger.RSA_key.xml_privKey, + RSABigInteger.EncryptBytes( + RSABigInteger.RSA_key.xml_pubKey, + rand_message, + false + ), + false + ) + ) + , encdec //and return it + ) + ); + + var signverify = false; //test encrypt-decrypt + console.log( + 'sign by priv, verify signature by pub:\t', + ( + signverify = + RSABigInteger.CompareBytes( + rand_message, + RSABigInteger.DecryptBytes( + RSABigInteger.RSA_key.xml_pubKey, + RSABigInteger.EncryptBytes( + RSABigInteger.RSA_key.xml_privKey, + rand_message, + true + ), + true + ) + ) + , signverify //and return it + ) + ); + + if(encdec === false || signverify === false){ + if(encdec === false){console.log('encdec === false');} + else if(signverify === false){console.log('signverify === false');} + // and show two variables for static-test + console.log( + '//multistring variable with privkey to load it;\n'+ + 'var rsaprivkey = (function () {/*'+RSABigInteger.RSA_key.xml_privKey+ + '\n*/}).toString().match(/[^]*\\\/\\*([^]*)\\*\\\/\\}$\/)[1];' + '\n' + + '//bytearray with generated message\n'+ + 'var rand_message = new Uint8Array(['+rand_message.toString()+']);' + ); + } + }, + 1 //wait to generate or load keys, and write it. + ); + } + + function STATIC_TEST(){ //test with static values to debug it. + +// copy and paste two generated variables, on fail, to debug that fail. +//____________________ + +//multistring variable with privkey to load it; +var rsaprivkey = (function () {/* + + VpqsJoYYQ9k= + + + PUFutJpgMDM= + +

+ qbYkLw== +

+ + gqMudw== + + + TnHzZQ== + + + Gb718w== + + + FoEoVQ== + + + FcEhbznTNec= + +
+*/}).toString().match(/[^]*\/\*([^]*)\*\/\}$/)[1]; +//bytearray with generated message +var rand_message = new Uint8Array([14,86,57,157,225,178,156,2,205,1,232,157,227,157,237,204,76,102,30,102,251,244,217,41,141,226,15,183,154,59,179,97,115,184,236,70,170,97,240,235,192,205,223,192,33,139,232,133,45,131,222,20,205,152,119,211,249,45,56,240,131,205,254,88,4,246,21,159,79,229,187,194,123,0,46,194,11,97,211,167,92,34,109,7,96,119,240,71,71,14,117,139,22,6,204,209,101,177,163,244,148,111,235,195,160,55,31,77,83,10,139,65,30,170,196,209,237,222,184,2,25,184,78,214,15,134,221,182,84,17,96,190,86,28,217,12,169,0,32,163,132,5,140,18,94,115,33,208,54,18,116,123,86,164,140,29,245,96,48,255,135,44,166,49,198,71,188,126,200,165,7,117,30,215,182,68,58,169,204,186,119,216,143,20,41,218,50,214,176,186,59,170,204,189,96,63,11,161,165,21,205,227,239,114,224,127,120,149,197,220,32,98,63,241,43,127,196,232,175,132,211,242,112,234,214,6,78,239,144,13,251,45,102,237,175,225,86,25,185]); + +//____________________ + + //and continue test it... + RSABigInteger.LoadXMLKey(rsaprivkey); //load key from multistring variable. + + //test encrypt-decrypt: + //console.log('rand_message', 'var rand_message = new Uint8Array(['+rand_message.toString()+']);'); + //console.log('xml_privKey', RSABigInteger.RSA_key.xml_privKey, '\nxml_pubKey', RSABigInteger.RSA_key.xml_pubKey); + + var readyInterval = setInterval( function(){ + if(ready===false){return;} //if not ready, return and repeat, by interval + else{clearInterval(readyInterval)}; //else clearInterval, and continue with this code. + + var encrypted, decrypted; + console.log( + 'RSA encrypt by pub, decrypt by priv:\t', + RSABigInteger.CompareBytes( + rand_message, + ( + decrypted = + RSABigInteger.DecryptBytes( + RSABigInteger.RSA_key.xml_privKey, + ( + encrypted = + RSABigInteger.EncryptBytes( + RSABigInteger.RSA_key.xml_pubKey, + rand_message, + false + ) + , encrypted //and return it + ), + false + ) + , decrypted //and return it + ) + ) + ); + console.log('encrypted.toString()', encrypted.toString()); + console.log('decrypted.toString()', decrypted.toString()); + + //test sign-verify + var signed, verified; + console.log( + 'sign by priv, verify signature by pub:\t', + RSABigInteger.CompareBytes( + rand_message, + ( + verified = + RSABigInteger.DecryptBytes( + RSABigInteger.RSA_key.xml_pubKey, + ( + signed = + RSABigInteger.EncryptBytes( + RSABigInteger.RSA_key.xml_privKey, + rand_message, + true + ) + , signed //and return it + ), + true + ) + , verified //and return it + ) + ) + ); + console.log('signed.toString()', signed.toString()); + console.log('verified.toString()', verified.toString()); + } + , + 1 + ); + + + } + + function RSABigInteger(){} //empty constructor for this object. + + //Add functions to RSABigInteger-object. All this available by call RSABigInteger.function(params); + RSABigInteger.TEST = TEST; //TEST() // Test RSA encryption-decryption. + RSABigInteger.STATIC_TEST = STATIC_TEST; //STATIC_TEST() // STATIC_TEST RSA encryption-decryption, and debug it, after copy-and-paste the values from test. + + return RSABigInteger; //return RSABigInteger-object, with functions inside. + +})(); + +// Now, add few polyfills (if this still not supported in old browsers): + +//String.repeat - polyfill (using in String.padStart) +if (!String.prototype.repeat) { + String.prototype.repeat = function(count) { + 'use strict'; + if (this == null) { + throw new TypeError('can\'t convert ' + this + ' to object'); + } + var str = '' + this; + count = +count; + if (count != count) { + count = 0; + } + if (count < 0) { + throw new RangeError('repeat count must be non-negative'); + } + if (count == Infinity) { + throw new RangeError('repeat count must be less than infinity'); + } + count = Math.floor(count); + if (str.length == 0 || count == 0) { + return ''; + } + // Обеспечение того, что count является 31-битным целым числом, позволяет нам значительно + // соптимизировать главную часть функции. Впрочем, большинство современных (на август + // 2014 года) браузеров не обрабатывают строки, длиннее 1 << 28 символов, так что: + if (str.length * count >= 1 << 28) { + throw new RangeError('repeat count must not overflow maximum string size'); + } + var rpt = ''; + for (var i = 0; i < count; i++) { + rpt += str; + } + return rpt; + } +} + +// String.padStart - polyfill (using in some functions - keyword "padStart") +// https://github.com/uxitten/polyfill/blob/master/string.polyfill.js +// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/padStart +if (!String.prototype.padStart) { + String.prototype.padStart = function padStart(targetLength,padString) { + targetLength = targetLength>>0; //floor if number or convert non-number to 0; + padString = String(padString || ' '); + if (this.length > targetLength) { + return String(this); + } + else { + targetLength = targetLength-this.length; + if (targetLength > padString.length) { + padString += padString.repeat(targetLength/padString.length); //append to original to ensure we are longer than needed + } + return padString.slice(0,targetLength) + String(this); + } + }; +} + +//Additional functions: +function B64ToHex(b64) { + var bin = atob(b64); + var hex = []; + + bin.split('') +// .forEach + .map + (function (ch) { + var h = ch.charCodeAt(0).toString(16); + if (h.length % 2) { h = '0' + h; } + hex.push(h); + }); + + return hex.join(''); +} +//console.log(B64ToHex('AQAB')); //010001 + +function HexToB64(hex) { + if (hex.length % 2) { hex = '0' + hex; } + + var bin = [], i = 0, d, b; + while (i < hex.length) { + d = parseInt(hex.slice(i, i + 2), 16); + b = String.fromCharCode(d); + bin.push(b); + i += 2; + } + + return btoa(bin.join('')); +} +//console.log(HexToB64('10001')); //AQAB