bd2b41230bb6c8a997e209d8a5a2267fb72f1bba84de85506c76236c7e3271e295b66ad1d4bb2eb1a7a7817ef985d9c41c2ebdd50f96b38b8c6ab726194ead 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121
  1. 'use strict';
  2. var hash = require('hash.js');
  3. var curves = require('../curves');
  4. var utils = require('../utils');
  5. var assert = utils.assert;
  6. var parseBytes = utils.parseBytes;
  7. var KeyPair = require('./key');
  8. var Signature = require('./signature');
  9. function EDDSA(curve) {
  10. assert(curve === 'ed25519', 'only tested with ed25519 so far');
  11. if (!(this instanceof EDDSA))
  12. return new EDDSA(curve);
  13. curve = curves[curve].curve;
  14. this.curve = curve;
  15. this.g = curve.g;
  16. this.g.precompute(curve.n.bitLength() + 1);
  17. this.pointClass = curve.point().constructor;
  18. this.encodingLength = Math.ceil(curve.n.bitLength() / 8);
  19. this.hash = hash.sha512;
  20. }
  21. module.exports = EDDSA;
  22. /**
  23. * @param {Array|String} message - message bytes
  24. * @param {Array|String|KeyPair} secret - secret bytes or a keypair
  25. * @returns {Signature} - signature
  26. */
  27. EDDSA.prototype.sign = function sign(message, secret) {
  28. message = parseBytes(message);
  29. var key = this.keyFromSecret(secret);
  30. var r = this.hashInt(key.messagePrefix(), message);
  31. var R = this.g.mul(r);
  32. var Rencoded = this.encodePoint(R);
  33. var s_ = this.hashInt(Rencoded, key.pubBytes(), message)
  34. .mul(key.priv());
  35. var S = r.add(s_).umod(this.curve.n);
  36. return this.makeSignature({ R: R, S: S, Rencoded: Rencoded });
  37. };
  38. /**
  39. * @param {Array} message - message bytes
  40. * @param {Array|String|Signature} sig - sig bytes
  41. * @param {Array|String|Point|KeyPair} pub - public key
  42. * @returns {Boolean} - true if public key matches sig of message
  43. */
  44. EDDSA.prototype.verify = function verify(message, sig, pub) {
  45. message = parseBytes(message);
  46. sig = this.makeSignature(sig);
  47. if (sig.S().gte(sig.eddsa.curve.n) || sig.S().isNeg()) {
  48. return false;
  49. }
  50. var key = this.keyFromPublic(pub);
  51. var h = this.hashInt(sig.Rencoded(), key.pubBytes(), message);
  52. var SG = this.g.mul(sig.S());
  53. var RplusAh = sig.R().add(key.pub().mul(h));
  54. return RplusAh.eq(SG);
  55. };
  56. EDDSA.prototype.hashInt = function hashInt() {
  57. var hash = this.hash();
  58. for (var i = 0; i < arguments.length; i++)
  59. hash.update(arguments[i]);
  60. return utils.intFromLE(hash.digest()).umod(this.curve.n);
  61. };
  62. EDDSA.prototype.keyFromPublic = function keyFromPublic(pub) {
  63. return KeyPair.fromPublic(this, pub);
  64. };
  65. EDDSA.prototype.keyFromSecret = function keyFromSecret(secret) {
  66. return KeyPair.fromSecret(this, secret);
  67. };
  68. EDDSA.prototype.makeSignature = function makeSignature(sig) {
  69. if (sig instanceof Signature)
  70. return sig;
  71. return new Signature(this, sig);
  72. };
  73. /**
  74. * * https://tools.ietf.org/html/draft-josefsson-eddsa-ed25519-03#section-5.2
  75. *
  76. * EDDSA defines methods for encoding and decoding points and integers. These are
  77. * helper convenience methods, that pass along to utility functions implied
  78. * parameters.
  79. *
  80. */
  81. EDDSA.prototype.encodePoint = function encodePoint(point) {
  82. var enc = point.getY().toArray('le', this.encodingLength);
  83. enc[this.encodingLength - 1] |= point.getX().isOdd() ? 0x80 : 0;
  84. return enc;
  85. };
  86. EDDSA.prototype.decodePoint = function decodePoint(bytes) {
  87. bytes = utils.parseBytes(bytes);
  88. var lastIx = bytes.length - 1;
  89. var normed = bytes.slice(0, lastIx).concat(bytes[lastIx] & ~0x80);
  90. var xIsOdd = (bytes[lastIx] & 0x80) !== 0;
  91. var y = utils.intFromLE(normed);
  92. return this.curve.pointFromY(y, xIsOdd);
  93. };
  94. EDDSA.prototype.encodeInt = function encodeInt(num) {
  95. return num.toArray('le', this.encodingLength);
  96. };
  97. EDDSA.prototype.decodeInt = function decodeInt(bytes) {
  98. return utils.intFromLE(bytes);
  99. };
  100. EDDSA.prototype.isPoint = function isPoint(val) {
  101. return val instanceof this.pointClass;
  102. };