| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297 | 
							- /**
 
-  * Prime number generation API.
 
-  *
 
-  * @author Dave Longley
 
-  *
 
-  * Copyright (c) 2014 Digital Bazaar, Inc.
 
-  */
 
- var forge = require('./forge');
 
- require('./util');
 
- require('./jsbn');
 
- require('./random');
 
- (function() {
 
- // forge.prime already defined
 
- if(forge.prime) {
 
-   module.exports = forge.prime;
 
-   return;
 
- }
 
- /* PRIME API */
 
- var prime = module.exports = forge.prime = forge.prime || {};
 
- var BigInteger = forge.jsbn.BigInteger;
 
- // primes are 30k+i for i = 1, 7, 11, 13, 17, 19, 23, 29
 
- var GCD_30_DELTA = [6, 4, 2, 4, 2, 4, 6, 2];
 
- var THIRTY = new BigInteger(null);
 
- THIRTY.fromInt(30);
 
- var op_or = function(x, y) {return x|y;};
 
- /**
 
-  * Generates a random probable prime with the given number of bits.
 
-  *
 
-  * Alternative algorithms can be specified by name as a string or as an
 
-  * object with custom options like so:
 
-  *
 
-  * {
 
-  *   name: 'PRIMEINC',
 
-  *   options: {
 
-  *     maxBlockTime: <the maximum amount of time to block the main
 
-  *       thread before allowing I/O other JS to run>,
 
-  *     millerRabinTests: <the number of miller-rabin tests to run>,
 
-  *     workerScript: <the worker script URL>,
 
-  *     workers: <the number of web workers (if supported) to use,
 
-  *       -1 to use estimated cores minus one>.
 
-  *     workLoad: the size of the work load, ie: number of possible prime
 
-  *       numbers for each web worker to check per work assignment,
 
-  *       (default: 100).
 
-  *   }
 
-  * }
 
-  *
 
-  * @param bits the number of bits for the prime number.
 
-  * @param options the options to use.
 
-  *          [algorithm] the algorithm to use (default: 'PRIMEINC').
 
-  *          [prng] a custom crypto-secure pseudo-random number generator to use,
 
-  *            that must define "getBytesSync".
 
-  *
 
-  * @return callback(err, num) called once the operation completes.
 
-  */
 
- prime.generateProbablePrime = function(bits, options, callback) {
 
-   if(typeof options === 'function') {
 
-     callback = options;
 
-     options = {};
 
-   }
 
-   options = options || {};
 
-   // default to PRIMEINC algorithm
 
-   var algorithm = options.algorithm || 'PRIMEINC';
 
-   if(typeof algorithm === 'string') {
 
-     algorithm = {name: algorithm};
 
-   }
 
-   algorithm.options = algorithm.options || {};
 
-   // create prng with api that matches BigInteger secure random
 
-   var prng = options.prng || forge.random;
 
-   var rng = {
 
-     // x is an array to fill with bytes
 
-     nextBytes: function(x) {
 
-       var b = prng.getBytesSync(x.length);
 
-       for(var i = 0; i < x.length; ++i) {
 
-         x[i] = b.charCodeAt(i);
 
-       }
 
-     }
 
-   };
 
-   if(algorithm.name === 'PRIMEINC') {
 
-     return primeincFindPrime(bits, rng, algorithm.options, callback);
 
-   }
 
-   throw new Error('Invalid prime generation algorithm: ' + algorithm.name);
 
- };
 
- function primeincFindPrime(bits, rng, options, callback) {
 
-   if('workers' in options) {
 
-     return primeincFindPrimeWithWorkers(bits, rng, options, callback);
 
-   }
 
-   return primeincFindPrimeWithoutWorkers(bits, rng, options, callback);
 
- }
 
- function primeincFindPrimeWithoutWorkers(bits, rng, options, callback) {
 
-   // initialize random number
 
-   var num = generateRandom(bits, rng);
 
-   /* Note: All primes are of the form 30k+i for i < 30 and gcd(30, i)=1. The
 
-   number we are given is always aligned at 30k + 1. Each time the number is
 
-   determined not to be prime we add to get to the next 'i', eg: if the number
 
-   was at 30k + 1 we add 6. */
 
-   var deltaIdx = 0;
 
-   // get required number of MR tests
 
-   var mrTests = getMillerRabinTests(num.bitLength());
 
-   if('millerRabinTests' in options) {
 
-     mrTests = options.millerRabinTests;
 
-   }
 
-   // find prime nearest to 'num' for maxBlockTime ms
 
-   // 10 ms gives 5ms of leeway for other calculations before dropping
 
-   // below 60fps (1000/60 == 16.67), but in reality, the number will
 
-   // likely be higher due to an 'atomic' big int modPow
 
-   var maxBlockTime = 10;
 
-   if('maxBlockTime' in options) {
 
-     maxBlockTime = options.maxBlockTime;
 
-   }
 
-   _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback);
 
- }
 
- function _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback) {
 
-   var start = +new Date();
 
-   do {
 
-     // overflow, regenerate random number
 
-     if(num.bitLength() > bits) {
 
-       num = generateRandom(bits, rng);
 
-     }
 
-     // do primality test
 
-     if(num.isProbablePrime(mrTests)) {
 
-       return callback(null, num);
 
-     }
 
-     // get next potential prime
 
-     num.dAddOffset(GCD_30_DELTA[deltaIdx++ % 8], 0);
 
-   } while(maxBlockTime < 0 || (+new Date() - start < maxBlockTime));
 
-   // keep trying later
 
-   forge.util.setImmediate(function() {
 
-     _primeinc(num, bits, rng, deltaIdx, mrTests, maxBlockTime, callback);
 
-   });
 
- }
 
