finitefields 0.0.8 → 0.0.10
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 +155 -2
- package/galois.ts +3 -10
- package/main.ts +25 -3
- package/maybe.ts +40 -0
- package/package.json +1 -1
package/ellipticcurves.ts
CHANGED
|
@@ -7,13 +7,16 @@
|
|
|
7
7
|
*
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import
|
|
10
|
+
import { PrimeField, type GF } from './galois.js';
|
|
11
|
+
import { empty, fold, just, nothing, type Maybe, type Nothing } from './maybe.js';
|
|
11
12
|
import { Util } from './galois.js';
|
|
12
13
|
|
|
14
|
+
let 𝒪:Nothing;
|
|
13
15
|
let log:(...x:any[])=>void;
|
|
14
16
|
let fail:(...x:any[])=>never;
|
|
15
17
|
let p256:()=>ECCurve;
|
|
16
18
|
|
|
19
|
+
𝒪 = nothing();
|
|
17
20
|
log = console.log;
|
|
18
21
|
fail = (...args:any[]): never => {
|
|
19
22
|
console.error(...args);
|
|
@@ -25,6 +28,7 @@ fail = (...args:any[]): never => {
|
|
|
25
28
|
p256 = ():ECCurve => ({
|
|
26
29
|
'#E': 0xffffffff00000000_ffffffffffffffff_bce6faada7179e84_f3b9cac2fc632551n,
|
|
27
30
|
'θ': 0xffffffff00000001_0000000000000000_00000000ffffffff_ffffffffffffffffn,
|
|
31
|
+
'a': -3n,
|
|
28
32
|
'b': 0x5ac635d8aa3a93e7_b3ebbd55769886bc_651d06b0cc53b0f6_3bce3c3e27d2604bn,
|
|
29
33
|
'p':
|
|
30
34
|
[
|
|
@@ -45,8 +49,10 @@ p256 = ():ECCurve => ({
|
|
|
45
49
|
});
|
|
46
50
|
|
|
47
51
|
type Tuple<a> = readonly [a,a];
|
|
52
|
+
type Coordinate = Maybe<Point>;
|
|
48
53
|
type infinity = false | true;
|
|
49
54
|
type ECformula = (a:bigint,b:bigint,f:GF)=>Function;
|
|
55
|
+
type Slope = bigint;
|
|
50
56
|
|
|
51
57
|
interface Tuples {
|
|
52
58
|
'p': Tuple<bigint>;
|
|
@@ -55,6 +61,7 @@ interface Tuples {
|
|
|
55
61
|
|
|
56
62
|
interface IECCurve {
|
|
57
63
|
'θ': bigint;
|
|
64
|
+
'a': bigint;
|
|
58
65
|
'b': bigint;
|
|
59
66
|
bitlen: bigint;
|
|
60
67
|
formula: ECformula;
|
|
@@ -66,6 +73,10 @@ interface ECCurve extends IECCurve,Tuples,hashE {};
|
|
|
66
73
|
interface Iellipticcurves<a> {
|
|
67
74
|
backend: a;
|
|
68
75
|
constructor:Function;
|
|
76
|
+
add:(a:Coordinate,b:Coordinate)=>Coordinate;
|
|
77
|
+
double:(a:Coordinate)=>Coordinate;
|
|
78
|
+
get p(): Coordinate;
|
|
79
|
+
get q(): Coordinate;
|
|
69
80
|
}
|
|
70
81
|
|
|
71
82
|
interface Icurve extends IECCurve {
|
|
@@ -107,6 +118,7 @@ class Point implements Ipoint {
|
|
|
107
118
|
class Curve<a> implements Icurve {
|
|
108
119
|
#E: bigint;
|
|
109
120
|
public θ: bigint;
|
|
121
|
+
public a: bigint;
|
|
110
122
|
public b: bigint;
|
|
111
123
|
public p: Point;
|
|
112
124
|
public q: Point;
|
|
@@ -121,6 +133,8 @@ class Curve<a> implements Icurve {
|
|
|
121
133
|
|| fail(m);
|
|
122
134
|
this.θ = curve.θ
|
|
123
135
|
|| fail(m);
|
|
136
|
+
this.a = curve.a
|
|
137
|
+
|| fail(m);
|
|
124
138
|
this.b = curve.b
|
|
125
139
|
|| fail(m);
|
|
126
140
|
this.bitlen = curve.bitlen
|
|
@@ -134,10 +148,148 @@ class Curve<a> implements Icurve {
|
|
|
134
148
|
}
|
|
135
149
|
}
|
|
136
150
|
|
|
137
|
-
abstract class EllipticCurves<a> implements Iellipticcurves<a> {
|
|
151
|
+
abstract class EllipticCurves<a extends GF> implements Iellipticcurves<a> {
|
|
138
152
|
public abstract backend: a;
|
|
139
153
|
private curve: Curve<a>;
|
|
140
154
|
|
|
155
|
+
private eq(p:Point,q:Point): boolean {
|
|
156
|
+
return (
|
|
157
|
+
(!p || !q) ?
|
|
158
|
+
fail() :
|
|
159
|
+
(p['∞'] && q['∞']) ?
|
|
160
|
+
true :
|
|
161
|
+
(p['∞'] && !q['∞']) ?
|
|
162
|
+
false :
|
|
163
|
+
(!p['∞'] && q['∞']) ?
|
|
164
|
+
false :
|
|
165
|
+
((p.x === q.x) && (p.y === q.y))
|
|
166
|
+
);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
private isprimefield(f:GF): f is PrimeField {
|
|
170
|
+
return (f instanceof PrimeField);
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
private slope(p_:Point,q_:Point): (a:bigint,p:bigint)=>bigint {
|
|
174
|
+
let f:a;
|
|
175
|
+
const { x:x1,y:y1 } = p_;
|
|
176
|
+
const { x:x2,y:y2 } = q_;
|
|
177
|
+
|
|
178
|
+
if (!this.isprimefield(this.backend))
|
|
179
|
+
return fail();
|
|
180
|
+
else
|
|
181
|
+
f = this.backend;
|
|
182
|
+
|
|
183
|
+
return (this.eq(p_,q_)) ?
|
|
184
|
+
(a:bigint,p:bigint): bigint =>
|
|
185
|
+
(f.mul(
|
|
186
|
+
f.add(a,
|
|
187
|
+
f.mul(3n, f.exp(x1, 2n))
|
|
188
|
+
),
|
|
189
|
+
f.inv(f.mul(y1, 2n))
|
|
190
|
+
) % p) :
|
|
191
|
+
(a:bigint,p:bigint): bigint =>
|
|
192
|
+
(f.mul(
|
|
193
|
+
f.sub(y2, y1),
|
|
194
|
+
f.inv(f.sub(x2, x1))
|
|
195
|
+
) % p);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
private isinfinity(p:Point): infinity {
|
|
199
|
+
return false;
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
protected addpoints(p:Coordinate,q:Coordinate): Coordinate {
|
|
203
|
+
let s:Slope;
|
|
204
|
+
let p_:Point;
|
|
205
|
+
let q_:Point;
|
|
206
|
+
let x:bigint;
|
|
207
|
+
let y:bigint;
|
|
208
|
+
let t:Point;
|
|
209
|
+
let mt:Coordinate;
|
|
210
|
+
let Δx:bigint, Δy:bigint;
|
|
211
|
+
let f:a;
|
|
212
|
+
|
|
213
|
+
if (!this.isprimefield(this.backend))
|
|
214
|
+
return fail();
|
|
215
|
+
else
|
|
216
|
+
f = this.backend;
|
|
217
|
+
|
|
218
|
+
if (empty(p) && empty(q))
|
|
219
|
+
return <Maybe<Point>>nothing();
|
|
220
|
+
else if (empty(p))
|
|
221
|
+
return <Maybe<Point>>just(q as unknown as Point);
|
|
222
|
+
else if (empty(q))
|
|
223
|
+
return <Maybe<Point>>just(p as unknown as Point);
|
|
224
|
+
else
|
|
225
|
+
[p_, q_] = [fold(p), fold(q)];
|
|
226
|
+
|
|
227
|
+
const { x:x1,y:y1 } = p_;
|
|
228
|
+
const { x:x2,y:y2 } = q_;
|
|
229
|
+
|
|
230
|
+
s = this.slope(p_, q_)(this.curve.a, this.backend.p);
|
|
231
|
+
Δx = f.sub(x1, x2);
|
|
232
|
+
x = (f.sub(s, f.mul(s, s)) % this.backend.p);
|
|
233
|
+
Δy = f.sub(x1, x);
|
|
234
|
+
y = (f.sub(
|
|
235
|
+
f.mul(s, Δy),
|
|
236
|
+
y1
|
|
237
|
+
) % this.backend.p);
|
|
238
|
+
|
|
239
|
+
t = new Point([x,y]);
|
|
240
|
+
if (this.isinfinity(t))
|
|
241
|
+
mt = nothing();
|
|
242
|
+
else
|
|
243
|
+
mt = just(t);
|
|
244
|
+
|
|
245
|
+
return mt;
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
protected doublepoint(a:Coordinate): Coordinate {
|
|
249
|
+
return this.add(a, a);
|
|
250
|
+
}
|
|
251
|
+
|
|
252
|
+
public add(a:Coordinate,b:Coordinate): Coordinate {
|
|
253
|
+
if (empty(a) && empty(b))
|
|
254
|
+
return <Maybe<Point>>nothing();
|
|
255
|
+
else if (empty(a))
|
|
256
|
+
return <Maybe<Point>>just(b as unknown as Point);
|
|
257
|
+
else if (empty(b))
|
|
258
|
+
return <Maybe<Point>>just(a as unknown as Point);
|
|
259
|
+
else
|
|
260
|
+
return <Maybe<Point>>this.addpoints(a,b);
|
|
261
|
+
}
|
|
262
|
+
|
|
263
|
+
public double(a:Coordinate): Coordinate {
|
|
264
|
+
if (a === 𝒪)
|
|
265
|
+
return nothing();
|
|
266
|
+
else
|
|
267
|
+
return this.doublepoint(a);
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
public get p(): Coordinate {
|
|
271
|
+
let p:Point;
|
|
272
|
+
let mp:Coordinate;
|
|
273
|
+
|
|
274
|
+
p = this.curve.p;
|
|
275
|
+
mp = (p['∞']) ?
|
|
276
|
+
nothing() :
|
|
277
|
+
just(p);
|
|
278
|
+
|
|
279
|
+
return mp;
|
|
280
|
+
}
|
|
281
|
+
public get q(): Coordinate {
|
|
282
|
+
let q:Point;
|
|
283
|
+
let mq:Coordinate;
|
|
284
|
+
|
|
285
|
+
q = this.curve.q;
|
|
286
|
+
mq = (q['∞']) ?
|
|
287
|
+
nothing() :
|
|
288
|
+
just(q);
|
|
289
|
+
|
|
290
|
+
return mq;
|
|
291
|
+
}
|
|
292
|
+
|
|
141
293
|
constructor(curve:ECCurve) {
|
|
142
294
|
this.curve = new Curve<a>(curve);
|
|
143
295
|
|
|
@@ -159,3 +311,4 @@ class ecℤp extends EllipticCurves<PrimeField>
|
|
|
159
311
|
}
|
|
160
312
|
|
|
161
313
|
export { ecℤp, p256 };
|
|
314
|
+
export type { Point, Coordinate };
|
package/galois.ts
CHANGED
|
@@ -146,8 +146,8 @@ Util = {
|
|
|
146
146
|
let a:bigint;
|
|
147
147
|
let e:bigint;
|
|
148
148
|
|
|
149
|
-
sign = (method==methods.SquareAndMultiply) ? '^' : 'x';
|
|
150
|
-
log(`${a_}${sign}${e_} (mod ${p}) = `);
|
|
149
|
+
// sign = (method==methods.SquareAndMultiply) ? '^' : 'x';
|
|
150
|
+
// log(`${a_}${sign}${e_} (mod ${p}) = `);
|
|
151
151
|
|
|
152
152
|
switch (method) {
|
|
153
153
|
case methods.SquareAndMultiply:
|
|
@@ -161,10 +161,8 @@ Util = {
|
|
|
161
161
|
|
|
162
162
|
case methods.DoubleAndAdd:
|
|
163
163
|
sq = (y:bigint,p_:bigint):bigint =>
|
|
164
|
-
// Util.binmethod(y,2n,p_,DoubleAndAdd)
|
|
165
164
|
((y+y)%p_)
|
|
166
165
|
mul = (y:bigint,z:bigint,p_:bigint):bigint =>
|
|
167
|
-
// Util.binmethod(y,z,p_,DoubleAndAdd)
|
|
168
166
|
((y+z)%p_);
|
|
169
167
|
a=e_;
|
|
170
168
|
e=a_;
|
|
@@ -184,18 +182,13 @@ Util = {
|
|
|
184
182
|
.fill(false,0,Number(bitlen))
|
|
185
183
|
.map((x:boolean,idx:number):boolean =>
|
|
186
184
|
(((e>>n--)&1n)===1n) && (!!idx));
|
|
187
|
-
|
|
188
|
-
bitstring.shift();
|
|
185
|
+
bitstring.shift();
|
|
189
186
|
// log(bitstring.map((x:boolean):number => (x)?1:0));
|
|
190
187
|
bitstring
|
|
191
188
|
.forEach((x:boolean):void => {
|
|
192
|
-
// val = (x) ?
|
|
193
|
-
// mul(a,sq(val,p),p) :
|
|
194
|
-
// sq(a,p);
|
|
195
189
|
val = (x) ?
|
|
196
190
|
mul(a,sq(val,p),p) :
|
|
197
191
|
sq(val,p);
|
|
198
|
-
// log(val);
|
|
199
192
|
|
|
200
193
|
return void 0;
|
|
201
194
|
});
|
package/main.ts
CHANGED
|
@@ -1,17 +1,39 @@
|
|
|
1
1
|
/* main.ts */
|
|
2
2
|
import { Polynomial } from './polynomial.js';
|
|
3
3
|
import { Util,PrimeField } from './galois.js';
|
|
4
|
-
import { ecℤp, p256 } from './ellipticcurves.js';
|
|
4
|
+
import { ecℤp, p256, type Coordinate, type Point } from './ellipticcurves.js';
|
|
5
|
+
import { empty, fold, just, nothing } from './maybe.js';
|
|
6
|
+
import type { Maybe, Just, Nothing } from './maybe.js';
|
|
5
7
|
|
|
6
8
|
let log:(...x:any[])=>void;
|
|
7
9
|
log = console.log;
|
|
8
10
|
|
|
9
11
|
let field:PrimeField;
|
|
10
12
|
let curve:ecℤp;
|
|
13
|
+
let mp:Coordinate;
|
|
14
|
+
let p:Point;
|
|
15
|
+
let q:Point;
|
|
11
16
|
|
|
12
17
|
field = new PrimeField(p256().θ, p256().bitlen);
|
|
13
|
-
log(field);
|
|
18
|
+
// log(field);
|
|
14
19
|
curve = new ecℤp(field, p256());
|
|
15
|
-
log(curve);
|
|
20
|
+
// log(curve);
|
|
21
|
+
|
|
22
|
+
// mp = curve.add(curve.p, curve.q);
|
|
23
|
+
mp = curve.q;
|
|
24
|
+
q = fold(mp);
|
|
25
|
+
p = fold(curve.p);
|
|
26
|
+
do {
|
|
27
|
+
mp = curve.double(mp);
|
|
28
|
+
if (empty(mp)) {
|
|
29
|
+
log(mp);
|
|
30
|
+
break;
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
p = fold(mp);
|
|
34
|
+
log(p);
|
|
35
|
+
}
|
|
36
|
+
} while (p.x !== q.x);
|
|
37
|
+
log(q);
|
|
16
38
|
|
|
17
39
|
export { Polynomial,Util,PrimeField,ecℤp,p256 };
|
package/maybe.ts
ADDED
|
@@ -0,0 +1,40 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* maybe datatype
|
|
3
|
+
*
|
|
4
|
+
* finitefields package by @dr-Jonas-Birch
|
|
5
|
+
*
|
|
6
|
+
* 2026
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
let log:(...args:any[])=>void;
|
|
11
|
+
let fail:(...args:any[])=>never;
|
|
12
|
+
|
|
13
|
+
log = console.log;
|
|
14
|
+
fail = (...args:any[]): never => {
|
|
15
|
+
console.error(...args);
|
|
16
|
+
throw new Error(args.toString());
|
|
17
|
+
|
|
18
|
+
return void 0 as never;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
type Nothing = readonly [];
|
|
22
|
+
type Just<a> = readonly [a];
|
|
23
|
+
type Maybe<a> =
|
|
24
|
+
| Nothing
|
|
25
|
+
| Just<a>;
|
|
26
|
+
|
|
27
|
+
let empty:<a>(x:Maybe<a>)=>boolean;
|
|
28
|
+
let nothing:()=>Nothing;
|
|
29
|
+
let just:<a>(x:a)=>Just<a>;
|
|
30
|
+
let fold:<a>(x:Maybe<a>)=>a|never;
|
|
31
|
+
let x:Function;
|
|
32
|
+
|
|
33
|
+
nothing = (): Nothing => [] as Nothing;
|
|
34
|
+
just = <a>(x:a): Just<a> => [x] as Just<a>;
|
|
35
|
+
empty = <a>(x:Maybe<a>): x is Nothing => !(x&&x.length);
|
|
36
|
+
fold = <a>(x:Maybe<a>): a|never =>
|
|
37
|
+
(!empty(x))?x[0] as a:fail("folding nothing") as never;
|
|
38
|
+
|
|
39
|
+
export type { Maybe, Just, Nothing };
|
|
40
|
+
export { nothing, just, empty, fold };
|