| 'use strict'; | 
|   | 
| var BN = require('bn.js'); | 
| var HmacDRBG = require('hmac-drbg'); | 
| var utils = require('../utils'); | 
| var curves = require('../curves'); | 
| var rand = require('brorand'); | 
| var assert = utils.assert; | 
|   | 
| var KeyPair = require('./key'); | 
| var Signature = require('./signature'); | 
|   | 
| function EC(options) { | 
|   if (!(this instanceof EC)) | 
|     return new EC(options); | 
|   | 
|   // Shortcut `elliptic.ec(curve-name)` | 
|   if (typeof options === 'string') { | 
|     assert(Object.prototype.hasOwnProperty.call(curves, options), | 
|       'Unknown curve ' + options); | 
|   | 
|     options = curves[options]; | 
|   } | 
|   | 
|   // Shortcut for `elliptic.ec(elliptic.curves.curveName)` | 
|   if (options instanceof curves.PresetCurve) | 
|     options = { curve: options }; | 
|   | 
|   this.curve = options.curve.curve; | 
|   this.n = this.curve.n; | 
|   this.nh = this.n.ushrn(1); | 
|   this.g = this.curve.g; | 
|   | 
|   // Point on curve | 
|   this.g = options.curve.g; | 
|   this.g.precompute(options.curve.n.bitLength() + 1); | 
|   | 
|   // Hash for function for DRBG | 
|   this.hash = options.hash || options.curve.hash; | 
| } | 
| module.exports = EC; | 
|   | 
| EC.prototype.keyPair = function keyPair(options) { | 
|   return new KeyPair(this, options); | 
| }; | 
|   | 
| EC.prototype.keyFromPrivate = function keyFromPrivate(priv, enc) { | 
|   return KeyPair.fromPrivate(this, priv, enc); | 
| }; | 
|   | 
| EC.prototype.keyFromPublic = function keyFromPublic(pub, enc) { | 
|   return KeyPair.fromPublic(this, pub, enc); | 
| }; | 
|   | 
| EC.prototype.genKeyPair = function genKeyPair(options) { | 
|   if (!options) | 
|     options = {}; | 
|   | 
|   // Instantiate Hmac_DRBG | 
|   var drbg = new HmacDRBG({ | 
|     hash: this.hash, | 
|     pers: options.pers, | 
|     persEnc: options.persEnc || 'utf8', | 
|     entropy: options.entropy || rand(this.hash.hmacStrength), | 
|     entropyEnc: options.entropy && options.entropyEnc || 'utf8', | 
|     nonce: this.n.toArray(), | 
|   }); | 
|   | 
|   var bytes = this.n.byteLength(); | 
|   var ns2 = this.n.sub(new BN(2)); | 
|   for (;;) { | 
|     var priv = new BN(drbg.generate(bytes)); | 
|     if (priv.cmp(ns2) > 0) | 
|       continue; | 
|   | 
|     priv.iaddn(1); | 
|     return this.keyFromPrivate(priv); | 
|   } | 
| }; | 
|   | 
| EC.prototype._truncateToN = function _truncateToN(msg, truncOnly) { | 
|   var delta = msg.byteLength() * 8 - this.n.bitLength(); | 
|   if (delta > 0) | 
|     msg = msg.ushrn(delta); | 
|   if (!truncOnly && msg.cmp(this.n) >= 0) | 
|     return msg.sub(this.n); | 
|   else | 
|     return msg; | 
| }; | 
|   | 
| EC.prototype.sign = function sign(msg, key, enc, options) { | 
|   if (typeof enc === 'object') { | 
|     options = enc; | 
|     enc = null; | 
|   } | 
|   if (!options) | 
|     options = {}; | 
|   | 
|   key = this.keyFromPrivate(key, enc); | 
|   msg = this._truncateToN(new BN(msg, 16)); | 
|   | 
|   // Zero-extend key to provide enough entropy | 
|   var bytes = this.n.byteLength(); | 
|   var bkey = key.getPrivate().toArray('be', bytes); | 
|   | 
|   // Zero-extend nonce to have the same byte size as N | 
|   var nonce = msg.toArray('be', bytes); | 
|   | 
|   // Instantiate Hmac_DRBG | 
|   var drbg = new HmacDRBG({ | 
|     hash: this.hash, | 
|     entropy: bkey, | 
|     nonce: nonce, | 
|     pers: options.pers, | 
|     persEnc: options.persEnc || 'utf8', | 
|   }); | 
|   | 
|   // Number of bytes to generate | 
|   var ns1 = this.n.sub(new BN(1)); | 
|   | 
|   for (var iter = 0; ; iter++) { | 
|     var k = options.k ? | 
|       options.k(iter) : | 
|       new BN(drbg.generate(this.n.byteLength())); | 
|     k = this._truncateToN(k, true); | 
|     if (k.cmpn(1) <= 0 || k.cmp(ns1) >= 0) | 
|       continue; | 
|   | 
|     var kp = this.g.mul(k); | 
|     if (kp.isInfinity()) | 
|       continue; | 
|   | 
|     var kpX = kp.getX(); | 
|     var r = kpX.umod(this.n); | 
|     if (r.cmpn(0) === 0) | 
|       continue; | 
|   | 
|     var s = k.invm(this.n).mul(r.mul(key.getPrivate()).iadd(msg)); | 
|     s = s.umod(this.n); | 
|     if (s.cmpn(0) === 0) | 
|       continue; | 
|   | 
|     var recoveryParam = (kp.getY().isOdd() ? 1 : 0) | | 
|                         (kpX.cmp(r) !== 0 ? 2 : 0); | 
|   | 
|     // Use complement of `s`, if it is > `n / 2` | 
|     if (options.canonical && s.cmp(this.nh) > 0) { | 
|       s = this.n.sub(s); | 
|       recoveryParam ^= 1; | 
|     } | 
|   | 
|     return new Signature({ r: r, s: s, recoveryParam: recoveryParam }); | 
|   } | 
| }; | 
|   | 
| EC.prototype.verify = function verify(msg, signature, key, enc) { | 
|   msg = this._truncateToN(new BN(msg, 16)); | 
|   key = this.keyFromPublic(key, enc); | 
|   signature = new Signature(signature, 'hex'); | 
|   | 
|   // Perform primitive values validation | 
|   var r = signature.r; | 
|   var s = signature.s; | 
|   if (r.cmpn(1) < 0 || r.cmp(this.n) >= 0) | 
|     return false; | 
|   if (s.cmpn(1) < 0 || s.cmp(this.n) >= 0) | 
|     return false; | 
|   | 
|   // Validate signature | 
|   var sinv = s.invm(this.n); | 
|   var u1 = sinv.mul(msg).umod(this.n); | 
|   var u2 = sinv.mul(r).umod(this.n); | 
|   var p; | 
|   | 
|   if (!this.curve._maxwellTrick) { | 
|     p = this.g.mulAdd(u1, key.getPublic(), u2); | 
|     if (p.isInfinity()) | 
|       return false; | 
|   | 
|     return p.getX().umod(this.n).cmp(r) === 0; | 
|   } | 
|   | 
|   // NOTE: Greg Maxwell's trick, inspired by: | 
|   // https://git.io/vad3K | 
|   | 
|   p = this.g.jmulAdd(u1, key.getPublic(), u2); | 
|   if (p.isInfinity()) | 
|     return false; | 
|   | 
|   // Compare `p.x` of Jacobian point with `r`, | 
|   // this will do `p.x == r * p.z^2` instead of multiplying `p.x` by the | 
|   // inverse of `p.z^2` | 
|   return p.eqXToP(r); | 
| }; | 
|   | 
| EC.prototype.recoverPubKey = function(msg, signature, j, enc) { | 
|   assert((3 & j) === j, 'The recovery param is more than two bits'); | 
|   signature = new Signature(signature, enc); | 
|   | 
|   var n = this.n; | 
|   var e = new BN(msg); | 
|   var r = signature.r; | 
|   var s = signature.s; | 
|   | 
|   // A set LSB signifies that the y-coordinate is odd | 
|   var isYOdd = j & 1; | 
|   var isSecondKey = j >> 1; | 
|   if (r.cmp(this.curve.p.umod(this.curve.n)) >= 0 && isSecondKey) | 
|     throw new Error('Unable to find sencond key candinate'); | 
|   | 
|   // 1.1. Let x = r + jn. | 
|   if (isSecondKey) | 
|     r = this.curve.pointFromX(r.add(this.curve.n), isYOdd); | 
|   else | 
|     r = this.curve.pointFromX(r, isYOdd); | 
|   | 
|   var rInv = signature.r.invm(n); | 
|   var s1 = n.sub(e).mul(rInv).umod(n); | 
|   var s2 = s.mul(rInv).umod(n); | 
|   | 
|   // 1.6.1 Compute Q = r^-1 (sR -  eG) | 
|   //               Q = r^-1 (sR + -eG) | 
|   return this.g.mulAdd(s1, r, s2); | 
| }; | 
|   | 
| EC.prototype.getKeyRecoveryParam = function(e, signature, Q, enc) { | 
|   signature = new Signature(signature, enc); | 
|   if (signature.recoveryParam !== null) | 
|     return signature.recoveryParam; | 
|   | 
|   for (var i = 0; i < 4; i++) { | 
|     var Qprime; | 
|     try { | 
|       Qprime = this.recoverPubKey(e, signature, i); | 
|     } catch (e) { | 
|       continue; | 
|     } | 
|   | 
|     if (Qprime.eq(Q)) | 
|       return i; | 
|   } | 
|   throw new Error('Unable to find valid recovery factor'); | 
| }; |