- // NOTE: This algorithm is indeterminate in nature because workers
 
- // run in parallel looking at different segments of numbers. Even if this
 
- // algorithm is run twice with the same input from a predictable RNG, it
 
- // may produce different outputs.
 
- function primeincFindPrimeWithWorkers(bits, rng, options, callback) {
 
-   // web workers unavailable
 
-   if(typeof Worker === 'undefined') {
 
-     return primeincFindPrimeWithoutWorkers(bits, rng, options, callback);
 
-   }
 
-   // initialize random number
 
-   var num = generateRandom(bits, rng);
 
-   // use web workers to generate keys
 
-   var numWorkers = options.workers;
 
-   var workLoad = options.workLoad || 100;
 
-   var range = workLoad * 30 / 8;
 
-   var workerScript = options.workerScript || 'forge/prime.worker.js';
 
-   if(numWorkers === -1) {
 
-     return forge.util.estimateCores(function(err, cores) {
 
-       if(err) {
 
-         // default to 2
 
-         cores = 2;
 
-       }
 
-       numWorkers = cores - 1;
 
-       generate();
 
-     });
 
-   }
 
-   generate();
 
-   function generate() {
 
-     // require at least 1 worker
 
-     numWorkers = Math.max(1, numWorkers);
 
-     // TODO: consider optimizing by starting workers outside getPrime() ...
 
-     // note that in order to clean up they will have to be made internally
 
-     // asynchronous which may actually be slower
 
-     // start workers immediately
 
-     var workers = [];
 
-     for(var i = 0; i < numWorkers; ++i) {
 
-       // FIXME: fix path or use blob URLs
 
-       workers[i] = new Worker(workerScript);
 
-     }
 
-     var running = numWorkers;
 
-     // listen for requests from workers and assign ranges to find prime
 
-     for(var i = 0; i < numWorkers; ++i) {
 
-       workers[i].addEventListener('message', workerMessage);
 
-     }
 
-     /* Note: The distribution of random numbers is unknown. Therefore, each
 
-     web worker is continuously allocated a range of numbers to check for a
 
-     random number until one is found.
 
-     Every 30 numbers will be checked just 8 times, because prime numbers
 
-     have the form:
 
-     30k+i, for i < 30 and gcd(30, i)=1 (there are 8 values of i for this)
 
-     Therefore, if we want a web worker to run N checks before asking for
 
-     a new range of numbers, each range must contain N*30/8 numbers.
 
-     For 100 checks (workLoad), this is a range of 375. */
 
-     var found = false;
 
-     function workerMessage(e) {
 
-       // ignore message, prime already found
 
-       if(found) {
 
-         return;
 
-       }
 
-       --running;
 
-       var data = e.data;
 
-       if(data.found) {
 
-         // terminate all workers
 
-         for(var i = 0; i < workers.length; ++i) {
 
-           workers[i].terminate();
 
-         }
 
-         found = true;
 
-         return callback(null, new BigInteger(data.prime, 16));
 
-       }
 
-       // overflow, regenerate random number
 
-       if(num.bitLength() > bits) {
 
-         num = generateRandom(bits, rng);
 
-       }
 
-       // assign new range to check
 
-       var hex = num.toString(16);
 
-       // start prime search
 
-       e.target.postMessage({
 
-         hex: hex,
 
-         workLoad: workLoad
 
-       });
 
-       num.dAddOffset(range, 0);
 
-     }
 
-   }
 
- }
 
- /**
 
-  * Generates a random number using the given number of bits and RNG.
 
-  *
 
-  * @param bits the number of bits for the number.
 
-  * @param rng the random number generator to use.
 
-  *
 
-  * @return the random number.
 
-  */
 
- function generateRandom(bits, rng) {
 
-   var num = new BigInteger(bits, rng);
 
-   // force MSB set
 
-   var bits1 = bits - 1;
 
-   if(!num.testBit(bits1)) {
 
-     num.bitwiseTo(BigInteger.ONE.shiftLeft(bits1), op_or, num);
 
-   }
 
-   // align number on 30k+1 boundary
 
-   num.dAddOffset(31 - num.mod(THIRTY).byteValue(), 0);
 
-   return num;
 
- }
 
- /**
 
-  * Returns the required number of Miller-Rabin tests to generate a
 
-  * prime with an error probability of (1/2)^80.
 
-  *
 
-  * See Handbook of Applied Cryptography Chapter 4, Table 4.4.
 
-  *
 
-  * @param bits the bit size.
 
-  *
 
-  * @return the required number of iterations.
 
-  */
 
- function getMillerRabinTests(bits) {
 
-   if(bits <= 100) return 27;
 
-   if(bits <= 150) return 18;
 
-   if(bits <= 200) return 15;
 
-   if(bits <= 250) return 12;
 
-   if(bits <= 300) return 9;
 
-   if(bits <= 350) return 8;
 
-   if(bits <= 400) return 7;
 
-   if(bits <= 500) return 6;
 
-   if(bits <= 600) return 5;
 
-   if(bits <= 800) return 4;
 
-   if(bits <= 1250) return 3;
 
-   return 2;
 
- }
 
- })();
 
 
  |