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 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];
@@ -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=>!!xy)) {
104
- case true:
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 false:
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)=>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): infinity {
199
- return false;
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.sub(x1, x2);
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
- if (this.isinfinity(t))
241
- mt = nothing();
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 <Maybe<Point>>just(b as unknown as Point);
384
+ return b;
257
385
  else if (empty(b))
258
- return <Maybe<Point>>just(a as unknown as Point);
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, p256 };
314
- export type { Point, Coordinate };
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
- (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,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(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
+ 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
- q = fold(mp);
51
+ // mp = curve.q;
52
+
53
+ q = fold(mq);
25
54
  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 };
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>): 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.12",
5
5
  "description": "Galois/Finite field crypto and raw elliptic curves",
6
6
  "main": "main.js",
7
7
  "scripts": {