From 06c662cc14ef64827b4622e2d643fd99d4304049 Mon Sep 17 00:00:00 2001
From: wltsmrz
Date: Fri, 7 Mar 2014 14:45:38 -0800
Subject: [PATCH] Add build/sjcl, remove grunt postinstall step
---
build/sjcl.js | 4125 +++++++++++++++++++++++++++++++++++++++++++++++++
package.json | 3 +-
2 files changed, 4126 insertions(+), 2 deletions(-)
create mode 100644 build/sjcl.js
diff --git a/build/sjcl.js b/build/sjcl.js
new file mode 100644
index 00000000..0f803799
--- /dev/null
+++ b/build/sjcl.js
@@ -0,0 +1,4125 @@
+/** @fileOverview Javascript cryptography implementation.
+ *
+ * Crush to remove comments, shorten variable names and
+ * generally reduce transmission size.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+"use strict";
+/*jslint indent: 2, bitwise: false, nomen: false, plusplus: false, white: false, regexp: false */
+/*global document, window, escape, unescape */
+
+/** @namespace The Stanford Javascript Crypto Library, top-level namespace. */
+var sjcl = {
+ /** @namespace Symmetric ciphers. */
+ cipher: {},
+
+ /** @namespace Hash functions. Right now only SHA256 is implemented. */
+ hash: {},
+
+ /** @namespace Key exchange functions. Right now only SRP is implemented. */
+ keyexchange: {},
+
+ /** @namespace Block cipher modes of operation. */
+ mode: {},
+
+ /** @namespace Miscellaneous. HMAC and PBKDF2. */
+ misc: {},
+
+ /**
+ * @namespace Bit array encoders and decoders.
+ *
+ * @description
+ * The members of this namespace are functions which translate between
+ * SJCL's bitArrays and other objects (usually strings). Because it
+ * isn't always clear which direction is encoding and which is decoding,
+ * the method names are "fromBits" and "toBits".
+ */
+ codec: {},
+
+ /** @namespace Exceptions. */
+ exception: {
+ /** @constructor Ciphertext is corrupt. */
+ corrupt: function(message) {
+ this.toString = function() { return "CORRUPT: "+this.message; };
+ this.message = message;
+ },
+
+ /** @constructor Invalid parameter. */
+ invalid: function(message) {
+ this.toString = function() { return "INVALID: "+this.message; };
+ this.message = message;
+ },
+
+ /** @constructor Bug or missing feature in SJCL. @constructor */
+ bug: function(message) {
+ this.toString = function() { return "BUG: "+this.message; };
+ this.message = message;
+ },
+
+ /** @constructor Something isn't ready. */
+ notReady: function(message) {
+ this.toString = function() { return "NOT READY: "+this.message; };
+ this.message = message;
+ }
+ }
+};
+
+if(typeof module != 'undefined' && module.exports){
+ module.exports = sjcl;
+}
+
+/** @fileOverview Low-level AES implementation.
+ *
+ * This file contains a low-level implementation of AES, optimized for
+ * size and for efficiency on several browsers. It is based on
+ * OpenSSL's aes_core.c, a public-domain implementation by Vincent
+ * Rijmen, Antoon Bosselaers and Paulo Barreto.
+ *
+ * An older version of this implementation is available in the public
+ * domain, but this one is (c) Emily Stark, Mike Hamburg, Dan Boneh,
+ * Stanford University 2008-2010 and BSD-licensed for liability
+ * reasons.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/**
+ * Schedule out an AES key for both encryption and decryption. This
+ * is a low-level class. Use a cipher mode to do bulk encryption.
+ *
+ * @constructor
+ * @param {Array} key The key as an array of 4, 6 or 8 words.
+ *
+ * @class Advanced Encryption Standard (low-level interface)
+ */
+sjcl.cipher.aes = function (key) {
+ if (!this._tables[0][0][0]) {
+ this._precompute();
+ }
+
+ var i, j, tmp,
+ encKey, decKey,
+ sbox = this._tables[0][4], decTable = this._tables[1],
+ keyLen = key.length, rcon = 1;
+
+ if (keyLen !== 4 && keyLen !== 6 && keyLen !== 8) {
+ throw new sjcl.exception.invalid("invalid aes key size");
+ }
+
+ this._key = [encKey = key.slice(0), decKey = []];
+
+ // schedule encryption keys
+ for (i = keyLen; i < 4 * keyLen + 28; i++) {
+ tmp = encKey[i-1];
+
+ // apply sbox
+ if (i%keyLen === 0 || (keyLen === 8 && i%keyLen === 4)) {
+ tmp = sbox[tmp>>>24]<<24 ^ sbox[tmp>>16&255]<<16 ^ sbox[tmp>>8&255]<<8 ^ sbox[tmp&255];
+
+ // shift rows and add rcon
+ if (i%keyLen === 0) {
+ tmp = tmp<<8 ^ tmp>>>24 ^ rcon<<24;
+ rcon = rcon<<1 ^ (rcon>>7)*283;
+ }
+ }
+
+ encKey[i] = encKey[i-keyLen] ^ tmp;
+ }
+
+ // schedule decryption keys
+ for (j = 0; i; j++, i--) {
+ tmp = encKey[j&3 ? i : i - 4];
+ if (i<=4 || j<4) {
+ decKey[j] = tmp;
+ } else {
+ decKey[j] = decTable[0][sbox[tmp>>>24 ]] ^
+ decTable[1][sbox[tmp>>16 & 255]] ^
+ decTable[2][sbox[tmp>>8 & 255]] ^
+ decTable[3][sbox[tmp & 255]];
+ }
+ }
+};
+
+sjcl.cipher.aes.prototype = {
+ // public
+ /* Something like this might appear here eventually
+ name: "AES",
+ blockSize: 4,
+ keySizes: [4,6,8],
+ */
+
+ /**
+ * Encrypt an array of 4 big-endian words.
+ * @param {Array} data The plaintext.
+ * @return {Array} The ciphertext.
+ */
+ encrypt:function (data) { return this._crypt(data,0); },
+
+ /**
+ * Decrypt an array of 4 big-endian words.
+ * @param {Array} data The ciphertext.
+ * @return {Array} The plaintext.
+ */
+ decrypt:function (data) { return this._crypt(data,1); },
+
+ /**
+ * The expanded S-box and inverse S-box tables. These will be computed
+ * on the client so that we don't have to send them down the wire.
+ *
+ * There are two tables, _tables[0] is for encryption and
+ * _tables[1] is for decryption.
+ *
+ * The first 4 sub-tables are the expanded S-box with MixColumns. The
+ * last (_tables[01][4]) is the S-box itself.
+ *
+ * @private
+ */
+ _tables: [[[],[],[],[],[]],[[],[],[],[],[]]],
+
+ /**
+ * Expand the S-box tables.
+ *
+ * @private
+ */
+ _precompute: function () {
+ var encTable = this._tables[0], decTable = this._tables[1],
+ sbox = encTable[4], sboxInv = decTable[4],
+ i, x, xInv, d=[], th=[], x2, x4, x8, s, tEnc, tDec;
+
+ // Compute double and third tables
+ for (i = 0; i < 256; i++) {
+ th[( d[i] = i<<1 ^ (i>>7)*283 )^i]=i;
+ }
+
+ for (x = xInv = 0; !sbox[x]; x ^= x2 || 1, xInv = th[xInv] || 1) {
+ // Compute sbox
+ s = xInv ^ xInv<<1 ^ xInv<<2 ^ xInv<<3 ^ xInv<<4;
+ s = s>>8 ^ s&255 ^ 99;
+ sbox[x] = s;
+ sboxInv[s] = x;
+
+ // Compute MixColumns
+ x8 = d[x4 = d[x2 = d[x]]];
+ tDec = x8*0x1010101 ^ x4*0x10001 ^ x2*0x101 ^ x*0x1010100;
+ tEnc = d[s]*0x101 ^ s*0x1010100;
+
+ for (i = 0; i < 4; i++) {
+ encTable[i][x] = tEnc = tEnc<<24 ^ tEnc>>>8;
+ decTable[i][s] = tDec = tDec<<24 ^ tDec>>>8;
+ }
+ }
+
+ // Compactify. Considerable speedup on Firefox.
+ for (i = 0; i < 5; i++) {
+ encTable[i] = encTable[i].slice(0);
+ decTable[i] = decTable[i].slice(0);
+ }
+ },
+
+ /**
+ * Encryption and decryption core.
+ * @param {Array} input Four words to be encrypted or decrypted.
+ * @param dir The direction, 0 for encrypt and 1 for decrypt.
+ * @return {Array} The four encrypted or decrypted words.
+ * @private
+ */
+ _crypt:function (input, dir) {
+ if (input.length !== 4) {
+ throw new sjcl.exception.invalid("invalid aes block size");
+ }
+
+ var key = this._key[dir],
+ // state variables a,b,c,d are loaded with pre-whitened data
+ a = input[0] ^ key[0],
+ b = input[dir ? 3 : 1] ^ key[1],
+ c = input[2] ^ key[2],
+ d = input[dir ? 1 : 3] ^ key[3],
+ a2, b2, c2,
+
+ nInnerRounds = key.length/4 - 2,
+ i,
+ kIndex = 4,
+ out = [0,0,0,0],
+ table = this._tables[dir],
+
+ // load up the tables
+ t0 = table[0],
+ t1 = table[1],
+ t2 = table[2],
+ t3 = table[3],
+ sbox = table[4];
+
+ // Inner rounds. Cribbed from OpenSSL.
+ for (i = 0; i < nInnerRounds; i++) {
+ a2 = t0[a>>>24] ^ t1[b>>16 & 255] ^ t2[c>>8 & 255] ^ t3[d & 255] ^ key[kIndex];
+ b2 = t0[b>>>24] ^ t1[c>>16 & 255] ^ t2[d>>8 & 255] ^ t3[a & 255] ^ key[kIndex + 1];
+ c2 = t0[c>>>24] ^ t1[d>>16 & 255] ^ t2[a>>8 & 255] ^ t3[b & 255] ^ key[kIndex + 2];
+ d = t0[d>>>24] ^ t1[a>>16 & 255] ^ t2[b>>8 & 255] ^ t3[c & 255] ^ key[kIndex + 3];
+ kIndex += 4;
+ a=a2; b=b2; c=c2;
+ }
+
+ // Last round.
+ for (i = 0; i < 4; i++) {
+ out[dir ? 3&-i : i] =
+ sbox[a>>>24 ]<<24 ^
+ sbox[b>>16 & 255]<<16 ^
+ sbox[c>>8 & 255]<<8 ^
+ sbox[d & 255] ^
+ key[kIndex++];
+ a2=a; a=b; b=c; c=d; d=a2;
+ }
+
+ return out;
+ }
+};
+
+
+/** @fileOverview Arrays of bits, encoded as arrays of Numbers.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** @namespace Arrays of bits, encoded as arrays of Numbers.
+ *
+ * @description
+ *
+ * These objects are the currency accepted by SJCL's crypto functions.
+ *
+ *
+ *
+ * Most of our crypto primitives operate on arrays of 4-byte words internally,
+ * but many of them can take arguments that are not a multiple of 4 bytes.
+ * This library encodes arrays of bits (whose size need not be a multiple of 8
+ * bits) as arrays of 32-bit words. The bits are packed, big-endian, into an
+ * array of words, 32 bits at a time. Since the words are double-precision
+ * floating point numbers, they fit some extra data. We use this (in a private,
+ * possibly-changing manner) to encode the number of bits actually present
+ * in the last word of the array.
+ *
+ *
+ *
+ * Because bitwise ops clear this out-of-band data, these arrays can be passed
+ * to ciphers like AES which want arrays of words.
+ *
+ */
+sjcl.bitArray = {
+ /**
+ * Array slices in units of bits.
+ * @param {bitArray} a The array to slice.
+ * @param {Number} bstart The offset to the start of the slice, in bits.
+ * @param {Number} bend The offset to the end of the slice, in bits. If this is undefined,
+ * slice until the end of the array.
+ * @return {bitArray} The requested slice.
+ */
+ bitSlice: function (a, bstart, bend) {
+ a = sjcl.bitArray._shiftRight(a.slice(bstart/32), 32 - (bstart & 31)).slice(1);
+ return (bend === undefined) ? a : sjcl.bitArray.clamp(a, bend-bstart);
+ },
+
+ /**
+ * Extract a number packed into a bit array.
+ * @param {bitArray} a The array to slice.
+ * @param {Number} bstart The offset to the start of the slice, in bits.
+ * @param {Number} length The length of the number to extract.
+ * @return {Number} The requested slice.
+ */
+ extract: function(a, bstart, blength) {
+ // FIXME: this Math.floor is not necessary at all, but for some reason
+ // seems to suppress a bug in the Chromium JIT.
+ var x, sh = Math.floor((-bstart-blength) & 31);
+ if ((bstart + blength - 1 ^ bstart) & -32) {
+ // it crosses a boundary
+ x = (a[bstart/32|0] << (32 - sh)) ^ (a[bstart/32+1|0] >>> sh);
+ } else {
+ // within a single word
+ x = a[bstart/32|0] >>> sh;
+ }
+ return x & ((1< 0 && len) {
+ a[l-1] = sjcl.bitArray.partial(len, a[l-1] & 0x80000000 >> (len-1), 1);
+ }
+ return a;
+ },
+
+ /**
+ * Make a partial word for a bit array.
+ * @param {Number} len The number of bits in the word.
+ * @param {Number} x The bits.
+ * @param {Number} [0] _end Pass 1 if x has already been shifted to the high side.
+ * @return {Number} The partial word.
+ */
+ partial: function (len, x, _end) {
+ if (len === 32) { return x; }
+ return (_end ? x|0 : x << (32-len)) + len * 0x10000000000;
+ },
+
+ /**
+ * Get the number of bits used by a partial word.
+ * @param {Number} x The partial word.
+ * @return {Number} The number of bits used by the partial word.
+ */
+ getPartial: function (x) {
+ return Math.round(x/0x10000000000) || 32;
+ },
+
+ /**
+ * Compare two arrays for equality in a predictable amount of time.
+ * @param {bitArray} a The first array.
+ * @param {bitArray} b The second array.
+ * @return {boolean} true if a == b; false otherwise.
+ */
+ equal: function (a, b) {
+ if (sjcl.bitArray.bitLength(a) !== sjcl.bitArray.bitLength(b)) {
+ return false;
+ }
+ var x = 0, i;
+ for (i=0; i= 32; shift -= 32) {
+ out.push(carry);
+ carry = 0;
+ }
+ if (shift === 0) {
+ return out.concat(a);
+ }
+
+ for (i=0; i>>shift);
+ carry = a[i] << (32-shift);
+ }
+ last2 = a.length ? a[a.length-1] : 0;
+ shift2 = sjcl.bitArray.getPartial(last2);
+ out.push(sjcl.bitArray.partial(shift+shift2 & 31, (shift + shift2 > 32) ? carry : out.pop(),1));
+ return out;
+ },
+
+ /** xor a block of 4 words together.
+ * @private
+ */
+ _xor4: function(x,y) {
+ return [x[0]^y[0],x[1]^y[1],x[2]^y[2],x[3]^y[3]];
+ }
+};
+
+/** @fileOverview Bit array codec implementations.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** @namespace UTF-8 strings */
+sjcl.codec.utf8String = {
+ /** Convert from a bitArray to a UTF-8 string. */
+ fromBits: function (arr) {
+ var out = "", bl = sjcl.bitArray.bitLength(arr), i, tmp;
+ for (i=0; i>> 24);
+ tmp <<= 8;
+ }
+ return decodeURIComponent(escape(out));
+ },
+
+ /** Convert from a UTF-8 string to a bitArray. */
+ toBits: function (str) {
+ str = unescape(encodeURIComponent(str));
+ var out = [], i, tmp=0;
+ for (i=0; i>>bits) >>> 26);
+ if (bits < 6) {
+ ta = arr[i] << (6-bits);
+ bits += 26;
+ i++;
+ } else {
+ ta <<= 6;
+ bits -= 6;
+ }
+ }
+ while ((out.length & 3) && !_noEquals) { out += "="; }
+ return out;
+ },
+
+ /** Convert from a base64 string to a bitArray */
+ toBits: function(str, _url) {
+ str = str.replace(/\s|=/g,'');
+ var out = [], i, bits=0, c = sjcl.codec.base64._chars, ta=0, x;
+ if (_url) c = c.substr(0,62) + '-_';
+ for (i=0; i 26) {
+ bits -= 26;
+ out.push(ta ^ x>>>bits);
+ ta = x << (32-bits);
+ } else {
+ bits += 6;
+ ta ^= x << (32-bits);
+ }
+ }
+ if (bits&56) {
+ out.push(sjcl.bitArray.partial(bits&56, ta, 1));
+ }
+ return out;
+ }
+};
+
+sjcl.codec.base64url = {
+ fromBits: function (arr) { return sjcl.codec.base64.fromBits(arr,1,1); },
+ toBits: function (str) { return sjcl.codec.base64.toBits(str,1); }
+};
+
+/** @fileOverview Bit array codec implementations.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** @namespace Arrays of bytes */
+sjcl.codec.bytes = {
+ /** Convert from a bitArray to an array of bytes. */
+ fromBits: function (arr) {
+ var out = [], bl = sjcl.bitArray.bitLength(arr), i, tmp;
+ for (i=0; i>> 24);
+ tmp <<= 8;
+ }
+ return out;
+ },
+ /** Convert from an array of bytes to a bitArray. */
+ toBits: function (bytes) {
+ var out = [], i, tmp=0;
+ for (i=0; i>>7 ^ a>>>18 ^ a>>>3 ^ a<<25 ^ a<<14) +
+ (b>>>17 ^ b>>>19 ^ b>>>10 ^ b<<15 ^ b<<13) +
+ w[i&15] + w[(i+9) & 15]) | 0;
+ }
+
+ tmp = (tmp + h7 + (h4>>>6 ^ h4>>>11 ^ h4>>>25 ^ h4<<26 ^ h4<<21 ^ h4<<7) + (h6 ^ h4&(h5^h6)) + k[i]); // | 0;
+
+ // shift register
+ h7 = h6; h6 = h5; h5 = h4;
+ h4 = h3 + tmp | 0;
+ h3 = h2; h2 = h1; h1 = h0;
+
+ h0 = (tmp + ((h1&h2) ^ (h3&(h1^h2))) + (h1>>>2 ^ h1>>>13 ^ h1>>>22 ^ h1<<30 ^ h1<<19 ^ h1<<10)) | 0;
+ }
+
+ h[0] = h[0]+h0 | 0;
+ h[1] = h[1]+h1 | 0;
+ h[2] = h[2]+h2 | 0;
+ h[3] = h[3]+h3 | 0;
+ h[4] = h[4]+h4 | 0;
+ h[5] = h[5]+h5 | 0;
+ h[6] = h[6]+h6 | 0;
+ h[7] = h[7]+h7 | 0;
+ }
+};
+
+
+
+/** @fileOverview Javascript SHA-512 implementation.
+ *
+ * This implementation was written for CryptoJS by Jeff Mott and adapted for
+ * SJCL by Stefan Thomas.
+ *
+ * CryptoJS (c) 2009–2012 by Jeff Mott. All rights reserved.
+ * Released with New BSD License
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ * @author Jeff Mott
+ * @author Stefan Thomas
+ */
+
+/**
+ * Context for a SHA-512 operation in progress.
+ * @constructor
+ * @class Secure Hash Algorithm, 512 bits.
+ */
+sjcl.hash.sha512 = function (hash) {
+ if (!this._key[0]) { this._precompute(); }
+ if (hash) {
+ this._h = hash._h.slice(0);
+ this._buffer = hash._buffer.slice(0);
+ this._length = hash._length;
+ } else {
+ this.reset();
+ }
+};
+
+/**
+ * Hash a string or an array of words.
+ * @static
+ * @param {bitArray|String} data the data to hash.
+ * @return {bitArray} The hash value, an array of 16 big-endian words.
+ */
+sjcl.hash.sha512.hash = function (data) {
+ return (new sjcl.hash.sha512()).update(data).finalize();
+};
+
+sjcl.hash.sha512.prototype = {
+ /**
+ * The hash's block size, in bits.
+ * @constant
+ */
+ blockSize: 1024,
+
+ /**
+ * Reset the hash state.
+ * @return this
+ */
+ reset:function () {
+ this._h = this._init.slice(0);
+ this._buffer = [];
+ this._length = 0;
+ return this;
+ },
+
+ /**
+ * Input several words to the hash.
+ * @param {bitArray|String} data the data to hash.
+ * @return this
+ */
+ update: function (data) {
+ if (typeof data === "string") {
+ data = sjcl.codec.utf8String.toBits(data);
+ }
+ var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
+ ol = this._length,
+ nl = this._length = ol + sjcl.bitArray.bitLength(data);
+ for (i = 1024+ol & -1024; i <= nl; i+= 1024) {
+ this._block(b.splice(0,32));
+ }
+ return this;
+ },
+
+ /**
+ * Complete hashing and output the hash value.
+ * @return {bitArray} The hash value, an array of 16 big-endian words.
+ */
+ finalize:function () {
+ var i, b = this._buffer, h = this._h;
+
+ // Round out and push the buffer
+ b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]);
+
+ // Round out the buffer to a multiple of 32 words, less the 4 length words.
+ for (i = b.length + 4; i & 31; i++) {
+ b.push(0);
+ }
+
+ // append the length
+ b.push(0);
+ b.push(0);
+ b.push(Math.floor(this._length / 0x100000000));
+ b.push(this._length | 0);
+
+ while (b.length) {
+ this._block(b.splice(0,32));
+ }
+
+ this.reset();
+ return h;
+ },
+
+ /**
+ * The SHA-512 initialization vector, to be precomputed.
+ * @private
+ */
+ _init:[],
+
+ /**
+ * Least significant 24 bits of SHA512 initialization values.
+ *
+ * Javascript only has 53 bits of precision, so we compute the 40 most
+ * significant bits and add the remaining 24 bits as constants.
+ *
+ * @private
+ */
+ _initr: [ 0xbcc908, 0xcaa73b, 0x94f82b, 0x1d36f1, 0xe682d1, 0x3e6c1f, 0x41bd6b, 0x7e2179 ],
+
+ /*
+ _init:
+ [0x6a09e667, 0xf3bcc908, 0xbb67ae85, 0x84caa73b, 0x3c6ef372, 0xfe94f82b, 0xa54ff53a, 0x5f1d36f1,
+ 0x510e527f, 0xade682d1, 0x9b05688c, 0x2b3e6c1f, 0x1f83d9ab, 0xfb41bd6b, 0x5be0cd19, 0x137e2179],
+ */
+
+ /**
+ * The SHA-512 hash key, to be precomputed.
+ * @private
+ */
+ _key:[],
+
+ /**
+ * Least significant 24 bits of SHA512 key values.
+ * @private
+ */
+ _keyr:
+ [0x28ae22, 0xef65cd, 0x4d3b2f, 0x89dbbc, 0x48b538, 0x05d019, 0x194f9b, 0x6d8118,
+ 0x030242, 0x706fbe, 0xe4b28c, 0xffb4e2, 0x7b896f, 0x1696b1, 0xc71235, 0x692694,
+ 0xf14ad2, 0x4f25e3, 0x8cd5b5, 0xac9c65, 0x2b0275, 0xa6e483, 0x41fbd4, 0x1153b5,
+ 0x66dfab, 0xb43210, 0xfb213f, 0xef0ee4, 0xa88fc2, 0x0aa725, 0x03826f, 0x0e6e70,
+ 0xd22ffc, 0x26c926, 0xc42aed, 0x95b3df, 0xaf63de, 0x77b2a8, 0xedaee6, 0x82353b,
+ 0xf10364, 0x423001, 0xf89791, 0x54be30, 0xef5218, 0x65a910, 0x71202a, 0xbbd1b8,
+ 0xd2d0c8, 0x41ab53, 0x8eeb99, 0x9b48a8, 0xc95a63, 0x418acb, 0x63e373, 0xb2b8a3,
+ 0xefb2fc, 0x172f60, 0xf0ab72, 0x6439ec, 0x631e28, 0x82bde9, 0xc67915, 0x72532b,
+ 0x26619c, 0xc0c207, 0xe0eb1e, 0x6ed178, 0x176fba, 0xc898a6, 0xf90dae, 0x1c471b,
+ 0x047d84, 0xc72493, 0xc9bebc, 0x100d4c, 0x3e42b6, 0x657e2a, 0xd6faec, 0x475817],
+
+ /*
+ _key:
+ [0x428a2f98, 0xd728ae22, 0x71374491, 0x23ef65cd, 0xb5c0fbcf, 0xec4d3b2f, 0xe9b5dba5, 0x8189dbbc,
+ 0x3956c25b, 0xf348b538, 0x59f111f1, 0xb605d019, 0x923f82a4, 0xaf194f9b, 0xab1c5ed5, 0xda6d8118,
+ 0xd807aa98, 0xa3030242, 0x12835b01, 0x45706fbe, 0x243185be, 0x4ee4b28c, 0x550c7dc3, 0xd5ffb4e2,
+ 0x72be5d74, 0xf27b896f, 0x80deb1fe, 0x3b1696b1, 0x9bdc06a7, 0x25c71235, 0xc19bf174, 0xcf692694,
+ 0xe49b69c1, 0x9ef14ad2, 0xefbe4786, 0x384f25e3, 0x0fc19dc6, 0x8b8cd5b5, 0x240ca1cc, 0x77ac9c65,
+ 0x2de92c6f, 0x592b0275, 0x4a7484aa, 0x6ea6e483, 0x5cb0a9dc, 0xbd41fbd4, 0x76f988da, 0x831153b5,
+ 0x983e5152, 0xee66dfab, 0xa831c66d, 0x2db43210, 0xb00327c8, 0x98fb213f, 0xbf597fc7, 0xbeef0ee4,
+ 0xc6e00bf3, 0x3da88fc2, 0xd5a79147, 0x930aa725, 0x06ca6351, 0xe003826f, 0x14292967, 0x0a0e6e70,
+ 0x27b70a85, 0x46d22ffc, 0x2e1b2138, 0x5c26c926, 0x4d2c6dfc, 0x5ac42aed, 0x53380d13, 0x9d95b3df,
+ 0x650a7354, 0x8baf63de, 0x766a0abb, 0x3c77b2a8, 0x81c2c92e, 0x47edaee6, 0x92722c85, 0x1482353b,
+ 0xa2bfe8a1, 0x4cf10364, 0xa81a664b, 0xbc423001, 0xc24b8b70, 0xd0f89791, 0xc76c51a3, 0x0654be30,
+ 0xd192e819, 0xd6ef5218, 0xd6990624, 0x5565a910, 0xf40e3585, 0x5771202a, 0x106aa070, 0x32bbd1b8,
+ 0x19a4c116, 0xb8d2d0c8, 0x1e376c08, 0x5141ab53, 0x2748774c, 0xdf8eeb99, 0x34b0bcb5, 0xe19b48a8,
+ 0x391c0cb3, 0xc5c95a63, 0x4ed8aa4a, 0xe3418acb, 0x5b9cca4f, 0x7763e373, 0x682e6ff3, 0xd6b2b8a3,
+ 0x748f82ee, 0x5defb2fc, 0x78a5636f, 0x43172f60, 0x84c87814, 0xa1f0ab72, 0x8cc70208, 0x1a6439ec,
+ 0x90befffa, 0x23631e28, 0xa4506ceb, 0xde82bde9, 0xbef9a3f7, 0xb2c67915, 0xc67178f2, 0xe372532b,
+ 0xca273ece, 0xea26619c, 0xd186b8c7, 0x21c0c207, 0xeada7dd6, 0xcde0eb1e, 0xf57d4f7f, 0xee6ed178,
+ 0x06f067aa, 0x72176fba, 0x0a637dc5, 0xa2c898a6, 0x113f9804, 0xbef90dae, 0x1b710b35, 0x131c471b,
+ 0x28db77f5, 0x23047d84, 0x32caab7b, 0x40c72493, 0x3c9ebe0a, 0x15c9bebc, 0x431d67c4, 0x9c100d4c,
+ 0x4cc5d4be, 0xcb3e42b6, 0x597f299c, 0xfc657e2a, 0x5fcb6fab, 0x3ad6faec, 0x6c44198c, 0x4a475817],
+ */
+
+ /**
+ * Function to precompute _init and _key.
+ * @private
+ */
+ _precompute: function () {
+ // XXX: This code is for precomputing the SHA256 constants, change for
+ // SHA512 and re-enable.
+ var i = 0, prime = 2, factor;
+
+ function frac(x) { return (x-Math.floor(x)) * 0x100000000 | 0; }
+ function frac2(x) { return (x-Math.floor(x)) * 0x10000000000 & 0xff; }
+
+ outer: for (; i<80; prime++) {
+ for (factor=2; factor*factor <= prime; factor++) {
+ if (prime % factor === 0) {
+ // not a prime
+ continue outer;
+ }
+ }
+
+ if (i<8) {
+ this._init[i*2] = frac(Math.pow(prime, 1/2));
+ this._init[i*2+1] = (frac2(Math.pow(prime, 1/2)) << 24) | this._initr[i];
+ }
+ this._key[i*2] = frac(Math.pow(prime, 1/3));
+ this._key[i*2+1] = (frac2(Math.pow(prime, 1/3)) << 24) | this._keyr[i];
+ i++;
+ }
+ },
+
+ /**
+ * Perform one cycle of SHA-512.
+ * @param {bitArray} words one block of words.
+ * @private
+ */
+ _block:function (words) {
+ var i, wrh, wrl,
+ w = words.slice(0),
+ h = this._h,
+ k = this._key,
+ h0h = h[ 0], h0l = h[ 1], h1h = h[ 2], h1l = h[ 3],
+ h2h = h[ 4], h2l = h[ 5], h3h = h[ 6], h3l = h[ 7],
+ h4h = h[ 8], h4l = h[ 9], h5h = h[10], h5l = h[11],
+ h6h = h[12], h6l = h[13], h7h = h[14], h7l = h[15];
+
+ // Working variables
+ var ah = h0h, al = h0l, bh = h1h, bl = h1l,
+ ch = h2h, cl = h2l, dh = h3h, dl = h3l,
+ eh = h4h, el = h4l, fh = h5h, fl = h5l,
+ gh = h6h, gl = h6l, hh = h7h, hl = h7l;
+
+ for (i=0; i<80; i++) {
+ // load up the input word for this round
+ if (i<16) {
+ wrh = w[i * 2];
+ wrl = w[i * 2 + 1];
+ } else {
+ // Gamma0
+ var gamma0xh = w[(i-15) * 2];
+ var gamma0xl = w[(i-15) * 2 + 1];
+ var gamma0h =
+ ((gamma0xl << 31) | (gamma0xh >>> 1)) ^
+ ((gamma0xl << 24) | (gamma0xh >>> 8)) ^
+ (gamma0xh >>> 7);
+ var gamma0l =
+ ((gamma0xh << 31) | (gamma0xl >>> 1)) ^
+ ((gamma0xh << 24) | (gamma0xl >>> 8)) ^
+ ((gamma0xh << 25) | (gamma0xl >>> 7));
+
+ // Gamma1
+ var gamma1xh = w[(i-2) * 2];
+ var gamma1xl = w[(i-2) * 2 + 1];
+ var gamma1h =
+ ((gamma1xl << 13) | (gamma1xh >>> 19)) ^
+ ((gamma1xh << 3) | (gamma1xl >>> 29)) ^
+ (gamma1xh >>> 6);
+ var gamma1l =
+ ((gamma1xh << 13) | (gamma1xl >>> 19)) ^
+ ((gamma1xl << 3) | (gamma1xh >>> 29)) ^
+ ((gamma1xh << 26) | (gamma1xl >>> 6));
+
+ // Shortcuts
+ var wr7h = w[(i-7) * 2];
+ var wr7l = w[(i-7) * 2 + 1];
+
+ var wr16h = w[(i-16) * 2];
+ var wr16l = w[(i-16) * 2 + 1];
+
+ // W(round) = gamma0 + W(round - 7) + gamma1 + W(round - 16)
+ wrl = gamma0l + wr7l;
+ wrh = gamma0h + wr7h + ((wrl >>> 0) < (gamma0l >>> 0) ? 1 : 0);
+ wrl += gamma1l;
+ wrh += gamma1h + ((wrl >>> 0) < (gamma1l >>> 0) ? 1 : 0);
+ wrl += wr16l;
+ wrh += wr16h + ((wrl >>> 0) < (wr16l >>> 0) ? 1 : 0);
+ }
+
+ w[i*2] = wrh |= 0;
+ w[i*2 + 1] = wrl |= 0;
+
+ // Ch
+ var chh = (eh & fh) ^ (~eh & gh);
+ var chl = (el & fl) ^ (~el & gl);
+
+ // Maj
+ var majh = (ah & bh) ^ (ah & ch) ^ (bh & ch);
+ var majl = (al & bl) ^ (al & cl) ^ (bl & cl);
+
+ // Sigma0
+ var sigma0h = ((al << 4) | (ah >>> 28)) ^ ((ah << 30) | (al >>> 2)) ^ ((ah << 25) | (al >>> 7));
+ var sigma0l = ((ah << 4) | (al >>> 28)) ^ ((al << 30) | (ah >>> 2)) ^ ((al << 25) | (ah >>> 7));
+
+ // Sigma1
+ var sigma1h = ((el << 18) | (eh >>> 14)) ^ ((el << 14) | (eh >>> 18)) ^ ((eh << 23) | (el >>> 9));
+ var sigma1l = ((eh << 18) | (el >>> 14)) ^ ((eh << 14) | (el >>> 18)) ^ ((el << 23) | (eh >>> 9));
+
+ // K(round)
+ var krh = k[i*2];
+ var krl = k[i*2+1];
+
+ // t1 = h + sigma1 + ch + K(round) + W(round)
+ var t1l = hl + sigma1l;
+ var t1h = hh + sigma1h + ((t1l >>> 0) < (hl >>> 0) ? 1 : 0);
+ t1l += chl;
+ t1h += chh + ((t1l >>> 0) < (chl >>> 0) ? 1 : 0);
+ t1l += krl;
+ t1h += krh + ((t1l >>> 0) < (krl >>> 0) ? 1 : 0);
+ t1l += wrl;
+ t1h += wrh + ((t1l >>> 0) < (wrl >>> 0) ? 1 : 0);
+
+ // t2 = sigma0 + maj
+ var t2l = sigma0l + majl;
+ var t2h = sigma0h + majh + ((t2l >>> 0) < (sigma0l >>> 0) ? 1 : 0);
+
+ // Update working variables
+ hh = gh;
+ hl = gl;
+ gh = fh;
+ gl = fl;
+ fh = eh;
+ fl = el;
+ el = (dl + t1l) | 0;
+ eh = (dh + t1h + ((el >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
+ dh = ch;
+ dl = cl;
+ ch = bh;
+ cl = bl;
+ bh = ah;
+ bl = al;
+ al = (t1l + t2l) | 0;
+ ah = (t1h + t2h + ((al >>> 0) < (t1l >>> 0) ? 1 : 0)) | 0;
+ }
+
+ // Intermediate hash
+ h0l = h[1] = (h0l + al) | 0;
+ h[0] = (h0h + ah + ((h0l >>> 0) < (al >>> 0) ? 1 : 0)) | 0;
+ h1l = h[3] = (h1l + bl) | 0;
+ h[2] = (h1h + bh + ((h1l >>> 0) < (bl >>> 0) ? 1 : 0)) | 0;
+ h2l = h[5] = (h2l + cl) | 0;
+ h[4] = (h2h + ch + ((h2l >>> 0) < (cl >>> 0) ? 1 : 0)) | 0;
+ h3l = h[7] = (h3l + dl) | 0;
+ h[6] = (h3h + dh + ((h3l >>> 0) < (dl >>> 0) ? 1 : 0)) | 0;
+ h4l = h[9] = (h4l + el) | 0;
+ h[8] = (h4h + eh + ((h4l >>> 0) < (el >>> 0) ? 1 : 0)) | 0;
+ h5l = h[11] = (h5l + fl) | 0;
+ h[10] = (h5h + fh + ((h5l >>> 0) < (fl >>> 0) ? 1 : 0)) | 0;
+ h6l = h[13] = (h6l + gl) | 0;
+ h[12] = (h6h + gh + ((h6l >>> 0) < (gl >>> 0) ? 1 : 0)) | 0;
+ h7l = h[15] = (h7l + hl) | 0;
+ h[14] = (h7h + hh + ((h7l >>> 0) < (hl >>> 0) ? 1 : 0)) | 0;
+ }
+};
+
+
+
+/** @fileOverview Javascript SHA-1 implementation.
+ *
+ * Based on the implementation in RFC 3174, method 1, and on the SJCL
+ * SHA-256 implementation.
+ *
+ * @author Quinn Slack
+ */
+
+/**
+ * Context for a SHA-1 operation in progress.
+ * @constructor
+ * @class Secure Hash Algorithm, 160 bits.
+ */
+sjcl.hash.sha1 = function (hash) {
+ if (hash) {
+ this._h = hash._h.slice(0);
+ this._buffer = hash._buffer.slice(0);
+ this._length = hash._length;
+ } else {
+ this.reset();
+ }
+};
+
+/**
+ * Hash a string or an array of words.
+ * @static
+ * @param {bitArray|String} data the data to hash.
+ * @return {bitArray} The hash value, an array of 5 big-endian words.
+ */
+sjcl.hash.sha1.hash = function (data) {
+ return (new sjcl.hash.sha1()).update(data).finalize();
+};
+
+sjcl.hash.sha1.prototype = {
+ /**
+ * The hash's block size, in bits.
+ * @constant
+ */
+ blockSize: 512,
+
+ /**
+ * Reset the hash state.
+ * @return this
+ */
+ reset:function () {
+ this._h = this._init.slice(0);
+ this._buffer = [];
+ this._length = 0;
+ return this;
+ },
+
+ /**
+ * Input several words to the hash.
+ * @param {bitArray|String} data the data to hash.
+ * @return this
+ */
+ update: function (data) {
+ if (typeof data === "string") {
+ data = sjcl.codec.utf8String.toBits(data);
+ }
+ var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
+ ol = this._length,
+ nl = this._length = ol + sjcl.bitArray.bitLength(data);
+ for (i = this.blockSize+ol & -this.blockSize; i <= nl;
+ i+= this.blockSize) {
+ this._block(b.splice(0,16));
+ }
+ return this;
+ },
+
+ /**
+ * Complete hashing and output the hash value.
+ * @return {bitArray} The hash value, an array of 5 big-endian words. TODO
+ */
+ finalize:function () {
+ var i, b = this._buffer, h = this._h;
+
+ // Round out and push the buffer
+ b = sjcl.bitArray.concat(b, [sjcl.bitArray.partial(1,1)]);
+ // Round out the buffer to a multiple of 16 words, less the 2 length words.
+ for (i = b.length + 2; i & 15; i++) {
+ b.push(0);
+ }
+
+ // append the length
+ b.push(Math.floor(this._length / 0x100000000));
+ b.push(this._length | 0);
+
+ while (b.length) {
+ this._block(b.splice(0,16));
+ }
+
+ this.reset();
+ return h;
+ },
+
+ /**
+ * The SHA-1 initialization vector.
+ * @private
+ */
+ _init:[0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0],
+
+ /**
+ * The SHA-1 hash key.
+ * @private
+ */
+ _key:[0x5A827999, 0x6ED9EBA1, 0x8F1BBCDC, 0xCA62C1D6],
+
+ /**
+ * The SHA-1 logical functions f(0), f(1), ..., f(79).
+ * @private
+ */
+ _f:function(t, b, c, d) {
+ if (t <= 19) {
+ return (b & c) | (~b & d);
+ } else if (t <= 39) {
+ return b ^ c ^ d;
+ } else if (t <= 59) {
+ return (b & c) | (b & d) | (c & d);
+ } else if (t <= 79) {
+ return b ^ c ^ d;
+ }
+ },
+
+ /**
+ * Circular left-shift operator.
+ * @private
+ */
+ _S:function(n, x) {
+ return (x << n) | (x >>> 32-n);
+ },
+
+ /**
+ * Perform one cycle of SHA-1.
+ * @param {bitArray} words one block of words.
+ * @private
+ */
+ _block:function (words) {
+ var t, tmp, a, b, c, d, e,
+ w = words.slice(0),
+ h = this._h,
+ k = this._key;
+
+ a = h[0]; b = h[1]; c = h[2]; d = h[3]; e = h[4];
+
+ for (t=0; t<=79; t++) {
+ if (t >= 16) {
+ w[t] = this._S(1, w[t-3] ^ w[t-8] ^ w[t-14] ^ w[t-16]);
+ }
+ tmp = (this._S(5, a) + this._f(t, b, c, d) + e + w[t] +
+ this._key[Math.floor(t/20)]) | 0;
+ e = d;
+ d = c;
+ c = this._S(30, b);
+ b = a;
+ a = tmp;
+ }
+
+ h[0] = (h[0]+a) |0;
+ h[1] = (h[1]+b) |0;
+ h[2] = (h[2]+c) |0;
+ h[3] = (h[3]+d) |0;
+ h[4] = (h[4]+e) |0;
+ }
+};
+
+/** @fileOverview CCM mode implementation.
+ *
+ * Special thanks to Roy Nicholson for pointing out a bug in our
+ * implementation.
+ *
+ * @author Emily Stark
+ * @author Mike Hamburg
+ * @author Dan Boneh
+ */
+
+/** @namespace CTR mode with CBC MAC. */
+sjcl.mode.ccm = {
+ /** The name of the mode.
+ * @constant
+ */
+ name: "ccm",
+
+ /** Encrypt in CCM mode.
+ * @static
+ * @param {Object} prf The pseudorandom function. It must have a block size of 16 bytes.
+ * @param {bitArray} plaintext The plaintext data.
+ * @param {bitArray} iv The initialization value.
+ * @param {bitArray} [adata=[]] The authenticated data.
+ * @param {Number} [tlen=64] the desired tag length, in bits.
+ * @return {bitArray} The encrypted data, an array of bytes.
+ */
+ encrypt: function(prf, plaintext, iv, adata, tlen) {
+ var L, i, out = plaintext.slice(0), tag, w=sjcl.bitArray, ivl = w.bitLength(iv) / 8, ol = w.bitLength(out) / 8;
+ tlen = tlen || 64;
+ adata = adata || [];
+
+ if (ivl < 7) {
+ throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");
+ }
+
+ // compute the length of the length
+ for (L=2; L<4 && ol >>> 8*L; L++) {}
+ if (L < 15 - ivl) { L = 15-ivl; }
+ iv = w.clamp(iv,8*(15-L));
+
+ // compute the tag
+ tag = sjcl.mode.ccm._computeTag(prf, plaintext, iv, adata, tlen, L);
+
+ // encrypt
+ out = sjcl.mode.ccm._ctrMode(prf, out, iv, tag, tlen, L);
+
+ return w.concat(out.data, out.tag);
+ },
+
+ /** Decrypt in CCM mode.
+ * @static
+ * @param {Object} prf The pseudorandom function. It must have a block size of 16 bytes.
+ * @param {bitArray} ciphertext The ciphertext data.
+ * @param {bitArray} iv The initialization value.
+ * @param {bitArray} [[]] adata The authenticated data.
+ * @param {Number} [64] tlen the desired tag length, in bits.
+ * @return {bitArray} The decrypted data.
+ */
+ decrypt: function(prf, ciphertext, iv, adata, tlen) {
+ tlen = tlen || 64;
+ adata = adata || [];
+ var L, i,
+ w=sjcl.bitArray,
+ ivl = w.bitLength(iv) / 8,
+ ol = w.bitLength(ciphertext),
+ out = w.clamp(ciphertext, ol - tlen),
+ tag = w.bitSlice(ciphertext, ol - tlen), tag2;
+
+
+ ol = (ol - tlen) / 8;
+
+ if (ivl < 7) {
+ throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");
+ }
+
+ // compute the length of the length
+ for (L=2; L<4 && ol >>> 8*L; L++) {}
+ if (L < 15 - ivl) { L = 15-ivl; }
+ iv = w.clamp(iv,8*(15-L));
+
+ // decrypt
+ out = sjcl.mode.ccm._ctrMode(prf, out, iv, tag, tlen, L);
+
+ // check the tag
+ tag2 = sjcl.mode.ccm._computeTag(prf, out.data, iv, adata, tlen, L);
+ if (!w.equal(out.tag, tag2)) {
+ throw new sjcl.exception.corrupt("ccm: tag doesn't match");
+ }
+
+ return out.data;
+ },
+
+ /* Compute the (unencrypted) authentication tag, according to the CCM specification
+ * @param {Object} prf The pseudorandom function.
+ * @param {bitArray} plaintext The plaintext data.
+ * @param {bitArray} iv The initialization value.
+ * @param {bitArray} adata The authenticated data.
+ * @param {Number} tlen the desired tag length, in bits.
+ * @return {bitArray} The tag, but not yet encrypted.
+ * @private
+ */
+ _computeTag: function(prf, plaintext, iv, adata, tlen, L) {
+ // compute B[0]
+ var q, mac, field = 0, offset = 24, tmp, i, macData = [], w=sjcl.bitArray, xor = w._xor4;
+
+ tlen /= 8;
+
+ // check tag length and message length
+ if (tlen % 2 || tlen < 4 || tlen > 16) {
+ throw new sjcl.exception.invalid("ccm: invalid tag length");
+ }
+
+ if (adata.length > 0xFFFFFFFF || plaintext.length > 0xFFFFFFFF) {
+ // I don't want to deal with extracting high words from doubles.
+ throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data");
+ }
+
+ // mac the flags
+ mac = [w.partial(8, (adata.length ? 1<<6 : 0) | (tlen-2) << 2 | L-1)];
+
+ // mac the iv and length
+ mac = w.concat(mac, iv);
+ mac[3] |= w.bitLength(plaintext)/8;
+ mac = prf.encrypt(mac);
+
+
+ if (adata.length) {
+ // mac the associated data. start with its length...
+ tmp = w.bitLength(adata)/8;
+ if (tmp <= 0xFEFF) {
+ macData = [w.partial(16, tmp)];
+ } else if (tmp <= 0xFFFFFFFF) {
+ macData = w.concat([w.partial(16,0xFFFE)], [tmp]);
+ } // else ...
+
+ // mac the data itself
+ macData = w.concat(macData, adata);
+ for (i=0; i bs) {
+ key = Hash.hash(key);
+ }
+
+ for (i=0; i
+ * This random number generator is a derivative of Ferguson and Schneier's
+ * generator Fortuna. It collects entropy from various events into several
+ * pools, implemented by streaming SHA-256 instances. It differs from
+ * ordinary Fortuna in a few ways, though.
+ *
+ *
+ *
+ * Most importantly, it has an entropy estimator. This is present because
+ * there is a strong conflict here between making the generator available
+ * as soon as possible, and making sure that it doesn't "run on empty".
+ * In Fortuna, there is a saved state file, and the system is likely to have
+ * time to warm up.
+ *
+ *
+ *
+ * Second, because users are unlikely to stay on the page for very long,
+ * and to speed startup time, the number of pools increases logarithmically:
+ * a new pool is created when the previous one is actually used for a reseed.
+ * This gives the same asymptotic guarantees as Fortuna, but gives more
+ * entropy to early reseeds.
+ *
+ *
+ *
+ * The entire mechanism here feels pretty klunky. Furthermore, there are
+ * several improvements that should be made, including support for
+ * dedicated cryptographic functions that may be present in some browsers;
+ * state files in local storage; cookies containing randomness; etc. So
+ * look for improvements in future versions.
+ *
+ */
+sjcl.prng = function(defaultParanoia) {
+
+ /* private */
+ this._pools = [new sjcl.hash.sha256()];
+ this._poolEntropy = [0];
+ this._reseedCount = 0;
+ this._robins = {};
+ this._eventId = 0;
+
+ this._collectorIds = {};
+ this._collectorIdNext = 0;
+
+ this._strength = 0;
+ this._poolStrength = 0;
+ this._nextReseed = 0;
+ this._key = [0,0,0,0,0,0,0,0];
+ this._counter = [0,0,0,0];
+ this._cipher = undefined;
+ this._defaultParanoia = defaultParanoia;
+
+ /* event listener stuff */
+ this._collectorsStarted = false;
+ this._callbacks = {progress: {}, seeded: {}};
+ this._callbackI = 0;
+
+ /* constants */
+ this._NOT_READY = 0;
+ this._READY = 1;
+ this._REQUIRES_RESEED = 2;
+
+ this._MAX_WORDS_PER_BURST = 65536;
+ this._PARANOIA_LEVELS = [0,48,64,96,128,192,256,384,512,768,1024];
+ this._MILLISECONDS_PER_RESEED = 30000;
+ this._BITS_PER_RESEED = 80;
+}
+
+sjcl.prng.prototype = {
+ /** Generate several random words, and return them in an array
+ * @param {Number} nwords The number of words to generate.
+ */
+ randomWords: function (nwords, paranoia) {
+ var out = [], i, readiness = this.isReady(paranoia), g;
+
+ if (readiness === this._NOT_READY) {
+ throw new sjcl.exception.notReady("generator isn't seeded");
+ } else if (readiness & this._REQUIRES_RESEED) {
+ this._reseedFromPools(!(readiness & this._READY));
+ }
+
+ for (i=0; i0) {
+ estimatedEntropy++;
+ tmp = tmp >>> 1;
+ }
+ }
+ }
+ this._pools[robin].update([id,this._eventId++,2,estimatedEntropy,t,data.length].concat(data));
+ }
+ break;
+
+ case "string":
+ if (estimatedEntropy === undefined) {
+ /* English text has just over 1 bit per character of entropy.
+ * But this might be HTML or something, and have far less
+ * entropy than English... Oh well, let's just say one bit.
+ */
+ estimatedEntropy = data.length;
+ }
+ this._pools[robin].update([id,this._eventId++,3,estimatedEntropy,t,data.length]);
+ this._pools[robin].update(data);
+ break;
+
+ default:
+ err=1;
+ }
+ if (err) {
+ throw new sjcl.exception.bug("random: addEntropy only supports number, array of numbers or string");
+ }
+
+ /* record the new strength */
+ this._poolEntropy[robin] += estimatedEntropy;
+ this._poolStrength += estimatedEntropy;
+
+ /* fire off events */
+ if (oldReady === this._NOT_READY) {
+ if (this.isReady() !== this._NOT_READY) {
+ this._fireEvent("seeded", Math.max(this._strength, this._poolStrength));
+ }
+ this._fireEvent("progress", this.getProgress());
+ }
+ },
+
+ /** Is the generator ready? */
+ isReady: function (paranoia) {
+ var entropyRequired = this._PARANOIA_LEVELS[ (paranoia !== undefined) ? paranoia : this._defaultParanoia ];
+
+ if (this._strength && this._strength >= entropyRequired) {
+ return (this._poolEntropy[0] > this._BITS_PER_RESEED && (new Date()).valueOf() > this._nextReseed) ?
+ this._REQUIRES_RESEED | this._READY :
+ this._READY;
+ } else {
+ return (this._poolStrength >= entropyRequired) ?
+ this._REQUIRES_RESEED | this._NOT_READY :
+ this._NOT_READY;
+ }
+ },
+
+ /** Get the generator's progress toward readiness, as a fraction */
+ getProgress: function (paranoia) {
+ var entropyRequired = this._PARANOIA_LEVELS[ paranoia ? paranoia : this._defaultParanoia ];
+
+ if (this._strength >= entropyRequired) {
+ return 1.0;
+ } else {
+ return (this._poolStrength > entropyRequired) ?
+ 1.0 :
+ this._poolStrength / entropyRequired;
+ }
+ },
+
+ /** start the built-in entropy collectors */
+ startCollectors: function () {
+ if (this._collectorsStarted) { return; }
+
+ if (window.addEventListener) {
+ window.addEventListener("load", this._loadTimeCollector, false);
+ window.addEventListener("mousemove", this._mouseCollector, false);
+ } else if (document.attachEvent) {
+ document.attachEvent("onload", this._loadTimeCollector);
+ document.attachEvent("onmousemove", this._mouseCollector);
+ }
+ else {
+ throw new sjcl.exception.bug("can't attach event");
+ }
+
+ this._collectorsStarted = true;
+ },
+
+ /** stop the built-in entropy collectors */
+ stopCollectors: function () {
+ if (!this._collectorsStarted) { return; }
+
+ if (window.removeEventListener) {
+ window.removeEventListener("load", this._loadTimeCollector, false);
+ window.removeEventListener("mousemove", this._mouseCollector, false);
+ } else if (window.detachEvent) {
+ window.detachEvent("onload", this._loadTimeCollector);
+ window.detachEvent("onmousemove", this._mouseCollector);
+ }
+ this._collectorsStarted = false;
+ },
+
+ /* use a cookie to store entropy.
+ useCookie: function (all_cookies) {
+ throw new sjcl.exception.bug("random: useCookie is unimplemented");
+ },*/
+
+ /** add an event listener for progress or seeded-ness. */
+ addEventListener: function (name, callback) {
+ this._callbacks[name][this._callbackI++] = callback;
+ },
+
+ /** remove an event listener for progress or seeded-ness */
+ removeEventListener: function (name, cb) {
+ var i, j, cbs=this._callbacks[name], jsTemp=[];
+
+ /* I'm not sure if this is necessary; in C++, iterating over a
+ * collection and modifying it at the same time is a no-no.
+ */
+
+ for (j in cbs) {
+ if (cbs.hasOwnProperty(j) && cbs[j] === cb) {
+ jsTemp.push(j);
+ }
+ }
+
+ for (i=0; i= 1 << this._pools.length) {
+ this._pools.push(new sjcl.hash.sha256());
+ this._poolEntropy.push(0);
+ }
+
+ /* how strong was this reseed? */
+ this._poolStrength -= strength;
+ if (strength > this._strength) {
+ this._strength = strength;
+ }
+
+ this._reseedCount ++;
+ this._reseed(reseedData);
+ },
+
+ _mouseCollector: function (ev) {
+ var x = ev.x || ev.clientX || ev.offsetX || 0, y = ev.y || ev.clientY || ev.offsetY || 0;
+ sjcl.random.addEntropy([x,y], 2, "mouse");
+ },
+
+ _loadTimeCollector: function (ev) {
+ sjcl.random.addEntropy((new Date()).valueOf(), 2, "loadtime");
+ },
+
+ _fireEvent: function (name, arg) {
+ var j, cbs=sjcl.random._callbacks[name], cbsTemp=[];
+ /* TODO: there is a race condition between removing collectors and firing them */
+
+ /* I'm not sure if this is necessary; in C++, iterating over a
+ * collection and modifying it at the same time is a no-no.
+ */
+
+ for (j in cbs) {
+ if (cbs.hasOwnProperty(j)) {
+ cbsTemp.push(cbs[j]);
+ }
+ }
+
+ for (j=0; j 4)) {
+ throw new sjcl.exception.invalid("json encrypt: invalid parameters");
+ }
+
+ if (typeof password === "string") {
+ tmp = sjcl.misc.cachedPbkdf2(password, p);
+ password = tmp.key.slice(0,p.ks/32);
+ p.salt = tmp.salt;
+ } else if (sjcl.ecc && password instanceof sjcl.ecc.elGamal.publicKey) {
+ tmp = password.kem();
+ p.kemtag = tmp.tag;
+ password = tmp.key.slice(0,p.ks/32);
+ }
+ if (typeof plaintext === "string") {
+ plaintext = sjcl.codec.utf8String.toBits(plaintext);
+ }
+ if (typeof adata === "string") {
+ adata = sjcl.codec.utf8String.toBits(adata);
+ }
+ prp = new sjcl.cipher[p.cipher](password);
+
+ /* return the json data */
+ j._add(rp, p);
+ rp.key = password;
+
+ /* do the encryption */
+ p.ct = sjcl.mode[p.mode].encrypt(prp, plaintext, p.iv, adata, p.ts);
+
+ //return j.encode(j._subtract(p, j.defaults));
+ return j.encode(p);
+ },
+
+ /** Simple decryption function.
+ * @param {String|bitArray} password The password or key.
+ * @param {String} ciphertext The ciphertext to decrypt.
+ * @param {Object} [params] Additional non-default parameters.
+ * @param {Object} [rp] A returned object with filled parameters.
+ * @return {String} The plaintext.
+ * @throws {sjcl.exception.invalid} if a parameter is invalid.
+ * @throws {sjcl.exception.corrupt} if the ciphertext is corrupt.
+ */
+ decrypt: function (password, ciphertext, params, rp) {
+ params = params || {};
+ rp = rp || {};
+
+ var j = sjcl.json, p = j._add(j._add(j._add({},j.defaults),j.decode(ciphertext)), params, true), ct, tmp, prp, adata=p.adata;
+ if (typeof p.salt === "string") {
+ p.salt = sjcl.codec.base64.toBits(p.salt);
+ }
+ if (typeof p.iv === "string") {
+ p.iv = sjcl.codec.base64.toBits(p.iv);
+ }
+
+ if (!sjcl.mode[p.mode] ||
+ !sjcl.cipher[p.cipher] ||
+ (typeof password === "string" && p.iter <= 100) ||
+ (p.ts !== 64 && p.ts !== 96 && p.ts !== 128) ||
+ (p.ks !== 128 && p.ks !== 192 && p.ks !== 256) ||
+ (!p.iv) ||
+ (p.iv.length < 2 || p.iv.length > 4)) {
+ throw new sjcl.exception.invalid("json decrypt: invalid parameters");
+ }
+
+ if (typeof password === "string") {
+ tmp = sjcl.misc.cachedPbkdf2(password, p);
+ password = tmp.key.slice(0,p.ks/32);
+ p.salt = tmp.salt;
+ } else if (sjcl.ecc && password instanceof sjcl.ecc.elGamal.secretKey) {
+ password = password.unkem(sjcl.codec.base64.toBits(p.kemtag)).slice(0,p.ks/32);
+ }
+ if (typeof adata === "string") {
+ adata = sjcl.codec.utf8String.toBits(adata);
+ }
+ prp = new sjcl.cipher[p.cipher](password);
+
+ /* do the decryption */
+ ct = sjcl.mode[p.mode].decrypt(prp, p.ct, p.iv, adata, p.ts);
+
+ /* return the json data */
+ j._add(rp, p);
+ rp.key = password;
+
+ return sjcl.codec.utf8String.fromBits(ct);
+ },
+
+ /** Encode a flat structure into a JSON string.
+ * @param {Object} obj The structure to encode.
+ * @return {String} A JSON string.
+ * @throws {sjcl.exception.invalid} if obj has a non-alphanumeric property.
+ * @throws {sjcl.exception.bug} if a parameter has an unsupported type.
+ */
+ encode: function (obj) {
+ var i, out='{', comma='';
+ for (i in obj) {
+ if (obj.hasOwnProperty(i)) {
+ if (!i.match(/^[a-z0-9]+$/i)) {
+ throw new sjcl.exception.invalid("json encode: invalid property name");
+ }
+ out += comma + '"' + i + '":';
+ comma = ',';
+
+ switch (typeof obj[i]) {
+ case 'number':
+ case 'boolean':
+ out += obj[i];
+ break;
+
+ case 'string':
+ out += '"' + escape(obj[i]) + '"';
+ break;
+
+ case 'object':
+ out += '"' + sjcl.codec.base64.fromBits(obj[i],0) + '"';
+ break;
+
+ default:
+ throw new sjcl.exception.bug("json encode: unsupported type");
+ }
+ }
+ }
+ return out+'}';
+ },
+
+ /** Decode a simple (flat) JSON string into a structure. The ciphertext,
+ * adata, salt and iv will be base64-decoded.
+ * @param {String} str The string.
+ * @return {Object} The decoded structure.
+ * @throws {sjcl.exception.invalid} if str isn't (simple) JSON.
+ */
+ decode: function (str) {
+ str = str.replace(/\s/g,'');
+ if (!str.match(/^\{.*\}$/)) {
+ throw new sjcl.exception.invalid("json decode: this isn't json!");
+ }
+ var a = str.replace(/^\{|\}$/g, '').split(/,/), out={}, i, m;
+ for (i=0; i= this.limbs.length) ? 0 : this.limbs[i];
+ },
+
+ /**
+ * Constant time comparison function.
+ * Returns 1 if this >= that, or zero otherwise.
+ */
+ greaterEquals: function(that) {
+ if (typeof that === "number") { that = new this._class(that); }
+ var less = 0, greater = 0, i, a, b;
+ i = Math.max(this.limbs.length, that.limbs.length) - 1;
+ for (; i>= 0; i--) {
+ a = this.getLimb(i);
+ b = that.getLimb(i);
+ greater |= (b - a) & ~less;
+ less |= (a - b) & ~greater;
+ }
+ return (greater | ~less) >>> 31;
+ },
+
+ /**
+ * Convert to a hex string.
+ */
+ toString: function() {
+ this.fullReduce();
+ var out="", i, s, l = this.limbs;
+ for (i=0; i < this.limbs.length; i++) {
+ s = l[i].toString(16);
+ while (i < this.limbs.length - 1 && s.length < 6) {
+ s = "0" + s;
+ }
+ out = s + out;
+ }
+ return "0x"+out;
+ },
+
+ /** this += that. Does not normalize. */
+ addM: function(that) {
+ if (typeof(that) !== "object") { that = new this._class(that); }
+ var i, l=this.limbs, ll=that.limbs;
+ for (i=l.length; i> r;
+ }
+ if (carry) {
+ l.push(carry);
+ }
+ return this;
+ },
+
+ /** this /= 2, rounded down. Requires normalized; ends up normalized. */
+ halveM: function() {
+ var i, carry=0, tmp, r=this.radix, l=this.limbs;
+ for (i=l.length-1; i>=0; i--) {
+ tmp = l[i];
+ l[i] = (tmp+carry)>>1;
+ carry = (tmp&1) << r;
+ }
+ if (!l[l.length-1]) {
+ l.pop();
+ }
+ return this;
+ },
+
+ /** this -= that. Does not normalize. */
+ subM: function(that) {
+ if (typeof(that) !== "object") { that = new this._class(that); }
+ var i, l=this.limbs, ll=that.limbs;
+ for (i=l.length; i 0; ci--) {
+ that.halveM();
+ if (out.greaterEquals(that)) {
+ out.subM(that).normalize();
+ }
+ }
+ return out.trim();
+ },
+
+ /** return inverse mod prime p. p must be odd. Binary extended Euclidean algorithm mod p. */
+ inverseMod: function(p) {
+ var a = new sjcl.bn(1), b = new sjcl.bn(0), x = new sjcl.bn(this), y = new sjcl.bn(p), tmp, i, nz=1;
+
+ if (!(p.limbs[0] & 1)) {
+ throw (new sjcl.exception.invalid("inverseMod: p must be odd"));
+ }
+
+ // invariant: y is odd
+ do {
+ if (x.limbs[0] & 1) {
+ if (!x.greaterEquals(y)) {
+ // x < y; swap everything
+ tmp = x; x = y; y = tmp;
+ tmp = a; a = b; b = tmp;
+ }
+ x.subM(y);
+ x.normalize();
+
+ if (!a.greaterEquals(b)) {
+ a.addM(p);
+ }
+ a.subM(b);
+ }
+
+ // cut everything in half
+ x.halveM();
+ if (a.limbs[0] & 1) {
+ a.addM(p);
+ }
+ a.normalize();
+ a.halveM();
+
+ // check for termination: x ?= 0
+ for (i=nz=0; i= 0; i--) {
+ out = w.concat(out, [w.partial(Math.min(this.radix,len), this.getLimb(i))]);
+ len -= this.radix;
+ }
+ return out;
+ },
+
+ /** Return the length in bits, rounded up to the nearest byte. */
+ bitLength: function() {
+ this.fullReduce();
+ var out = this.radix * (this.limbs.length - 1),
+ b = this.limbs[this.limbs.length - 1];
+ for (; b; b >>>= 1) {
+ out ++;
+ }
+ return out+7 & -8;
+ }
+};
+
+/** @this { sjcl.bn } */
+sjcl.bn.fromBits = function(bits) {
+ var Class = this, out = new Class(), words=[], w=sjcl.bitArray, t = this.prototype,
+ l = Math.min(this.bitLength || 0x100000000, w.bitLength(bits)), e = l % t.radix || t.radix;
+
+ words[0] = w.extract(bits, 0, e);
+ for (; e < l; e += t.radix) {
+ words.unshift(w.extract(bits, e, t.radix));
+ }
+
+ out.limbs = words;
+ return out;
+};
+
+
+
+sjcl.bn.prototype.ipv = 1 / (sjcl.bn.prototype.placeVal = Math.pow(2,sjcl.bn.prototype.radix));
+sjcl.bn.prototype.radixMask = (1 << sjcl.bn.prototype.radix) - 1;
+
+/**
+ * Creates a new subclass of bn, based on reduction modulo a pseudo-Mersenne prime,
+ * i.e. a prime of the form 2^e + sum(a * 2^b),where the sum is negative and sparse.
+ */
+sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
+ /** @constructor */
+ function p(it) {
+ this.initWith(it);
+ /*if (this.limbs[this.modOffset]) {
+ this.reduce();
+ }*/
+ }
+
+ var ppr = p.prototype = new sjcl.bn(), i, tmp, mo;
+ mo = ppr.modOffset = Math.ceil(tmp = exponent / ppr.radix);
+ ppr.exponent = exponent;
+ ppr.offset = [];
+ ppr.factor = [];
+ ppr.minOffset = mo;
+ ppr.fullMask = 0;
+ ppr.fullOffset = [];
+ ppr.fullFactor = [];
+ ppr.modulus = p.modulus = new sjcl.bn(Math.pow(2,exponent));
+
+ ppr.fullMask = 0|-Math.pow(2, exponent % ppr.radix);
+
+ for (i=0; i mo) {
+ l = limbs.pop();
+ ll = limbs.length;
+ for (k=0; k=0; i--) {
+ for (j=sjcl.bn.prototype.radix-4; j>=0; j-=4) {
+ out = out.doubl().doubl().doubl().doubl().add(multiples[k[i]>>j & 0xF]);
+ }
+ }
+
+ return out;
+ },
+
+ /**
+ * Multiply this point by k, added to affine2*k2, and return the answer in Jacobian coordinates.
+ * @param {bigInt} k The coefficient to multiply this by.
+ * @param {sjcl.ecc.point} affine This point in affine coordinates.
+ * @param {bigInt} k2 The coefficient to multiply affine2 this by.
+ * @param {sjcl.ecc.point} affine The other point in affine coordinates.
+ * @return {sjcl.ecc.pointJac} The result of the multiplication and addition, in Jacobian coordinates.
+ */
+ mult2: function(k1, affine, k2, affine2) {
+ if (typeof(k1) === "number") {
+ k1 = [k1];
+ } else if (k1.limbs !== undefined) {
+ k1 = k1.normalize().limbs;
+ }
+
+ if (typeof(k2) === "number") {
+ k2 = [k2];
+ } else if (k2.limbs !== undefined) {
+ k2 = k2.normalize().limbs;
+ }
+
+ var i, j, out = new sjcl.ecc.point(this.curve).toJac(), m1 = affine.multiples(),
+ m2 = affine2.multiples(), l1, l2;
+
+ for (i=Math.max(k1.length,k2.length)-1; i>=0; i--) {
+ l1 = k1[i] | 0;
+ l2 = k2[i] | 0;
+ for (j=sjcl.bn.prototype.radix-4; j>=0; j-=4) {
+ out = out.doubl().doubl().doubl().doubl().add(m1[l1>>j & 0xF]).add(m2[l2>>j & 0xF]);
+ }
+ }
+
+ return out;
+ },
+
+ isValid: function() {
+ var z2 = this.z.square(), z4 = z2.square(), z6 = z4.mul(z2);
+ return this.y.square().equals(
+ this.curve.b.mul(z6).add(this.x.mul(
+ this.curve.a.mul(z4).add(this.x.square()))));
+ }
+};
+
+/**
+ * Construct an elliptic curve. Most users will not use this and instead start with one of the NIST curves defined below.
+ *
+ * @constructor
+ * @param {bigInt} p The prime modulus.
+ * @param {bigInt} r The prime order of the curve.
+ * @param {bigInt} a The constant a in the equation of the curve y^2 = x^3 + ax + b (for NIST curves, a is always -3).
+ * @param {bigInt} x The x coordinate of a base point of the curve.
+ * @param {bigInt} y The y coordinate of a base point of the curve.
+ */
+sjcl.ecc.curve = function(Field, r, a, b, x, y) {
+ this.field = Field;
+ this.r = Field.prototype.modulus.sub(r);
+ this.a = new Field(a);
+ this.b = new Field(b);
+ this.G = new sjcl.ecc.point(this, new Field(x), new Field(y));
+};
+
+sjcl.ecc.curve.prototype.fromBits = function (bits) {
+ var w = sjcl.bitArray, l = this.field.prototype.exponent + 7 & -8,
+ p = new sjcl.ecc.point(this, this.field.fromBits(w.bitSlice(bits, 0, l)),
+ this.field.fromBits(w.bitSlice(bits, l, 2*l)));
+ if (!p.isValid()) {
+ throw new sjcl.exception.corrupt("not on the curve!");
+ }
+ return p;
+};
+
+sjcl.ecc.curves = {
+ c192: new sjcl.ecc.curve(
+ sjcl.bn.prime.p192,
+ "0x662107c8eb94364e4b2dd7ce",
+ -3,
+ "0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1",
+ "0x188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012",
+ "0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811"),
+
+ c224: new sjcl.ecc.curve(
+ sjcl.bn.prime.p224,
+ "0xe95c1f470fc1ec22d6baa3a3d5c4",
+ -3,
+ "0xb4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4",
+ "0xb70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+ "0xbd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"),
+
+ c256: new sjcl.ecc.curve(
+ sjcl.bn.prime.p256,
+ "0x4319055358e8617b0c46353d039cdaae",
+ -3,
+ "0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b",
+ "0x6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
+ "0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"),
+
+ c384: new sjcl.ecc.curve(
+ sjcl.bn.prime.p384,
+ "0x389cb27e0bc8d21fa7e5f24cb74f58851313e696333ad68c",
+ -3,
+ "0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aef",
+ "0xaa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7",
+ "0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f")
+};
+
+
+/* Diffie-Hellman-like public-key system */
+sjcl.ecc._dh = function(cn) {
+ sjcl.ecc[cn] = {
+ /** @constructor */
+ publicKey: function(curve, point) {
+ this._curve = curve;
+ this._curveBitLength = curve.r.bitLength();
+ if (point instanceof Array) {
+ this._point = curve.fromBits(point);
+ } else {
+ this._point = point;
+ }
+
+ this.get = function() {
+ var pointbits = this._point.toBits();
+ var len = sjcl.bitArray.bitLength(pointbits);
+ var x = sjcl.bitArray.bitSlice(pointbits, 0, len/2);
+ var y = sjcl.bitArray.bitSlice(pointbits, len/2);
+ return { x: x, y: y };
+ }
+ },
+
+ /** @constructor */
+ secretKey: function(curve, exponent) {
+ this._curve = curve;
+ this._curveBitLength = curve.r.bitLength();
+ this._exponent = exponent;
+
+ this.get = function() {
+ return this._exponent.toBits();
+ }
+ },
+
+ /** @constructor */
+ generateKeys: function(curve, paranoia, sec) {
+ if (curve === undefined) {
+ curve = 256;
+ }
+ if (typeof curve === "number") {
+ curve = sjcl.ecc.curves['c'+curve];
+ if (curve === undefined) {
+ throw new sjcl.exception.invalid("no such curve");
+ }
+ }
+ if (sec === undefined) {
+ var sec = sjcl.bn.random(curve.r, paranoia);
+ }
+ var pub = curve.G.mult(sec);
+ return { pub: new sjcl.ecc[cn].publicKey(curve, pub),
+ sec: new sjcl.ecc[cn].secretKey(curve, sec) };
+ }
+ };
+};
+
+sjcl.ecc._dh("elGamal");
+
+sjcl.ecc.elGamal.publicKey.prototype = {
+ kem: function(paranoia) {
+ var sec = sjcl.bn.random(this._curve.r, paranoia),
+ tag = this._curve.G.mult(sec).toBits(),
+ key = sjcl.hash.sha256.hash(this._point.mult(sec).toBits());
+ return { key: key, tag: tag };
+ }
+};
+
+sjcl.ecc.elGamal.secretKey.prototype = {
+ unkem: function(tag) {
+ return sjcl.hash.sha256.hash(this._curve.fromBits(tag).mult(this._exponent).toBits());
+ },
+
+ dh: function(pk) {
+ return sjcl.hash.sha256.hash(pk._point.mult(this._exponent).toBits());
+ }
+};
+
+sjcl.ecc._dh("ecdsa");
+
+sjcl.ecc.ecdsa.secretKey.prototype = {
+ sign: function(hash, paranoia, fakeLegacyVersion, fixedKForTesting) {
+ if (sjcl.bitArray.bitLength(hash) > this._curveBitLength) {
+ hash = sjcl.bitArray.clamp(hash, this._curveBitLength);
+ }
+ var R = this._curve.r,
+ l = R.bitLength(),
+ k = fixedKForTesting || sjcl.bn.random(R.sub(1), paranoia).add(1),
+ r = this._curve.G.mult(k).x.mod(R),
+ ss = sjcl.bn.fromBits(hash).add(r.mul(this._exponent)),
+ s = fakeLegacyVersion ? ss.inverseMod(R).mul(k).mod(R)
+ : ss.mul(k.inverseMod(R)).mod(R);
+ return sjcl.bitArray.concat(r.toBits(l), s.toBits(l));
+ }
+};
+
+sjcl.ecc.ecdsa.publicKey.prototype = {
+ verify: function(hash, rs, fakeLegacyVersion) {
+ if (sjcl.bitArray.bitLength(hash) > this._curveBitLength) {
+ hash = sjcl.bitArray.clamp(hash, this._curveBitLength);
+ }
+ var w = sjcl.bitArray,
+ R = this._curve.r,
+ l = this._curveBitLength,
+ r = sjcl.bn.fromBits(w.bitSlice(rs,0,l)),
+ ss = sjcl.bn.fromBits(w.bitSlice(rs,l,2*l)),
+ s = fakeLegacyVersion ? ss : ss.inverseMod(R),
+ hG = sjcl.bn.fromBits(hash).mul(s).mod(R),
+ hA = r.mul(s).mod(R),
+ r2 = this._curve.G.mult2(hG, hA, this._point).x;
+ if (r.equals(0) || ss.equals(0) || r.greaterEquals(R) || ss.greaterEquals(R) || !r2.equals(r)) {
+ if (fakeLegacyVersion === undefined) {
+ return this.verify(hash, rs, true);
+ } else {
+ throw (new sjcl.exception.corrupt("signature didn't check out"));
+ }
+ }
+ return true;
+ }
+};
+
+/** @fileOverview Javascript SRP implementation.
+ *
+ * This file contains a partial implementation of the SRP (Secure Remote
+ * Password) password-authenticated key exchange protocol. Given a user
+ * identity, salt, and SRP group, it generates the SRP verifier that may
+ * be sent to a remote server to establish and SRP account.
+ *
+ * For more information, see http://srp.stanford.edu/.
+ *
+ * @author Quinn Slack
+ */
+
+/**
+ * Compute the SRP verifier from the username, password, salt, and group.
+ * @class SRP
+ */
+sjcl.keyexchange.srp = {
+ /**
+ * Calculates SRP v, the verifier.
+ * v = g^x mod N [RFC 5054]
+ * @param {String} I The username.
+ * @param {String} P The password.
+ * @param {Object} s A bitArray of the salt.
+ * @param {Object} group The SRP group. Use sjcl.keyexchange.srp.knownGroup
+ to obtain this object.
+ * @return {Object} A bitArray of SRP v.
+ */
+ makeVerifier: function(I, P, s, group) {
+ var x;
+ x = sjcl.keyexchange.srp.makeX(I, P, s);
+ x = sjcl.bn.fromBits(x);
+ return group.g.powermod(x, group.N);
+ },
+
+ /**
+ * Calculates SRP x.
+ * x = SHA1( | SHA( | ":" | )) [RFC 2945]
+ * @param {String} I The username.
+ * @param {String} P The password.
+ * @param {Object} s A bitArray of the salt.
+ * @return {Object} A bitArray of SRP x.
+ */
+ makeX: function(I, P, s) {
+ var inner = sjcl.hash.sha1.hash(I + ':' + P);
+ return sjcl.hash.sha1.hash(sjcl.bitArray.concat(s, inner));
+ },
+
+ /**
+ * Returns the known SRP group with the given size (in bits).
+ * @param {String} i The size of the known SRP group.
+ * @return {Object} An object with "N" and "g" properties.
+ */
+ knownGroup:function(i) {
+ if (typeof i !== "string") { i = i.toString(); }
+ if (!sjcl.keyexchange.srp._didInitKnownGroups) { sjcl.keyexchange.srp._initKnownGroups(); }
+ return sjcl.keyexchange.srp._knownGroups[i];
+ },
+
+ /**
+ * Initializes bignum objects for known group parameters.
+ * @private
+ */
+ _didInitKnownGroups: false,
+ _initKnownGroups:function() {
+ var i, size, group;
+ for (i=0; i < sjcl.keyexchange.srp._knownGroupSizes.length; i++) {
+ size = sjcl.keyexchange.srp._knownGroupSizes[i].toString();
+ group = sjcl.keyexchange.srp._knownGroups[size];
+ group.N = new sjcl.bn(group.N);
+ group.g = new sjcl.bn(group.g);
+ }
+ sjcl.keyexchange.srp._didInitKnownGroups = true;
+ },
+
+ _knownGroupSizes: [1024, 1536, 2048],
+ _knownGroups: {
+ 1024: {
+ N: "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C" +
+ "9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE4" +
+ "8E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B29" +
+ "7BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9A" +
+ "FD5138FE8376435B9FC61D2FC0EB06E3",
+ g:2
+ },
+
+ 1536: {
+ N: "9DEF3CAFB939277AB1F12A8617A47BBBDBA51DF499AC4C80BEEEA961" +
+ "4B19CC4D5F4F5F556E27CBDE51C6A94BE4607A291558903BA0D0F843" +
+ "80B655BB9A22E8DCDF028A7CEC67F0D08134B1C8B97989149B609E0B" +
+ "E3BAB63D47548381DBC5B1FC764E3F4B53DD9DA1158BFD3E2B9C8CF5" +
+ "6EDF019539349627DB2FD53D24B7C48665772E437D6C7F8CE442734A" +
+ "F7CCB7AE837C264AE3A9BEB87F8A2FE9B8B5292E5A021FFF5E91479E" +
+ "8CE7A28C2442C6F315180F93499A234DCF76E3FED135F9BB",
+ g: 2
+ },
+
+ 2048: {
+ N: "AC6BDB41324A9A9BF166DE5E1389582FAF72B6651987EE07FC319294" +
+ "3DB56050A37329CBB4A099ED8193E0757767A13DD52312AB4B03310D" +
+ "CD7F48A9DA04FD50E8083969EDB767B0CF6095179A163AB3661A05FB" +
+ "D5FAAAE82918A9962F0B93B855F97993EC975EEAA80D740ADBF4FF74" +
+ "7359D041D5C33EA71D281E446B14773BCA97B43A23FB801676BD207A" +
+ "436C6481F1D2B9078717461A5B9D32E688F87748544523B524B0D57D" +
+ "5EA77A2775D2ECFA032CFBDBF52FB3786160279004E57AE6AF874E73" +
+ "03CE53299CCC041C7BC308D82A5698F3A8D0C38271AE35F8E9DBFBB6" +
+ "94B5C803D89F7AE435DE236D525F54759B65E372FCD68EF20FA7111F" +
+ "9E4AFF73",
+ g: 2
+ }
+ }
+
+};
+
+
+// ----- for secp256k1 ------
+
+// Overwrite NIST-P256 with secp256k1
+sjcl.ecc.curves.c256 = new sjcl.ecc.curve(
+ sjcl.bn.pseudoMersennePrime(256, [[0,-1],[4,-1],[6,-1],[7,-1],[8,-1],[9,-1],[32,-1]]),
+ "0x14551231950b75fc4402da1722fc9baee",
+ 0,
+ 7,
+ "0x79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798",
+ "0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8"
+);
+
+// Replace point addition and doubling algorithms
+// NIST-P256 is a=-3, we need algorithms for a=0
+sjcl.ecc.pointJac.prototype.add = function(T) {
+ var S = this;
+ if (S.curve !== T.curve) {
+ throw("sjcl.ecc.add(): Points must be on the same curve to add them!");
+ }
+
+ if (S.isIdentity) {
+ return T.toJac();
+ } else if (T.isIdentity) {
+ return S;
+ }
+
+ var z1z1 = S.z.square();
+ var h = T.x.mul(z1z1).subM(S.x);
+ var s2 = T.y.mul(S.z).mul(z1z1);
+
+ if (h.equals(0)) {
+ if (S.y.equals(T.y.mul(z1z1.mul(S.z)))) {
+ // same point
+ return S.doubl();
+ } else {
+ // inverses
+ return new sjcl.ecc.pointJac(S.curve);
+ }
+ }
+
+ var hh = h.square();
+ var i = hh.copy().doubleM().doubleM();
+ var j = h.mul(i);
+ var r = s2.sub(S.y).doubleM();
+ var v = S.x.mul(i);
+
+ var x = r.square().subM(j).subM(v.copy().doubleM());
+ var y = r.mul(v.sub(x)).subM(S.y.mul(j).doubleM());
+ var z = S.z.add(h).square().subM(z1z1).subM(hh);
+
+ return new sjcl.ecc.pointJac(this.curve,x,y,z);
+};
+
+sjcl.ecc.pointJac.prototype.doubl = function () {
+ if (this.isIdentity) { return this; }
+
+ var a = this.x.square();
+ var b = this.y.square();
+ var c = b.square();
+ var d = this.x.add(b).square().subM(a).subM(c).doubleM();
+ var e = a.mul(3);
+ var f = e.square();
+ var x = f.sub(d.copy().doubleM());
+ var y = e.mul(d.sub(x)).subM(c.doubleM().doubleM().doubleM());
+ var z = this.y.mul(this.z).doubleM();
+ return new sjcl.ecc.pointJac(this.curve, x, y, z);
+};
+
+sjcl.ecc.point.prototype.toBytesCompressed = function () {
+ var header = this.y.mod(2).toString() == "0x0" ? 0x02 : 0x03;
+ return [header].concat(sjcl.codec.bytes.fromBits(this.x.toBits()))
+};
+
+/** @fileOverview Javascript RIPEMD-160 implementation.
+ *
+ * @author Artem S Vybornov
+ */
+(function() {
+
+/**
+ * Context for a RIPEMD-160 operation in progress.
+ * @constructor
+ * @class RIPEMD, 160 bits.
+ */
+sjcl.hash.ripemd160 = function (hash) {
+ if (hash) {
+ this._h = hash._h.slice(0);
+ this._buffer = hash._buffer.slice(0);
+ this._length = hash._length;
+ } else {
+ this.reset();
+ }
+};
+
+/**
+ * Hash a string or an array of words.
+ * @static
+ * @param {bitArray|String} data the data to hash.
+ * @return {bitArray} The hash value, an array of 5 big-endian words.
+ */
+sjcl.hash.ripemd160.hash = function (data) {
+ return (new sjcl.hash.ripemd160()).update(data).finalize();
+};
+
+sjcl.hash.ripemd160.prototype = {
+ /**
+ * Reset the hash state.
+ * @return this
+ */
+ reset: function () {
+ this._h = _h0.slice(0);
+ this._buffer = [];
+ this._length = 0;
+ return this;
+ },
+
+ /**
+ * Reset the hash state.
+ * @param {bitArray|String} data the data to hash.
+ * @return this
+ */
+ update: function (data) {
+ if ( typeof data === "string" )
+ data = sjcl.codec.utf8String.toBits(data);
+
+ var i, b = this._buffer = sjcl.bitArray.concat(this._buffer, data),
+ ol = this._length,
+ nl = this._length = ol + sjcl.bitArray.bitLength(data);
+ for (i = 512+ol & -512; i <= nl; i+= 512) {
+ var words = b.splice(0,16);
+ for ( var w = 0; w < 16; ++w )
+ words[w] = _cvt(words[w]);
+
+ _block.call( this, words );
+ }
+
+ return this;
+ },
+
+ /**
+ * Complete hashing and output the hash value.
+ * @return {bitArray} The hash value, an array of 5 big-endian words.
+ */
+ finalize: function () {
+ var b = sjcl.bitArray.concat( this._buffer, [ sjcl.bitArray.partial(1,1) ] ),
+ l = ( this._length + 1 ) % 512,
+ z = ( l > 448 ? 512 : 448 ) - l % 448,
+ zp = z % 32;
+
+ if ( zp > 0 )
+ b = sjcl.bitArray.concat( b, [ sjcl.bitArray.partial(zp,0) ] )
+ for ( ; z >= 32; z -= 32 )
+ b.push(0);
+
+ b.push( _cvt( this._length | 0 ) );
+ b.push( _cvt( Math.floor(this._length / 0x100000000) ) );
+
+ while ( b.length ) {
+ var words = b.splice(0,16);
+ for ( var w = 0; w < 16; ++w )
+ words[w] = _cvt(words[w]);
+
+ _block.call( this, words );
+ }
+
+ var h = this._h;
+ this.reset();
+
+ for ( var w = 0; w < 5; ++w )
+ h[w] = _cvt(h[w]);
+
+ return h;
+ }
+};
+
+var _h0 = [ 0x67452301, 0xefcdab89, 0x98badcfe, 0x10325476, 0xc3d2e1f0 ];
+
+var _k1 = [ 0x00000000, 0x5a827999, 0x6ed9eba1, 0x8f1bbcdc, 0xa953fd4e ];
+var _k2 = [ 0x50a28be6, 0x5c4dd124, 0x6d703ef3, 0x7a6d76e9, 0x00000000 ];
+for ( var i = 4; i >= 0; --i ) {
+ for ( var j = 1; j < 16; ++j ) {
+ _k1.splice(i,0,_k1[i]);
+ _k2.splice(i,0,_k2[i]);
+ }
+}
+
+var _r1 = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 7, 4, 13, 1, 10, 6, 15, 3, 12, 0, 9, 5, 2, 14, 11, 8,
+ 3, 10, 14, 4, 9, 15, 8, 1, 2, 7, 0, 6, 13, 11, 5, 12,
+ 1, 9, 11, 10, 0, 8, 12, 4, 13, 3, 7, 15, 14, 5, 6, 2,
+ 4, 0, 5, 9, 7, 12, 2, 10, 14, 1, 3, 8, 11, 6, 15, 13 ];
+var _r2 = [ 5, 14, 7, 0, 9, 2, 11, 4, 13, 6, 15, 8, 1, 10, 3, 12,
+ 6, 11, 3, 7, 0, 13, 5, 10, 14, 15, 8, 12, 4, 9, 1, 2,
+ 15, 5, 1, 3, 7, 14, 6, 9, 11, 8, 12, 2, 10, 0, 4, 13,
+ 8, 6, 4, 1, 3, 11, 15, 0, 5, 12, 2, 13, 9, 7, 10, 14,
+ 12, 15, 10, 4, 1, 5, 8, 7, 6, 2, 13, 14, 0, 3, 9, 11 ];
+
+var _s1 = [ 11, 14, 15, 12, 5, 8, 7, 9, 11, 13, 14, 15, 6, 7, 9, 8,
+ 7, 6, 8, 13, 11, 9, 7, 15, 7, 12, 15, 9, 11, 7, 13, 12,
+ 11, 13, 6, 7, 14, 9, 13, 15, 14, 8, 13, 6, 5, 12, 7, 5,
+ 11, 12, 14, 15, 14, 15, 9, 8, 9, 14, 5, 6, 8, 6, 5, 12,
+ 9, 15, 5, 11, 6, 8, 13, 12, 5, 12, 13, 14, 11, 8, 5, 6 ];
+var _s2 = [ 8, 9, 9, 11, 13, 15, 15, 5, 7, 7, 8, 11, 14, 14, 12, 6,
+ 9, 13, 15, 7, 12, 8, 9, 11, 7, 7, 12, 7, 6, 15, 13, 11,
+ 9, 7, 15, 11, 8, 6, 6, 14, 12, 13, 5, 14, 13, 13, 7, 5,
+ 15, 5, 8, 11, 14, 14, 6, 14, 6, 9, 12, 9, 12, 5, 15, 8,
+ 8, 5, 12, 9, 12, 5, 14, 6, 8, 13, 6, 5, 15, 13, 11, 11 ];
+
+function _f0(x,y,z) {
+ return x ^ y ^ z;
+};
+
+function _f1(x,y,z) {
+ return (x & y) | (~x & z);
+};
+
+function _f2(x,y,z) {
+ return (x | ~y) ^ z;
+};
+
+function _f3(x,y,z) {
+ return (x & z) | (y & ~z);
+};
+
+function _f4(x,y,z) {
+ return x ^ (y | ~z);
+};
+
+function _rol(n,l) {
+ return (n << l) | (n >>> (32-l));
+}
+
+function _cvt(n) {
+ return ( (n & 0xff << 0) << 24 )
+ | ( (n & 0xff << 8) << 8 )
+ | ( (n & 0xff << 16) >>> 8 )
+ | ( (n & 0xff << 24) >>> 24 );
+}
+
+function _block(X) {
+ var A1 = this._h[0], B1 = this._h[1], C1 = this._h[2], D1 = this._h[3], E1 = this._h[4],
+ A2 = this._h[0], B2 = this._h[1], C2 = this._h[2], D2 = this._h[3], E2 = this._h[4];
+
+ var j = 0, T;
+
+ for ( ; j < 16; ++j ) {
+ T = _rol( A1 + _f0(B1,C1,D1) + X[_r1[j]] + _k1[j], _s1[j] ) + E1;
+ A1 = E1; E1 = D1; D1 = _rol(C1,10); C1 = B1; B1 = T;
+ T = _rol( A2 + _f4(B2,C2,D2) + X[_r2[j]] + _k2[j], _s2[j] ) + E2;
+ A2 = E2; E2 = D2; D2 = _rol(C2,10); C2 = B2; B2 = T; }
+ for ( ; j < 32; ++j ) {
+ T = _rol( A1 + _f1(B1,C1,D1) + X[_r1[j]] + _k1[j], _s1[j] ) + E1;
+ A1 = E1; E1 = D1; D1 = _rol(C1,10); C1 = B1; B1 = T;
+ T = _rol( A2 + _f3(B2,C2,D2) + X[_r2[j]] + _k2[j], _s2[j] ) + E2;
+ A2 = E2; E2 = D2; D2 = _rol(C2,10); C2 = B2; B2 = T; }
+ for ( ; j < 48; ++j ) {
+ T = _rol( A1 + _f2(B1,C1,D1) + X[_r1[j]] + _k1[j], _s1[j] ) + E1;
+ A1 = E1; E1 = D1; D1 = _rol(C1,10); C1 = B1; B1 = T;
+ T = _rol( A2 + _f2(B2,C2,D2) + X[_r2[j]] + _k2[j], _s2[j] ) + E2;
+ A2 = E2; E2 = D2; D2 = _rol(C2,10); C2 = B2; B2 = T; }
+ for ( ; j < 64; ++j ) {
+ T = _rol( A1 + _f3(B1,C1,D1) + X[_r1[j]] + _k1[j], _s1[j] ) + E1;
+ A1 = E1; E1 = D1; D1 = _rol(C1,10); C1 = B1; B1 = T;
+ T = _rol( A2 + _f1(B2,C2,D2) + X[_r2[j]] + _k2[j], _s2[j] ) + E2;
+ A2 = E2; E2 = D2; D2 = _rol(C2,10); C2 = B2; B2 = T; }
+ for ( ; j < 80; ++j ) {
+ T = _rol( A1 + _f4(B1,C1,D1) + X[_r1[j]] + _k1[j], _s1[j] ) + E1;
+ A1 = E1; E1 = D1; D1 = _rol(C1,10); C1 = B1; B1 = T;
+ T = _rol( A2 + _f0(B2,C2,D2) + X[_r2[j]] + _k2[j], _s2[j] ) + E2;
+ A2 = E2; E2 = D2; D2 = _rol(C2,10); C2 = B2; B2 = T; }
+
+ T = this._h[1] + C1 + D2;
+ this._h[1] = this._h[2] + D1 + E2;
+ this._h[2] = this._h[3] + E1 + A2;
+ this._h[3] = this._h[4] + A1 + B2;
+ this._h[4] = this._h[0] + B1 + C2;
+ this._h[0] = T;
+}
+
+})();
+
+sjcl.bn.ZERO = new sjcl.bn(0);
+
+/** [ this / that , this % that ] */
+sjcl.bn.prototype.divRem = function (that) {
+ if (typeof(that) !== "object") { that = new this._class(that); }
+ var thisa = this.abs(), thata = that.abs(), quot = new this._class(0),
+ ci = 0;
+ if (!thisa.greaterEquals(thata)) {
+ return [new sjcl.bn(0), this.copy()];
+ } else if (thisa.equals(thata)) {
+ return [new sjcl.bn(1), new sjcl.bn(0)];
+ }
+
+ for (; thisa.greaterEquals(thata); ci++) {
+ thata.doubleM();
+ }
+ for (; ci > 0; ci--) {
+ quot.doubleM();
+ thata.halveM();
+ if (thisa.greaterEquals(thata)) {
+ quot.addM(1);
+ thisa.subM(that).normalize();
+ }
+ }
+ return [quot, thisa];
+};
+
+/** this /= that (rounded to nearest int) */
+sjcl.bn.prototype.divRound = function (that) {
+ var dr = this.divRem(that), quot = dr[0], rem = dr[1];
+
+ if (rem.doubleM().greaterEquals(that)) {
+ quot.addM(1);
+ }
+
+ return quot;
+};
+
+/** this /= that (rounded down) */
+sjcl.bn.prototype.div = function (that) {
+ var dr = this.divRem(that);
+ return dr[0];
+};
+
+sjcl.bn.prototype.sign = function () {
+ return this.greaterEquals(sjcl.bn.ZERO) ? 1 : -1;
+};
+
+/** -this */
+sjcl.bn.prototype.neg = function () {
+ return sjcl.bn.ZERO.sub(this);
+};
+
+/** |this| */
+sjcl.bn.prototype.abs = function () {
+ if (this.sign() === -1) {
+ return this.neg();
+ } else return this;
+};
+
+/** this >> that */
+sjcl.bn.prototype.shiftRight = function (that) {
+ if ("number" !== typeof that) {
+ throw new Error("shiftRight expects a number");
+ }
+
+ that = +that;
+
+ if (that < 0) {
+ return this.shiftLeft(that);
+ }
+
+ var a = new sjcl.bn(this);
+
+ while (that >= this.radix) {
+ a.limbs.shift();
+ that -= this.radix;
+ }
+
+ while (that--) {
+ a.halveM();
+ }
+
+ return a;
+};
+
+/** this >> that */
+sjcl.bn.prototype.shiftLeft = function (that) {
+ if ("number" !== typeof that) {
+ throw new Error("shiftLeft expects a number");
+ }
+
+ that = +that;
+
+ if (that < 0) {
+ return this.shiftRight(that);
+ }
+
+ var a = new sjcl.bn(this);
+
+ while (that >= this.radix) {
+ a.limbs.unshift(0);
+ that -= this.radix;
+ }
+
+ while (that--) {
+ a.doubleM();
+ }
+
+ return a;
+};
+
+/** (int)this */
+// NOTE Truncates to 32-bit integer
+sjcl.bn.prototype.toNumber = function () {
+ return this.limbs[0] | 0;
+};
+
+/** find n-th bit, 0 = LSB */
+sjcl.bn.prototype.testBit = function (bitIndex) {
+ var limbIndex = Math.floor(bitIndex / this.radix);
+ var bitIndexInLimb = bitIndex % this.radix;
+
+ if (limbIndex >= this.limbs.length) return 0;
+
+ return (this.limbs[limbIndex] >>> bitIndexInLimb) & 1;
+};
+
+/** set n-th bit, 0 = LSB */
+sjcl.bn.prototype.setBitM = function (bitIndex) {
+ var limbIndex = Math.floor(bitIndex / this.radix);
+ var bitIndexInLimb = bitIndex % this.radix;
+
+ while (limbIndex >= this.limbs.length) this.limbs.push(0);
+
+ this.limbs[limbIndex] |= 1 << bitIndexInLimb;
+
+ this.cnormalize();
+
+ return this;
+};
+
+sjcl.bn.prototype.modInt = function (n) {
+ return this.toNumber() % n;
+};
+
+sjcl.bn.prototype.invDigit = function ()
+{
+ var radixMod = 1 + this.radixMask;
+
+ if (this.limbs.length < 1) return 0;
+ var x = this.limbs[0];
+ if ((x&1) == 0) return 0;
+ var y = x&3; // y == 1/x mod 2^2
+ y = (y*(2-(x&0xf)*y))&0xf; // y == 1/x mod 2^4
+ y = (y*(2-(x&0xff)*y))&0xff; // y == 1/x mod 2^8
+ y = (y*(2-(((x&0xffff)*y)&0xffff)))&0xffff; // y == 1/x mod 2^16
+ // last step - calculate inverse mod DV directly;
+ // assumes 16 < radixMod <= 32 and assumes ability to handle 48-bit ints
+ y = (y*(2-x*y%radixMod))%radixMod; // y == 1/x mod 2^dbits
+ // we really want the negative inverse, and -DV < y < DV
+ return (y>0)?radixMod-y:-y;
+};
+
+// returns bit length of the integer x
+function nbits(x) {
+ var r = 1, t;
+ if((t=x>>>16) != 0) { x = t; r += 16; }
+ if((t=x>>8) != 0) { x = t; r += 8; }
+ if((t=x>>4) != 0) { x = t; r += 4; }
+ if((t=x>>2) != 0) { x = t; r += 2; }
+ if((t=x>>1) != 0) { x = t; r += 1; }
+ return r;
+}
+
+// JSBN-style add and multiply for SJCL w/ 24 bit radix
+sjcl.bn.prototype.am = function (i,x,w,j,c,n) {
+ var xl = x&0xfff, xh = x>>12;
+ while (--n >= 0) {
+ var l = this.limbs[i]&0xfff;
+ var h = this.limbs[i++]>>12;
+ var m = xh*l+h*xl;
+ l = xl*l+((m&0xfff)<<12)+w.limbs[j]+c;
+ c = (l>>24)+(m>>12)+xh*h;
+ w.limbs[j++] = l&0xffffff;
+ }
+ return c;
+}
+
+var Montgomery = function (m)
+{
+ this.m = m;
+ this.mt = m.limbs.length;
+ this.mt2 = this.mt * 2;
+ this.mp = m.invDigit();
+ this.mpl = this.mp&0x7fff;
+ this.mph = this.mp>>15;
+ this.um = (1<<(m.radix-15))-1;
+};
+
+Montgomery.prototype.reduce = function (x)
+{
+ var radixMod = x.radixMask + 1;
+ while (x.limbs.length <= this.mt2) // pad x so am has enough room later
+ x.limbs[x.limbs.length] = 0;
+ for (var i = 0; i < this.mt; ++i) {
+ // faster way of calculating u0 = x[i]*mp mod 2^radix
+ var j = x.limbs[i]&0x7fff;
+ var u0 = (j*this.mpl+(((j*this.mph+(x.limbs[i]>>15)*this.mpl)&this.um)<<15))&x.radixMask;
+ // use am to combine the multiply-shift-add into one call
+ j = i+this.mt;
+ x.limbs[j] += this.m.am(0,u0,x,i,0,this.mt);
+ // propagate carry
+ while (x.limbs[j] >= radixMod) { x.limbs[j] -= radixMod; x.limbs[++j]++; }
+ }
+ x.trim();
+ x = x.shiftRight(this.mt * this.m.radix);
+ if (x.greaterEquals(this.m)) x = x.sub(this.m);
+ return x.trim().normalize().reduce();
+};
+
+Montgomery.prototype.square = function (x)
+{
+ return this.reduce(x.square());
+};
+
+Montgomery.prototype.multiply = function (x, y)
+{
+ return this.reduce(x.mul(y));
+};
+
+Montgomery.prototype.convert = function (x)
+{
+ return x.abs().shiftLeft(this.mt * this.m.radix).mod(this.m);
+};
+
+Montgomery.prototype.revert = function (x)
+{
+ return this.reduce(x.copy());
+};
+
+sjcl.bn.prototype.powermodMontgomery = function (e, m)
+{
+ var i = e.bitLength(), k, r = new this._class(1);
+
+ if (i <= 0) return r;
+ else if (i < 18) k = 1;
+ else if (i < 48) k = 3;
+ else if (i < 144) k = 4;
+ else if (i < 768) k = 5;
+ else k = 6;
+
+ if (i < 8 || !m.testBit(0)) {
+ // For small exponents and even moduli, use a simple square-and-multiply
+ // algorithm.
+ return this.powermod(e, m);
+ }
+
+ var z = new Montgomery(m);
+
+ e.trim().normalize();
+
+ // precomputation
+ var g = new Array(), n = 3, k1 = k-1, km = (1< 1) {
+ var g2 = z.square(g[1]);
+
+ while (n <= km) {
+ g[n] = z.multiply(g2, g[n-2]);
+ n += 2;
+ }
+ }
+
+ var j = e.limbs.length-1, w, is1 = true, r2 = new this._class(), t;
+ i = nbits(e.limbs[j])-1;
+ while (j >= 0) {
+ if (i >= k1) w = (e.limbs[j]>>(i-k1))&km;
+ else {
+ w = (e.limbs[j]&((1<<(i+1))-1))<<(k1-i);
+ if (j > 0) w |= e.limbs[j-1]>>(this.radix+i-k1);
+ }
+
+ n = k;
+ while ((w&1) == 0) { w >>= 1; --n; }
+ if ((i -= n) < 0) { i += this.radix; --j; }
+ if (is1) { // ret == 1, don't bother squaring or multiplying it
+ r = g[w].copy();
+ is1 = false;
+ } else {
+ while (n > 1) { r2 = z.square(r); r = z.square(r2); n -= 2; }
+ if (n > 0) r2 = z.square(r); else { t = r; r = r2; r2 = t; }
+ r = z.multiply(r2,g[w]);
+ }
+
+ while (j >= 0 && (e.limbs[j]&(1<