eddsa.js 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574
  1. "use strict";
  2. /**
  3. * @fileOverview
  4. * Digital signature scheme based on Curve25519 (Ed25519 or EdDSA).
  5. */
  6. /*
  7. * Copyright (c) 2011, 2012, 2014 Ron Garret
  8. * Copyright (c) 2014 Mega Limited
  9. * under the MIT License.
  10. *
  11. * Authors: Guy K. Kloss, Ron Garret
  12. *
  13. * You should have received a copy of the license along with this program.
  14. */
  15. var core = require('./core');
  16. var curve255 = require('./curve255');
  17. var utils = require('./utils');
  18. var BigInteger = require('jsbn').BigInteger;
  19. var crypto = require('crypto');
  20. /**
  21. * @exports jodid25519/eddsa
  22. * Digital signature scheme based on Curve25519 (Ed25519 or EdDSA).
  23. *
  24. * @description
  25. * Digital signature scheme based on Curve25519 (Ed25519 or EdDSA).
  26. *
  27. * <p>
  28. * This code is adapted from fast-djbec.js, a faster but more complicated
  29. * version of the Ed25519 encryption scheme (as compared to djbec.js).
  30. * It uses two different representations for big integers: The jsbn
  31. * BigInteger class, which can represent arbitrary-length numbers, and a
  32. * special fixed-length representation optimised for 256-bit integers.
  33. * The reason both are needed is that the Ed25519 algorithm requires some
  34. * 512-bit numbers.</p>
  35. */
  36. var ns = {};
  37. function _bi255(value) {
  38. if (!(this instanceof _bi255)) {
  39. return new _bi255(value);
  40. }
  41. if (typeof value === 'undefined') {
  42. return _ZERO;
  43. }
  44. var c = value.constructor;
  45. if ((c === Array || c === Uint16Array || c === Uint32Array) && (value.length === 16)) {
  46. this.n = value;
  47. } else if ((c === Array) && (value.length === 32)) {
  48. this.n = _bytes2bi255(value).n;
  49. } else if (c === String) {
  50. this.n = utils.hexDecode(value);
  51. } else if (c === Number) {
  52. this.n = [value & 0xffff,
  53. value >> 16, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
  54. } else if (value instanceof _bi255) {
  55. this.n = value.n.slice(0); // Copy constructor
  56. } else {
  57. throw "Bad argument for bignum: " + value;
  58. }
  59. }
  60. _bi255.prototype = {
  61. 'toString' : function() {
  62. return utils.hexEncode(this.n);
  63. },
  64. 'toSource' : function() {
  65. return '_' + utils.hexEncode(this.n);
  66. },
  67. 'plus' : function(n1) {
  68. return _bi255(core.bigintadd(this.n, n1.n));
  69. },
  70. 'minus' : function(n1) {
  71. return _bi255(core.bigintsub(this.n, n1.n)).modq();
  72. },
  73. 'times' : function(n1) {
  74. return _bi255(core.mulmodp(this.n, n1.n));
  75. },
  76. 'divide' : function(n1) {
  77. return this.times(n1.inv());
  78. },
  79. 'sqr' : function() {
  80. return _bi255(core.sqrmodp(this.n));
  81. },
  82. 'cmp' : function(n1) {
  83. return core.bigintcmp(this.n, n1.n);
  84. },
  85. 'equals' : function(n1) {
  86. return this.cmp(n1) === 0;
  87. },
  88. 'isOdd' : function() {
  89. return (this.n[0] & 1) === 1;
  90. },
  91. 'shiftLeft' : function(cnt) {
  92. _shiftL(this.n, cnt);
  93. return this;
  94. },
  95. 'shiftRight' : function(cnt) {
  96. _shiftR(this.n, cnt);
  97. return this;
  98. },
  99. 'inv' : function() {
  100. return _bi255(core.invmodp(this.n));
  101. },
  102. 'pow' : function(e) {
  103. return _bi255(_pow(this.n, e.n));
  104. },
  105. 'modq' : function() {
  106. return _modq(this);
  107. },
  108. 'bytes' : function() {
  109. return _bi255_bytes(this);
  110. }
  111. };
  112. function _shiftL(n, cnt) {
  113. var lastcarry = 0;
  114. for (var i = 0; i < 16; i++) {
  115. var carry = n[i] >> (16 - cnt);
  116. n[i] = (n[i] << cnt) & 0xffff | lastcarry;
  117. lastcarry = carry;
  118. }
  119. return n;
  120. }
  121. function _shiftR(n, cnt) {
  122. var lastcarry = 0;
  123. for (var i = 15; i >= 0; i--) {
  124. var carry = n[i] << (16 - cnt) & 0xffff;
  125. n[i] = (n[i] >> cnt) | lastcarry;
  126. lastcarry = carry;
  127. }
  128. return n;
  129. }
  130. function _bi255_bytes(n) {
  131. n = _bi255(n); // Make a copy because shiftRight is destructive
  132. var a = new Array(32);
  133. for (var i = 31; i >= 0; i--) {
  134. a[i] = n.n[0] & 0xff;
  135. n.shiftRight(8);
  136. }
  137. return a;
  138. }
  139. function _bytes2bi255(a) {
  140. var n = _ZERO;
  141. for (var i = 0; i < 32; i++) {
  142. n.shiftLeft(8);
  143. n = n.plus(_bi255(a[i]));
  144. }
  145. return n;
  146. }
  147. function _pow(n, e) {
  148. var result = core.ONE();
  149. for (var i = 0; i < 256; i++) {
  150. if (core.getbit(e, i) === 1) {
  151. result = core.mulmodp(result, n);
  152. }
  153. n = core.sqrmodp(n);
  154. }
  155. return result;
  156. }
  157. var _ZERO = _bi255(0);
  158. var _ONE = _bi255(1);
  159. var _TWO = _bi255(2);
  160. // This is the core prime.
  161. var _Q = _bi255([0xffff - 18, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
  162. 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff,
  163. 0xffff, 0xffff, 0x7fff]);
  164. function _modq(n) {
  165. core.reduce(n.n);
  166. if (n.cmp(_Q) >= 0) {
  167. return _modq(n.minus(_Q));
  168. }
  169. if (n.cmp(_ZERO) === -1) {
  170. return _modq(n.plus(_Q));
  171. } else {
  172. return n;
  173. }
  174. }
  175. // _RECOVERY_EXPONENT = _Q.plus(_bi255(3)).divide(_bi255(8));
  176. var _RECOVERY_EXPONENT = _bi255('0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffe');
  177. // _D = _Q.minus(_bi255(121665)).divide(_bi255(121666));
  178. var _D = _bi255('52036cee2b6ffe738cc740797779e89800700a4d4141d8ab75eb4dca135978a3');
  179. // _I = _TWO.pow(_Q.minus(_ONE).divide(_bi255(4)));
  180. var _I = _bi255('2b8324804fc1df0b2b4d00993dfbd7a72f431806ad2fe478c4ee1b274a0ea0b0');
  181. // _L = _TWO.pow(_bi255(252)).plus(_bi255('14def9dea2f79cd65812631a5cf5d3ed'));
  182. var _L = _bi255('1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed');
  183. var _L_BI = _bi('1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed', 16);
  184. // ////////////////////////////////////////////////////////////
  185. function _isoncurve(p) {
  186. var x = p[0];
  187. var y = p[1];
  188. var xsqr = x.sqr();
  189. var ysqr = y.sqr();
  190. var v = _D.times(xsqr).times(ysqr);
  191. return ysqr.minus(xsqr).minus(_ONE).minus(v).modq().equals(_ZERO);
  192. }
  193. function _xrecover(y) {
  194. var ysquared = y.sqr();
  195. var xx = ysquared.minus(_ONE).divide(_ONE.plus(_D.times(ysquared)));
  196. var x = xx.pow(_RECOVERY_EXPONENT);
  197. if (!(x.times(x).minus(xx).equals(_ZERO))) {
  198. x = x.times(_I);
  199. }
  200. if (x.isOdd()) {
  201. x = _Q.minus(x);
  202. }
  203. return x;
  204. }
  205. function _x_pt_add(pt1, pt2) {
  206. var x1 = pt1[0];
  207. var y1 = pt1[1];
  208. var z1 = pt1[2];
  209. var t1 = pt1[3];
  210. var x2 = pt2[0];
  211. var y2 = pt2[1];
  212. var z2 = pt2[2];
  213. var t2 = pt2[3];
  214. var A = y1.minus(x1).times(y2.plus(x2));
  215. var B = y1.plus(x1).times(y2.minus(x2));
  216. var C = z1.times(_TWO).times(t2);
  217. var D = t1.times(_TWO).times(z2);
  218. var E = D.plus(C);
  219. var F = B.minus(A);
  220. var G = B.plus(A);
  221. var H = D.minus(C);
  222. return [E.times(F), G.times(H), F.times(G), E.times(H)];
  223. }
  224. function _xpt_double(pt1) {
  225. var x1 = pt1[0];
  226. var y1 = pt1[1];
  227. var z1 = pt1[2];
  228. var A = x1.times(x1);
  229. var B = y1.times(y1);
  230. var C = _TWO.times(z1).times(z1);
  231. var D = _Q.minus(A);
  232. var J = x1.plus(y1);
  233. var E = J.times(J).minus(A).minus(B);
  234. var G = D.plus(B);
  235. var F = G.minus(C);
  236. var H = D.minus(B);
  237. return [E.times(F), G.times(H), F.times(G), E.times(H)];
  238. }
  239. function _xpt_mult(pt, n) {
  240. if (n.equals(_ZERO)) {
  241. return [_ZERO, _ONE, _ONE, _ZERO];
  242. }
  243. var odd = n.isOdd();
  244. n.shiftRight(1);
  245. var value = _xpt_double(_xpt_mult(pt, n));
  246. return odd ? _x_pt_add(value, pt) : value;
  247. }
  248. function _pt_xform(pt) {
  249. var x = pt[0];
  250. var y = pt[1];
  251. return [x, y, _ONE, x.times(y)];
  252. }
  253. function _pt_unxform(pt) {
  254. var x = pt[0];
  255. var y = pt[1];
  256. var z = pt[2];
  257. var invz = z.inv();
  258. return [x.times(invz), y.times(invz)];
  259. }
  260. function _scalarmult(pt, n) {
  261. return _pt_unxform(_xpt_mult(_pt_xform(pt), n));
  262. }
  263. function _bytesgetbit(bytes, n) {
  264. return (bytes[bytes.length - (n >>> 3) - 1] >> (n & 7)) & 1;
  265. }
  266. function _xpt_mult_bytes(pt, bytes) {
  267. var r = [_ZERO, _ONE, _ONE, _ZERO];
  268. for (var i = (bytes.length << 3) - 1; i >= 0; i--) {
  269. r = _xpt_double(r);
  270. if (_bytesgetbit(bytes, i) === 1) {
  271. r = _x_pt_add(r, pt);
  272. }
  273. }
  274. return r;
  275. }
  276. function _scalarmultBytes(pt, bytes) {
  277. return _pt_unxform(_xpt_mult_bytes(_pt_xform(pt), bytes));
  278. }
  279. var _by = _bi255(4).divide(_bi255(5));
  280. var _bx = _xrecover(_by);
  281. var _bp = [_bx, _by];
  282. function _encodeint(n) {
  283. return n.bytes(32).reverse();
  284. }
  285. function _decodeint(b) {
  286. return _bi255(b.slice(0).reverse());
  287. }
  288. function _encodepoint(p) {
  289. var v = _encodeint(p[1]);
  290. if (p[0].isOdd()) {
  291. v[31] |= 0x80;
  292. }
  293. return v;
  294. }
  295. function _decodepoint(v) {
  296. v = v.slice(0);
  297. var signbit = v[31] >> 7;
  298. v[31] &= 127;
  299. var y = _decodeint(v);
  300. var x = _xrecover(y);
  301. if ((x.n[0] & 1) !== signbit) {
  302. x = _Q.minus(x);
  303. }
  304. var p = [x, y];
  305. if (!_isoncurve(p)) {
  306. throw ('Point is not on curve');
  307. }
  308. return p;
  309. }
  310. // //////////////////////////////////////////////////
  311. /**
  312. * Factory function to create a suitable BigInteger.
  313. *
  314. * @param value
  315. * The value for the big integer.
  316. * @param base {integer}
  317. * Base of the conversion of elements in ``value``.
  318. * @returns
  319. * A BigInteger object.
  320. */
  321. function _bi(value, base) {
  322. if (base !== undefined) {
  323. if (base === 256) {
  324. return _bi(utils.string2bytes(value));
  325. }
  326. return new BigInteger(value, base);
  327. } else if (typeof value === 'string') {
  328. return new BigInteger(value, 10);
  329. } else if ((value instanceof Array) || (value instanceof Uint8Array)
  330. || Buffer.isBuffer(value)) {
  331. return new BigInteger(value);
  332. } else if (typeof value === 'number') {
  333. return new BigInteger(value.toString(), 10);
  334. } else {
  335. throw "Can't convert " + value + " to BigInteger";
  336. }
  337. }
  338. function _bi2bytes(n, cnt) {
  339. if (cnt === undefined) {
  340. cnt = (n.bitLength() + 7) >>> 3;
  341. }
  342. var bytes = new Array(cnt);
  343. for (var i = cnt - 1; i >= 0; i--) {
  344. bytes[i] = n[0] & 255; // n.and(0xff);
  345. n = n.shiftRight(8);
  346. }
  347. return bytes;
  348. }
  349. BigInteger.prototype.bytes = function(n) {
  350. return _bi2bytes(this, n);
  351. };
  352. // /////////////////////////////////////////////////////////
  353. function _bytehash(s) {
  354. var sha = crypto.createHash('sha512').update(s).digest();
  355. return _bi2bytes(_bi(sha), 64).reverse();
  356. }
  357. function _stringhash(s) {
  358. var sha = crypto.createHash('sha512').update(s).digest();
  359. return _map(_chr, _bi2bytes(_bi(sha), 64)).join('');
  360. }
  361. function _inthash(s) {
  362. // Need a leading 0 to prevent sign extension
  363. return _bi([0].concat(_bytehash(s)));
  364. }
  365. function _inthash_lo(s) {
  366. return _bi255(_bytehash(s).slice(32, 64));
  367. }
  368. function _inthash_mod_l(s) {
  369. return _inthash(s).mod(_L_BI);
  370. }
  371. function _get_a(sk) {
  372. var a = _inthash_lo(sk);
  373. a.n[0] &= 0xfff8;
  374. a.n[15] &= 0x3fff;
  375. a.n[15] |= 0x4000;
  376. return a;
  377. }
  378. function _publickey(sk) {
  379. return _encodepoint(_scalarmult(_bp, _get_a(sk)));
  380. }
  381. function _map(f, l) {
  382. var result = new Array(l.length);
  383. for (var i = 0; i < l.length; i++) {
  384. result[i] = f(l[i]);
  385. }
  386. return result;
  387. }
  388. function _chr(n) {
  389. return String.fromCharCode(n);
  390. }
  391. function _ord(c) {
  392. return c.charCodeAt(0);
  393. }
  394. function _pt_add(p1, p2) {
  395. return _pt_unxform(_x_pt_add(_pt_xform(p1), _pt_xform(p2)));
  396. }
  397. // Exports for the API.
  398. /**
  399. * Checks whether a point is on the curve.
  400. *
  401. * @function
  402. * @param point {string}
  403. * The point to check for in a byte string representation.
  404. * @returns {boolean}
  405. * true if the point is on the curve, false otherwise.
  406. */
  407. ns.isOnCurve = function(point) {
  408. try {
  409. _isoncurve(_decodepoint(utils.string2bytes(point)));
  410. } catch(e) {
  411. if (e === 'Point is not on curve') {
  412. return false;
  413. } else {
  414. throw e;
  415. }
  416. }
  417. return true;
  418. };
  419. /**
  420. * Computes the EdDSA public key.
  421. *
  422. * <p>Note: Seeds should be a byte string, not a unicode string containing
  423. * multi-byte characters.</p>
  424. *
  425. * @function
  426. * @param keySeed {string}
  427. * Private key seed in the form of a byte string.
  428. * @returns {string}
  429. * Public key as byte string computed from the private key seed
  430. * (32 bytes).
  431. */
  432. ns.publicKey = function(keySeed) {
  433. return utils.bytes2string(_publickey(keySeed));
  434. };
  435. /**
  436. * Computes an EdDSA signature of a message.
  437. *
  438. * <p>Notes:</p>
  439. *
  440. * <ul>
  441. * <li>Unicode messages need to be converted to a byte representation
  442. * (e. g. UTF-8).</li>
  443. * <li>If `publicKey` is given, and it is *not* a point of the curve,
  444. * the signature will be faulty, but no error will be thrown.</li>
  445. * </ul>
  446. *
  447. * @function
  448. * @param message {string}
  449. * Message in the form of a byte string.
  450. * @param keySeed {string}
  451. * Private key seed in the form of a byte string.
  452. * @param publicKey {string}
  453. * Public key as byte string (if not present, it will be computed from
  454. * the private key seed).
  455. * @returns {string}
  456. * Detached message signature in the form of a byte string (64 bytes).
  457. */
  458. ns.sign = function(message, keySeed, publicKey) {
  459. if (publicKey === undefined) {
  460. publicKey = _publickey(keySeed);
  461. } else {
  462. publicKey = utils.string2bytes(publicKey);
  463. }
  464. var a = _bi(_get_a(keySeed).toString(), 16);
  465. var hs = _stringhash(keySeed);
  466. var r = _bytehash(hs.slice(32, 64) + message);
  467. var rp = _scalarmultBytes(_bp, r);
  468. var erp = _encodepoint(rp);
  469. r = _bi(r).mod(_bi(1, 10).shiftLeft(512));
  470. var s = _map(_chr, erp).join('') + _map(_chr, publicKey).join('') + message;
  471. s = _inthash_mod_l(s).multiply(a).add(r).mod(_L_BI);
  472. return utils.bytes2string(erp.concat(_encodeint(s)));
  473. };
  474. /**
  475. * Verifies an EdDSA signature of a message with the public key.
  476. *
  477. * <p>Note: Unicode messages need to be converted to a byte representation
  478. * (e. g. UTF-8).</p>
  479. *
  480. * @function
  481. * @param signature {string}
  482. * Message signature in the form of a byte string. Can be detached
  483. * (64 bytes), or attached to be sliced off.
  484. * @param message {string}
  485. * Message in the form of a byte string.
  486. * @param publicKey {string}
  487. * Public key as byte string (if not present, it will be computed from
  488. * the private key seed).
  489. * @returns {boolean}
  490. * true, if the signature verifies.
  491. */
  492. ns.verify = function(signature, message, publicKey) {
  493. signature = utils.string2bytes(signature.slice(0, 64));
  494. publicKey = utils.string2bytes(publicKey);
  495. var rpe = signature.slice(0, 32);
  496. var rp = _decodepoint(rpe);
  497. var a = _decodepoint(publicKey);
  498. var s = _decodeint(signature.slice(32, 64));
  499. var h = _inthash(utils.bytes2string(rpe.concat(publicKey)) + message);
  500. var v1 = _scalarmult(_bp, s);
  501. var value = _scalarmultBytes(a, _bi2bytes(h));
  502. var v2 = _pt_add(rp, value);
  503. return v1[0].equals(v2[0]) && v1[1].equals(v2[1]);
  504. };
  505. /**
  506. * Generates a new random private key seed of 32 bytes length (256 bit).
  507. *
  508. * @function
  509. * @returns {string}
  510. * Byte string containing a new random private key seed.
  511. */
  512. ns.generateKeySeed = function() {
  513. return core.generateKey(false);
  514. };
  515. module.exports = ns;