diff --git a/.gitignore b/.gitignore index 6b9478d9..43220117 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,7 @@ # Ignore object files. *.o -build/ripple*.js +build/*.js tags bin/rippled Debug/*.* @@ -51,4 +51,4 @@ test/config.js npm-debug.log # Ignore dist folder, build for bower -dist/ \ No newline at end of file +dist/ diff --git a/README.md b/README.md index 433fab8d..65f636c5 100644 --- a/README.md +++ b/README.md @@ -78,7 +78,7 @@ remote.connect(function() { 2. `cd` into the repository and install dependencies with `npm install` -3. `npm test` or `node_modules\.bin\mocha test\*-test.js` +3. `npm test` or `node_modules/.bin/mocha test/*-test.js` **Generating code coverage** diff --git a/build/sjcl.js b/build/sjcl.js deleted file mode 100644 index 6eb17447..00000000 --- a/build/sjcl.js +++ /dev/null @@ -1,4550 +0,0 @@ -/** @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 - } - } - -}; - - -/** - * Check that the point is valid based on the method described in - * SEC 1: Elliptic Curve Cryptography, section 3.2.2.1: - * Elliptic Curve Public Key Validation Primitive - * http://www.secg.org/download/aid-780/sec1-v2.pdf - * - * @returns {Boolean} - */ -sjcl.ecc.point.prototype.isValidPoint = function() { - - var self = this; - - var field_modulus = self.curve.field.modulus; - - if (self.isIdentity) { - return false; - } - - // Check that coordinatres are in bounds - // Return false if x < 1 or x > (field_modulus - 1) - if (((new sjcl.bn(1).greaterEquals(self.x)) && - !self.x.equals(1)) || - (self.x.greaterEquals(field_modulus.sub(1))) && - !self.x.equals(1)) { - - return false; - } - - // Return false if y < 1 or y > (field_modulus - 1) - if (((new sjcl.bn(1).greaterEquals(self.y)) && - !self.y.equals(1)) || - (self.y.greaterEquals(field_modulus.sub(1))) && - !self.y.equals(1)) { - - return false; - } - - if (!self.isOnCurve()) { - return false; - } - - // TODO check to make sure point is a scalar multiple of base_point - - return true; - -}; - -/** - * Check that the point is on the curve - * - * @returns {Boolean} - */ -sjcl.ecc.point.prototype.isOnCurve = function() { - - var self = this; - - var field_order = self.curve.r; - var component_a = self.curve.a; - var component_b = self.curve.b; - var field_modulus = self.curve.field.modulus; - - var left_hand_side = self.y.mul(self.y).mod(field_modulus); - var right_hand_side = self.x.mul(self.x).mul(self.x).add(component_a.mul(self.x)).add(component_b).mod(field_modulus); - - return left_hand_side.equals(right_hand_side); - -}; - - -sjcl.ecc.point.prototype.toString = function() { - return '(' + - this.x.toString() + ', ' + - this.y.toString() + - ')'; -}; - -sjcl.ecc.pointJac.prototype.toString = function() { - return '(' + - this.x.toString() + ', ' + - this.y.toString() + ', ' + - this.z.toString() + - ')'; -}; - -// ----- 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.z.mul(this.y).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< 0 && typeof k_for_testing[0] === 'number') { - k = k_for_testing; - } else if (typeof k_for_testing === 'string' && /^[0-9a-fA-F]+$/.test(k_for_testing)) { - k = sjcl.bn.fromBits(sjcl.codec.hex.toBits(k_for_testing)); - } else { - // This is the only option that should be used in production - k = sjcl.bn.random(R.sub(1), paranoia).add(1); - } - - var r = this._curve.G.mult(k).x.mod(R); - var s = sjcl.bn.fromBits(hash).add(r.mul(this._exponent)).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) { - var w = sjcl.bitArray, - R = this._curve.r, - l = R.bitLength(), - r = sjcl.bn.fromBits(w.bitSlice(rs,0,l)), - s = sjcl.bn.fromBits(w.bitSlice(rs,l,2*l)), - sInv = s.inverseMod(R), - hG = sjcl.bn.fromBits(hash).mul(sInv).mod(R), - hA = r.mul(sInv).mod(R), - r2 = this._curve.G.mult2(hG, hA, this._point).x; - - if (r.equals(0) || s.equals(0) || r.greaterEquals(R) || s.greaterEquals(R) || !r2.equals(r)) { - throw (new sjcl.exception.corrupt("signature didn't check out")); - } - return true; -}; - -sjcl.ecc.ecdsa.secretKey.prototype.canonicalizeSignature = function(rs) { - var w = sjcl.bitArray, - R = this._curve.r, - l = R.bitLength(); - - var r = sjcl.bn.fromBits(w.bitSlice(rs,0,l)), - s = sjcl.bn.fromBits(w.bitSlice(rs,l,2*l)); - - // For a canonical signature we want the lower of two possible values for s - // 0 < s <= n/2 - if (!R.copy().halveM().greaterEquals(s)) { - s = R.sub(s); - } - - return w.concat(r.toBits(l), s.toBits(l)); -}; - - -sjcl.ecc.ecdsa.secretKey.prototype.signDER = function(hash, paranoia) { - return this.encodeDER(this.sign(hash, paranoia)); -}; - -sjcl.ecc.ecdsa.secretKey.prototype.encodeDER = function(rs) { - var w = sjcl.bitArray, - R = this._curve.r, - l = R.bitLength(); - - var rb = sjcl.codec.bytes.fromBits(w.bitSlice(rs,0,l)), - sb = sjcl.codec.bytes.fromBits(w.bitSlice(rs,l,2*l)); - - // Drop empty leading bytes - while (!rb[0] && rb.length) rb.shift(); - while (!sb[0] && sb.length) sb.shift(); - - // If high bit is set, prepend an extra zero byte (DER signed integer) - if (rb[0] & 0x80) rb.unshift(0); - if (sb[0] & 0x80) sb.unshift(0); - - var buffer = [].concat( - 0x30, - 4 + rb.length + sb.length, - 0x02, - rb.length, - rb, - 0x02, - sb.length, - sb - ); - - return sjcl.codec.bytes.toBits(buffer); -}; - - -/** - * This module uses the public key recovery method - * described in SEC 1: Elliptic Curve Cryptography, - * section 4.1.6, "Public Key Recovery Operation". - * http://www.secg.org/download/aid-780/sec1-v2.pdf - * - * Implementation based on: - * https://github.com/bitcoinjs/bitcoinjs-lib/blob/89cf731ac7309b4f98994e3b4b67b7226020181f/src/ecdsa.js - */ - -// Defined here so that this value only needs to be calculated once -var FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR; - -/** - * Sign the given hash such that the public key, prepending an extra byte - * so that the public key will be recoverable from the signature - * - * @param {bitArray} hash - * @param {Number} paranoia - * @returns {bitArray} Signature formatted as bitArray - */ -sjcl.ecc.ecdsa.secretKey.prototype.signWithRecoverablePublicKey = function(hash, paranoia, k_for_testing) { - - var self = this; - - // Convert hash to bits and determine encoding for output - var hash_bits; - if (typeof hash === 'object' && hash.length > 0 && typeof hash[0] === 'number') { - hash_bits = hash; - } else { - throw new sjcl.exception.invalid('hash. Must be a bitArray'); - } - - // Sign hash with standard, canonicalized method - var standard_signature = self.sign(hash_bits, paranoia, k_for_testing); - var canonical_signature = self.canonicalizeSignature(standard_signature); - - // Extract r and s signature components from canonical signature - var r_and_s = getRandSFromSignature(self._curve, canonical_signature); - - // Rederive public key - var public_key = self._curve.G.mult(sjcl.bn.fromBits(self.get())); - - // Determine recovery factor based on which possible value - // returns the correct public key - var recovery_factor = calculateRecoveryFactor(self._curve, r_and_s.r, r_and_s.s, hash_bits, public_key); - - // Prepend recovery_factor to signature and encode in DER - // The value_to_prepend should be 4 bytes total - var value_to_prepend = recovery_factor + 27; - - var final_signature_bits = sjcl.bitArray.concat([value_to_prepend], canonical_signature); - - // Return value in bits - return final_signature_bits; - -}; - - -/** - * Recover the public key from a signature created with the - * signWithRecoverablePublicKey method in this module - * - * @static - * - * @param {bitArray} hash - * @param {bitArray} signature - * @param {sjcl.ecc.curve} [sjcl.ecc.curves['c256']] curve - * @returns {sjcl.ecc.ecdsa.publicKey} Public key - */ -sjcl.ecc.ecdsa.publicKey.recoverFromSignature = function(hash, signature, curve) { - - if (!signature || signature instanceof sjcl.ecc.curve) { - throw new sjcl.exception.invalid('must supply hash and signature to recover public key'); - } - - if (!curve) { - curve = sjcl.ecc.curves['c256']; - } - - // Convert hash to bits and determine encoding for output - var hash_bits; - if (typeof hash === 'object' && hash.length > 0 && typeof hash[0] === 'number') { - hash_bits = hash; - } else { - throw new sjcl.exception.invalid('hash. Must be a bitArray'); - } - - var signature_bits; - if (typeof signature === 'object' && signature.length > 0 && typeof signature[0] === 'number') { - signature_bits = signature; - } else { - throw new sjcl.exception.invalid('signature. Must be a bitArray'); - } - - // Extract recovery_factor from first 4 bytes - var recovery_factor = signature_bits[0] - 27; - - if (recovery_factor < 0 || recovery_factor > 3) { - throw new sjcl.exception.invalid('signature. Signature must be generated with algorithm ' + - 'that prepends the recovery factor in order to recover the public key'); - } - - // Separate r and s values - var r_and_s = getRandSFromSignature(curve, signature_bits.slice(1)); - var signature_r = r_and_s.r; - var signature_s = r_and_s.s; - - // Recover public key using recovery_factor - var recovered_public_key_point = recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, hash_bits, recovery_factor); - var recovered_public_key = new sjcl.ecc.ecdsa.publicKey(curve, recovered_public_key_point); - - return recovered_public_key; - -}; - - -/** - * Retrieve the r and s components of a signature - * - * @param {sjcl.ecc.curve} curve - * @param {bitArray} signature - * @returns {Object} Object with 'r' and 's' fields each as an sjcl.bn - */ -function getRandSFromSignature(curve, signature) { - - var r_length = curve.r.bitLength(); - - return { - r: sjcl.bn.fromBits(sjcl.bitArray.bitSlice(signature, 0, r_length)), - s: sjcl.bn.fromBits(sjcl.bitArray.bitSlice(signature, r_length, sjcl.bitArray.bitLength(signature))) - }; -}; - - -/** - * Determine the recovery factor by trying all four - * possibilities and figuring out which results in the - * correct public key - * - * @param {sjcl.ecc.curve} curve - * @param {sjcl.bn} r - * @param {sjcl.bn} s - * @param {bitArray} hash_bits - * @param {sjcl.ecc.point} original_public_key_point - * @returns {Number, 0-3} Recovery factor - */ -function calculateRecoveryFactor(curve, r, s, hash_bits, original_public_key_point) { - - var original_public_key_point_bits = original_public_key_point.toBits(); - - // TODO: verify that it is possible for the recovery_factor to be 2 or 3, - // we may only need 1 bit because the canonical signature might remove the - // possibility of us needing to "use the second candidate key" - for (var possible_factor = 0; possible_factor < 4; possible_factor++) { - - var resulting_public_key_point; - try { - resulting_public_key_point = recoverPublicKeyPointFromSignature(curve, r, s, hash_bits, possible_factor); - } catch (err) { - // console.log(err, err.stack); - continue; - } - - if (sjcl.bitArray.equal(resulting_public_key_point.toBits(), original_public_key_point_bits)) { - return possible_factor; - } - - } - - throw new sjcl.exception.bug('unable to calculate recovery factor from signature'); - -}; - - -/** - * Recover the public key from the signature. - * - * @param {sjcl.ecc.curve} curve - * @param {sjcl.bn} r - * @param {sjcl.bn} s - * @param {bitArray} hash_bits - * @param {Number, 0-3} recovery_factor - * @returns {sjcl.point} Public key corresponding to signature - */ -function recoverPublicKeyPointFromSignature(curve, signature_r, signature_s, hash_bits, recovery_factor) { - - var field_order = curve.r; - var field_modulus = curve.field.modulus; - - // Reduce the recovery_factor to the two bits used - recovery_factor = recovery_factor & 3; - - // The less significant bit specifies whether the y coordinate - // of the compressed point is even or not. - var compressed_point_y_coord_is_even = recovery_factor & 1; - - // The more significant bit specifies whether we should use the - // first or second candidate key. - var use_second_candidate_key = recovery_factor >> 1; - - // Calculate (field_order + 1) / 4 - if (!FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR) { - FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR = field_modulus.add(1).div(4); - } - - // In the paper they write "1. For j from 0 to h do the following..." - // That is not necessary here because we are given the recovery_factor - // step 1.1 Let x = r + jn - // Here "j" is either 0 or 1 - var x; - if (use_second_candidate_key) { - x = signature_r.add(field_order); - } else { - x = signature_r; - } - - // step 1.2 and 1.3 convert x to an elliptic curve point - // Following formula in section 2.3.4 Octet-String-to-Elliptic-Curve-Point Conversion - var alpha = x.mul(x).mul(x).add(curve.a.mul(x)).add(curve.b).mod(field_modulus); - var beta = alpha.powermodMontgomery(FIELD_MODULUS_PLUS_ONE_DIVIDED_BY_FOUR, field_modulus); - - // If beta is even but y isn't or - // if beta is odd and y is even - // then subtract beta from the field_modulus - var y; - var beta_is_even = beta.mod(2).equals(0); - if (beta_is_even && !compressed_point_y_coord_is_even || - !beta_is_even && compressed_point_y_coord_is_even) { - y = beta; - } else { - y = field_modulus.sub(beta); - } - - // generated_point_R is the point generated from x and y - var generated_point_R = new sjcl.ecc.point(curve, x, y); - - // step 1.4 check that R is valid and R x field_order !== infinity - // TODO: add check for R x field_order === infinity - if (!generated_point_R.isValidPoint()) { - throw new sjcl.exception.corrupt('point R. Not a valid point on the curve. Cannot recover public key'); - } - - // step 1.5 Compute e from M - var message_e = sjcl.bn.fromBits(hash_bits); - var message_e_neg = new sjcl.bn(0).sub(message_e).mod(field_order); - - // step 1.6 Compute Q = r^-1 (sR - eG) - // console.log('r: ', signature_r); - var signature_r_inv = signature_r.inverseMod(field_order); - var public_key_point = generated_point_R.mult2(signature_s, message_e_neg, curve.G).mult(signature_r_inv); - - // Validate public key point - if (!public_key_point.isValidPoint()) { - throw new sjcl.exception.corrupt('public_key_point. Not a valid point on the curve. Cannot recover public key'); - } - - // Verify that this public key matches the signature - if (!verify_raw(curve, message_e, signature_r, signature_s, public_key_point)) { - throw new sjcl.exception.corrupt('cannot recover public key'); - } - - return public_key_point; - -}; - - -/** - * Verify a signature given the raw components - * using method defined in section 4.1.5: - * "Alternative Verifying Operation" - * - * @param {sjcl.ecc.curve} curve - * @param {sjcl.bn} e - * @param {sjcl.bn} r - * @param {sjcl.bn} s - * @param {sjcl.ecc.point} public_key_point - * @returns {Boolean} - */ -function verify_raw(curve, e, r, s, public_key_point) { - - var field_order = curve.r; - - // Return false if r is out of bounds - if ((new sjcl.bn(1)).greaterEquals(r) || r.greaterEquals(new sjcl.bn(field_order))) { - return false; - } - - // Return false if s is out of bounds - if ((new sjcl.bn(1)).greaterEquals(s) || s.greaterEquals(new sjcl.bn(field_order))) { - return false; - } - - // Check that r = (u1 + u2)G - // u1 = e x s^-1 (mod field_order) - // u2 = r x s^-1 (mod field_order) - var s_mod_inverse_field_order = s.inverseMod(field_order); - var u1 = e.mul(s_mod_inverse_field_order).mod(field_order); - var u2 = r.mul(s_mod_inverse_field_order).mod(field_order); - - var point_computed = curve.G.mult2(u1, u2, public_key_point); - - return r.equals(point_computed.x.mod(field_order)); - -}; - - -sjcl.bn.prototype.jacobi = function (that) { - var a = this; - that = new sjcl.bn(that); - - if (that.sign() === -1) return; - - // 1. If a = 0 then return(0). - if (a.equals(0)) { return 0; } - - // 2. If a = 1 then return(1). - if (a.equals(1)) { return 1; } - - var s = 0; - - // 3. Write a = 2^e * a1, where a1 is odd. - var e = 0; - while (!a.testBit(e)) e++; - var a1 = a.shiftRight(e); - - // 4. If e is even then set s ← 1. - if ((e & 1) === 0) { - s = 1; - } else { - var residue = that.modInt(8); - - if (residue === 1 || residue === 7) { - // Otherwise set s ← 1 if n ≡ 1 or 7 (mod 8) - s = 1; - } else if (residue === 3 || residue === 5) { - // Or set s ← −1 if n ≡ 3 or 5 (mod 8). - s = -1; - } - } - - // 5. If n ≡ 3 (mod 4) and a1 ≡ 3 (mod 4) then set s ← −s. - if (that.modInt(4) === 3 && a1.modInt(4) === 3) { - s = -s; - } - - if (a1.equals(1)) { - return s; - } else { - return s * that.mod(a1).jacobi(a1); - } -}; diff --git a/package.json b/package.json index 1f520960..d50e5d6f 100644 --- a/package.json +++ b/package.json @@ -37,9 +37,10 @@ "yargs": "~1.3.1" }, "scripts": { + "postinstall": "node_modules/.bin/gulp concat-sjcl", "build": "node_modules/.bin/gulp", "pretest": "node_modules/.bin/gulp concat-sjcl", - "test": "./node_modules/.bin/istanbul test -x build/sjcl.js -x src/js/jsbn/* ./node_modules/.bin/_mocha -- --reporter spec test/*-test.js", + "test": "./node_modules/.bin/istanbul test -x build/sjcl.js -x src/js/jsbn/* ./node_modules/mocha/bin/mocha -- --reporter spec test/*-test.js", "coveralls": "cat ./coverage/lcov.info | ./node_modules/.bin/coveralls" }, "repository": {