diff --git a/core/bn.js b/core/bn.js index 16978e7..55ecdba 100644 --- a/core/bn.js +++ b/core/bn.js @@ -275,6 +275,21 @@ sjcl.bn.prototype = { return out; }, + mulmod: function(x, N) { + return this.mod(N).mul(x.mod(N)).mod(N); + }, + + powermod: function(x, N) { + var result = new sjcl.bn(1), a = new sjcl.bn(this), k = new sjcl.bn(x); + while (true) { + if (k.limbs[0] & 1) { result = result.mulmod(a, N); } + k.halveM(); + if (k.equals(0)) { break; } + a = a.mulmod(a, N); + } + return result.normalize().reduce(); + }, + trim: function() { var l = this.limbs, p; do { diff --git a/test/bn_test.js b/test/bn_test.js new file mode 100644 index 0000000..4a6c140 --- /dev/null +++ b/test/bn_test.js @@ -0,0 +1,22 @@ +new sjcl.test.TestCase("Bignum modular exponentiation test", function (cb) { + if (!sjcl.bn) { + this.unimplemented(); + 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]; + try { + g = new sjcl.bn(tv.g); + x = new sjcl.bn(tv.x); + N = new sjcl.bn(tv.N); + v = g.powermod(x, N); + this.require(v.equals(new sjcl.bn(tv.v))); + } catch(e) { + this.fail(e); + } + } + cb && cb(); +}); diff --git a/test/bn_vectors.js b/test/bn_vectors.js new file mode 100644 index 0000000..053f68a --- /dev/null +++ b/test/bn_vectors.js @@ -0,0 +1,56 @@ +sjcl.test.vector.bn_powermod = [ + { + g: 2, + x: 3, + N: 3, + v: 2 + }, + { + g: 2, + x: "10000000000000000000000000", + N: 1337, + v: 1206 + }, + { + g: 17, + x: 90, + N: 34717861147, + v: 28445204336 + }, + { + g: 2, + x: "0x844A000000000000000000000", + N: 13, + v: 9 + }, + { + g: 2, + x: 0x1010, + N: 131, + v: 59 + }, + { + g: 2, + x: "43207437777777877617151", + N: 13, + v: 2 + }, + { + g: 2, + x: "389274238947216444871600001871964319565192765874149", + N: 117, + v: 44 + }, + { + g: 2, + x: "89457115510016156219817846189181057618965150496979174671534084187", + N: "1897166415676096761", + v: "16840615e646a4c5c8d" + }, + { + g: 2, + x: "94B7555AABE9127CC58CCF4993DB6CF84D16C124", + N: "EEAF0AB9ADB38DD69C33F80AFA8FC5E86072618775FF3C0B9EA2314C9C256576D674DF7496EA81D3383B4813D692C6E0E0D5D8E250B98BE48E495C1D6089DAD15DC7D7B46154D6B6CE8EF4AD69B15D4982559B297BCF1885C529F566660E57EC68EDBC3C05726CC02FD4CBF4976EAA9AFD5138FE8376435B9FC61D2FC0EB06E3", + v: "7E273DE8696FFC4F4E337D05B4B375BEB0DDE1569E8FA00A9886D8129BADA1F1822223CA1A605B530E379BA4729FDC59F105B4787E5186F5C671085A1447B52A48CF1970B4FB6F8400BBF4CEBFBB168152E08AB5EA53D15C1AFF87B2B9DA6E04E058AD51CC72BFC9033B564E26480D78E955A5E29E7AB245DB2BE315E2099AFB" + } +]