bn.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532
  1. /**
  2. * Constructs a new bignum from another bignum, a number or a hex string.
  3. */
  4. sjcl.bn = function(it) {
  5. this.initWith(it);
  6. };
  7. sjcl.bn.prototype = {
  8. radix: 24,
  9. maxMul: 8,
  10. _class: sjcl.bn,
  11. copy: function() {
  12. return new this._class(this);
  13. },
  14. /**
  15. * Initializes this with it, either as a bn, a number, or a hex string.
  16. */
  17. initWith: function(it) {
  18. var i=0, k, n, l;
  19. switch(typeof it) {
  20. case "object":
  21. this.limbs = it.limbs.slice(0);
  22. break;
  23. case "number":
  24. this.limbs = [it];
  25. this.normalize();
  26. break;
  27. case "string":
  28. it = it.replace(/^0x/, '');
  29. this.limbs = [];
  30. // hack
  31. k = this.radix / 4;
  32. for (i=0; i < it.length; i+=k) {
  33. this.limbs.push(parseInt(it.substring(Math.max(it.length - i - k, 0), it.length - i),16));
  34. }
  35. break;
  36. default:
  37. this.limbs = [0];
  38. }
  39. return this;
  40. },
  41. /**
  42. * Returns true if "this" and "that" are equal. Calls fullReduce().
  43. * Equality test is in constant time.
  44. */
  45. equals: function(that) {
  46. if (typeof that === "number") { that = new this._class(that); }
  47. var difference = 0, i;
  48. this.fullReduce();
  49. that.fullReduce();
  50. for (i = 0; i < this.limbs.length || i < that.limbs.length; i++) {
  51. difference |= this.getLimb(i) ^ that.getLimb(i);
  52. }
  53. return (difference === 0);
  54. },
  55. /**
  56. * Get the i'th limb of this, zero if i is too large.
  57. */
  58. getLimb: function(i) {
  59. return (i >= this.limbs.length) ? 0 : this.limbs[i];
  60. },
  61. /**
  62. * Constant time comparison function.
  63. * Returns 1 if this >= that, or zero otherwise.
  64. */
  65. greaterEquals: function(that) {
  66. if (typeof that === "number") { that = new this._class(that); }
  67. var less = 0, greater = 0, i, a, b;
  68. i = Math.max(this.limbs.length, that.limbs.length) - 1;
  69. for (; i>= 0; i--) {
  70. a = this.getLimb(i);
  71. b = that.getLimb(i);
  72. greater |= (b - a) & ~less;
  73. less |= (a - b) & ~greater;
  74. }
  75. return (greater | ~less) >>> 31;
  76. },
  77. /**
  78. * Convert to a hex string.
  79. */
  80. toString: function() {
  81. this.fullReduce();
  82. var out="", i, s, l = this.limbs;
  83. for (i=0; i < this.limbs.length; i++) {
  84. s = l[i].toString(16);
  85. while (i < this.limbs.length - 1 && s.length < 6) {
  86. s = "0" + s;
  87. }
  88. out = s + out;
  89. }
  90. return "0x"+out;
  91. },
  92. /** this += that. Does not normalize. */
  93. addM: function(that) {
  94. if (typeof(that) !== "object") { that = new this._class(that); }
  95. var i, l=this.limbs, ll=that.limbs;
  96. for (i=l.length; i<ll.length; i++) {
  97. l[i] = 0;
  98. }
  99. for (i=0; i<ll.length; i++) {
  100. l[i] += ll[i];
  101. }
  102. return this;
  103. },
  104. /** this *= 2. Requires normalized; ends up normalized. */
  105. doubleM: function() {
  106. var i, carry=0, tmp, r=this.radix, m=this.radixMask, l=this.limbs;
  107. for (i=0; i<l.length; i++) {
  108. tmp = l[i];
  109. tmp = tmp+tmp+carry;
  110. l[i] = tmp & m;
  111. carry = tmp >> r;
  112. }
  113. if (carry) {
  114. l.push(carry);
  115. }
  116. return this;
  117. },
  118. /** this /= 2, rounded down. Requires normalized; ends up normalized. */
  119. halveM: function() {
  120. var i, carry=0, tmp, r=this.radix, l=this.limbs;
  121. for (i=l.length-1; i>=0; i--) {
  122. tmp = l[i];
  123. l[i] = (tmp+carry)>>1;
  124. carry = (tmp&1) << r;
  125. }
  126. if (!l[l.length-1]) {
  127. l.pop();
  128. }
  129. return this;
  130. },
  131. /** this -= that. Does not normalize. */
  132. subM: function(that) {
  133. if (typeof(that) !== "object") { that = new this._class(that); }
  134. var i, l=this.limbs, ll=that.limbs;
  135. for (i=l.length; i<ll.length; i++) {
  136. l[i] = 0;
  137. }
  138. for (i=0; i<ll.length; i++) {
  139. l[i] -= ll[i];
  140. }
  141. return this;
  142. },
  143. mod: function(that) {
  144. that = new sjcl.bn(that).normalize(); // copy before we begin
  145. var out = new sjcl.bn(this).normalize(), ci=0;
  146. for (; out.greaterEquals(that); ci++) {
  147. that.doubleM();
  148. }
  149. for (; ci > 0; ci--) {
  150. that.halveM();
  151. if (out.greaterEquals(that)) {
  152. out.subM(that).normalize();
  153. }
  154. }
  155. return out.trim();
  156. },
  157. /** return inverse mod prime p. p must be odd. Binary extended Euclidean algorithm mod p. */
  158. inverseMod: function(p) {
  159. 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;
  160. if (!(p.limbs[0] & 1)) {
  161. throw (new sjcl.exception.invalid("inverseMod: p must be odd"));
  162. }
  163. // invariant: y is odd
  164. do {
  165. if (x.limbs[0] & 1) {
  166. if (!x.greaterEquals(y)) {
  167. // x < y; swap everything
  168. tmp = x; x = y; y = tmp;
  169. tmp = a; a = b; b = tmp;
  170. }
  171. x.subM(y);
  172. x.normalize();
  173. if (!a.greaterEquals(b)) {
  174. a.addM(p);
  175. }
  176. a.subM(b);
  177. }
  178. // cut everything in half
  179. x.halveM();
  180. if (a.limbs[0] & 1) {
  181. a.addM(p);
  182. }
  183. a.normalize();
  184. a.halveM();
  185. // check for termination: x ?= 0
  186. for (i=nz=0; i<x.limbs.length; i++) {
  187. nz |= x.limbs[i];
  188. }
  189. } while(nz);
  190. if (!y.equals(1)) {
  191. throw (new sjcl.exception.invalid("inverseMod: p and x must be relatively prime"));
  192. }
  193. return b;
  194. },
  195. /** this + that. Does not normalize. */
  196. add: function(that) {
  197. return this.copy().addM(that);
  198. },
  199. /** this - that. Does not normalize. */
  200. sub: function(that) {
  201. return this.copy().subM(that);
  202. },
  203. /** this * that. Normalizes and reduces. */
  204. mul: function(that) {
  205. if (typeof(that) === "number") { that = new this._class(that); }
  206. var i, j, a = this.limbs, b = that.limbs, al = a.length, bl = b.length, out = new this._class(), c = out.limbs, ai, ii=this.maxMul;
  207. for (i=0; i < this.limbs.length + that.limbs.length + 1; i++) {
  208. c[i] = 0;
  209. }
  210. for (i=0; i<al; i++) {
  211. ai = a[i];
  212. for (j=0; j<bl; j++) {
  213. c[i+j] += ai * b[j];
  214. }
  215. if (!--ii) {
  216. ii = this.maxMul;
  217. out.cnormalize();
  218. }
  219. }
  220. return out.cnormalize().reduce();
  221. },
  222. /** this ^ 2. Normalizes and reduces. */
  223. square: function() {
  224. return this.mul(this);
  225. },
  226. /** this ^ n. Uses square-and-multiply. Normalizes and reduces. */
  227. power: function(l) {
  228. if (typeof(l) === "number") {
  229. l = [l];
  230. } else if (l.limbs !== undefined) {
  231. l = l.normalize().limbs;
  232. }
  233. var i, j, out = new this._class(1), pow = this;
  234. for (i=0; i<l.length; i++) {
  235. for (j=0; j<this.radix; j++) {
  236. if (l[i] & (1<<j)) {
  237. out = out.mul(pow);
  238. }
  239. pow = pow.square();
  240. }
  241. }
  242. return out;
  243. },
  244. mulmod: function(x, N) {
  245. return this.mod(N).mul(x.mod(N)).mod(N);
  246. },
  247. powermod: function(x, N) {
  248. var result = new sjcl.bn(1), a = new sjcl.bn(this), k = new sjcl.bn(x);
  249. while (true) {
  250. if (k.limbs[0] & 1) { result = result.mulmod(a, N); }
  251. k.halveM();
  252. if (k.equals(0)) { break; }
  253. a = a.mulmod(a, N);
  254. }
  255. return result.normalize().reduce();
  256. },
  257. trim: function() {
  258. var l = this.limbs, p;
  259. do {
  260. p = l.pop();
  261. } while (l.length && p === 0);
  262. l.push(p);
  263. return this;
  264. },
  265. /** Reduce mod a modulus. Stubbed for subclassing. */
  266. reduce: function() {
  267. return this;
  268. },
  269. /** Reduce and normalize. */
  270. fullReduce: function() {
  271. return this.normalize();
  272. },
  273. /** Propagate carries. */
  274. normalize: function() {
  275. var carry=0, i, pv = this.placeVal, ipv = this.ipv, l, m, limbs = this.limbs, ll = limbs.length, mask = this.radixMask;
  276. for (i=0; i < ll || (carry !== 0 && carry !== -1); i++) {
  277. l = (limbs[i]||0) + carry;
  278. m = limbs[i] = l & mask;
  279. carry = (l-m)*ipv;
  280. }
  281. if (carry === -1) {
  282. limbs[i-1] -= this.placeVal;
  283. }
  284. return this;
  285. },
  286. /** Constant-time normalize. Does not allocate additional space. */
  287. cnormalize: function() {
  288. var carry=0, i, ipv = this.ipv, l, m, limbs = this.limbs, ll = limbs.length, mask = this.radixMask;
  289. for (i=0; i < ll-1; i++) {
  290. l = limbs[i] + carry;
  291. m = limbs[i] = l & mask;
  292. carry = (l-m)*ipv;
  293. }
  294. limbs[i] += carry;
  295. return this;
  296. },
  297. /** Serialize to a bit array */
  298. toBits: function(len) {
  299. this.fullReduce();
  300. len = len || this.exponent || this.limbs.length * this.radix;
  301. var i = Math.floor((len-1)/24), w=sjcl.bitArray, e = (len + 7 & -8) % this.radix || this.radix,
  302. out = [w.partial(e, this.getLimb(i))];
  303. for (i--; i >= 0; i--) {
  304. out = w.concat(out, [w.partial(this.radix, this.getLimb(i))]);
  305. }
  306. return out;
  307. },
  308. /** Return the length in bits, rounded up to the nearest byte. */
  309. bitLength: function() {
  310. this.fullReduce();
  311. var out = this.radix * (this.limbs.length - 1),
  312. b = this.limbs[this.limbs.length - 1];
  313. for (; b; b >>= 1) {
  314. out ++;
  315. }
  316. return out+7 & -8;
  317. }
  318. };
  319. sjcl.bn.fromBits = function(bits) {
  320. var Class = this, out = new Class(), words=[], w=sjcl.bitArray, t = this.prototype,
  321. l = Math.min(this.bitLength || 0x100000000, w.bitLength(bits)), e = l % t.radix || t.radix;
  322. words[0] = w.extract(bits, 0, e);
  323. for (; e < l; e += t.radix) {
  324. words.unshift(w.extract(bits, e, t.radix));
  325. }
  326. out.limbs = words;
  327. return out;
  328. };
  329. sjcl.bn.prototype.ipv = 1 / (sjcl.bn.prototype.placeVal = Math.pow(2,sjcl.bn.prototype.radix));
  330. sjcl.bn.prototype.radixMask = (1 << sjcl.bn.prototype.radix) - 1;
  331. /**
  332. * Creates a new subclass of bn, based on reduction modulo a pseudo-Mersenne prime,
  333. * i.e. a prime of the form 2^e + sum(a * 2^b),where the sum is negative and sparse.
  334. */
  335. sjcl.bn.pseudoMersennePrime = function(exponent, coeff) {
  336. function p(it) {
  337. this.initWith(it);
  338. /*if (this.limbs[this.modOffset]) {
  339. this.reduce();
  340. }*/
  341. }
  342. var ppr = p.prototype = new sjcl.bn(), i, tmp, mo;
  343. mo = ppr.modOffset = Math.ceil(tmp = exponent / ppr.radix);
  344. ppr.exponent = exponent;
  345. ppr.offset = [];
  346. ppr.factor = [];
  347. ppr.minOffset = mo;
  348. ppr.fullMask = 0;
  349. ppr.fullOffset = [];
  350. ppr.fullFactor = [];
  351. ppr.modulus = p.modulus = new sjcl.bn(Math.pow(2,exponent));
  352. ppr.fullMask = 0|-Math.pow(2, exponent % ppr.radix);
  353. for (i=0; i<coeff.length; i++) {
  354. ppr.offset[i] = Math.floor(coeff[i][0] / ppr.radix - tmp);
  355. ppr.fullOffset[i] = Math.ceil(coeff[i][0] / ppr.radix - tmp);
  356. ppr.factor[i] = coeff[i][1] * Math.pow(1/2, exponent - coeff[i][0] + ppr.offset[i] * ppr.radix);
  357. ppr.fullFactor[i] = coeff[i][1] * Math.pow(1/2, exponent - coeff[i][0] + ppr.fullOffset[i] * ppr.radix);
  358. ppr.modulus.addM(new sjcl.bn(Math.pow(2,coeff[i][0])*coeff[i][1]));
  359. ppr.minOffset = Math.min(ppr.minOffset, -ppr.offset[i]); // conservative
  360. }
  361. ppr._class = p;
  362. ppr.modulus.cnormalize();
  363. /** Approximate reduction mod p. May leave a number which is negative or slightly larger than p. */
  364. ppr.reduce = function() {
  365. var i, k, l, mo = this.modOffset, limbs = this.limbs, aff, off = this.offset, ol = this.offset.length, fac = this.factor, ll;
  366. i = this.minOffset;
  367. while (limbs.length > mo) {
  368. l = limbs.pop();
  369. ll = limbs.length;
  370. for (k=0; k<ol; k++) {
  371. limbs[ll+off[k]] -= fac[k] * l;
  372. }
  373. i--;
  374. if (!i) {
  375. limbs.push(0);
  376. this.cnormalize();
  377. i = this.minOffset;
  378. }
  379. }
  380. this.cnormalize();
  381. return this;
  382. };
  383. ppr._strongReduce = (ppr.fullMask === -1) ? ppr.reduce : function() {
  384. var limbs = this.limbs, i = limbs.length - 1, k, l;
  385. this.reduce();
  386. if (i === this.modOffset - 1) {
  387. l = limbs[i] & this.fullMask;
  388. limbs[i] -= l;
  389. for (k=0; k<this.fullOffset.length; k++) {
  390. limbs[i+this.fullOffset[k]] -= this.fullFactor[k] * l;
  391. }
  392. this.normalize();
  393. }
  394. };
  395. /** mostly constant-time, very expensive full reduction. */
  396. ppr.fullReduce = function() {
  397. var greater, i;
  398. // massively above the modulus, may be negative
  399. this._strongReduce();
  400. // less than twice the modulus, may be negative
  401. this.addM(this.modulus);
  402. this.addM(this.modulus);
  403. this.normalize();
  404. // probably 2-3x the modulus
  405. this._strongReduce();
  406. // less than the power of 2. still may be more than
  407. // the modulus
  408. // HACK: pad out to this length
  409. for (i=this.limbs.length; i<this.modOffset; i++) {
  410. this.limbs[i] = 0;
  411. }
  412. // constant-time subtract modulus
  413. greater = this.greaterEquals(this.modulus);
  414. for (i=0; i<this.limbs.length; i++) {
  415. this.limbs[i] -= this.modulus.limbs[i] * greater;
  416. }
  417. this.cnormalize();
  418. return this;
  419. };
  420. ppr.inverse = function() {
  421. return (this.power(this.modulus.sub(2)));
  422. };
  423. p.fromBits = sjcl.bn.fromBits;
  424. return p;
  425. };
  426. // a small Mersenne prime
  427. sjcl.bn.prime = {
  428. p127: sjcl.bn.pseudoMersennePrime(127, [[0,-1]]),
  429. // Bernstein's prime for Curve25519
  430. p25519: sjcl.bn.pseudoMersennePrime(255, [[0,-19]]),
  431. // NIST primes
  432. p192: sjcl.bn.pseudoMersennePrime(192, [[0,-1],[64,-1]]),
  433. p224: sjcl.bn.pseudoMersennePrime(224, [[0,1],[96,-1]]),
  434. p256: sjcl.bn.pseudoMersennePrime(256, [[0,-1],[96,1],[192,1],[224,-1]]),
  435. p384: sjcl.bn.pseudoMersennePrime(384, [[0,-1],[32,1],[96,-1],[128,-1]]),
  436. p521: sjcl.bn.pseudoMersennePrime(521, [[0,-1]])
  437. };
  438. sjcl.bn.random = function(modulus, paranoia) {
  439. if (typeof modulus !== "object") { modulus = new sjcl.bn(modulus); }
  440. var words, i, l = modulus.limbs.length, m = modulus.limbs[l-1]+1, out = new sjcl.bn();
  441. while (true) {
  442. // get a sequence whose first digits make sense
  443. do {
  444. words = sjcl.random.randomWords(l, paranoia);
  445. if (words[l-1] < 0) { words[l-1] += 0x100000000; }
  446. } while (Math.floor(words[l-1] / m) === Math.floor(0x100000000 / m));
  447. words[l-1] %= m;
  448. // mask off all the limbs
  449. for (i=0; i<l-1; i++) {
  450. words[i] &= modulus.radixMask;
  451. }
  452. // check the rest of the digitssj
  453. out.limbs = words;
  454. if (!out.greaterEquals(modulus)) {
  455. return out;
  456. }
  457. }
  458. };