finitefields 0.0.6 → 0.0.8
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 +161 -0
- package/galois.ts +95 -14
- package/main.ts +8 -21
- package/package.json +1 -1
- package/main.js +0 -25
|
@@ -0,0 +1,161 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* elliptic curves
|
|
3
|
+
*
|
|
4
|
+
* finitefields package by @dr-Jonas-Birch
|
|
5
|
+
*
|
|
6
|
+
* 2026
|
|
7
|
+
*
|
|
8
|
+
*/
|
|
9
|
+
|
|
10
|
+
import type { GF,PrimeField } from './galois.js';
|
|
11
|
+
import { Util } from './galois.js';
|
|
12
|
+
|
|
13
|
+
let log:(...x:any[])=>void;
|
|
14
|
+
let fail:(...x:any[])=>never;
|
|
15
|
+
let p256:()=>ECCurve;
|
|
16
|
+
|
|
17
|
+
log = console.log;
|
|
18
|
+
fail = (...args:any[]): never => {
|
|
19
|
+
console.error(...args);
|
|
20
|
+
throw new Error(args.toString());
|
|
21
|
+
|
|
22
|
+
return void 0 as never;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
p256 = ():ECCurve => ({
|
|
26
|
+
'#E': 0xffffffff00000000_ffffffffffffffff_bce6faada7179e84_f3b9cac2fc632551n,
|
|
27
|
+
'θ': 0xffffffff00000001_0000000000000000_00000000ffffffff_ffffffffffffffffn,
|
|
28
|
+
'b': 0x5ac635d8aa3a93e7_b3ebbd55769886bc_651d06b0cc53b0f6_3bce3c3e27d2604bn,
|
|
29
|
+
'p':
|
|
30
|
+
[
|
|
31
|
+
0x6b17d1f2e12c4247_f8bce6e563a440f2_77037d812deb33a0_f4a13945d898c296n,
|
|
32
|
+
0x4fe342e2fe1a7f9b_8ee7eb4a7c0f9e16_2bce33576b315ece_cbb6406837bf51f5n
|
|
33
|
+
],
|
|
34
|
+
'q':
|
|
35
|
+
[
|
|
36
|
+
0xc97445f45cdef9f0_d3e05e1e585fc297_235b82b5be8ff3ef_ca67c59852018192n,
|
|
37
|
+
0xb28ef557ba31dfcb_dd21ac46e2a91e3c_304f44cb87058ada_2cb815151e610046n
|
|
38
|
+
],
|
|
39
|
+
bitlen: 256n,
|
|
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) // + b
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
type Tuple<a> = readonly [a,a];
|
|
48
|
+
type infinity = false | true;
|
|
49
|
+
type ECformula = (a:bigint,b:bigint,f:GF)=>Function;
|
|
50
|
+
|
|
51
|
+
interface Tuples {
|
|
52
|
+
'p': Tuple<bigint>;
|
|
53
|
+
'q': Tuple<bigint>;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
interface IECCurve {
|
|
57
|
+
'θ': bigint;
|
|
58
|
+
'b': bigint;
|
|
59
|
+
bitlen: bigint;
|
|
60
|
+
formula: ECformula;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
type hashE = {'#E':bigint};
|
|
64
|
+
interface ECCurve extends IECCurve,Tuples,hashE {};
|
|
65
|
+
|
|
66
|
+
interface Iellipticcurves<a> {
|
|
67
|
+
backend: a;
|
|
68
|
+
constructor:Function;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
interface Icurve extends IECCurve {
|
|
72
|
+
p: Point;
|
|
73
|
+
q: Point;
|
|
74
|
+
constructor:Function;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
interface Ipoint {
|
|
78
|
+
'x': bigint;
|
|
79
|
+
'y': bigint;
|
|
80
|
+
'∞': infinity;
|
|
81
|
+
constructor: Function;
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
class Point implements Ipoint {
|
|
85
|
+
public 'x':bigint;
|
|
86
|
+
public 'y':bigint;
|
|
87
|
+
public '∞':infinity;
|
|
88
|
+
|
|
89
|
+
constructor(point:Tuple<bigint>) {
|
|
90
|
+
[ this['x'], this['y'], this['∞'] ] = [0n,0n,false];
|
|
91
|
+
|
|
92
|
+
switch (point.every((xy:bigint):xy is bigint=>!!xy)) {
|
|
93
|
+
case true:
|
|
94
|
+
[ this['x'], this['y'] ] = point;
|
|
95
|
+
break;
|
|
96
|
+
case false:
|
|
97
|
+
(this['∞'] as unknown as number)++;
|
|
98
|
+
break;
|
|
99
|
+
default:
|
|
100
|
+
return fail();
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
class Curve<a> implements Icurve {
|
|
108
|
+
#E: bigint;
|
|
109
|
+
public θ: bigint;
|
|
110
|
+
public b: bigint;
|
|
111
|
+
public p: Point;
|
|
112
|
+
public q: Point;
|
|
113
|
+
public bitlen: bigint;
|
|
114
|
+
public formula:ECformula;
|
|
115
|
+
|
|
116
|
+
constructor(curve:ECCurve) {
|
|
117
|
+
let m:string;
|
|
118
|
+
|
|
119
|
+
m = 'argument error (incomplete curve params)' as const;
|
|
120
|
+
this.#E = curve['#E']
|
|
121
|
+
|| fail(m);
|
|
122
|
+
this.θ = curve.θ
|
|
123
|
+
|| fail(m);
|
|
124
|
+
this.b = curve.b
|
|
125
|
+
|| fail(m);
|
|
126
|
+
this.bitlen = curve.bitlen
|
|
127
|
+
|| fail(m);
|
|
128
|
+
this.formula = curve.formula
|
|
129
|
+
|| fail(m);
|
|
130
|
+
this.p = new Point(curve.p);
|
|
131
|
+
this.q = new Point(curve.q);
|
|
132
|
+
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
abstract class EllipticCurves<a> implements Iellipticcurves<a> {
|
|
138
|
+
public abstract backend: a;
|
|
139
|
+
private curve: Curve<a>;
|
|
140
|
+
|
|
141
|
+
constructor(curve:ECCurve) {
|
|
142
|
+
this.curve = new Curve<a>(curve);
|
|
143
|
+
|
|
144
|
+
return this;
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
class ecℤp extends EllipticCurves<PrimeField>
|
|
149
|
+
implements Iellipticcurves<PrimeField>
|
|
150
|
+
{
|
|
151
|
+
public backend:PrimeField;
|
|
152
|
+
|
|
153
|
+
constructor(field:PrimeField, curve:ECCurve) {
|
|
154
|
+
super(curve);
|
|
155
|
+
this.backend = field;
|
|
156
|
+
|
|
157
|
+
return this;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
export { ecℤp, p256 };
|
package/galois.ts
CHANGED
|
@@ -19,15 +19,30 @@ fail = (...args:any[]): never => {
|
|
|
19
19
|
return void 0 as never;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
enum fieldops {
|
|
23
|
+
$add,
|
|
24
|
+
$sub,
|
|
25
|
+
$mul,
|
|
26
|
+
$inv,
|
|
27
|
+
$exp
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
enum methods {
|
|
31
|
+
SquareAndMultiply,
|
|
32
|
+
DoubleAndAdd
|
|
33
|
+
}
|
|
34
|
+
|
|
22
35
|
const arithmeticsℤp = (p:bigint,op:fieldops) =>
|
|
23
36
|
(op==fieldops.$add) ?
|
|
24
37
|
(a:bigint,b:bigint=0n) => (a+b)%p :
|
|
25
38
|
(op==fieldops.$sub) ?
|
|
26
39
|
(a:bigint,b:bigint=0n) => ((a-b)<1)?(a-b+p):(a-b)%p :
|
|
27
40
|
(op==fieldops.$mul) ?
|
|
28
|
-
(a:bigint,b:bigint=0n) => (a
|
|
41
|
+
(a:bigint,b:bigint=0n) => (!a||!b)?0n:Util.dblad(a,b,p) :
|
|
29
42
|
(op==fieldops.$inv) ?
|
|
30
43
|
(a:bigint) => (!a)?fail('0 has no inverse'):Util.sqmul(a,(p-2n),p) :
|
|
44
|
+
(op==fieldops.$exp) ?
|
|
45
|
+
(a:bigint,b:bigint=0n) => (!a)?0n:(!b)?1n:Util.sqmul(a,b,p) :
|
|
31
46
|
fail('unknown field operation');
|
|
32
47
|
|
|
33
48
|
Util = {
|
|
@@ -44,6 +59,28 @@ Util = {
|
|
|
44
59
|
let n:number;
|
|
45
60
|
let r:bigint;
|
|
46
61
|
let ret:boolean;
|
|
62
|
+
// let pow:(x:bigint,e:bigint,p_:bigint)=>bigint;
|
|
63
|
+
|
|
64
|
+
// pow = (x:bigint,e:bigint,p_:bigint): bigint => {
|
|
65
|
+
// let n_:bigint;
|
|
66
|
+
// let v:bigint;
|
|
67
|
+
|
|
68
|
+
// if (e == 1n)
|
|
69
|
+
// return (x%p_);
|
|
70
|
+
// else if (!e)
|
|
71
|
+
// return (1n%p_);
|
|
72
|
+
// else if (e<0n)
|
|
73
|
+
// return fail("trying to raise to negative power");
|
|
74
|
+
|
|
75
|
+
// n_ = e;
|
|
76
|
+
// v = x;
|
|
77
|
+
// while (--n_)
|
|
78
|
+
// v = (v*v)%p_;
|
|
79
|
+
|
|
80
|
+
// return v;
|
|
81
|
+
// }
|
|
82
|
+
|
|
83
|
+
return true;
|
|
47
84
|
|
|
48
85
|
if (p<2n)
|
|
49
86
|
return true;
|
|
@@ -51,7 +88,8 @@ Util = {
|
|
|
51
88
|
for (n=0, ret=true; n<s; n++) {
|
|
52
89
|
r = this.rnd(bitlen,(p-1n));
|
|
53
90
|
r += 1n;
|
|
54
|
-
if (((r**(p-1n))%p) != 1n) {
|
|
91
|
+
// if (((r**(p-1n))%p) != 1n) {
|
|
92
|
+
if (this.sqmul(r,(p-1n),p) !== 1n) {
|
|
55
93
|
ret = false;
|
|
56
94
|
break;
|
|
57
95
|
}
|
|
@@ -92,18 +130,50 @@ Util = {
|
|
|
92
130
|
return fail('eea() not implemented') as never;
|
|
93
131
|
},
|
|
94
132
|
|
|
95
|
-
sqmul(a:bigint,e:bigint,p:bigint): bigint
|
|
133
|
+
sqmul: (a:bigint,e:bigint,p:bigint): bigint =>
|
|
134
|
+
Util.binmethod(a,e,p,methods.SquareAndMultiply),
|
|
135
|
+
dblad: (a:bigint,e:bigint,p:bigint): bigint =>
|
|
136
|
+
Util.binmethod(a,e,p,methods.DoubleAndAdd),
|
|
137
|
+
|
|
138
|
+
binmethod(a_:bigint,e_:bigint,p:bigint,method:methods): bigint {
|
|
96
139
|
let bitstring:boolean[];
|
|
97
140
|
let bitlen:bigint;
|
|
98
141
|
let n:bigint;
|
|
99
142
|
let val:bigint;
|
|
100
143
|
let mul:(y:bigint,z:bigint,p_:bigint)=>bigint;
|
|
101
144
|
let sq:(y:bigint,p_:bigint)=>bigint;
|
|
145
|
+
let sign:string;
|
|
146
|
+
let a:bigint;
|
|
147
|
+
let e:bigint;
|
|
148
|
+
|
|
149
|
+
sign = (method==methods.SquareAndMultiply) ? '^' : 'x';
|
|
150
|
+
log(`${a_}${sign}${e_} (mod ${p}) = `);
|
|
151
|
+
|
|
152
|
+
switch (method) {
|
|
153
|
+
case methods.SquareAndMultiply:
|
|
154
|
+
sq = (y:bigint,p_:bigint):bigint =>
|
|
155
|
+
Util.binmethod(y,y,p_,methods.DoubleAndAdd);
|
|
156
|
+
mul = (y:bigint,z:bigint,p_:bigint):bigint =>
|
|
157
|
+
Util.binmethod(y,z,p_,methods.DoubleAndAdd);
|
|
158
|
+
a=a_;
|
|
159
|
+
e=e_;
|
|
160
|
+
break;
|
|
102
161
|
|
|
103
|
-
|
|
162
|
+
case methods.DoubleAndAdd:
|
|
163
|
+
sq = (y:bigint,p_:bigint):bigint =>
|
|
164
|
+
// Util.binmethod(y,2n,p_,DoubleAndAdd)
|
|
165
|
+
((y+y)%p_)
|
|
166
|
+
mul = (y:bigint,z:bigint,p_:bigint):bigint =>
|
|
167
|
+
// Util.binmethod(y,z,p_,DoubleAndAdd)
|
|
168
|
+
((y+z)%p_);
|
|
169
|
+
a=e_;
|
|
170
|
+
e=a_;
|
|
171
|
+
break;
|
|
104
172
|
|
|
105
|
-
|
|
106
|
-
|
|
173
|
+
default:
|
|
174
|
+
return fail('argument error');
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
107
177
|
|
|
108
178
|
val = a;
|
|
109
179
|
bitlen = this.countbits(e);
|
|
@@ -114,12 +184,18 @@ Util = {
|
|
|
114
184
|
.fill(false,0,Number(bitlen))
|
|
115
185
|
.map((x:boolean,idx:number):boolean =>
|
|
116
186
|
(((e>>n--)&1n)===1n) && (!!idx));
|
|
187
|
+
// if (method === methods.DoubleAndAdd)
|
|
188
|
+
bitstring.shift();
|
|
117
189
|
// log(bitstring.map((x:boolean):number => (x)?1:0));
|
|
118
190
|
bitstring
|
|
119
191
|
.forEach((x:boolean):void => {
|
|
192
|
+
// val = (x) ?
|
|
193
|
+
// mul(a,sq(val,p),p) :
|
|
194
|
+
// sq(a,p);
|
|
120
195
|
val = (x) ?
|
|
121
196
|
mul(a,sq(val,p),p) :
|
|
122
|
-
sq(
|
|
197
|
+
sq(val,p);
|
|
198
|
+
// log(val);
|
|
123
199
|
|
|
124
200
|
return void 0;
|
|
125
201
|
});
|
|
@@ -128,19 +204,14 @@ Util = {
|
|
|
128
204
|
}
|
|
129
205
|
}
|
|
130
206
|
|
|
131
|
-
enum fieldops {
|
|
132
|
-
$add,
|
|
133
|
-
$sub,
|
|
134
|
-
$mul,
|
|
135
|
-
$inv
|
|
136
|
-
}
|
|
137
|
-
|
|
138
207
|
interface Igalois {
|
|
139
208
|
add: (a:bigint,b:bigint)=>bigint;
|
|
140
209
|
sub: (a:bigint,b:bigint)=>bigint;
|
|
141
210
|
mul: (a:bigint,b:bigint)=>bigint;
|
|
142
211
|
inv: (a:bigint)=>bigint;
|
|
212
|
+
exp: (a:bigint,b:bigint)=>bigint;
|
|
143
213
|
verify:()=>void;
|
|
214
|
+
get p(): bigint;
|
|
144
215
|
constructor:Function;
|
|
145
216
|
}
|
|
146
217
|
|
|
@@ -149,7 +220,9 @@ interface Iutil {
|
|
|
149
220
|
countbits: (x:bigint)=>bigint;
|
|
150
221
|
rnd: (bitlen:bigint,max:bigint)=>bigint;
|
|
151
222
|
eea: (x:bigint,p:bigint)=>bigint;
|
|
223
|
+
binmethod: (a:bigint,e:bigint,p:bigint,method:methods)=>bigint;
|
|
152
224
|
sqmul: (a:bigint,e:bigint,p:bigint)=>bigint;
|
|
225
|
+
dblad: (a:bigint,e:bigint,p:bigint)=>bigint;
|
|
153
226
|
}
|
|
154
227
|
|
|
155
228
|
abstract class GF implements Igalois {
|
|
@@ -159,9 +232,14 @@ abstract class GF implements Igalois {
|
|
|
159
232
|
public abstract sub: typeof this.add;
|
|
160
233
|
public abstract mul: typeof this.add;
|
|
161
234
|
public abstract inv: (a:bigint)=>bigint;
|
|
235
|
+
public abstract exp: typeof this.add;
|
|
162
236
|
|
|
163
237
|
public abstract verify(): void;
|
|
164
238
|
|
|
239
|
+
public get p(): bigint {
|
|
240
|
+
return this.modulus;
|
|
241
|
+
}
|
|
242
|
+
|
|
165
243
|
constructor(field:bigint,bitlen:bigint) {
|
|
166
244
|
this.modulus = field;
|
|
167
245
|
this.bitlen = bitlen;
|
|
@@ -177,6 +255,7 @@ class PrimeField extends GF implements Igalois {
|
|
|
177
255
|
public sub: typeof this.add;
|
|
178
256
|
public mul: typeof this.add;
|
|
179
257
|
public inv: (a:bigint)=>bigint;
|
|
258
|
+
public exp: typeof this.add;
|
|
180
259
|
|
|
181
260
|
public verify(): void {
|
|
182
261
|
if (!Util.isprime(this.modulus))
|
|
@@ -193,6 +272,7 @@ class PrimeField extends GF implements Igalois {
|
|
|
193
272
|
this.sub = arithmeticsℤp(this.modulus, fieldops.$sub);
|
|
194
273
|
this.mul = arithmeticsℤp(this.modulus, fieldops.$mul);
|
|
195
274
|
this.inv = arithmeticsℤp(this.modulus, fieldops.$inv);
|
|
275
|
+
this.exp = arithmeticsℤp(this.modulus, fieldops.$exp);
|
|
196
276
|
|
|
197
277
|
return this;
|
|
198
278
|
}
|
|
@@ -200,3 +280,4 @@ class PrimeField extends GF implements Igalois {
|
|
|
200
280
|
}
|
|
201
281
|
|
|
202
282
|
export { Util, PrimeField };
|
|
283
|
+
export type { GF }
|
package/main.ts
CHANGED
|
@@ -1,30 +1,17 @@
|
|
|
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
5
|
|
|
5
6
|
let log:(...x:any[])=>void;
|
|
6
7
|
log = console.log;
|
|
7
8
|
|
|
8
|
-
let
|
|
9
|
-
let
|
|
10
|
-
let p3:Polynomial;
|
|
11
|
-
let x0:bigint;
|
|
12
|
-
let x1:bigint;
|
|
13
|
-
let x2:bigint;
|
|
14
|
-
let x3:bigint;
|
|
9
|
+
let field:PrimeField;
|
|
10
|
+
let curve:ecℤp;
|
|
15
11
|
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
12
|
+
field = new PrimeField(p256().θ, p256().bitlen);
|
|
13
|
+
log(field);
|
|
14
|
+
curve = new ecℤp(field, p256());
|
|
15
|
+
log(curve);
|
|
20
16
|
|
|
21
|
-
|
|
22
|
-
p2 = new Polynomial({ tobject:0n, x3:1n, x2:0n, x:1n, 1:1n }, 2n);
|
|
23
|
-
// log(p1, " + ", p2, " =");
|
|
24
|
-
// p3 = Polynomial.add(p1,p2);
|
|
25
|
-
p3 = new Polynomial(1n<<254n, 2n);
|
|
26
|
-
|
|
27
|
-
log(p3, p3.eval());
|
|
28
|
-
// log(p3.eval());
|
|
29
|
-
|
|
30
|
-
export { Polynomial,Util,PrimeField };
|
|
17
|
+
export { Polynomial,Util,PrimeField,ecℤp,p256 };
|
package/package.json
CHANGED
package/main.js
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
/* main.ts */
|
|
2
|
-
import { Polynomial } from './polynomial.js';
|
|
3
|
-
import { Util, PrimeField } from './galois.js';
|
|
4
|
-
let log;
|
|
5
|
-
log = console.log;
|
|
6
|
-
let p1;
|
|
7
|
-
let p2;
|
|
8
|
-
let p3;
|
|
9
|
-
let x0;
|
|
10
|
-
let x1;
|
|
11
|
-
let x2;
|
|
12
|
-
let x3;
|
|
13
|
-
x0 = BigInt(1);
|
|
14
|
-
x1 = BigInt(0);
|
|
15
|
-
x2 = BigInt(1);
|
|
16
|
-
x3 = BigInt(0);
|
|
17
|
-
p1 = new Polynomial([x0, x1, x2, x3], 2n);
|
|
18
|
-
p2 = new Polynomial({ tobject: 0n, x3: 1n, x2: 0n, x: 1n, 1: 1n }, 2n);
|
|
19
|
-
// log(p1, " + ", p2, " =");
|
|
20
|
-
// p3 = Polynomial.add(p1,p2);
|
|
21
|
-
p3 = new Polynomial(1n << 254n, 2n);
|
|
22
|
-
log(p3, p3.eval());
|
|
23
|
-
// log(p3.eval());
|
|
24
|
-
export { Polynomial, Util, PrimeField };
|
|
25
|
-
//# sourceMappingURL=main.js.map
|