Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
Download
80621 views
1
'use strict';
2
3
var bn = require('bn.js');
4
var elliptic = require('../../elliptic');
5
6
var getNAF = elliptic.utils.getNAF;
7
var getJSF = elliptic.utils.getJSF;
8
var assert = elliptic.utils.assert;
9
10
function BaseCurve(type, conf) {
11
this.type = type;
12
this.p = new bn(conf.p, 16);
13
14
// Use Montgomery, when there is no fast reduction for the prime
15
this.red = conf.prime ? bn.red(conf.prime) : bn.mont(this.p);
16
17
// Useful for many curves
18
this.zero = new bn(0).toRed(this.red);
19
this.one = new bn(1).toRed(this.red);
20
this.two = new bn(2).toRed(this.red);
21
22
// Curve configuration, optional
23
this.n = conf.n && new bn(conf.n, 16);
24
this.g = conf.g && this.pointFromJSON(conf.g, conf.gRed);
25
26
// Temporary arrays
27
this._wnafT1 = new Array(4);
28
this._wnafT2 = new Array(4);
29
this._wnafT3 = new Array(4);
30
this._wnafT4 = new Array(4);
31
}
32
module.exports = BaseCurve;
33
34
BaseCurve.prototype.point = function point() {
35
throw new Error('Not implemented');
36
};
37
38
BaseCurve.prototype.validate = function validate() {
39
throw new Error('Not implemented');
40
};
41
42
BaseCurve.prototype._fixedNafMul = function _fixedNafMul(p, k) {
43
var doubles = p._getDoubles();
44
45
var naf = getNAF(k, 1);
46
var I = (1 << (doubles.step + 1)) - (doubles.step % 2 === 0 ? 2 : 1);
47
I /= 3;
48
49
// Translate into more windowed form
50
var repr = [];
51
for (var j = 0; j < naf.length; j += doubles.step) {
52
var nafW = 0;
53
for (var k = j + doubles.step - 1; k >= j; k--)
54
nafW = (nafW << 1) + naf[k];
55
repr.push(nafW);
56
}
57
58
var a = this.jpoint(null, null, null);
59
var b = this.jpoint(null, null, null);
60
for (var i = I; i > 0; i--) {
61
for (var j = 0; j < repr.length; j++) {
62
var nafW = repr[j];
63
if (nafW === i)
64
b = b.mixedAdd(doubles.points[j]);
65
else if (nafW === -i)
66
b = b.mixedAdd(doubles.points[j].neg());
67
}
68
a = a.add(b);
69
}
70
return a.toP();
71
};
72
73
BaseCurve.prototype._wnafMul = function _wnafMul(p, k) {
74
var w = 4;
75
76
// Precompute window
77
var nafPoints = p._getNAFPoints(w);
78
w = nafPoints.wnd;
79
var wnd = nafPoints.points;
80
81
// Get NAF form
82
var naf = getNAF(k, w);
83
84
// Add `this`*(N+1) for every w-NAF index
85
var acc = this.jpoint(null, null, null);
86
for (var i = naf.length - 1; i >= 0; i--) {
87
// Count zeroes
88
for (var k = 0; i >= 0 && naf[i] === 0; i--)
89
k++;
90
if (i >= 0)
91
k++;
92
acc = acc.dblp(k);
93
94
if (i < 0)
95
break;
96
var z = naf[i];
97
assert(z !== 0);
98
if (p.type === 'affine') {
99
// J +- P
100
if (z > 0)
101
acc = acc.mixedAdd(wnd[(z - 1) >> 1]);
102
else
103
acc = acc.mixedAdd(wnd[(-z - 1) >> 1].neg());
104
} else {
105
// J +- J
106
if (z > 0)
107
acc = acc.add(wnd[(z - 1) >> 1]);
108
else
109
acc = acc.add(wnd[(-z - 1) >> 1].neg());
110
}
111
}
112
return p.type === 'affine' ? acc.toP() : acc;
113
};
114
115
BaseCurve.prototype._wnafMulAdd = function _wnafMulAdd(defW,
116
points,
117
coeffs,
118
len) {
119
var wndWidth = this._wnafT1;
120
var wnd = this._wnafT2;
121
var naf = this._wnafT3;
122
123
// Fill all arrays
124
var max = 0;
125
for (var i = 0; i < len; i++) {
126
var p = points[i];
127
var nafPoints = p._getNAFPoints(defW);
128
wndWidth[i] = nafPoints.wnd;
129
wnd[i] = nafPoints.points;
130
}
131
132
// Comb small window NAFs
133
for (var i = len - 1; i >= 1; i -= 2) {
134
var a = i - 1;
135
var b = i;
136
if (wndWidth[a] !== 1 || wndWidth[b] !== 1) {
137
naf[a] = getNAF(coeffs[a], wndWidth[a]);
138
naf[b] = getNAF(coeffs[b], wndWidth[b]);
139
max = Math.max(naf[a].length, max);
140
max = Math.max(naf[b].length, max);
141
continue;
142
}
143
144
var comb = [
145
points[a], /* 1 */
146
null, /* 3 */
147
null, /* 5 */
148
points[b] /* 7 */
149
];
150
151
// Try to avoid Projective points, if possible
152
if (points[a].y.cmp(points[b].y) === 0) {
153
comb[1] = points[a].add(points[b]);
154
comb[2] = points[a].toJ().mixedAdd(points[b].neg());
155
} else if (points[a].y.cmp(points[b].y.redNeg()) === 0) {
156
comb[1] = points[a].toJ().mixedAdd(points[b]);
157
comb[2] = points[a].add(points[b].neg());
158
} else {
159
comb[1] = points[a].toJ().mixedAdd(points[b]);
160
comb[2] = points[a].toJ().mixedAdd(points[b].neg());
161
}
162
163
var index = [
164
-3, /* -1 -1 */
165
-1, /* -1 0 */
166
-5, /* -1 1 */
167
-7, /* 0 -1 */
168
0, /* 0 0 */
169
7, /* 0 1 */
170
5, /* 1 -1 */
171
1, /* 1 0 */
172
3 /* 1 1 */
173
];
174
175
var jsf = getJSF(coeffs[a], coeffs[b]);
176
max = Math.max(jsf[0].length, max);
177
naf[a] = new Array(max);
178
naf[b] = new Array(max);
179
for (var j = 0; j < max; j++) {
180
var ja = jsf[0][j] | 0;
181
var jb = jsf[1][j] | 0;
182
183
naf[a][j] = index[(ja + 1) * 3 + (jb + 1)];
184
naf[b][j] = 0;
185
wnd[a] = comb;
186
}
187
}
188
189
var acc = this.jpoint(null, null, null);
190
var tmp = this._wnafT4;
191
for (var i = max; i >= 0; i--) {
192
var k = 0;
193
194
while (i >= 0) {
195
var zero = true;
196
for (var j = 0; j < len; j++) {
197
tmp[j] = naf[j][i] | 0;
198
if (tmp[j] !== 0)
199
zero = false;
200
}
201
if (!zero)
202
break;
203
k++;
204
i--;
205
}
206
if (i >= 0)
207
k++;
208
acc = acc.dblp(k);
209
if (i < 0)
210
break;
211
212
for (var j = 0; j < len; j++) {
213
var z = tmp[j];
214
var p;
215
if (z === 0)
216
continue;
217
else if (z > 0)
218
p = wnd[j][(z - 1) >> 1];
219
else if (z < 0)
220
p = wnd[j][(-z - 1) >> 1].neg();
221
222
if (p.type === 'affine')
223
acc = acc.mixedAdd(p);
224
else
225
acc = acc.add(p);
226
}
227
}
228
// Zeroify references
229
for (var i = 0; i < len; i++)
230
wnd[i] = null;
231
return acc.toP();
232
};
233
234
function BasePoint(curve, type) {
235
this.curve = curve;
236
this.type = type;
237
this.precomputed = null;
238
}
239
BaseCurve.BasePoint = BasePoint;
240
241
BasePoint.prototype.validate = function validate() {
242
return this.curve.validate(this);
243
};
244
245
BasePoint.prototype.precompute = function precompute(power) {
246
if (this.precomputed)
247
return this;
248
249
var precomputed = {
250
doubles: null,
251
naf: null,
252
beta: null
253
};
254
precomputed.naf = this._getNAFPoints(8);
255
precomputed.doubles = this._getDoubles(4, power);
256
precomputed.beta = this._getBeta();
257
this.precomputed = precomputed;
258
259
return this;
260
};
261
262
BasePoint.prototype._getDoubles = function _getDoubles(step, power) {
263
if (this.precomputed && this.precomputed.doubles)
264
return this.precomputed.doubles;
265
266
var doubles = [ this ];
267
var acc = this;
268
for (var i = 0; i < power; i += step) {
269
for (var j = 0; j < step; j++)
270
acc = acc.dbl();
271
doubles.push(acc);
272
}
273
return {
274
step: step,
275
points: doubles
276
};
277
};
278
279
BasePoint.prototype._getNAFPoints = function _getNAFPoints(wnd) {
280
if (this.precomputed && this.precomputed.naf)
281
return this.precomputed.naf;
282
283
var res = [ this ];
284
var max = (1 << wnd) - 1;
285
var dbl = max === 1 ? null : this.dbl();
286
for (var i = 1; i < max; i++)
287
res[i] = res[i - 1].add(dbl);
288
return {
289
wnd: wnd,
290
points: res
291
};
292
};
293
294
BasePoint.prototype._getBeta = function _getBeta() {
295
return null;
296
};
297
298
BasePoint.prototype.dblp = function dblp(k) {
299
var r = this;
300
for (var i = 0; i < k; i++)
301
r = r.dbl();
302
return r;
303
};
304
305