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 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( // y^2 =
142
+ (f.add(f.add( // y^2 =
46
143
  f.exp(x, 3n), // x^3
47
144
  f.mul(a,x)), // + ax
48
- b) // + 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=>!!xy)) {
104
- case true:
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 false:
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)=>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): infinity {
199
- return false;
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.sub(x1, x2);
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
- if (this.isinfinity(t))
241
- mt = nothing();
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 <Maybe<Point>>just(b as unknown as Point);
366
+ return b;
257
367
  else if (empty(b))
258
- return <Maybe<Point>>just(a as unknown as Point);
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, p256 };
314
- export type { Point, Coordinate };
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
- (op==fieldops.$add) ?
37
- (a:bigint,b:bigint=0n) => (a+b)%p :
38
- (op==fieldops.$sub) ?
39
- (a:bigint,b:bigint=0n) => ((a-b)<1)?(a-b+p):(a-b)%p :
40
- (op==fieldops.$mul) ?
41
- (a:bigint,b:bigint=0n) => (!a||!b)?0n:Util.dblad(a,b,p) :
42
- (op==fieldops.$inv) ?
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) :
46
- fail('unknown field operation');
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 (val%p);
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, p256, type Coordinate, type Point } from './ellipticcurves.js';
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(p256().θ, p256().bitlen);
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
- q = fold(mp);
50
+ // mp = curve.q;
51
+
52
+ q = fold(mq);
25
53
  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);
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>): x is Nothing => !(x&&x.length);
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
 
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "finitefields",
3
3
  "type": "module",
4
- "version": "0.0.10",
4
+ "version": "0.0.11",
5
5
  "description": "Galois/Finite field crypto and raw elliptic curves",
6
6
  "main": "main.js",
7
7
  "scripts": {