﻿// AES based pseudorandom number generator
/* Constructor. Called with an array of 32 byte (0-255) values
containing the initial seed. */
function AESprng(seed) {
    this.key = new Array();
    this.key = seed;
    this.itext = hexToByteArray("9F489613248148F9C27945C6AE62EECA3E3367BB14064E4E6DC67A9F28AB3BD1");
    this.nbytes = 0; // Bytes left in buffer
    this.next = AESprng_next;
    this.nextbits = AESprng_nextbits;
    this.nextInt = AESprng_nextInt;
    this.round = AESprng_round;
    /* Encrypt the initial text with the seed key
    three times, feeding the output of the encryption
    back into the key for the next round. */
    bsb = blockSizeInBits;
    blockSizeInBits = 256;
    var i, ct;
    for (i = 0; i < 3; i++) {
        this.key = rijndaelEncrypt(this.itext, this.key, "ECB");
    }
    /* Now make between one and four additional
    key-feedback rounds, with the number determined
    by bits from the result of the first three
    rounds. */
    var n = 1 + (this.key[3] & 2) + (this.key[9] & 1);
    for (i = 0; i < n; i++) {
        this.key = rijndaelEncrypt(this.itext, this.key, "ECB");
    }
    blockSizeInBits = bsb;
}
function AESprng_round() {
    bsb = blockSizeInBits;
    blockSizeInBits = 256;
    this.key = rijndaelEncrypt(this.itext, this.key, "ECB");
    this.nbytes = 32;
    blockSizeInBits = bsb;
}
// Return next byte from the generator
function AESprng_next() {
    if (this.nbytes <= 0) {
        this.round();
    }
    return (this.key[--this.nbytes]);
}
// Return n bit integer value (up to maximum integer size)
function AESprng_nextbits(n) {
    var i, w = 0, nbytes = Math.floor((n + 7) / 8);
    for (i = 0; i < nbytes; i++) {
        w = (w << 8) | this.next();
    }
    return w & ((1 << n) - 1);
}
// Return integer between 0 and n inclusive
function AESprng_nextInt(n) {
    var p = 1, nb = 0;
    // Determine smallest p, 2^p > n
    // nb = log_2 p
    while (n >= p) {
        p <<= 1;
        nb++;
    }
    p--;
    /* Generate values from 0 through n by first generating
    values v from 0 to (2^p)-1, then discarding any results v > n.
    For the rationale behind this (and why taking
    values mod (n + 1) is biased toward smaller values, see
    Ferguson and Schneier, "Practical Cryptography",
    ISBN 0-471-22357-3, section 10.8). */
    while (true) {
        var v = this.nextbits(nb) & p;
        if (v <= n) {
            return v;
        }
    }
}
