Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80621 views
1
'use strict';
2
3
var curve = require('../curve');
4
var elliptic = require('../../elliptic');
5
var bn = require('bn.js');
6
var inherits = require('inherits');
7
var Base = curve.base;
8
9
var assert = elliptic.utils.assert;
10
11
function ShortCurve(conf) {
12
Base.call(this, 'short', conf);
13
14
this.a = new bn(conf.a, 16).toRed(this.red);
15
this.b = new bn(conf.b, 16).toRed(this.red);
16
this.tinv = this.two.redInvm();
17
18
this.zeroA = this.a.fromRed().cmpn(0) === 0;
19
this.threeA = this.a.fromRed().sub(this.p).cmpn(-3) === 0;
20
21
// If the curve is endomorphic, precalculate beta and lambda
22
this.endo = this._getEndomorphism(conf);
23
this._endoWnafT1 = new Array(4);
24
this._endoWnafT2 = new Array(4);
25
}
26
inherits(ShortCurve, Base);
27
module.exports = ShortCurve;
28
29
ShortCurve.prototype._getEndomorphism = function _getEndomorphism(conf) {
30
// No efficient endomorphism
31
if (!this.zeroA || !this.g || !this.n || this.p.modn(3) !== 1)
32
return;
33
34
// Compute beta and lambda, that lambda * P = (beta * Px; Py)
35
var beta;
36
var lambda;
37
if (conf.beta) {
38
beta = new bn(conf.beta, 16).toRed(this.red);
39
} else {
40
var betas = this._getEndoRoots(this.p);
41
// Choose the smallest beta
42
beta = betas[0].cmp(betas[1]) < 0 ? betas[0] : betas[1];
43
beta = beta.toRed(this.red);
44
}
45
if (conf.lambda) {
46
lambda = new bn(conf.lambda, 16);
47
} else {
48
// Choose the lambda that is matching selected beta
49
var lambdas = this._getEndoRoots(this.n);
50
if (this.g.mul(lambdas[0]).x.cmp(this.g.x.redMul(beta)) === 0) {
51
lambda = lambdas[0];
52
} else {
53
lambda = lambdas[1];
54
assert(this.g.mul(lambda).x.cmp(this.g.x.redMul(beta)) === 0);
55
}
56
}
57
58
// Get basis vectors, used for balanced length-two representation
59
var basis;
60
if (conf.basis) {
61
basis = conf.basis.map(function(vec) {
62
return {
63
a: new bn(vec.a, 16),
64
b: new bn(vec.b, 16)
65
};
66
});
67
} else {
68
basis = this._getEndoBasis(lambda);
69
}
70
71
return {
72
beta: beta,
73
lambda: lambda,
74
basis: basis
75
};
76
};
77
78
ShortCurve.prototype._getEndoRoots = function _getEndoRoots(num) {
79
// Find roots of for x^2 + x + 1 in F
80
// Root = (-1 +- Sqrt(-3)) / 2
81
//
82
var red = num === this.p ? this.red : bn.mont(num);
83
var tinv = new bn(2).toRed(red).redInvm();
84
var ntinv = tinv.redNeg();
85
86
var s = new bn(3).toRed(red).redNeg().redSqrt().redMul(tinv);
87
88
var l1 = ntinv.redAdd(s).fromRed();
89
var l2 = ntinv.redSub(s).fromRed();
90
return [ l1, l2 ];
91
};
92
93
ShortCurve.prototype._getEndoBasis = function _getEndoBasis(lambda) {
94
// aprxSqrt >= sqrt(this.n)
95
var aprxSqrt = this.n.shrn(Math.floor(this.n.bitLength() / 2));
96
97
// 3.74
98
// Run EGCD, until r(L + 1) < aprxSqrt
99
var u = lambda;
100
var v = this.n.clone();
101
var x1 = new bn(1);
102
var y1 = new bn(0);
103
var x2 = new bn(0);
104
var y2 = new bn(1);
105
106
// NOTE: all vectors are roots of: a + b * lambda = 0 (mod n)
107
var a0;
108
var b0;
109
// First vector
110
var a1;
111
var b1;
112
// Second vector
113
var a2;
114
var b2;
115
116
var prevR;
117
var i = 0;
118
var r;
119
var x;
120
while (u.cmpn(0) !== 0) {
121
var q = v.div(u);
122
r = v.sub(q.mul(u));
123
x = x2.sub(q.mul(x1));
124
var y = y2.sub(q.mul(y1));
125
126
if (!a1 && r.cmp(aprxSqrt) < 0) {
127
a0 = prevR.neg();
128
b0 = x1;
129
a1 = r.neg();
130
b1 = x;
131
} else if (a1 && ++i === 2) {
132
break;
133
}
134
prevR = r;
135
136
v = u;
137
u = r;
138
x2 = x1;
139
x1 = x;
140
y2 = y1;
141
y1 = y;
142
}
143
a2 = r.neg();
144
b2 = x;
145
146
var len1 = a1.sqr().add(b1.sqr());
147
var len2 = a2.sqr().add(b2.sqr());
148
if (len2.cmp(len1) >= 0) {
149
a2 = a0;
150
b2 = b0;
151
}
152
153
// Normalize signs
154
if (a1.sign) {
155
a1 = a1.neg();
156
b1 = b1.neg();
157
}
158
if (a2.sign) {
159
a2 = a2.neg();
160
b2 = b2.neg();
161
}
162
163
return [
164
{ a: a1, b: b1 },
165
{ a: a2, b: b2 }
166
];
167
};
168
169
ShortCurve.prototype._endoSplit = function _endoSplit(k) {
170
var basis = this.endo.basis;
171
var v1 = basis[0];
172
var v2 = basis[1];
173
174
var c1 = v2.b.mul(k).divRound(this.n);
175
var c2 = v1.b.neg().mul(k).divRound(this.n);
176
177
var p1 = c1.mul(v1.a);
178
var p2 = c2.mul(v2.a);
179
var q1 = c1.mul(v1.b);
180
var q2 = c2.mul(v2.b);
181
182
// Calculate answer
183
var k1 = k.sub(p1).sub(p2);
184
var k2 = q1.add(q2).neg();
185
return { k1: k1, k2: k2 };
186
};
187
188
ShortCurve.prototype.pointFromX = function pointFromX(odd, x) {
189
x = new bn(x, 16);
190
if (!x.red)
191
x = x.toRed(this.red);
192
193
var y2 = x.redSqr().redMul(x).redIAdd(x.redMul(this.a)).redIAdd(this.b);
194
var y = y2.redSqrt();
195
196
// XXX Is there any way to tell if the number is odd without converting it
197
// to non-red form?
198
var isOdd = y.fromRed().isOdd();
199
if (odd && !isOdd || !odd && isOdd)
200
y = y.redNeg();
201
202
return this.point(x, y);
203
};
204
205
ShortCurve.prototype.validate = function validate(point) {
206
if (point.inf)
207
return true;
208
209
var x = point.x;
210
var y = point.y;
211
212
var ax = this.a.redMul(x);
213
var rhs = x.redSqr().redMul(x).redIAdd(ax).redIAdd(this.b);
214
return y.redSqr().redISub(rhs).cmpn(0) === 0;
215
};
216
217
ShortCurve.prototype._endoWnafMulAdd =
218
function _endoWnafMulAdd(points, coeffs) {
219
var npoints = this._endoWnafT1;
220
var ncoeffs = this._endoWnafT2;
221
for (var i = 0; i < points.length; i++) {
222
var split = this._endoSplit(coeffs[i]);
223
var p = points[i];
224
var beta = p._getBeta();
225
226
if (split.k1.sign) {
227
split.k1.sign = !split.k1.sign;
228
p = p.neg(true);
229
}
230
if (split.k2.sign) {
231
split.k2.sign = !split.k2.sign;
232
beta = beta.neg(true);
233
}
234
235
npoints[i * 2] = p;
236
npoints[i * 2 + 1] = beta;
237
ncoeffs[i * 2] = split.k1;
238
ncoeffs[i * 2 + 1] = split.k2;
239
}
240
var res = this._wnafMulAdd(1, npoints, ncoeffs, i * 2);
241
242
// Clean-up references to points and coefficients
243
for (var j = 0; j < i * 2; j++) {
244
npoints[j] = null;
245
ncoeffs[j] = null;
246
}
247
return res;
248
};
249
250
function Point(curve, x, y, isRed) {
251
Base.BasePoint.call(this, curve, 'affine');
252
if (x === null && y === null) {
253
this.x = null;
254
this.y = null;
255
this.inf = true;
256
} else {
257
this.x = new bn(x, 16);
258
this.y = new bn(y, 16);
259
// Force redgomery representation when loading from JSON
260
if (isRed) {
261
this.x.forceRed(this.curve.red);
262
this.y.forceRed(this.curve.red);
263
}
264
if (!this.x.red)
265
this.x = this.x.toRed(this.curve.red);
266
if (!this.y.red)
267
this.y = this.y.toRed(this.curve.red);
268
this.inf = false;
269
}
270
}
271
inherits(Point, Base.BasePoint);
272
273
ShortCurve.prototype.point = function point(x, y, isRed) {
274
return new Point(this, x, y, isRed);
275
};
276
277
ShortCurve.prototype.pointFromJSON = function pointFromJSON(obj, red) {
278
return Point.fromJSON(this, obj, red);
279
};
280
281
Point.prototype._getBeta = function _getBeta() {
282
if (!this.curve.endo)
283
return;
284
285
var pre = this.precomputed;
286
if (pre && pre.beta)
287
return pre.beta;
288
289
var beta = this.curve.point(this.x.redMul(this.curve.endo.beta), this.y);
290
if (pre) {
291
var curve = this.curve;
292
var endoMul = function(p) {
293
return curve.point(p.x.redMul(curve.endo.beta), p.y);
294
};
295
pre.beta = beta;
296
beta.precomputed = {
297
beta: null,
298
naf: pre.naf && {
299
wnd: pre.naf.wnd,
300
points: pre.naf.points.map(endoMul)
301
},
302
doubles: pre.doubles && {
303
step: pre.doubles.step,
304
points: pre.doubles.points.map(endoMul)
305
}
306
};
307
}
308
return beta;
309
};
310
311
Point.prototype.toJSON = function toJSON() {
312
if (!this.precomputed)
313
return [ this.x, this.y ];
314
315
return [ this.x, this.y, this.precomputed && {
316
doubles: this.precomputed.doubles && {
317
step: this.precomputed.doubles.step,
318
points: this.precomputed.doubles.points.slice(1)
319
},
320
naf: this.precomputed.naf && {
321
wnd: this.precomputed.naf.wnd,
322
points: this.precomputed.naf.points.slice(1)
323
}
324
} ];
325
};
326
327
Point.fromJSON = function fromJSON(curve, obj, red) {
328
if (typeof obj === 'string')
329
obj = JSON.parse(obj);
330
var res = curve.point(obj[0], obj[1], red);
331
if (!obj[2])
332
return res;
333
334
function obj2point(obj) {
335
return curve.point(obj[0], obj[1], red);
336
}
337
338
var pre = obj[2];
339
res.precomputed = {
340
beta: null,
341
doubles: pre.doubles && {
342
step: pre.doubles.step,
343
points: [ res ].concat(pre.doubles.points.map(obj2point))
344
},
345
naf: pre.naf && {
346
wnd: pre.naf.wnd,
347
points: [ res ].concat(pre.naf.points.map(obj2point))
348
}
349
};
350
return res;
351
};
352
353
Point.prototype.inspect = function inspect() {
354
if (this.isInfinity())
355
return '<EC Point Infinity>';
356
return '<EC Point x: ' + this.x.fromRed().toString(16, 2) +
357
' y: ' + this.y.fromRed().toString(16, 2) + '>';
358
};
359
360
Point.prototype.isInfinity = function isInfinity() {
361
return this.inf;
362
};
363
364
Point.prototype.add = function add(p) {
365
// O + P = P
366
if (this.inf)
367
return p;
368
369
// P + O = P
370
if (p.inf)
371
return this;
372
373
// P + P = 2P
374
if (this.eq(p))
375
return this.dbl();
376
377
// P + (-P) = O
378
if (this.neg().eq(p))
379
return this.curve.point(null, null);
380
381
// P + Q = O
382
if (this.x.cmp(p.x) === 0)
383
return this.curve.point(null, null);
384
385
var c = this.y.redSub(p.y);
386
if (c.cmpn(0) !== 0)
387
c = c.redMul(this.x.redSub(p.x).redInvm());
388
var nx = c.redSqr().redISub(this.x).redISub(p.x);
389
var ny = c.redMul(this.x.redSub(nx)).redISub(this.y);
390
return this.curve.point(nx, ny);
391
};
392
393
Point.prototype.dbl = function dbl() {
394
if (this.inf)
395
return this;
396
397
// 2P = O
398
var ys1 = this.y.redAdd(this.y);
399
if (ys1.cmpn(0) === 0)
400
return this.curve.point(null, null);
401
402
var a = this.curve.a;
403
404
var x2 = this.x.redSqr();
405
var dyinv = ys1.redInvm();
406
var c = x2.redAdd(x2).redIAdd(x2).redIAdd(a).redMul(dyinv);
407
408
var nx = c.redSqr().redISub(this.x.redAdd(this.x));
409
var ny = c.redMul(this.x.redSub(nx)).redISub(this.y);
410
return this.curve.point(nx, ny);
411
};
412
413
Point.prototype.getX = function getX() {
414
return this.x.fromRed();
415
};
416
417
Point.prototype.getY = function getY() {
418
return this.y.fromRed();
419
};
420
421
Point.prototype.mul = function mul(k) {
422
k = new bn(k, 16);
423
424
if (this.precomputed && this.precomputed.doubles)
425
return this.curve._fixedNafMul(this, k);
426
else if (this.curve.endo)
427
return this.curve._endoWnafMulAdd([ this ], [ k ]);
428
else
429
return this.curve._wnafMul(this, k);
430
};
431
432
Point.prototype.mulAdd = function mulAdd(k1, p2, k2) {
433
var points = [ this, p2 ];
434
var coeffs = [ k1, k2 ];
435
if (this.curve.endo)
436
return this.curve._endoWnafMulAdd(points, coeffs);
437
else
438
return this.curve._wnafMulAdd(1, points, coeffs, 2);
439
};
440
441
Point.prototype.eq = function eq(p) {
442
return this === p ||
443
this.inf === p.inf &&
444
(this.inf || this.x.cmp(p.x) === 0 && this.y.cmp(p.y) === 0);
445
};
446
447
Point.prototype.neg = function neg(_precompute) {
448
if (this.inf)
449
return this;
450
451
var res = this.curve.point(this.x, this.y.redNeg());
452
if (_precompute && this.precomputed) {
453
var pre = this.precomputed;
454
var negate = function(p) {
455
return p.neg();
456
};
457
res.precomputed = {
458
naf: pre.naf && {
459
wnd: pre.naf.wnd,
460
points: pre.naf.points.map(negate)
461
},
462
doubles: pre.doubles && {
463
step: pre.doubles.step,
464
points: pre.doubles.points.map(negate)
465
}
466
};
467
}
468
return res;
469
};
470
471
Point.prototype.toJ = function toJ() {
472
if (this.inf)
473
return this.curve.jpoint(null, null, null);
474
475
var res = this.curve.jpoint(this.x, this.y, this.curve.one);
476
return res;
477
};
478
479
function JPoint(curve, x, y, z) {
480
Base.BasePoint.call(this, curve, 'jacobian');
481
if (x === null && y === null && z === null) {
482
this.x = this.curve.one;
483
this.y = this.curve.one;
484
this.z = new bn(0);
485
} else {
486
this.x = new bn(x, 16);
487
this.y = new bn(y, 16);
488
this.z = new bn(z, 16);
489
}
490
if (!this.x.red)
491
this.x = this.x.toRed(this.curve.red);
492
if (!this.y.red)
493
this.y = this.y.toRed(this.curve.red);
494
if (!this.z.red)
495
this.z = this.z.toRed(this.curve.red);
496
497
this.zOne = this.z === this.curve.one;
498
}
499
inherits(JPoint, Base.BasePoint);
500
501
ShortCurve.prototype.jpoint = function jpoint(x, y, z) {
502
return new JPoint(this, x, y, z);
503
};
504
505
JPoint.prototype.toP = function toP() {
506
if (this.isInfinity())
507
return this.curve.point(null, null);
508
509
var zinv = this.z.redInvm();
510
var zinv2 = zinv.redSqr();
511
var ax = this.x.redMul(zinv2);
512
var ay = this.y.redMul(zinv2).redMul(zinv);
513
514
return this.curve.point(ax, ay);
515
};
516
517
JPoint.prototype.neg = function neg() {
518
return this.curve.jpoint(this.x, this.y.redNeg(), this.z);
519
};
520
521
JPoint.prototype.add = function add(p) {
522
// O + P = P
523
if (this.isInfinity())
524
return p;
525
526
// P + O = P
527
if (p.isInfinity())
528
return this;
529
530
// 12M + 4S + 7A
531
var pz2 = p.z.redSqr();
532
var z2 = this.z.redSqr();
533
var u1 = this.x.redMul(pz2);
534
var u2 = p.x.redMul(z2);
535
var s1 = this.y.redMul(pz2.redMul(p.z));
536
var s2 = p.y.redMul(z2.redMul(this.z));
537
538
var h = u1.redSub(u2);
539
var r = s1.redSub(s2);
540
if (h.cmpn(0) === 0) {
541
if (r.cmpn(0) !== 0)
542
return this.curve.jpoint(null, null, null);
543
else
544
return this.dbl();
545
}
546
547
var h2 = h.redSqr();
548
var h3 = h2.redMul(h);
549
var v = u1.redMul(h2);
550
551
var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v);
552
var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3));
553
var nz = this.z.redMul(p.z).redMul(h);
554
555
return this.curve.jpoint(nx, ny, nz);
556
};
557
558
JPoint.prototype.mixedAdd = function mixedAdd(p) {
559
// O + P = P
560
if (this.isInfinity())
561
return p.toJ();
562
563
// P + O = P
564
if (p.isInfinity())
565
return this;
566
567
// 8M + 3S + 7A
568
var z2 = this.z.redSqr();
569
var u1 = this.x;
570
var u2 = p.x.redMul(z2);
571
var s1 = this.y;
572
var s2 = p.y.redMul(z2).redMul(this.z);
573
574
var h = u1.redSub(u2);
575
var r = s1.redSub(s2);
576
if (h.cmpn(0) === 0) {
577
if (r.cmpn(0) !== 0)
578
return this.curve.jpoint(null, null, null);
579
else
580
return this.dbl();
581
}
582
583
var h2 = h.redSqr();
584
var h3 = h2.redMul(h);
585
var v = u1.redMul(h2);
586
587
var nx = r.redSqr().redIAdd(h3).redISub(v).redISub(v);
588
var ny = r.redMul(v.redISub(nx)).redISub(s1.redMul(h3));
589
var nz = this.z.redMul(h);
590
591
return this.curve.jpoint(nx, ny, nz);
592
};
593
594
JPoint.prototype.dblp = function dblp(pow) {
595
if (pow === 0)
596
return this;
597
if (this.isInfinity())
598
return this;
599
if (!pow)
600
return this.dbl();
601
602
if (this.curve.zeroA || this.curve.threeA) {
603
var r = this;
604
for (var i = 0; i < pow; i++)
605
r = r.dbl();
606
return r;
607
}
608
609
// 1M + 2S + 1A + N * (4S + 5M + 8A)
610
// N = 1 => 6M + 6S + 9A
611
var a = this.curve.a;
612
var tinv = this.curve.tinv;
613
614
var jx = this.x;
615
var jy = this.y;
616
var jz = this.z;
617
var jz4 = jz.redSqr().redSqr();
618
619
// Reuse results
620
var jyd = jy.redAdd(jy);
621
for (var i = 0; i < pow; i++) {
622
var jx2 = jx.redSqr();
623
var jyd2 = jyd.redSqr();
624
var jyd4 = jyd2.redSqr();
625
var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4));
626
627
var t1 = jx.redMul(jyd2);
628
var nx = c.redSqr().redISub(t1.redAdd(t1));
629
var t2 = t1.redISub(nx);
630
var dny = c.redMul(t2);
631
dny = dny.redIAdd(dny).redISub(jyd4);
632
var nz = jyd.redMul(jz);
633
if (i + 1 < pow)
634
jz4 = jz4.redMul(jyd4);
635
636
jx = nx;
637
jz = nz;
638
jyd = dny;
639
}
640
641
return this.curve.jpoint(jx, jyd.redMul(tinv), jz);
642
};
643
644
JPoint.prototype.dbl = function dbl() {
645
if (this.isInfinity())
646
return this;
647
648
if (this.curve.zeroA)
649
return this._zeroDbl();
650
else if (this.curve.threeA)
651
return this._threeDbl();
652
else
653
return this._dbl();
654
};
655
656
JPoint.prototype._zeroDbl = function _zeroDbl() {
657
var nx;
658
var ny;
659
var nz;
660
// Z = 1
661
if (this.zOne) {
662
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
663
// #doubling-mdbl-2007-bl
664
// 1M + 5S + 14A
665
666
// XX = X1^2
667
var xx = this.x.redSqr();
668
// YY = Y1^2
669
var yy = this.y.redSqr();
670
// YYYY = YY^2
671
var yyyy = yy.redSqr();
672
// S = 2 * ((X1 + YY)^2 - XX - YYYY)
673
var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
674
s = s.redIAdd(s);
675
// M = 3 * XX + a; a = 0
676
var m = xx.redAdd(xx).redIAdd(xx);
677
// T = M ^ 2 - 2*S
678
var t = m.redSqr().redISub(s).redISub(s);
679
680
// 8 * YYYY
681
var yyyy8 = yyyy.redIAdd(yyyy);
682
yyyy8 = yyyy8.redIAdd(yyyy8);
683
yyyy8 = yyyy8.redIAdd(yyyy8);
684
685
// X3 = T
686
nx = t;
687
// Y3 = M * (S - T) - 8 * YYYY
688
ny = m.redMul(s.redISub(t)).redISub(yyyy8);
689
// Z3 = 2*Y1
690
nz = this.y.redAdd(this.y);
691
} else {
692
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html
693
// #doubling-dbl-2009-l
694
// 2M + 5S + 13A
695
696
// A = X1^2
697
var a = this.x.redSqr();
698
// B = Y1^2
699
var b = this.y.redSqr();
700
// C = B^2
701
var c = b.redSqr();
702
// D = 2 * ((X1 + B)^2 - A - C)
703
var d = this.x.redAdd(b).redSqr().redISub(a).redISub(c);
704
d = d.redIAdd(d);
705
// E = 3 * A
706
var e = a.redAdd(a).redIAdd(a);
707
// F = E^2
708
var f = e.redSqr();
709
710
// 8 * C
711
var c8 = c.redIAdd(c);
712
c8 = c8.redIAdd(c8);
713
c8 = c8.redIAdd(c8);
714
715
// X3 = F - 2 * D
716
nx = f.redISub(d).redISub(d);
717
// Y3 = E * (D - X3) - 8 * C
718
ny = e.redMul(d.redISub(nx)).redISub(c8);
719
// Z3 = 2 * Y1 * Z1
720
nz = this.y.redMul(this.z);
721
nz = nz.redIAdd(nz);
722
}
723
724
return this.curve.jpoint(nx, ny, nz);
725
};
726
727
JPoint.prototype._threeDbl = function _threeDbl() {
728
var nx;
729
var ny;
730
var nz;
731
// Z = 1
732
if (this.zOne) {
733
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html
734
// #doubling-mdbl-2007-bl
735
// 1M + 5S + 15A
736
737
// XX = X1^2
738
var xx = this.x.redSqr();
739
// YY = Y1^2
740
var yy = this.y.redSqr();
741
// YYYY = YY^2
742
var yyyy = yy.redSqr();
743
// S = 2 * ((X1 + YY)^2 - XX - YYYY)
744
var s = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
745
s = s.redIAdd(s);
746
// M = 3 * XX + a
747
var m = xx.redAdd(xx).redIAdd(xx).redIAdd(this.curve.a);
748
// T = M^2 - 2 * S
749
var t = m.redSqr().redISub(s).redISub(s);
750
// X3 = T
751
nx = t;
752
// Y3 = M * (S - T) - 8 * YYYY
753
var yyyy8 = yyyy.redIAdd(yyyy);
754
yyyy8 = yyyy8.redIAdd(yyyy8);
755
yyyy8 = yyyy8.redIAdd(yyyy8);
756
ny = m.redMul(s.redISub(t)).redISub(yyyy8);
757
// Z3 = 2 * Y1
758
nz = this.y.redAdd(this.y);
759
} else {
760
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
761
// 3M + 5S
762
763
// delta = Z1^2
764
var delta = this.z.redSqr();
765
// gamma = Y1^2
766
var gamma = this.y.redSqr();
767
// beta = X1 * gamma
768
var beta = this.x.redMul(gamma);
769
// alpha = 3 * (X1 - delta) * (X1 + delta)
770
var alpha = this.x.redSub(delta).redMul(this.x.redAdd(delta));
771
alpha = alpha.redAdd(alpha).redIAdd(alpha);
772
// X3 = alpha^2 - 8 * beta
773
var beta4 = beta.redIAdd(beta);
774
beta4 = beta4.redIAdd(beta4);
775
var beta8 = beta4.redAdd(beta4);
776
nx = alpha.redSqr().redISub(beta8);
777
// Z3 = (Y1 + Z1)^2 - gamma - delta
778
nz = this.y.redAdd(this.z).redSqr().redISub(gamma).redISub(delta);
779
// Y3 = alpha * (4 * beta - X3) - 8 * gamma^2
780
var ggamma8 = gamma.redSqr();
781
ggamma8 = ggamma8.redIAdd(ggamma8);
782
ggamma8 = ggamma8.redIAdd(ggamma8);
783
ggamma8 = ggamma8.redIAdd(ggamma8);
784
ny = alpha.redMul(beta4.redISub(nx)).redISub(ggamma8);
785
}
786
787
return this.curve.jpoint(nx, ny, nz);
788
};
789
790
JPoint.prototype._dbl = function _dbl() {
791
var a = this.curve.a;
792
793
// 4M + 6S + 10A
794
var jx = this.x;
795
var jy = this.y;
796
var jz = this.z;
797
var jz4 = jz.redSqr().redSqr();
798
799
var jx2 = jx.redSqr();
800
var jy2 = jy.redSqr();
801
802
var c = jx2.redAdd(jx2).redIAdd(jx2).redIAdd(a.redMul(jz4));
803
804
var jxd4 = jx.redAdd(jx);
805
jxd4 = jxd4.redIAdd(jxd4);
806
var t1 = jxd4.redMul(jy2);
807
var nx = c.redSqr().redISub(t1.redAdd(t1));
808
var t2 = t1.redISub(nx);
809
810
var jyd8 = jy2.redSqr();
811
jyd8 = jyd8.redIAdd(jyd8);
812
jyd8 = jyd8.redIAdd(jyd8);
813
jyd8 = jyd8.redIAdd(jyd8);
814
var ny = c.redMul(t2).redISub(jyd8);
815
var nz = jy.redAdd(jy).redMul(jz);
816
817
return this.curve.jpoint(nx, ny, nz);
818
};
819
820
JPoint.prototype.trpl = function trpl() {
821
if (!this.curve.zeroA)
822
return this.dbl().add(this);
823
824
// hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-0.html#tripling-tpl-2007-bl
825
// 5M + 10S + ...
826
827
// XX = X1^2
828
var xx = this.x.redSqr();
829
// YY = Y1^2
830
var yy = this.y.redSqr();
831
// ZZ = Z1^2
832
var zz = this.z.redSqr();
833
// YYYY = YY^2
834
var yyyy = yy.redSqr();
835
// M = 3 * XX + a * ZZ2; a = 0
836
var m = xx.redAdd(xx).redIAdd(xx);
837
// MM = M^2
838
var mm = m.redSqr();
839
// E = 6 * ((X1 + YY)^2 - XX - YYYY) - MM
840
var e = this.x.redAdd(yy).redSqr().redISub(xx).redISub(yyyy);
841
e = e.redIAdd(e);
842
e = e.redAdd(e).redIAdd(e);
843
e = e.redISub(mm);
844
// EE = E^2
845
var ee = e.redSqr();
846
// T = 16*YYYY
847
var t = yyyy.redIAdd(yyyy);
848
t = t.redIAdd(t);
849
t = t.redIAdd(t);
850
t = t.redIAdd(t);
851
// U = (M + E)^2 - MM - EE - T
852
var u = m.redIAdd(e).redSqr().redISub(mm).redISub(ee).redISub(t);
853
// X3 = 4 * (X1 * EE - 4 * YY * U)
854
var yyu4 = yy.redMul(u);
855
yyu4 = yyu4.redIAdd(yyu4);
856
yyu4 = yyu4.redIAdd(yyu4);
857
var nx = this.x.redMul(ee).redISub(yyu4);
858
nx = nx.redIAdd(nx);
859
nx = nx.redIAdd(nx);
860
// Y3 = 8 * Y1 * (U * (T - U) - E * EE)
861
var ny = this.y.redMul(u.redMul(t.redISub(u)).redISub(e.redMul(ee)));
862
ny = ny.redIAdd(ny);
863
ny = ny.redIAdd(ny);
864
ny = ny.redIAdd(ny);
865
// Z3 = (Z1 + E)^2 - ZZ - EE
866
var nz = this.z.redAdd(e).redSqr().redISub(zz).redISub(ee);
867
868
return this.curve.jpoint(nx, ny, nz);
869
};
870
871
JPoint.prototype.mul = function mul(k, kbase) {
872
k = new bn(k, kbase);
873
874
return this.curve._wnafMul(this, k);
875
};
876
877
JPoint.prototype.eq = function eq(p) {
878
if (p.type === 'affine')
879
return this.eq(p.toJ());
880
881
if (this === p)
882
return true;
883
884
// x1 * z2^2 == x2 * z1^2
885
var z2 = this.z.redSqr();
886
var pz2 = p.z.redSqr();
887
if (this.x.redMul(pz2).redISub(p.x.redMul(z2)).cmpn(0) !== 0)
888
return false;
889
890
// y1 * z2^3 == y2 * z1^3
891
var z3 = z2.redMul(this.z);
892
var pz3 = pz2.redMul(p.z);
893
return this.y.redMul(pz3).redISub(p.y.redMul(z3)).cmpn(0) === 0;
894
};
895
896
JPoint.prototype.inspect = function inspect() {
897
if (this.isInfinity())
898
return '<EC JPoint Infinity>';
899
return '<EC JPoint x: ' + this.x.toString(16, 2) +
900
' y: ' + this.y.toString(16, 2) +
901
' z: ' + this.z.toString(16, 2) + '>';
902
};
903
904
JPoint.prototype.isInfinity = function isInfinity() {
905
// XXX This code assumes that zero is always zero in red
906
return this.z.cmpn(0) === 0;
907
};
908
909