| 'use strict'; | 
|   | 
| var BN = require('bn.js'); | 
| var utils = require('../utils'); | 
| var getNAF = utils.getNAF; | 
| var getJSF = utils.getJSF; | 
| var assert = utils.assert; | 
|   | 
| function BaseCurve(type, conf) { | 
|   this.type = type; | 
|   this.p = new BN(conf.p, 16); | 
|   | 
|   // Use Montgomery, when there is no fast reduction for the prime | 
|   this.red = conf.prime ? BN.red(conf.prime) : BN.mont(this.p); | 
|   | 
|   // Useful for many curves | 
|   this.zero = new BN(0).toRed(this.red); | 
|   this.one = new BN(1).toRed(this.red); | 
|   this.two = new BN(2).toRed(this.red); | 
|   | 
|   // Curve configuration, optional | 
|   this.n = conf.n && new BN(conf.n, 16); | 
|   this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed); | 
|   | 
|   // Temporary arrays | 
|   this._wnafT1 = new Array(4); | 
|   this._wnafT2 = new Array(4); | 
|   this._wnafT3 = new Array(4); | 
|   this._wnafT4 = new Array(4); | 
|   | 
|   this._bitLength = this.n ? this.n.bitLength() : 0; | 
|   | 
|   // Generalized Greg Maxwell's trick | 
|   var adjustCount = this.n && this.p.div(this.n); | 
|   if (!adjustCount || adjustCount.cmpn(100) > 0) { | 
|     this.redN = null; | 
|   } else { | 
|     this._maxwellTrick = true; | 
|     this.redN = this.n.toRed(this.red); | 
|   } | 
| } | 
| module.exports = BaseCurve; | 
|   | 
| BaseCurve.prototype.point = function point() { | 
|   throw new Error('Not implemented'); | 
| }; | 
|   | 
| BaseCurve.prototype.validate = function validate() { | 
|   throw new Error('Not implemented'); | 
| }; | 
|   | 
| BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) { | 
|   assert(p.precomputed); | 
|   var doubles = p._getDoubles(); | 
|   | 
|   var naf = getNAF(k, 1, this._bitLength); | 
|   var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1); | 
|   I /= 3; | 
|   | 
|   // Translate into more windowed form | 
|   var repr = []; | 
|   var j; | 
|   var nafW; | 
|   for (j = 0; j < naf.length; j += doubles.step) { | 
|     nafW = 0; | 
|     for (var l = j + doubles.step - 1; l >= j; l--) | 
|       nafW = (nafW << 1) + naf[l]; | 
|     repr.push(nafW); | 
|   } | 
|   | 
|   var a = this.jpoint(null, null, null); | 
|   var b = this.jpoint(null, null, null); | 
|   for (var i = I; i > 0; i--) { | 
|     for (j = 0; j < repr.length; j++) { | 
|       nafW = repr[j]; | 
|       if (nafW === i) | 
|         b = b.mixedAdd(doubles.points[j]); | 
|       else if (nafW === -i) | 
|         b = b.mixedAdd(doubles.points[j].neg()); | 
|     } | 
|     a = a.add(b); | 
|   } | 
|   return a.toP(); | 
| }; | 
|   | 
| BaseCurve.prototype._wnafMul = function _wnafMul(p, k) { | 
|   var w = 4; | 
|   | 
|   // Precompute window | 
|   var nafPoints = p._getNAFPoints(w); | 
|   w = nafPoints.wnd; | 
|   var wnd = nafPoints.points; | 
|   | 
|   // Get NAF form | 
|   var naf = getNAF(k, w, this._bitLength); | 
|   | 
|   // Add `this`*(N+1) for every w-NAF index | 
|   var acc = this.jpoint(null, null, null); | 
|   for (var i = naf.length - 1; i >= 0; i--) { | 
|     // Count zeroes | 
|     for (var l = 0; i >= 0 && naf[i] === 0; i--) | 
|       l++; | 
|     if (i >= 0) | 
|       l++; | 
|     acc = acc.dblp(l); | 
|   | 
|     if (i < 0) | 
|       break; | 
|     var z = naf[i]; | 
|     assert(z !== 0); | 
|     if (p.type === 'affine') { | 
|       // J +- P | 
|       if (z > 0) | 
|         acc = acc.mixedAdd(wnd[(z - 1) >> 1]); | 
|       else | 
|         acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg()); | 
|     } else { | 
|       // J +- J | 
|       if (z > 0) | 
|         acc = acc.add(wnd[(z - 1) >> 1]); | 
|       else | 
|         acc = acc.add(wnd[(-z - 1) >> 1].neg()); | 
|     } | 
|   } | 
|   return p.type === 'affine' ? acc.toP() : acc; | 
| }; | 
|   | 
| BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW, | 
|   points, | 
|   coeffs, | 
|   len, | 
|   jacobianResult) { | 
|   var wndWidth = this._wnafT1; | 
|   var wnd = this._wnafT2; | 
|   var naf = this._wnafT3; | 
|   | 
|   // Fill all arrays | 
|   var max = 0; | 
|   var i; | 
|   var j; | 
|   var p; | 
|   for (i = 0; i < len; i++) { | 
|     p = points[i]; | 
|     var nafPoints = p._getNAFPoints(defW); | 
|     wndWidth[i] = nafPoints.wnd; | 
|     wnd[i] = nafPoints.points; | 
|   } | 
|   | 
|   // Comb small window NAFs | 
|   for (i = len - 1; i >= 1; i -= 2) { | 
|     var a = i - 1; | 
|     var b = i; | 
|     if (wndWidth[a] !== 1 || wndWidth[b] !== 1) { | 
|       naf[a] = getNAF(coeffs[a], wndWidth[a], this._bitLength); | 
|       naf[b] = getNAF(coeffs[b], wndWidth[b], this._bitLength); | 
|       max = Math.max(naf[a].length, max); | 
|       max = Math.max(naf[b].length, max); | 
|       continue; | 
|     } | 
|   | 
|     var comb = [ | 
|       points[a], /* 1 */ | 
|       null, /* 3 */ | 
|       null, /* 5 */ | 
|       points[b], /* 7 */ | 
|     ]; | 
|   | 
|     // Try to avoid Projective points, if possible | 
|     if (points[a].y.cmp(points[b].y) === 0) { | 
|       comb[1] = points[a].add(points[b]); | 
|       comb[2] = points[a].toJ().mixedAdd(points[b].neg()); | 
|     } else if (points[a].y.cmp(points[b].y.redNeg()) === 0) { | 
|       comb[1] = points[a].toJ().mixedAdd(points[b]); | 
|       comb[2] = points[a].add(points[b].neg()); | 
|     } else { | 
|       comb[1] = points[a].toJ().mixedAdd(points[b]); | 
|       comb[2] = points[a].toJ().mixedAdd(points[b].neg()); | 
|     } | 
|   | 
|     var index = [ | 
|       -3, /* -1 -1 */ | 
|       -1, /* -1 0 */ | 
|       -5, /* -1 1 */ | 
|       -7, /* 0 -1 */ | 
|       0, /* 0 0 */ | 
|       7, /* 0 1 */ | 
|       5, /* 1 -1 */ | 
|       1, /* 1 0 */ | 
|       3,  /* 1 1 */ | 
|     ]; | 
|   | 
|     var jsf = getJSF(coeffs[a], coeffs[b]); | 
|     max = Math.max(jsf[0].length, max); | 
|     naf[a] = new Array(max); | 
|     naf[b] = new Array(max); | 
|     for (j = 0; j < max; j++) { | 
|       var ja = jsf[0][j] | 0; | 
|       var jb = jsf[1][j] | 0; | 
|   | 
|       naf[a][j] = index[(ja + 1) * 3 + (jb + 1)]; | 
|       naf[b][j] = 0; | 
|       wnd[a] = comb; | 
|     } | 
|   } | 
|   | 
|   var acc = this.jpoint(null, null, null); | 
|   var tmp = this._wnafT4; | 
|   for (i = max; i >= 0; i--) { | 
|     var k = 0; | 
|   | 
|     while (i >= 0) { | 
|       var zero = true; | 
|       for (j = 0; j < len; j++) { | 
|         tmp[j] = naf[j][i] | 0; | 
|         if (tmp[j] !== 0) | 
|           zero = false; | 
|       } | 
|       if (!zero) | 
|         break; | 
|       k++; | 
|       i--; | 
|     } | 
|     if (i >= 0) | 
|       k++; | 
|     acc = acc.dblp(k); | 
|     if (i < 0) | 
|       break; | 
|   | 
|     for (j = 0; j < len; j++) { | 
|       var z = tmp[j]; | 
|       p; | 
|       if (z === 0) | 
|         continue; | 
|       else if (z > 0) | 
|         p = wnd[j][(z - 1) >> 1]; | 
|       else if (z < 0) | 
|         p = wnd[j][(-z - 1) >> 1].neg(); | 
|   | 
|       if (p.type === 'affine') | 
|         acc = acc.mixedAdd(p); | 
|       else | 
|         acc = acc.add(p); | 
|     } | 
|   } | 
|   // Zeroify references | 
|   for (i = 0; i < len; i++) | 
|     wnd[i] = null; | 
|   | 
|   if (jacobianResult) | 
|     return acc; | 
|   else | 
|     return acc.toP(); | 
| }; | 
|   | 
| function BasePoint(curve, type) { | 
|   this.curve = curve; | 
|   this.type = type; | 
|   this.precomputed = null; | 
| } | 
| BaseCurve.BasePoint = BasePoint; | 
|   | 
| BasePoint.prototype.eq = function eq(/*other*/) { | 
|   throw new Error('Not implemented'); | 
| }; | 
|   | 
| BasePoint.prototype.validate = function validate() { | 
|   return this.curve.validate(this); | 
| }; | 
|   | 
| BaseCurve.prototype.decodePoint = function decodePoint(bytes, enc) { | 
|   bytes = utils.toArray(bytes, enc); | 
|   | 
|   var len = this.p.byteLength(); | 
|   | 
|   // uncompressed, hybrid-odd, hybrid-even | 
|   if ((bytes[0] === 0x04 || bytes[0] === 0x06 || bytes[0] === 0x07) && | 
|       bytes.length - 1 === 2 * len) { | 
|     if (bytes[0] === 0x06) | 
|       assert(bytes[bytes.length - 1] % 2 === 0); | 
|     else if (bytes[0] === 0x07) | 
|       assert(bytes[bytes.length - 1] % 2 === 1); | 
|   | 
|     var res =  this.point(bytes.slice(1, 1 + len), | 
|       bytes.slice(1 + len, 1 + 2 * len)); | 
|   | 
|     return res; | 
|   } else if ((bytes[0] === 0x02 || bytes[0] === 0x03) && | 
|               bytes.length - 1 === len) { | 
|     return this.pointFromX(bytes.slice(1, 1 + len), bytes[0] === 0x03); | 
|   } | 
|   throw new Error('Unknown point format'); | 
| }; | 
|   | 
| BasePoint.prototype.encodeCompressed = function encodeCompressed(enc) { | 
|   return this.encode(enc, true); | 
| }; | 
|   | 
| BasePoint.prototype._encode = function _encode(compact) { | 
|   var len = this.curve.p.byteLength(); | 
|   var x = this.getX().toArray('be', len); | 
|   | 
|   if (compact) | 
|     return [ this.getY().isEven() ? 0x02 : 0x03 ].concat(x); | 
|   | 
|   return [ 0x04 ].concat(x, this.getY().toArray('be', len)); | 
| }; | 
|   | 
| BasePoint.prototype.encode = function encode(enc, compact) { | 
|   return utils.encode(this._encode(compact), enc); | 
| }; | 
|   | 
| BasePoint.prototype.precompute = function precompute(power) { | 
|   if (this.precomputed) | 
|     return this; | 
|   | 
|   var precomputed = { | 
|     doubles: null, | 
|     naf: null, | 
|     beta: null, | 
|   }; | 
|   precomputed.naf = this._getNAFPoints(8); | 
|   precomputed.doubles = this._getDoubles(4, power); | 
|   precomputed.beta = this._getBeta(); | 
|   this.precomputed = precomputed; | 
|   | 
|   return this; | 
| }; | 
|   | 
| BasePoint.prototype._hasDoubles = function _hasDoubles(k) { | 
|   if (!this.precomputed) | 
|     return false; | 
|   | 
|   var doubles = this.precomputed.doubles; | 
|   if (!doubles) | 
|     return false; | 
|   | 
|   return doubles.points.length >= Math.ceil((k.bitLength() + 1) / doubles.step); | 
| }; | 
|   | 
| BasePoint.prototype._getDoubles = function _getDoubles(step, power) { | 
|   if (this.precomputed && this.precomputed.doubles) | 
|     return this.precomputed.doubles; | 
|   | 
|   var doubles = [ this ]; | 
|   var acc = this; | 
|   for (var i = 0; i < power; i += step) { | 
|     for (var j = 0; j < step; j++) | 
|       acc = acc.dbl(); | 
|     doubles.push(acc); | 
|   } | 
|   return { | 
|     step: step, | 
|     points: doubles, | 
|   }; | 
| }; | 
|   | 
| BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) { | 
|   if (this.precomputed && this.precomputed.naf) | 
|     return this.precomputed.naf; | 
|   | 
|   var res = [ this ]; | 
|   var max = (1 << wnd) - 1; | 
|   var dbl = max === 1 ? null : this.dbl(); | 
|   for (var i = 1; i < max; i++) | 
|     res[i] = res[i - 1].add(dbl); | 
|   return { | 
|     wnd: wnd, | 
|     points: res, | 
|   }; | 
| }; | 
|   | 
| BasePoint.prototype._getBeta = function _getBeta() { | 
|   return null; | 
| }; | 
|   | 
| BasePoint.prototype.dblp = function dblp(k) { | 
|   var r = this; | 
|   for (var i = 0; i < k; i++) | 
|     r = r.dbl(); | 
|   return r; | 
| }; |