finitefields 0.0.10 → 0.0.11
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 +131 -21
- package/galois.ts +46 -14
- package/main.ts +42 -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];
|
|
@@ -100,11 +197,11 @@ class Point implements Ipoint {
|
|
|
100
197
|
constructor(point:Tuple<bigint>) {
|
|
101
198
|
[ this['x'], this['y'], this['∞'] ] = [0n,0n,false];
|
|
102
199
|
|
|
103
|
-
switch (point.every((xy:bigint):xy is bigint
|
|
104
|
-
case
|
|
200
|
+
switch (point.every((xy:bigint):xy is bigint=>!xy)) {
|
|
201
|
+
case false:
|
|
105
202
|
[ this['x'], this['y'] ] = point;
|
|
106
203
|
break;
|
|
107
|
-
case
|
|
204
|
+
case true:
|
|
108
205
|
(this['∞'] as unknown as number)++;
|
|
109
206
|
break;
|
|
110
207
|
default:
|
|
@@ -170,7 +267,7 @@ abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
|
170
267
|
return (f instanceof PrimeField);
|
|
171
268
|
}
|
|
172
269
|
|
|
173
|
-
private slope(p_:Point,q_:Point): (a:bigint,p:bigint)=>
|
|
270
|
+
private slope(p_:Point,q_:Point): (a:bigint,p:bigint)=>Slope {
|
|
174
271
|
let f:a;
|
|
175
272
|
const { x:x1,y:y1 } = p_;
|
|
176
273
|
const { x:x2,y:y2 } = q_;
|
|
@@ -195,8 +292,19 @@ abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
|
195
292
|
) % p);
|
|
196
293
|
}
|
|
197
294
|
|
|
198
|
-
private isinfinity(p:Point):
|
|
199
|
-
|
|
295
|
+
private isinfinity(f:PrimeField,p:Point,q:Point): boolean {
|
|
296
|
+
let invpy:bigint;
|
|
297
|
+
let invqy:bigint;
|
|
298
|
+
const [ px,py ]:[bigint,bigint] = [p.x,p.y];
|
|
299
|
+
const [ qx,qy ]:[bigint,bigint] = [q.x,q.y];
|
|
300
|
+
|
|
301
|
+
invpy = f.mul(-1n, py);
|
|
302
|
+
invqy = f.mul(-1n,qy);
|
|
303
|
+
// log('isinfinity(p) -> !!p[∞] -> ', !!(p['∞']));
|
|
304
|
+
// log(p);
|
|
305
|
+
return ((px===qx) && (py===invqy) && (qy===invpy)) ?
|
|
306
|
+
true : // Q = P + (-P) === ∞
|
|
307
|
+
false;
|
|
200
308
|
}
|
|
201
309
|
|
|
202
310
|
protected addpoints(p:Coordinate,q:Coordinate): Coordinate {
|
|
@@ -227,9 +335,13 @@ abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
|
227
335
|
const { x:x1,y:y1 } = p_;
|
|
228
336
|
const { x:x2,y:y2 } = q_;
|
|
229
337
|
|
|
338
|
+
if (this.isinfinity(f,p_,q_))
|
|
339
|
+
return nothing();
|
|
340
|
+
|
|
230
341
|
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);
|
|
342
|
+
Δx = f.add(x1, x2);
|
|
343
|
+
// x = (f.sub(s, f.mul(s, s)) % this.backend.p);
|
|
344
|
+
x = f.sub(f.mul(s,s),Δx);
|
|
233
345
|
Δy = f.sub(x1, x);
|
|
234
346
|
y = (f.sub(
|
|
235
347
|
f.mul(s, Δy),
|
|
@@ -237,10 +349,8 @@ abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
|
237
349
|
) % this.backend.p);
|
|
238
350
|
|
|
239
351
|
t = new Point([x,y]);
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
else
|
|
243
|
-
mt = just(t);
|
|
352
|
+
// log('t', t);
|
|
353
|
+
mt = just(t);
|
|
244
354
|
|
|
245
355
|
return mt;
|
|
246
356
|
}
|
|
@@ -253,15 +363,15 @@ abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
|
253
363
|
if (empty(a) && empty(b))
|
|
254
364
|
return <Maybe<Point>>nothing();
|
|
255
365
|
else if (empty(a))
|
|
256
|
-
return
|
|
366
|
+
return b;
|
|
257
367
|
else if (empty(b))
|
|
258
|
-
return
|
|
368
|
+
return a;
|
|
259
369
|
else
|
|
260
370
|
return <Maybe<Point>>this.addpoints(a,b);
|
|
261
371
|
}
|
|
262
372
|
|
|
263
373
|
public double(a:Coordinate): Coordinate {
|
|
264
|
-
if (a
|
|
374
|
+
if (empty(a))
|
|
265
375
|
return nothing();
|
|
266
376
|
else
|
|
267
377
|
return this.doublepoint(a);
|
|
@@ -310,5 +420,5 @@ class ecℤp extends EllipticCurves<PrimeField>
|
|
|
310
420
|
}
|
|
311
421
|
}
|
|
312
422
|
|
|
313
|
-
export { ecℤp,
|
|
314
|
-
export type {
|
|
423
|
+
export { Point,ecℤp,birch17,p256,mkcurve };
|
|
424
|
+
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,51 @@ 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
|
+
mp = curve.p;
|
|
46
|
+
mq = curve.q;
|
|
47
|
+
log(curve.p);
|
|
48
|
+
|
|
22
49
|
// mp = curve.add(curve.p, curve.q);
|
|
23
|
-
mp = curve.q;
|
|
24
|
-
|
|
50
|
+
// mp = curve.q;
|
|
51
|
+
|
|
52
|
+
q = fold(mq);
|
|
25
53
|
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 };
|
|
54
|
+
for (n=0n; n<22n; n++) {
|
|
55
|
+
mp = curve.add(mp, mq);
|
|
56
|
+
log(mp);
|
|
57
|
+
}
|
|
58
|
+
log(mp);
|
|
59
|
+
|
|
60
|
+
export { Polynomial,Util,PrimeField,ecℤp,Point };
|
|
61
|
+
export { p256,empty,fold,just,nothing };
|
|
62
|
+
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
|
|