finitefields 0.0.10 → 0.0.12
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/ellipticcurves.ts +150 -22
- package/galois.ts +46 -14
- package/main.ts +43 -19
- package/maybe.ts +1 -1
- package/package.json +1 -1
package/ellipticcurves.ts
CHANGED
|
@@ -11,12 +11,13 @@ import { PrimeField, type GF } from './galois.js';
|
|
|
11
11
|
import { empty, fold, just, nothing, type Maybe, type Nothing } from './maybe.js';
|
|
12
12
|
import { Util } from './galois.js';
|
|
13
13
|
|
|
14
|
-
let 𝒪:Nothing;
|
|
15
14
|
let log:(...x:any[])=>void;
|
|
16
15
|
let fail:(...x:any[])=>never;
|
|
16
|
+
let mkcurve:(field:PrimeField)=>ECCurve;
|
|
17
|
+
|
|
18
|
+
let birch17:()=>ECCurve;
|
|
17
19
|
let p256:()=>ECCurve;
|
|
18
20
|
|
|
19
|
-
𝒪 = nothing();
|
|
20
21
|
log = console.log;
|
|
21
22
|
fail = (...args:any[]): never => {
|
|
22
23
|
console.error(...args);
|
|
@@ -25,6 +26,102 @@ fail = (...args:any[]): never => {
|
|
|
25
26
|
return void 0 as never;
|
|
26
27
|
}
|
|
27
28
|
|
|
29
|
+
mkcurve = (field:PrimeField): ECCurve => {
|
|
30
|
+
let bitlen:bigint;
|
|
31
|
+
let n:bigint;
|
|
32
|
+
let x:bigint, y:bigint;
|
|
33
|
+
let q:Point;
|
|
34
|
+
let mq:Coordinate;
|
|
35
|
+
let p:bigint;
|
|
36
|
+
let ret:boolean;
|
|
37
|
+
let test:(t:Coordinate,f:PrimeField)=>boolean;
|
|
38
|
+
let formula:ECformula;
|
|
39
|
+
|
|
40
|
+
formula = (a:bigint,b:bigint,f:PrimeField)=>(x:bigint,y:bigint) =>
|
|
41
|
+
(f.add(f.add( // y^2 =
|
|
42
|
+
f.exp(x, 3n), // x^3
|
|
43
|
+
f.mul(a,x)), // + ax
|
|
44
|
+
b) % f.p); // + b
|
|
45
|
+
|
|
46
|
+
test = (mt:Coordinate,f:PrimeField): boolean => {
|
|
47
|
+
let y2:bigint;
|
|
48
|
+
let y2_:bigint;
|
|
49
|
+
let x:bigint, y:bigint;
|
|
50
|
+
let t:Point;
|
|
51
|
+
let a_:bigint, b_:bigint;
|
|
52
|
+
let p_:bigint;
|
|
53
|
+
|
|
54
|
+
if (empty(mt))
|
|
55
|
+
return true;
|
|
56
|
+
else
|
|
57
|
+
t = fold(mt);
|
|
58
|
+
|
|
59
|
+
p_ = f.p;
|
|
60
|
+
x=t.x, y=t.y;
|
|
61
|
+
a_ = 2n;
|
|
62
|
+
b_ = 2n;
|
|
63
|
+
|
|
64
|
+
y2 = Util.sqmul(y, 2n, p_);
|
|
65
|
+
y2_ = formula(a_, b_, f)(x,y);
|
|
66
|
+
|
|
67
|
+
return (y2 === y2_);
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
x=y = 0n;
|
|
71
|
+
ret = false;
|
|
72
|
+
p = field.p;
|
|
73
|
+
bitlen = Util.countbits(p);
|
|
74
|
+
y = Util.rnd(bitlen, p) % p;
|
|
75
|
+
|
|
76
|
+
if (p<4)
|
|
77
|
+
return fail();
|
|
78
|
+
|
|
79
|
+
for ((n=Util.sqmul(2n,bitlen,p)-1n); n; n--) {
|
|
80
|
+
x = (!x)?Util.rnd(bitlen, p) % p:x--;
|
|
81
|
+
q = new Point([x,y]);
|
|
82
|
+
mq = (q['∞'])?nothing():just(q);
|
|
83
|
+
if (test(mq,field)) {
|
|
84
|
+
(ret as unknown as number)++;
|
|
85
|
+
break;
|
|
86
|
+
}
|
|
87
|
+
y = (!y)?Util.rnd(bitlen, p) % p:y++;
|
|
88
|
+
q = new Point([x,y]);
|
|
89
|
+
mq = (q['∞'])?nothing():just(q);
|
|
90
|
+
if (test(mq,field)) {
|
|
91
|
+
(ret as unknown as number)++;
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
return (!ret)?fail('curve generation failed'):{
|
|
97
|
+
'#E': p,
|
|
98
|
+
'θ': p,
|
|
99
|
+
'a': 3n,
|
|
100
|
+
'b': 2n,
|
|
101
|
+
'p': [x,y],
|
|
102
|
+
'q': [x,y],
|
|
103
|
+
bitlen,
|
|
104
|
+
formula
|
|
105
|
+
};
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
birch17 = ():ECCurve => ({
|
|
109
|
+
'#E': 17n,
|
|
110
|
+
'θ': 17n,
|
|
111
|
+
a: 2n,
|
|
112
|
+
b: 2n,
|
|
113
|
+
// p: [ 10n, 11n ],
|
|
114
|
+
// q: [ 10n, 11n ],
|
|
115
|
+
p: [ 5n, 1n ],
|
|
116
|
+
q: [ 5n, 1n ],
|
|
117
|
+
bitlen: 5n,
|
|
118
|
+
formula: (a:bigint,b:bigint,f:PrimeField)=>(x:bigint,y:bigint) =>
|
|
119
|
+
(f.add(f.add( // y^2 =
|
|
120
|
+
f.exp(x, 3n), // x^3
|
|
121
|
+
f.mul(a,x)), // + ax
|
|
122
|
+
b) % f.p) // + b
|
|
123
|
+
});
|
|
124
|
+
|
|
28
125
|
p256 = ():ECCurve => ({
|
|
29
126
|
'#E': 0xffffffff00000000_ffffffffffffffff_bce6faada7179e84_f3b9cac2fc632551n,
|
|
30
127
|
'θ': 0xffffffff00000001_0000000000000000_00000000ffffffff_ffffffffffffffffn,
|
|
@@ -42,10 +139,10 @@ p256 = ():ECCurve => ({
|
|
|
42
139
|
],
|
|
43
140
|
bitlen: 256n,
|
|
44
141
|
formula: (a:bigint,b:bigint,f:PrimeField)=>(x:bigint,y:bigint) =>
|
|
45
|
-
f.add(f.add(
|
|
142
|
+
(f.add(f.add( // y^2 =
|
|
46
143
|
f.exp(x, 3n), // x^3
|
|
47
144
|
f.mul(a,x)), // + ax
|
|
48
|
-
b)
|
|
145
|
+
b) % f.p) // + b
|
|
49
146
|
});
|
|
50
147
|
|
|
51
148
|
type Tuple<a> = readonly [a,a];
|
|
@@ -92,6 +189,24 @@ interface Ipoint {
|
|
|
92
189
|
constructor: Function;
|
|
93
190
|
}
|
|
94
191
|
|
|
192
|
+
(Array as any).prototype.origToString = Array.prototype.toString;
|
|
193
|
+
Array.prototype.toString = function(this:Maybe<Point>): string {
|
|
194
|
+
let p:Point;
|
|
195
|
+
let x:bigint;
|
|
196
|
+
let y:bigint;
|
|
197
|
+
|
|
198
|
+
if (!empty(this)) {
|
|
199
|
+
if (!(typeof this === 'object') && ('∞' in this[0]))
|
|
200
|
+
return (this as any).origToString();
|
|
201
|
+
p = fold(this);
|
|
202
|
+
[x,y] = [p.x,p.y];
|
|
203
|
+
|
|
204
|
+
return `(${x},${y})`;
|
|
205
|
+
}
|
|
206
|
+
else
|
|
207
|
+
return '∞';
|
|
208
|
+
}
|
|
209
|
+
|
|
95
210
|
class Point implements Ipoint {
|
|
96
211
|
public 'x':bigint;
|
|
97
212
|
public 'y':bigint;
|
|
@@ -100,17 +215,17 @@ class Point implements Ipoint {
|
|
|
100
215
|
constructor(point:Tuple<bigint>) {
|
|
101
216
|
[ this['x'], this['y'], this['∞'] ] = [0n,0n,false];
|
|
102
217
|
|
|
103
|
-
switch (point.every((xy:bigint):xy is bigint
|
|
104
|
-
case
|
|
218
|
+
switch (point.every((xy:bigint):xy is bigint=>!xy)) {
|
|
219
|
+
case false:
|
|
105
220
|
[ this['x'], this['y'] ] = point;
|
|
106
221
|
break;
|
|
107
|
-
case
|
|
222
|
+
case true:
|
|
108
223
|
(this['∞'] as unknown as number)++;
|
|
109
224
|
break;
|
|
110
225
|
default:
|
|
111
226
|
return fail();
|
|
112
227
|
}
|
|
113
|
-
|
|
228
|
+
|
|
114
229
|
return this;
|
|
115
230
|
}
|
|
116
231
|
}
|
|
@@ -170,7 +285,7 @@ abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
|
170
285
|
return (f instanceof PrimeField);
|
|
171
286
|
}
|
|
172
287
|
|
|
173
|
-
private slope(p_:Point,q_:Point): (a:bigint,p:bigint)=>
|
|
288
|
+
private slope(p_:Point,q_:Point): (a:bigint,p:bigint)=>Slope {
|
|
174
289
|
let f:a;
|
|
175
290
|
const { x:x1,y:y1 } = p_;
|
|
176
291
|
const { x:x2,y:y2 } = q_;
|
|
@@ -195,8 +310,19 @@ abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
|
195
310
|
) % p);
|
|
196
311
|
}
|
|
197
312
|
|
|
198
|
-
private isinfinity(p:Point):
|
|
199
|
-
|
|
313
|
+
private isinfinity(f:PrimeField,p:Point,q:Point): boolean {
|
|
314
|
+
let invpy:bigint;
|
|
315
|
+
let invqy:bigint;
|
|
316
|
+
const [ px,py ]:[bigint,bigint] = [p.x,p.y];
|
|
317
|
+
const [ qx,qy ]:[bigint,bigint] = [q.x,q.y];
|
|
318
|
+
|
|
319
|
+
invpy = f.mul(-1n, py);
|
|
320
|
+
invqy = f.mul(-1n,qy);
|
|
321
|
+
// log('isinfinity(p) -> !!p[∞] -> ', !!(p['∞']));
|
|
322
|
+
// log(p);
|
|
323
|
+
return ((px===qx) && (py===invqy) && (qy===invpy)) ?
|
|
324
|
+
true : // Q = P + (-P) === ∞
|
|
325
|
+
false;
|
|
200
326
|
}
|
|
201
327
|
|
|
202
328
|
protected addpoints(p:Coordinate,q:Coordinate): Coordinate {
|
|
@@ -227,9 +353,13 @@ abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
|
227
353
|
const { x:x1,y:y1 } = p_;
|
|
228
354
|
const { x:x2,y:y2 } = q_;
|
|
229
355
|
|
|
356
|
+
if (this.isinfinity(f,p_,q_))
|
|
357
|
+
return nothing();
|
|
358
|
+
|
|
230
359
|
s = this.slope(p_, q_)(this.curve.a, this.backend.p);
|
|
231
|
-
Δx = f.
|
|
232
|
-
x = (f.sub(s, f.mul(s, s)) % this.backend.p);
|
|
360
|
+
Δx = f.add(x1, x2);
|
|
361
|
+
// x = (f.sub(s, f.mul(s, s)) % this.backend.p);
|
|
362
|
+
x = f.sub(f.mul(s,s),Δx);
|
|
233
363
|
Δy = f.sub(x1, x);
|
|
234
364
|
y = (f.sub(
|
|
235
365
|
f.mul(s, Δy),
|
|
@@ -237,10 +367,8 @@ abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
|
237
367
|
) % this.backend.p);
|
|
238
368
|
|
|
239
369
|
t = new Point([x,y]);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
else
|
|
243
|
-
mt = just(t);
|
|
370
|
+
// log('t', t);
|
|
371
|
+
mt = just(t);
|
|
244
372
|
|
|
245
373
|
return mt;
|
|
246
374
|
}
|
|
@@ -253,15 +381,15 @@ abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
|
253
381
|
if (empty(a) && empty(b))
|
|
254
382
|
return <Maybe<Point>>nothing();
|
|
255
383
|
else if (empty(a))
|
|
256
|
-
return
|
|
384
|
+
return b;
|
|
257
385
|
else if (empty(b))
|
|
258
|
-
return
|
|
386
|
+
return a;
|
|
259
387
|
else
|
|
260
388
|
return <Maybe<Point>>this.addpoints(a,b);
|
|
261
389
|
}
|
|
262
390
|
|
|
263
391
|
public double(a:Coordinate): Coordinate {
|
|
264
|
-
if (a
|
|
392
|
+
if (empty(a))
|
|
265
393
|
return nothing();
|
|
266
394
|
else
|
|
267
395
|
return this.doublepoint(a);
|
|
@@ -310,5 +438,5 @@ class ecℤp extends EllipticCurves<PrimeField>
|
|
|
310
438
|
}
|
|
311
439
|
}
|
|
312
440
|
|
|
313
|
-
export { ecℤp,
|
|
314
|
-
export type {
|
|
441
|
+
export { Point,ecℤp,birch17,p256,mkcurve };
|
|
442
|
+
export type { Coordinate,ECCurve };
|
package/galois.ts
CHANGED
|
@@ -32,18 +32,28 @@ enum methods {
|
|
|
32
32
|
DoubleAndAdd
|
|
33
33
|
}
|
|
34
34
|
|
|
35
|
-
const arithmeticsℤp = (p:bigint,op:fieldops) =>
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
(
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
35
|
+
const arithmeticsℤp = (p:bigint,op:fieldops) => {
|
|
36
|
+
let x:bigint;
|
|
37
|
+
|
|
38
|
+
return (
|
|
39
|
+
(op==fieldops.$add) ?
|
|
40
|
+
(a:bigint,b:bigint=0n) => ((x=((a+b)%p))<0n)?((x+p)%p):x :
|
|
41
|
+
(op==fieldops.$sub) ?
|
|
42
|
+
(a:bigint,b:bigint=0n) => ((x=((a-b)%p))<0n)?((x+p)%p):x :
|
|
43
|
+
(op==fieldops.$mul) ?
|
|
44
|
+
(a:bigint,b:bigint=0n) =>
|
|
45
|
+
(!a||!b)?0n:((x=Util.dblad(a,b,p)%p)<0)?((x+p)%p):x :
|
|
46
|
+
(op==fieldops.$inv) ?
|
|
47
|
+
(a:bigint) =>
|
|
48
|
+
(!a)?fail('0 has no inverse'):(a<0)?-a%p:Util.sqmul(a,(p-2n),p) :
|
|
49
|
+
(op==fieldops.$exp) ?
|
|
50
|
+
(a:bigint,b:bigint=0n):bigint =>
|
|
51
|
+
(!a)?0n:(!b)?1n:(b<0) ?
|
|
52
|
+
arithmeticsℤp(p,fieldops.$inv)(Util.sqmul(a,-b,p)) :
|
|
53
|
+
Util.sqmul(a,b,p) :
|
|
54
|
+
fail('unknown field operation')
|
|
55
|
+
);
|
|
56
|
+
}
|
|
47
57
|
|
|
48
58
|
Util = {
|
|
49
59
|
countbits(x:bigint): bigint {
|
|
@@ -80,7 +90,7 @@ Util = {
|
|
|
80
90
|
// return v;
|
|
81
91
|
// }
|
|
82
92
|
|
|
83
|
-
return true;
|
|
93
|
+
// return true;
|
|
84
94
|
|
|
85
95
|
if (p<2n)
|
|
86
96
|
return true;
|
|
@@ -145,10 +155,30 @@ Util = {
|
|
|
145
155
|
let sign:string;
|
|
146
156
|
let a:bigint;
|
|
147
157
|
let e:bigint;
|
|
158
|
+
let minus:boolean;
|
|
148
159
|
|
|
149
160
|
// sign = (method==methods.SquareAndMultiply) ? '^' : 'x';
|
|
150
161
|
// log(`${a_}${sign}${e_} (mod ${p}) = `);
|
|
151
162
|
|
|
163
|
+
minus = false;
|
|
164
|
+
if (((a_===0n) || (e_===0n)) && (method===methods.DoubleAndAdd))
|
|
165
|
+
return 0n;
|
|
166
|
+
else if (a_ === 0n)
|
|
167
|
+
return 0n;
|
|
168
|
+
|
|
169
|
+
if (a_<0) {
|
|
170
|
+
(minus as unknown as number) ^= 1;
|
|
171
|
+
a_*=-1n;
|
|
172
|
+
a_%=p;
|
|
173
|
+
}
|
|
174
|
+
if ((e_<0) && (method===methods.DoubleAndAdd)) {
|
|
175
|
+
(minus as unknown as number) ^= 1;
|
|
176
|
+
e_*=1n;
|
|
177
|
+
e_%=p;
|
|
178
|
+
}
|
|
179
|
+
else if (e_<0)
|
|
180
|
+
return fail('cannot raise to a negative exponent');
|
|
181
|
+
|
|
152
182
|
switch (method) {
|
|
153
183
|
case methods.SquareAndMultiply:
|
|
154
184
|
sq = (y:bigint,p_:bigint):bigint =>
|
|
@@ -193,7 +223,9 @@ Util = {
|
|
|
193
223
|
return void 0;
|
|
194
224
|
});
|
|
195
225
|
|
|
196
|
-
return (
|
|
226
|
+
return (minus && (method===methods.DoubleAndAdd)) ?
|
|
227
|
+
((val*-1n)%p) :
|
|
228
|
+
(val%p);
|
|
197
229
|
}
|
|
198
230
|
}
|
|
199
231
|
|
package/main.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
/* main.ts */
|
|
2
2
|
import { Polynomial } from './polynomial.js';
|
|
3
3
|
import { Util,PrimeField } from './galois.js';
|
|
4
|
-
import { ecℤp,
|
|
4
|
+
import { birch17, ecℤp, mkcurve, p256,Point } from './ellipticcurves.js';
|
|
5
5
|
import { empty, fold, just, nothing } from './maybe.js';
|
|
6
|
+
import type { Coordinate, ECCurve } from './ellipticcurves.js';
|
|
6
7
|
import type { Maybe, Just, Nothing } from './maybe.js';
|
|
7
8
|
|
|
8
9
|
let log:(...x:any[])=>void;
|
|
@@ -11,29 +12,52 @@ log = console.log;
|
|
|
11
12
|
let field:PrimeField;
|
|
12
13
|
let curve:ecℤp;
|
|
13
14
|
let mp:Coordinate;
|
|
15
|
+
let mq:Coordinate;
|
|
16
|
+
let mt:Coordinate;
|
|
14
17
|
let p:Point;
|
|
15
18
|
let q:Point;
|
|
19
|
+
let mycurve:ECCurve;
|
|
20
|
+
let n:bigint;
|
|
16
21
|
|
|
17
|
-
field = new PrimeField(
|
|
22
|
+
field = new PrimeField(birch17().θ, birch17().bitlen);
|
|
23
|
+
curve = new ecℤp(field, birch17());
|
|
24
|
+
// log(curve);
|
|
25
|
+
// field = new PrimeField(p256().θ, p256().bitlen);
|
|
26
|
+
// curve = new ecℤp(field, p256());
|
|
27
|
+
// field = new PrimeField(17n,5n);
|
|
28
|
+
// mycurve = mkcurve(field);
|
|
29
|
+
// log(mycurve);
|
|
18
30
|
// log(field);
|
|
19
|
-
curve = new ecℤp(field, p256());
|
|
20
31
|
// log(curve);
|
|
21
32
|
|
|
33
|
+
// log('[5,1] + [5,16] = ');
|
|
34
|
+
// q = new Point([5n,16n]);
|
|
35
|
+
// mq = just(q);
|
|
36
|
+
// mp = curve.p;
|
|
37
|
+
// mt = curve.add(mp, mq);
|
|
38
|
+
// log (mt);
|
|
39
|
+
// log(curve.add(mp, mt));
|
|
40
|
+
|
|
41
|
+
// log(mp);
|
|
42
|
+
// process.exit(0);
|
|
43
|
+
// p = undefined as any;
|
|
44
|
+
|
|
45
|
+
log(['Adding point (5,1) to itself:']);
|
|
46
|
+
mp = curve.p;
|
|
47
|
+
mq = curve.q;
|
|
48
|
+
log('n=0', mp.toString());
|
|
49
|
+
|
|
22
50
|
// mp = curve.add(curve.p, curve.q);
|
|
23
|
-
mp = curve.q;
|
|
24
|
-
|
|
51
|
+
// mp = curve.q;
|
|
52
|
+
|
|
53
|
+
q = fold(mq);
|
|
25
54
|
p = fold(curve.p);
|
|
26
|
-
|
|
27
|
-
mp = curve.
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
}
|
|
36
|
-
} while (p.x !== q.x);
|
|
37
|
-
log(q);
|
|
38
|
-
|
|
39
|
-
export { Polynomial,Util,PrimeField,ecℤp,p256 };
|
|
55
|
+
for (n=1n; n<23n; n++) {
|
|
56
|
+
mp = curve.add(mp, mq);
|
|
57
|
+
log('n='+n.toString(), mp.toString());
|
|
58
|
+
}
|
|
59
|
+
log('n='+n.toString(), mp.toString());
|
|
60
|
+
|
|
61
|
+
export { Polynomial,Util,PrimeField,ecℤp,Point };
|
|
62
|
+
export { p256,empty,fold,just,nothing };
|
|
63
|
+
export type { Coordinate,Maybe,Just,Nothing }
|
package/maybe.ts
CHANGED
|
@@ -32,7 +32,7 @@ let x:Function;
|
|
|
32
32
|
|
|
33
33
|
nothing = (): Nothing => [] as Nothing;
|
|
34
34
|
just = <a>(x:a): Just<a> => [x] as Just<a>;
|
|
35
|
-
empty = <a>(x:Maybe<a>):
|
|
35
|
+
empty = <a>(x:Maybe<a>): boolean => (!x || !x.length);
|
|
36
36
|
fold = <a>(x:Maybe<a>): a|never =>
|
|
37
37
|
(!empty(x))?x[0] as a:fail("folding nothing") as never;
|
|
38
38
|
|