diff --git a/core/bn.js b/core/bn.js index 55ecdba4..672fd085 100644 --- a/core/bn.js +++ b/core/bn.js @@ -275,10 +275,12 @@ sjcl.bn.prototype = { return out; }, - mulmod: function(x, N) { - return this.mod(N).mul(x.mod(N)).mod(N); + /** this * that mod N */ + mulmod: function(that, N) { + return this.mod(N).mul(that.mod(N)).mod(N); }, + /** this ^ x mod N */ powermod: function(x, N) { var result = new sjcl.bn(1), a = new sjcl.bn(this), k = new sjcl.bn(x); while (true) { diff --git a/core/sjcl.js b/core/sjcl.js index 6f1337ee..0c6a17c2 100644 --- a/core/sjcl.js +++ b/core/sjcl.js @@ -60,9 +60,9 @@ var sjcl = { this.message = message; }, - /** @class Bug or missing feature in SJCL. */ + /** @class Something isn't ready. */ notReady: function(message) { - this.toString = function() { return "GENERATOR NOT READY: "+this.message; }; + this.toString = function() { return "NOT READY: "+this.message; }; this.message = message; } } diff --git a/sjcl.js b/sjcl.js index 7a65e280..107d002a 100644 --- a/sjcl.js +++ b/sjcl.js @@ -1,4 +1,4 @@ -"use strict";var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"GENERATOR NOT READY: "+this.message};this.message=a}}}; +"use strict";var sjcl={cipher:{},hash:{},keyexchange:{},mode:{},misc:{},codec:{},exception:{corrupt:function(a){this.toString=function(){return"CORRUPT: "+this.message};this.message=a},invalid:function(a){this.toString=function(){return"INVALID: "+this.message};this.message=a},bug:function(a){this.toString=function(){return"BUG: "+this.message};this.message=a},notReady:function(a){this.toString=function(){return"NOT READY: "+this.message};this.message=a}}}; sjcl.cipher.aes=function(a){this.p[0][0][0]||this.M();var b,c,d,e,f=this.p[0][4],g=this.p[1];b=a.length;var h=1;if(b!==4&&b!==6&&b!==8)throw new sjcl.exception.invalid("invalid aes key size");this.c=[d=a.slice(0),e=[]];for(a=b;a<4*b+28;a++){c=d[a-1];if(a%b===0||b===8&&a%b===4){c=f[c>>>24]<<24^f[c>>16&255]<<16^f[c>>8&255]<<8^f[c&255];if(a%b===0){c=c<<8^c>>>24^h<<24;h=h<<1^(h>>7)*283}}d[a]=d[a-b]^c}for(b=0;a;b++,a--){c=d[b&3?a:a-4];e[b]=a<=4||b<4?c:g[0][f[c>>>24]]^g[1][f[c>>16&255]]^g[2][f[c>>8&255]]^ g[3][f[c&255]]}}; sjcl.cipher.aes.prototype={encrypt:function(a){return this.U(a,0)},decrypt:function(a){return this.U(a,1)},p:[[[],[],[],[],[]],[[],[],[],[],[]]],M:function(){var a=this.p[0],b=this.p[1],c=a[4],d=b[4],e,f,g,h=[],i=[],j,k,l,m;for(e=0;e<0x100;e++)i[(h[e]=e<<1^(e>>7)*283)^e]=e;for(f=g=0;!c[f];f^=j||1,g=i[g]||1){l=g^g<<1^g<<2^g<<3^g<<4;l=l>>8^l&255^99;c[f]=l;d[l]=f;k=h[e=h[j=h[f]]];m=k*0x1010101^e*0x10001^j*0x101^f*0x1010100;k=h[l]*0x101^l*0x1010100;for(e=0;e<4;e++){a[e][f]=k=k<<24^k>>>8;b[e][l]=m=m<<24^m>>>8}}for(e= @@ -10,13 +10,13 @@ a[d]^b[d];return c===0},fa:function(a,b,c,d){var e;e=0;if(d===undefined)d=[];for sjcl.codec.utf8String={fromBits:function(a){var b="",c=sjcl.bitArray.bitLength(a),d,e;for(d=0;d>>24);e<<=8}return decodeURIComponent(escape(b))},toBits:function(a){a=unescape(encodeURIComponent(a));var b=[],c,d=0;for(c=0;c>>e)>>>26);if(e<6){g=a[d]<<6-e;e+=26;d++}else{g<<=6;e-=6}}for(;c.length&3&&!b;)c+="=";return c},toBits:function(a){a=a.replace(/\s|=/g,"");var b=[],c,d=0,e=sjcl.codec.base64.R,f=0,g;for(c=0;c26){d-=26;b.push(f^g>>>d);f=g<<32-d}else{d+=6;f^=g<<32-d}}d&56&&b.push(sjcl.bitArray.partial(d&56,f,1));return b}};sjcl.hash.sha1=function(a){if(a){this.h=a.h.slice(0);this.e=a.e.slice(0);this.d=a.d}else this.reset()};sjcl.hash.sha1.hash=function(a){return(new sjcl.hash.sha1).update(a).finalize()}; -sjcl.hash.sha1.prototype={blockSize:512,reset:function(){this.h=this.w.slice(0);this.e=[];this.d=0;return this},update:function(a){if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);var b,c=this.e=sjcl.bitArray.concat(this.e,a);b=this.d;a=this.d=b+sjcl.bitArray.bitLength(a);for(b=this.blockSize+b&-this.blockSize;b<=a;b+=this.blockSize)this.q(c.splice(0,16));return this},finalize:function(){var a,b=this.e,c=this.h;b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0); -b.push(Math.floor(this.d/0x100000000));for(b.push(this.d|0);b.length;)this.q(b.splice(0,16));this.reset();return c},w:[1732584193,4023233417,2562383102,271733878,3285377520],c:[1518500249,1859775393,2400959708,3395469782],ja:function(a,b,c,d){if(a<=19)return b&c|~b&d;else if(a<=39)return b^c^d;else if(a<=59)return b&c|b&d|c&d;else if(a<=79)return b^c^d},D:function(a,b){return b<>>32-a},q:function(a){var b,c,d,e,f,g,h=a.slice(0),i=this.h;c=i[0];d=i[1];e=i[2];f=i[3];g=i[4];for(a=0;a<=79;a++){if(a>= -16)h[a]=this.D(1,h[a-3]^h[a-8]^h[a-14]^h[a-16]);b=this.D(5,c)+this.ja(a,d,e,f)+g+h[a]+this.c[Math.floor(a/20)]|0;g=f;f=e;e=this.D(30,d);d=c;c=b}i[0]=i[0]+c|0;i[1]=i[1]+d|0;i[2]=i[2]+e|0;i[3]=i[3]+f|0;i[4]=i[4]+g|0}};sjcl.hash.sha256=function(a){this.c[0]||this.M();if(a){this.h=a.h.slice(0);this.e=a.e.slice(0);this.d=a.d}else this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()}; +if(d>26){d-=26;b.push(f^g>>>d);f=g<<32-d}else{d+=6;f^=g<<32-d}}d&56&&b.push(sjcl.bitArray.partial(d&56,f,1));return b}};sjcl.hash.sha256=function(a){this.c[0]||this.M();if(a){this.h=a.h.slice(0);this.e=a.e.slice(0);this.d=a.d}else this.reset()};sjcl.hash.sha256.hash=function(a){return(new sjcl.hash.sha256).update(a).finalize()}; sjcl.hash.sha256.prototype={blockSize:512,reset:function(){this.h=this.w.slice(0);this.e=[];this.d=0;return this},update:function(a){if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);var b,c=this.e=sjcl.bitArray.concat(this.e,a);b=this.d;a=this.d=b+sjcl.bitArray.bitLength(a);for(b=512+b&-512;b<=a;b+=512)this.q(c.splice(0,16));return this},finalize:function(){var a,b=this.e,c=this.h;b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0);b.push(Math.floor(this.d/ 4294967296));for(b.push(this.d|0);b.length;)this.q(b.splice(0,16));this.reset();return c},w:[],c:[],M:function(){function a(e){return(e-Math.floor(e))*0x100000000|0}var b=0,c=2,d;a:for(;b<64;c++){for(d=2;d*d<=c;d++)if(c%d===0)continue a;if(b<8)this.w[b]=a(Math.pow(c,0.5));this.c[b]=a(Math.pow(c,1/3));b++}},q:function(a){var b,c,d=a.slice(0),e=this.h,f=this.c,g=e[0],h=e[1],i=e[2],j=e[3],k=e[4],l=e[5],m=e[6],n=e[7];for(a=0;a<64;a++){if(a<16)b=d[a];else{b=d[a+1&15];c=d[a+14&15];b=d[a&15]=(b>>>7^b>>>18^ -b>>>3^b<<25^b<<14)+(c>>>17^c>>>19^c>>>10^c<<15^c<<13)+d[a&15]+d[a+9&15]|0}b=b+n+(k>>>6^k>>>11^k>>>25^k<<26^k<<21^k<<7)+(m^k&(l^m))+f[a];n=m;m=l;l=k;k=j+b|0;j=i;i=h;h=g;g=b+(h&i^j&(h^i))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0}e[0]=e[0]+g|0;e[1]=e[1]+h|0;e[2]=e[2]+i|0;e[3]=e[3]+j|0;e[4]=e[4]+k|0;e[5]=e[5]+l|0;e[6]=e[6]+m|0;e[7]=e[7]+n|0}}; +b>>>3^b<<25^b<<14)+(c>>>17^c>>>19^c>>>10^c<<15^c<<13)+d[a&15]+d[a+9&15]|0}b=b+n+(k>>>6^k>>>11^k>>>25^k<<26^k<<21^k<<7)+(m^k&(l^m))+f[a];n=m;m=l;l=k;k=j+b|0;j=i;i=h;h=g;g=b+(h&i^j&(h^i))+(h>>>2^h>>>13^h>>>22^h<<30^h<<19^h<<10)|0}e[0]=e[0]+g|0;e[1]=e[1]+h|0;e[2]=e[2]+i|0;e[3]=e[3]+j|0;e[4]=e[4]+k|0;e[5]=e[5]+l|0;e[6]=e[6]+m|0;e[7]=e[7]+n|0}};sjcl.hash.sha1=function(a){if(a){this.h=a.h.slice(0);this.e=a.e.slice(0);this.d=a.d}else this.reset()};sjcl.hash.sha1.hash=function(a){return(new sjcl.hash.sha1).update(a).finalize()}; +sjcl.hash.sha1.prototype={blockSize:512,reset:function(){this.h=this.w.slice(0);this.e=[];this.d=0;return this},update:function(a){if(typeof a==="string")a=sjcl.codec.utf8String.toBits(a);var b,c=this.e=sjcl.bitArray.concat(this.e,a);b=this.d;a=this.d=b+sjcl.bitArray.bitLength(a);for(b=this.blockSize+b&-this.blockSize;b<=a;b+=this.blockSize)this.q(c.splice(0,16));return this},finalize:function(){var a,b=this.e,c=this.h;b=sjcl.bitArray.concat(b,[sjcl.bitArray.partial(1,1)]);for(a=b.length+2;a&15;a++)b.push(0); +b.push(Math.floor(this.d/0x100000000));for(b.push(this.d|0);b.length;)this.q(b.splice(0,16));this.reset();return c},w:[1732584193,4023233417,2562383102,271733878,3285377520],c:[1518500249,1859775393,2400959708,3395469782],ja:function(a,b,c,d){if(a<=19)return b&c|~b&d;else if(a<=39)return b^c^d;else if(a<=59)return b&c|b&d|c&d;else if(a<=79)return b^c^d},D:function(a,b){return b<>>32-a},q:function(a){var b,c,d,e,f,g,h=a.slice(0),i=this.h;c=i[0];d=i[1];e=i[2];f=i[3];g=i[4];for(a=0;a<=79;a++){if(a>= +16)h[a]=this.D(1,h[a-3]^h[a-8]^h[a-14]^h[a-16]);b=this.D(5,c)+this.ja(a,d,e,f)+g+h[a]+this.c[Math.floor(a/20)]|0;g=f;f=e;e=this.D(30,d);d=c;c=b}i[0]=i[0]+c|0;i[1]=i[1]+d|0;i[2]=i[2]+e|0;i[3]=i[3]+f|0;i[4]=i[4]+g|0}}; sjcl.mode.ccm={name:"ccm",encrypt:function(a,b,c,d,e){var f,g=b.slice(0),h=sjcl.bitArray,i=h.bitLength(c)/8,j=h.bitLength(g)/8;e=e||64;d=d||[];if(i<7)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(f=2;f<4&&j>>>8*f;f++);if(f<15-i)f=15-i;c=h.clamp(c,8*(15-f));b=sjcl.mode.ccm.T(a,b,c,d,e,f);g=sjcl.mode.ccm.V(a,g,c,b,e,f);return h.concat(g.data,g.tag)},decrypt:function(a,b,c,d,e){e=e||64;d=d||[];var f=sjcl.bitArray,g=f.bitLength(c)/8,h=f.bitLength(b),i=f.clamp(b,h-e),j=f.bitSlice(b, h-e);h=(h-e)/8;if(g<7)throw new sjcl.exception.invalid("ccm: iv must be at least 7 bytes");for(b=2;b<4&&h>>>8*b;b++);if(b<15-g)b=15-g;c=f.clamp(c,8*(15-b));i=sjcl.mode.ccm.V(a,i,c,j,e,b);a=sjcl.mode.ccm.T(a,i.data,c,d,e,b);if(!f.equal(i.tag,a))throw new sjcl.exception.corrupt("ccm: tag doesn't match");return i.data},T:function(a,b,c,d,e,f){var g=[],h=sjcl.bitArray,i=h.m;e/=8;if(e%2||e<4||e>16)throw new sjcl.exception.invalid("ccm: invalid tag length");if(d.length>0xffffffff||b.length>0xffffffff)throw new sjcl.exception.bug("ccm: can't deal with 4GiB or more data"); f=[h.partial(8,(d.length?64:0)|e-2<<2|f-1)];f=h.concat(f,c);f[3]|=h.bitLength(b)/8;f=a.encrypt(f);if(d.length){c=h.bitLength(d)/8;if(c<=65279)g=[h.partial(16,c)];else if(c<=0xffffffff)g=h.concat([h.partial(16,65534)],[c]);g=h.concat(g,d);for(d=0;d>>31,a[1]<<1^a[2]>>>31,a[2]<<1^a[3]>>>31,a[3]<<1^(a[0]>>>31)*135]}};sjcl.misc.hmac=function(a,b){this.aa=b=b||sjcl.hash.sha256;var c=[[],[]],d=b.prototype.blockSize/32;this.t=[new b,new b];if(a.length>d)a=b.hash(a);for(b=0;b0;){b++;e>>>=1}this.j[g].update([d,this.Y++,2,b,f,a.length].concat(a));break;case "string":if(b===undefined)b=a.length;this.j[g].update([d,this.Y++,3,b,f,a.length]);this.j[g].update(a);break;default:throw new sjcl.exception.bug("random: addEntropy only supports number, array or string");}this.s[g]+=b;this.n+=b;if(h===0){this.isReady()!==0&&this.Z("seeded", diff --git a/test/bn_test.js b/test/bn_test.js index 32861acc..7756b302 100644 --- a/test/bn_test.js +++ b/test/bn_test.js @@ -4,7 +4,7 @@ new sjcl.test.TestCase("Bignum modular reduction test", function (cb) { cb && cb(); return; } - + var a, N, r; for (i=0; i < sjcl.test.vector.bn_mod.length; i++) { tv = sjcl.test.vector.bn_mod[i]; @@ -26,7 +26,7 @@ new sjcl.test.TestCase("Bignum modular multiplication test", function (cb) { cb && cb(); return; } - + var a, b, N, r; for(var j=0;j<10;j++)for (i=0; i < sjcl.test.vector.bn_mulmod.length; i++) { tv = sjcl.test.vector.bn_mulmod[i]; @@ -49,7 +49,7 @@ new sjcl.test.TestCase("Bignum modular exponentiation test", function (cb) { cb && cb(); return; } - + var i, tv, g, x, N, v; for (i=0; i < sjcl.test.vector.bn_powermod.length; i++) { tv = sjcl.test.vector.bn_powermod[i]; diff --git a/test/bn_vectors.js b/test/bn_vectors.js index b01ba408..3dd5a3ba 100644 --- a/test/bn_vectors.js +++ b/test/bn_vectors.js @@ -1,3 +1,6 @@ +// Verify with Mathematica: +// BaseForm[Mod[16^^a, 16^^N], 16] +// should return "16^^r". sjcl.test.vector.bn_mod = [ { a: "cfb9caac51a13eb13592d47863e463b306547683070424a7c7a41302e30453c2f5f6f2c432a267d2d72746c534d6c233c5c6740776e5c473592d4786377d745c534f2d502427612249266a45382a6f512e527d475577484f277e7a4ce62c7919c0b34b9f125124c574bac9738edb0998bfa8f5b8076c5266ae06e1b9121303d7ff8f0380a24526474d592a7d5e69f125124c574bac9738ed77d745c534f2d502427612249266a45382a6f512e527d4755560144ced0a078454a727d24db5d77484f27b0998bfa8f5b8076c5266ae06e1b9121303d7ff8f0380a24526474d592a7d5e682b2358377d745c534f2d502427612249266a45382a6f512e527d4755560144ced0a078454a727d24db5d77484f277e7b3d28256d71482d2a287d666b3ac7053b02c6543592d47863b6a0541cfa603219b694bec483592d478630", @@ -9,21 +12,15 @@ sjcl.test.vector.bn_mod = [ } ] +// Verify with Mathematica: +// BaseForm[Mod[16^^a * 16^^b, 16^^N], 16] +// should return "16^^r". sjcl.test.vector.bn_mulmod = [ { a: "94B7555AABE9127CC58CCF4993DB6CF84D16C1244021612e464d6e2f4c724f2b3e275a43385a5a6d4c7441284648362a4526474d592a7d5e682b2358377d745c534f2d502427612249266a45382a6f512e527d475577484f277e7b3d28256d71482d2a287d666b52247027", b: "70424648242f4273612a524e4a44717b655b487b395d2f407d4c7141503e33442a657637257968345237677d6e736f5f24546b642a23283e463b306547683070424a7c7a41302e30453c2f5f6f2c432a267d2d72746c534d6c233c5c6740776e5c4725562029623d7a673d", N: "EEAF0AB9ADB38D8775FF3C0B9EA27496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", r: "266bd21de6da4ce62c7919c0b34b9f125124c574bac9738edb0998bfa8f5b8076c5266ae06e1b9121303d7ff8f0380a2f51de2fdc93bba83b4c4f49e2ddc65c24a8e2ecbac374e49181792aeeada8fc5438073187b2cf3d63f93d560144ced0a078454a727d24db5d09e56" - }, - { - a: "94B7555AABE9127CC58CCF4993DB6CF84D16C1244021612e464d6e2f4c724f2b3e275a43385a5a6d4c7441284648362a4526474d592a7d5e682b2358377d745c534f2d502427612249266a45382a6f512e527d475577484f277e7b3d28256d71482d2a287d666b52247027", - b: "70424648242f42364d5635424967654d212a2e4532656123234b3822524f58762e75374d22252f324865406f43386a5d3d435f66315a7e6b6b20277978244f5856626a4f5c796f374c3373612a524e4a44717b655b487b395d2f407d4c7141503e33442a657637257968345237677d6e736f5f24546b642a23283e463b306547683070424a7c7a41302e30453c2f5f6f2c432a267d2d72746c534d6c233c5c6740776e5c4725562029623d7a673d", - N: "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", - r: "4701ff9bffd27e43a071e0a4c09b22945af95c8d81fda91e1fcbf2c6a54fc9d3f824ec\ -2dc88b88ba455c206965c03dbcb19c5e1826435de032abeac7a576f176a3a037455f0e\ -7f9681755eb6e7ee91a4d58fc75b6db59563e6b4fb69efec1ccc53b7a0003b6c0be278\ -cb9f8075d4bb6eef64015f09749db233e27bf3a1b48ba7" } ] @@ -57,7 +54,7 @@ sjcl.test.vector.bn_powermod = [ x: 0x1010, N: 131, v: 59 - }, + }, { g: 2, x: "43207437777777877617151", @@ -75,18 +72,14 @@ sjcl.test.vector.bn_powermod = [ x: "89457115510016156219817846189181057618965150496979174671534084187", N: "1897166415676096761", v: "16840615e646a4c5c8d" - }, - { - g: 2, - x: "eeaf0ab9adb3008dd6c314c9c25600057674df692c0006e0d5d8e2050b98be48e4", - N: "b48130d6e07674df740e1d33b4816e0d5d8e20e2050b98be48e457674df74096ea", - v: "9c3219b694befb9caac51a13eb1ac7053b02c654b6a0541cfa60c483592d478630" - }, -// // The following values are from TLS-SRP RFC 5054. -// { -// g: 2, -// x: "94B7555AABE9127CC58CCF4993DB6CF84D16C124", -// N: "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", -// v: "7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D8129BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78E955A5E29E7AB245DB2BE315E2099AFB" -// } + }//, + // // This was disabled because it's slow (~2.5s with `rhino -O 9`). Once + // // a better powermod algorithm is implemented (e.g., using Montgomery + // // reduction), this can be re-enabled. + // { + // g: 2, + // x: "eeaf0ab9adb3008dd6c314c9c25600057674df692c0006e0d5d8e2050b98be48e4", + // N: "b48130d6e07674df740e1d33b4816e0d5d8e20e2050b98be48e457674df74096ea", + // v: "9c3219b694befb9caac51a13eb1ac7053b02c654b6a0541cfa60c483592d478630" + // } ] diff --git a/test/run_tests_browser.js b/test/run_tests_browser.js index 40733e82..617d751a 100644 --- a/test/run_tests_browser.js +++ b/test/run_tests_browser.js @@ -18,12 +18,12 @@ function testCore(coreName, cb) { "hmac_test.js", "hmac_vectors.js", "pbkdf2_test.js", - "srp_test.js", - "srp_vectors.js", + "ecdh_test.js", + "ecdsa_test.js", "bn_test.js", "bn_vectors.js", - "ecdh_test.js", - "ecdsa_test.js" + "srp_test.js", + "srp_vectors.js" ], i; for (i=1; i