Source: BlumBlumShub.js

/**
 * xethya-random-bbs
 *
 * Copyright © 2016 Joel A. Villarreal Bertoldi. All rights reserved.
 *
 * This source code is licensed under the MIT license found in the
 * LICENSE.txt file in the root directory of this source tree.
 */

/**
 * Default constant value for setting up the BBS PRNG.
 * P must be a prime number.
 * @type {Number}
 */
const P = 87566873;

/**
 * Default constant value for setting up the BBS PRNG.
 * Q must be a prime number.
 * @type {Number}
 */
const Q = 5631179;

/**
 * A list of default seed values, tested to be evenly distributed.
 * @see  http://wiki.fib.upc.es/sim/index.php/Blum_Blum_Shub#Tests
 * @type {Array.<Number>}
 */
const DefaultSeeds = [193945, 740191, 191];

/**
 * Instantiates a Blum Blum Shub PRNG.
 */
class BlumBlumShub {

  /**
   * Initializes the generator.
   *
   * @param  {Number} p    A prime value (defaults to P).
   * @param  {Number} q    A prime value (defaults to Q).
   * @param  {Number} seedNumber A seed number to feed the generator (defaults to any value
   *                       in DefaultSeeds).
   * @constructor
   */
  constructor(settings) {
    const defaults = {
      p: P,
      q: Q,
      seedNumber: null,
    };

    this.settings = Object.assign({}, defaults, settings);

    let seedNumber = this.settings.seedNumber;
    const { p, q } = this.settings;

    if (seedNumber) {
      seedNumber = Math.abs(seedNumber);
    } else {
      seedNumber = DefaultSeeds[Math.floor(Math.random() * (DefaultSeeds.length))];
    }

    this.seedNumber = seedNumber;
    this.randomIndex = seedNumber;
    this.M = p * q;
    this.P = p;
    this.Q = q;
  }

  /**
   * Determines if the generator works better by being reinstantiated after
   * every generated number.
   *
   * @return {Boolean}
   * @static
   */
  static recommendsToReinstantiate() {
    return false;
  }

  /**
   * Generates a pseudo-random number and updates the seed for a next roll.
   * Number is always between 0 and 1.
   *
   * @return {Number}
   */
  generateRandom() {
    const r = this.randomIndex * this.randomIndex % this.M;
    this.randomIndex = r;
    return Math.abs(r / this.M);
  }

  /**
   * Same as `generateRandom()`, but converts the number to an Integer.
   *
   * @return {Number}
   */
  generateRandomInteger() {
    return Number(this.generateRandom().toString().replace(/\./, ''));
  }
}

export { P, Q, DefaultSeeds, BlumBlumShub };