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 EdwardsCurve(conf) {
12
// NOTE: Important as we are creating point in Base.call()
13
this.twisted = (conf.a | 0) !== 1;
14
this.mOneA = this.twisted && (conf.a | 0) === -1;
15
this.extended = this.mOneA;
16
17
Base.call(this, 'edwards', conf);
18
19
this.a = new bn(conf.a, 16).mod(this.red.m).toRed(this.red);
20
this.c = new bn(conf.c, 16).toRed(this.red);
21
this.c2 = this.c.redSqr();
22
this.d = new bn(conf.d, 16).toRed(this.red);
23
this.dd = this.d.redAdd(this.d);
24
25
assert(!this.twisted || this.c.fromRed().cmpn(1) === 0);
26
this.oneC = (conf.c | 0) === 1;
27
}
28
inherits(EdwardsCurve, Base);
29
module.exports = EdwardsCurve;
30
31
EdwardsCurve.prototype._mulA = function _mulA(num) {
32
if (this.mOneA)
33
return num.redNeg();
34
else
35
return this.a.redMul(num);
36
};
37
38
EdwardsCurve.prototype._mulC = function _mulC(num) {
39
if (this.oneC)
40
return num;
41
else
42
return this.c.redMul(num);
43
};
44
45
// Just for compatibility with Short curve
46
EdwardsCurve.prototype.jpoint = function jpoint(x, y, z, t) {
47
return this.point(x, y, z, t);
48
};
49
50
EdwardsCurve.prototype.pointFromX = function pointFromX(odd, x) {
51
x = new bn(x, 16);
52
if (!x.red)
53
x = x.toRed(this.red);
54
55
var x2 = x.redSqr();
56
var rhs = this.c2.redSub(this.a.redMul(x2));
57
var lhs = this.one.redSub(this.c2.redMul(this.d).redMul(x2));
58
59
var y = rhs.redMul(lhs.redInvm()).redSqrt();
60
var isOdd = y.fromRed().isOdd();
61
if (odd && !isOdd || !odd && isOdd)
62
y = y.redNeg();
63
64
return this.point(x, y, curve.one);
65
};
66
67
EdwardsCurve.prototype.validate = function validate(point) {
68
if (point.isInfinity())
69
return true;
70
71
// Curve: A * X^2 + Y^2 = C^2 * (1 + D * X^2 * Y^2)
72
point.normalize();
73
74
var x2 = point.x.redSqr();
75
var y2 = point.y.redSqr();
76
var lhs = x2.redMul(this.a).redAdd(y2);
77
var rhs = this.c2.redMul(this.one.redAdd(this.d.redMul(x2).redMul(y2)));
78
79
return lhs.cmp(rhs) === 0;
80
};
81
82
function Point(curve, x, y, z, t) {
83
Base.BasePoint.call(this, curve, 'projective');
84
if (x === null && y === null && z === null) {
85
this.x = this.curve.zero;
86
this.y = this.curve.one;
87
this.z = this.curve.one;
88
this.t = this.curve.zero;
89
this.zOne = true;
90
} else {
91
this.x = new bn(x, 16);
92
this.y = new bn(y, 16);
93
this.z = z ? new bn(z, 16) : this.curve.one;
94
this.t = t && new bn(t, 16);
95
if (!this.x.red)
96
this.x = this.x.toRed(this.curve.red);
97
if (!this.y.red)
98
this.y = this.y.toRed(this.curve.red);
99
if (!this.z.red)
100
this.z = this.z.toRed(this.curve.red);
101
if (this.t && !this.t.red)
102
this.t = this.t.toRed(this.curve.red);
103
this.zOne = this.z === this.curve.one;
104
105
// Use extended coordinates
106
if (this.curve.extended && !this.t) {
107
this.t = this.x.redMul(this.y);
108
if (!this.zOne)
109
this.t = this.t.redMul(this.z.redInvm());
110
}
111
}
112
}
113
inherits(Point, Base.BasePoint);
114
115
EdwardsCurve.prototype.pointFromJSON = function pointFromJSON(obj) {
116
return Point.fromJSON(this, obj);
117
};
118
119
EdwardsCurve.prototype.point = function point(x, y, z, t) {
120
return new Point(this, x, y, z, t);
121
};
122
123
Point.fromJSON = function fromJSON(curve, obj) {
124
return new Point(curve, obj[0], obj[1], obj[2]);
125
};
126
127
Point.prototype.inspect = function inspect() {
128
if (this.isInfinity())
129
return '<EC Point Infinity>';
130
return '<EC Point x: ' + this.x.fromRed().toString(16, 2) +
131
' y: ' + this.y.fromRed().toString(16, 2) +
132
' z: ' + this.z.fromRed().toString(16, 2) + '>';
133
};
134
135
Point.prototype.isInfinity = function isInfinity() {
136
// XXX This code assumes that zero is always zero in red
137
return this.x.cmpn(0) === 0 &&
138
this.y.cmp(this.z) === 0;
139
};
140
141
Point.prototype._extDbl = function _extDbl() {
142
// hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
143
// #doubling-dbl-2008-hwcd
144
// 4M + 4S
145
146
// A = X1^2
147
var a = this.x.redSqr();
148
// B = Y1^2
149
var b = this.y.redSqr();
150
// C = 2 * Z1^2
151
var c = this.z.redSqr();
152
c = c.redIAdd(c);
153
// D = a * A
154
var d = this.curve._mulA(a);
155
// E = (X1 + Y1)^2 - A - B
156
var e = this.x.redAdd(this.y).redSqr().redISub(a).redISub(b);
157
// G = D + B
158
var g = d.redAdd(b);
159
// F = G - C
160
var f = g.redSub(c);
161
// H = D - B
162
var h = d.redSub(b);
163
// X3 = E * F
164
var nx = e.redMul(f);
165
// Y3 = G * H
166
var ny = g.redMul(h);
167
// T3 = E * H
168
var nt = e.redMul(h);
169
// Z3 = F * G
170
var nz = f.redMul(g);
171
return this.curve.point(nx, ny, nz, nt);
172
};
173
174
Point.prototype._projDbl = function _projDbl() {
175
// hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
176
// #doubling-dbl-2008-bbjlp
177
// #doubling-dbl-2007-bl
178
// and others
179
// Generally 3M + 4S or 2M + 4S
180
181
// B = (X1 + Y1)^2
182
var b = this.x.redAdd(this.y).redSqr();
183
// C = X1^2
184
var c = this.x.redSqr();
185
// D = Y1^2
186
var d = this.y.redSqr();
187
188
var nx;
189
var ny;
190
var nz;
191
if (this.curve.twisted) {
192
// E = a * C
193
var e = this.curve._mulA(c);
194
// F = E + D
195
var f = e.redAdd(d);
196
if (this.zOne) {
197
// X3 = (B - C - D) * (F - 2)
198
nx = b.redSub(c).redSub(d).redMul(f.redSub(this.curve.two));
199
// Y3 = F * (E - D)
200
ny = f.redMul(e.redSub(d));
201
// Z3 = F^2 - 2 * F
202
nz = f.redSqr().redSub(f).redSub(f);
203
} else {
204
// H = Z1^2
205
var h = this.z.redSqr();
206
// J = F - 2 * H
207
var j = f.redSub(h).redISub(h);
208
// X3 = (B-C-D)*J
209
nx = b.redSub(c).redISub(d).redMul(j);
210
// Y3 = F * (E - D)
211
ny = f.redMul(e.redSub(d));
212
// Z3 = F * J
213
nz = f.redMul(j);
214
}
215
} else {
216
// E = C + D
217
var e = c.redAdd(d);
218
// H = (c * Z1)^2
219
var h = this.curve._mulC(this.c.redMul(this.z)).redSqr();
220
// J = E - 2 * H
221
var j = e.redSub(h).redSub(h);
222
// X3 = c * (B - E) * J
223
nx = this.curve._mulC(b.redISub(e)).redMul(j);
224
// Y3 = c * E * (C - D)
225
ny = this.curve._mulC(e).redMul(c.redISub(d));
226
// Z3 = E * J
227
nz = e.redMul(j);
228
}
229
return this.curve.point(nx, ny, nz);
230
};
231
232
Point.prototype.dbl = function dbl() {
233
if (this.isInfinity())
234
return this;
235
236
// Double in extended coordinates
237
if (this.curve.extended)
238
return this._extDbl();
239
else
240
return this._projDbl();
241
};
242
243
Point.prototype._extAdd = function _extAdd(p) {
244
// hyperelliptic.org/EFD/g1p/auto-twisted-extended-1.html
245
// #addition-add-2008-hwcd-3
246
// 8M
247
248
// A = (Y1 - X1) * (Y2 - X2)
249
var a = this.y.redSub(this.x).redMul(p.y.redSub(p.x));
250
// B = (Y1 + X1) * (Y2 + X2)
251
var b = this.y.redAdd(this.x).redMul(p.y.redAdd(p.x));
252
// C = T1 * k * T2
253
var c = this.t.redMul(this.curve.dd).redMul(p.t);
254
// D = Z1 * 2 * Z2
255
var d = this.z.redMul(p.z.redAdd(p.z));
256
// E = B - A
257
var e = b.redSub(a);
258
// F = D - C
259
var f = d.redSub(c);
260
// G = D + C
261
var g = d.redAdd(c);
262
// H = B + A
263
var h = b.redAdd(a);
264
// X3 = E * F
265
var nx = e.redMul(f);
266
// Y3 = G * H
267
var ny = g.redMul(h);
268
// T3 = E * H
269
var nt = e.redMul(h);
270
// Z3 = F * G
271
var nz = f.redMul(g);
272
return this.curve.point(nx, ny, nz, nt);
273
};
274
275
Point.prototype._projAdd = function _projAdd(p) {
276
// hyperelliptic.org/EFD/g1p/auto-twisted-projective.html
277
// #addition-add-2008-bbjlp
278
// #addition-add-2007-bl
279
// 10M + 1S
280
281
// A = Z1 * Z2
282
var a = this.z.redMul(p.z);
283
// B = A^2
284
var b = a.redSqr();
285
// C = X1 * X2
286
var c = this.x.redMul(p.x);
287
// D = Y1 * Y2
288
var d = this.y.redMul(p.y);
289
// E = d * C * D
290
var e = this.curve.d.redMul(c).redMul(d);
291
// F = B - E
292
var f = b.redSub(e);
293
// G = B + E
294
var g = b.redAdd(e);
295
// X3 = A * F * ((X1 + Y1) * (X2 + Y2) - C - D)
296
var tmp = this.x.redAdd(this.y).redMul(p.x.redAdd(p.y)).redISub(c).redISub(d);
297
var nx = a.redMul(f).redMul(tmp);
298
var ny;
299
var nz;
300
if (this.curve.twisted) {
301
// Y3 = A * G * (D - a * C)
302
ny = a.redMul(g).redMul(d.redSub(this.curve._mulA(c)));
303
// Z3 = F * G
304
nz = f.redMul(g);
305
} else {
306
// Y3 = A * G * (D - C)
307
ny = a.redMul(g).redMul(d.redSub(c));
308
// Z3 = c * F * G
309
nz = this.curve._mulC(f).redMul(g);
310
}
311
return this.curve.point(nx, ny, nz);
312
};
313
314
Point.prototype.add = function add(p) {
315
if (this.isInfinity())
316
return p;
317
if (p.isInfinity())
318
return this;
319
320
if (this.curve.extended)
321
return this._extAdd(p);
322
else
323
return this._projAdd(p);
324
};
325
326
Point.prototype.mul = function mul(k) {
327
if (this.precomputed && this.precomputed.doubles)
328
return this.curve._fixedNafMul(this, k);
329
else
330
return this.curve._wnafMul(this, k);
331
};
332
333
Point.prototype.mulAdd = function mulAdd(k1, p, k2) {
334
return this.curve._wnafMulAdd(1, [ this, p ], [ k1, k2 ], 2);
335
};
336
337
Point.prototype.normalize = function normalize() {
338
if (this.zOne)
339
return this;
340
341
// Normalize coordinates
342
var zi = this.z.redInvm();
343
this.x = this.x.redMul(zi);
344
this.y = this.y.redMul(zi);
345
if (this.t)
346
this.t = this.t.redMul(zi);
347
this.z = this.curve.one;
348
this.zOne = true;
349
return this;
350
};
351
352
Point.prototype.neg = function neg() {
353
return this.curve.point(this.x.redNeg(),
354
this.y,
355
this.z,
356
this.t && this.t.redNeg());
357
};
358
359
Point.prototype.getX = function getX() {
360
this.normalize();
361
return this.x.fromRed();
362
};
363
364
Point.prototype.getY = function getY() {
365
this.normalize();
366
return this.y.fromRed();
367
};
368
369
// Compatibility with BaseCurve
370
Point.prototype.toP = Point.prototype.normalize;
371
Point.prototype.mixedAdd = Point.prototype.add;
372
373