functionalscript 0.0.548 → 0.0.550
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/package.json +1 -1
- package/prime_field/module.f.cjs +106 -0
- package/prime_field/test.f.cjs +87 -0
- package/secp/module.f.cjs +119 -0
- package/secp/test.f.cjs +48 -0
package/package.json
CHANGED
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
const op = require('../types/function/operator/module.f.cjs')
|
|
2
|
+
|
|
3
|
+
/** @typedef {op.Reduce<bigint>} Reduce */
|
|
4
|
+
|
|
5
|
+
/** @typedef {op.Unary<bigint, bigint>} Unary*/
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* @typedef {{
|
|
9
|
+
* readonly p: bigint
|
|
10
|
+
* readonly middle: bigint
|
|
11
|
+
* readonly max: bigint
|
|
12
|
+
* readonly neg: Unary
|
|
13
|
+
* readonly sub: Reduce
|
|
14
|
+
* readonly add: Reduce
|
|
15
|
+
* readonly abs: Unary
|
|
16
|
+
* readonly mul: Reduce
|
|
17
|
+
* readonly reciprocal: Unary
|
|
18
|
+
* readonly div: Reduce
|
|
19
|
+
* readonly pow: Reduce
|
|
20
|
+
* readonly pow2: Unary
|
|
21
|
+
* readonly pow3: Unary
|
|
22
|
+
* }} PrimeField
|
|
23
|
+
*/
|
|
24
|
+
|
|
25
|
+
/** @type {<T>(zero: T, add: op.Reduce<T>) => (a: T) => (n: bigint) => T} */
|
|
26
|
+
const scalar_mul = (zero, add) => a => n => {
|
|
27
|
+
let ai = a
|
|
28
|
+
let ni = n
|
|
29
|
+
let result = zero
|
|
30
|
+
while (true) {
|
|
31
|
+
if ((ni & 1n) === 1n) {
|
|
32
|
+
result = add(result)(ai)
|
|
33
|
+
}
|
|
34
|
+
ni >>= 1n
|
|
35
|
+
if (ni === 0n) {
|
|
36
|
+
return result
|
|
37
|
+
}
|
|
38
|
+
ai = add(ai)(ai)
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
/** @type {(p: bigint) => PrimeField} */
|
|
43
|
+
const prime_field = p => {
|
|
44
|
+
/** @type {Reduce} */
|
|
45
|
+
const sub = a => b => {
|
|
46
|
+
const r = a - b
|
|
47
|
+
return r < 0 ? r + p : r
|
|
48
|
+
}
|
|
49
|
+
/** @type {Reduce} */
|
|
50
|
+
const mul = a => b => a * b % p
|
|
51
|
+
/** @type {Unary} */
|
|
52
|
+
const reciprocal = a => {
|
|
53
|
+
if (a === 0n) { throw '1/0' }
|
|
54
|
+
let a1 = a
|
|
55
|
+
let a0 = p
|
|
56
|
+
let f0 = 0n
|
|
57
|
+
let f1 = 1n
|
|
58
|
+
while (a1 !== 1n) {
|
|
59
|
+
const q = a0 / a1
|
|
60
|
+
const a2 = a0 % a1
|
|
61
|
+
a0 = a1
|
|
62
|
+
a1 = a2
|
|
63
|
+
const f2 = sub(f0)(mul(f1)(q))
|
|
64
|
+
f0 = f1
|
|
65
|
+
f1 = f2
|
|
66
|
+
}
|
|
67
|
+
return f1
|
|
68
|
+
}
|
|
69
|
+
const middle = p >> 1n
|
|
70
|
+
/** @type {Unary} */
|
|
71
|
+
const pow2 = a => mul(a)(a)
|
|
72
|
+
/** @type {Reduce} */
|
|
73
|
+
const pow = scalar_mul(1n, mul)
|
|
74
|
+
return {
|
|
75
|
+
p,
|
|
76
|
+
middle,
|
|
77
|
+
max: p - 1n,
|
|
78
|
+
neg: a => a === 0n ? 0n : p - a,
|
|
79
|
+
sub,
|
|
80
|
+
add: a => b => {
|
|
81
|
+
const r = a + b
|
|
82
|
+
return r < p ? r : r - p
|
|
83
|
+
},
|
|
84
|
+
abs: a => middle < a ? p - a : a,
|
|
85
|
+
mul,
|
|
86
|
+
reciprocal,
|
|
87
|
+
div: a => b => mul(a)(reciprocal(b)),
|
|
88
|
+
pow,
|
|
89
|
+
pow2,
|
|
90
|
+
pow3: a => mul(a)(pow2(a))
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
module.exports = {
|
|
95
|
+
scalar_mul,
|
|
96
|
+
prime_field,
|
|
97
|
+
/** @type {(f: PrimeField) => (a: bigint) => bigint|null} */
|
|
98
|
+
sqrt: ({p, mul, pow }) => {
|
|
99
|
+
if ((p & 3n) !== 3n) { throw 'sqrt' }
|
|
100
|
+
const sqrt_k = (p + 1n) >> 2n
|
|
101
|
+
return a => {
|
|
102
|
+
const result = pow(a)(sqrt_k)
|
|
103
|
+
return mul(result)(result) === a ? result : null
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
const { prime_field, sqrt } = require('./module.f.cjs')
|
|
2
|
+
|
|
3
|
+
module.exports = {
|
|
4
|
+
prime_field_test: () => {
|
|
5
|
+
const p = 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_fffffffe_fffffc2fn;
|
|
6
|
+
const f = prime_field(p)
|
|
7
|
+
const sqrt_f = sqrt(f)
|
|
8
|
+
return {
|
|
9
|
+
neg: () => {
|
|
10
|
+
if (f.neg(0n) !== 0n) { throw '-0' }
|
|
11
|
+
if (f.neg(1n) !== p - 1n) { throw '-1' }
|
|
12
|
+
},
|
|
13
|
+
sub: () => {
|
|
14
|
+
if (f.sub(10n)(4n) !== 6n) { throw '10 - 4'}
|
|
15
|
+
if (f.sub(11n)(14n) !== p - 3n) { throw '11 - 14' }
|
|
16
|
+
},
|
|
17
|
+
add: () => {
|
|
18
|
+
if (f.add(13n)(24n) !== 37n) { throw '13 + 24' }
|
|
19
|
+
if (f.add(77n)(f.neg(12n)) !== 65n) { throw '77 + (-12)' }
|
|
20
|
+
},
|
|
21
|
+
mul: () => {
|
|
22
|
+
if (f.mul(100n)(0n) !== 0n) { throw '100 * 0' }
|
|
23
|
+
if (f.mul(101n)(205n) !== 20_705n) { throw '101 * 205' }
|
|
24
|
+
if (f.mul(304n)(f.neg(1n)) !== f.neg(304n)) { throw '304 * -1' }
|
|
25
|
+
if (f.mul(f.neg(507n))(609n) !== f.neg(308_763n)) { throw '-507 * 609' }
|
|
26
|
+
if (f.mul(f.neg(713n))(f.neg(825n)) !== 588_225n) { throw '-713 * -825' }
|
|
27
|
+
},
|
|
28
|
+
reciprocal: () => {
|
|
29
|
+
let i = 1n
|
|
30
|
+
while (i < 10_000n) {
|
|
31
|
+
const x = f.reciprocal(i)
|
|
32
|
+
if (f.mul(x)(i) !== 1n) { throw i }
|
|
33
|
+
++i
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
pow: () => {
|
|
37
|
+
/** @type {(a: bigint) => void} */
|
|
38
|
+
const test = a => {
|
|
39
|
+
if (f.pow(a)(0n) !== 1n) { throw '**0'}
|
|
40
|
+
if (f.pow(a)(1n) !== a) { throw '**1' }
|
|
41
|
+
// https://en.wikipedia.org/wiki/Fermat%27s_little_theorem
|
|
42
|
+
// a^(p-1) % p = 1
|
|
43
|
+
if (f.abs(f.pow(a)(f.middle)) !== 1n) { throw '**middle' }
|
|
44
|
+
if (f.pow(a)(f.sub(f.max)(1n)) !== f.reciprocal(a)) { throw '**(max-1)' }
|
|
45
|
+
if (f.pow(a)(f.max) !== 1n) { throw '**max' }
|
|
46
|
+
}
|
|
47
|
+
// 0
|
|
48
|
+
if (f.pow(0n)(0n) !== 1n) { throw '0**0'}
|
|
49
|
+
if (f.pow(0n)(f.max) !== 0n) { throw '0**max' }
|
|
50
|
+
// 1
|
|
51
|
+
test(1n)
|
|
52
|
+
// 2
|
|
53
|
+
test(2n)
|
|
54
|
+
if (f.pow(2n)(2n) !== 4n) { throw '2**2' }
|
|
55
|
+
if (f.pow(2n)(3n) !== 8n) { throw '2**3' }
|
|
56
|
+
if (f.pow(2n)(128n) !== 1n << 128n) { throw '2**128' }
|
|
57
|
+
// 3
|
|
58
|
+
test(3n)
|
|
59
|
+
if (f.pow(3n)(2n) !== 9n) { throw '3**2' }
|
|
60
|
+
if (f.pow(3n)(3n) !== 27n) { throw '3**3' }
|
|
61
|
+
if (f.pow(3n)(100n) !== 3n ** 100n) { throw '3**100' }
|
|
62
|
+
if (f.pow(3n)(110n) !== 3n ** 110n) { throw '3**110' }
|
|
63
|
+
if (f.pow(3n)(120n) !== 3n ** 120n) { throw '3**120' }
|
|
64
|
+
if (f.pow(3n)(121n) !== 3n ** 121n) { throw '3**121' }
|
|
65
|
+
//
|
|
66
|
+
test(f.middle)
|
|
67
|
+
test(f.max - 1n)
|
|
68
|
+
test(f.max)
|
|
69
|
+
},
|
|
70
|
+
sqrt: () => {
|
|
71
|
+
/** @type {(a: bigint) => void} */
|
|
72
|
+
const test = a => {
|
|
73
|
+
const a2 = f.mul(a)(a)
|
|
74
|
+
const s = sqrt_f(a2)
|
|
75
|
+
if (s !== null && f.abs(s) !== f.abs(a)) { throw 'sqrt' }
|
|
76
|
+
}
|
|
77
|
+
let i = 1n
|
|
78
|
+
while (i < 1000n) {
|
|
79
|
+
test(i)
|
|
80
|
+
++i;
|
|
81
|
+
}
|
|
82
|
+
test(f.middle);
|
|
83
|
+
test(f.max);
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
const op = require('../types/function/operator/module.f.cjs')
|
|
2
|
+
const pf = require('../prime_field/module.f.cjs')
|
|
3
|
+
const { scalar_mul, prime_field, sqrt } = pf
|
|
4
|
+
|
|
5
|
+
/** @typedef {readonly[bigint, bigint]} Point2D */
|
|
6
|
+
|
|
7
|
+
/** @typedef {Point2D|null} Point */
|
|
8
|
+
|
|
9
|
+
/**
|
|
10
|
+
* @typedef {{
|
|
11
|
+
* readonly p: bigint
|
|
12
|
+
* readonly a: readonly[bigint, bigint]
|
|
13
|
+
* readonly g: readonly[bigint, bigint]
|
|
14
|
+
* readonly n: bigint
|
|
15
|
+
* }} Init
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {{
|
|
20
|
+
* readonly pf: pf.PrimeField
|
|
21
|
+
* readonly nf: pf.PrimeField
|
|
22
|
+
* readonly y2: (x: bigint) => bigint
|
|
23
|
+
* readonly y: (x: bigint) => bigint|null
|
|
24
|
+
* readonly neg: (a: Point) => Point
|
|
25
|
+
* readonly add: op.Reduce<Point>
|
|
26
|
+
* readonly mul: (a: Point) => (n: bigint) => Point
|
|
27
|
+
* }} Curve
|
|
28
|
+
*/
|
|
29
|
+
|
|
30
|
+
/** @type {(i: Init) => Curve} */
|
|
31
|
+
const curve = ({ p, a: [a0, a1], n }) => {
|
|
32
|
+
const pf = prime_field(p)
|
|
33
|
+
const { pow2, pow3, sub, add, mul, neg, div } = pf
|
|
34
|
+
const mul3 = mul(3n)
|
|
35
|
+
const mul2 = mul(2n)
|
|
36
|
+
const addA1 = add(a1)
|
|
37
|
+
const mulA1 = mul(a1)
|
|
38
|
+
const addA0 = add(a0)
|
|
39
|
+
// y**2 = a1*x**3 + a0
|
|
40
|
+
/** @type {(x: bigint) => bigint} */
|
|
41
|
+
const y2 = x => addA0(add(pow3(x))(mulA1(x)))
|
|
42
|
+
/** @type {op.Reduce<Point>} */
|
|
43
|
+
const addPoint = p => q => {
|
|
44
|
+
if (p === null) {
|
|
45
|
+
return q
|
|
46
|
+
}
|
|
47
|
+
if (q === null) {
|
|
48
|
+
return p
|
|
49
|
+
}
|
|
50
|
+
const [px, py] = p
|
|
51
|
+
const [qx, qy] = q
|
|
52
|
+
const md = px === qx
|
|
53
|
+
// (3 * px ** 2 + a1) / (2 * py)
|
|
54
|
+
? py !== qy || py === 0n ? null : [addA1(mul3(pow2(px))), mul2(py)]
|
|
55
|
+
// (py - qy) / (px - qx)
|
|
56
|
+
: [sub(py)(qy), sub(px)(qx)]
|
|
57
|
+
if (md === null) {
|
|
58
|
+
return null
|
|
59
|
+
}
|
|
60
|
+
const [ma, mb] = md
|
|
61
|
+
const m = div(ma)(mb)
|
|
62
|
+
// m ** 2 - px - qx
|
|
63
|
+
const rx = sub(pow2(m))(add(px)(qx))
|
|
64
|
+
// [rx, m * (px - rx) - py]
|
|
65
|
+
return [rx, sub(mul(m)(sub(px)(rx)))(py)]
|
|
66
|
+
}
|
|
67
|
+
const sqrt_p = sqrt(pf)
|
|
68
|
+
return {
|
|
69
|
+
pf,
|
|
70
|
+
nf: prime_field(n),
|
|
71
|
+
y2,
|
|
72
|
+
y: x => sqrt_p(y2(x)),
|
|
73
|
+
neg: p => {
|
|
74
|
+
if (p === null) {
|
|
75
|
+
return null
|
|
76
|
+
}
|
|
77
|
+
const [x, y] = p
|
|
78
|
+
return [x, neg(y)]
|
|
79
|
+
},
|
|
80
|
+
add: addPoint,
|
|
81
|
+
mul: scalar_mul(null, addPoint)
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
module.exports = {
|
|
86
|
+
curve,
|
|
87
|
+
/** @type {(a: Point) => (b: Point) => boolean} */
|
|
88
|
+
eq: a => b => {
|
|
89
|
+
if (a === null || b === null) {
|
|
90
|
+
return a === b
|
|
91
|
+
}
|
|
92
|
+
const [ax, ay] = a
|
|
93
|
+
const [bx, by] = b
|
|
94
|
+
return ax === bx && ay === by
|
|
95
|
+
},
|
|
96
|
+
/** @type {Init} */
|
|
97
|
+
secp256k1: {
|
|
98
|
+
p: 0xffffffff_ffffffff_ffffffff_ffffffff_ffffffff_ffffffff_fffffffe_fffffc2fn,
|
|
99
|
+
a: [7n, 0n],
|
|
100
|
+
g: [
|
|
101
|
+
0x79be667e_f9dcbbac_55a06295_ce870b07_029bfcdb_2dce28d9_59f2815b_16f81798n,
|
|
102
|
+
0x483ada77_26a3c465_5da4fbfc_0e1108a8_fd17b448_a6855419_9c47d08f_fb10d4b8n
|
|
103
|
+
],
|
|
104
|
+
n: 0xffffffff_ffffffff_ffffffff_fffffffe_baaedce6_af48a03b_bfd25e8c_d0364141n,
|
|
105
|
+
},
|
|
106
|
+
/** @type {Init} */
|
|
107
|
+
secp192r1: {
|
|
108
|
+
p: 0xffffffff_ffffffff_ffffffff_fffffffe_ffffffff_ffffffffn,
|
|
109
|
+
a: [
|
|
110
|
+
0x64210519_e59c80e7_0fa7e9ab_72243049_feb8deec_c146b9b1n,
|
|
111
|
+
0xffffffff_ffffffff_ffffffff_fffffffe_ffffffff_fffffffcn
|
|
112
|
+
],
|
|
113
|
+
g: [
|
|
114
|
+
0x188da80e_b03090f6_7cbf20eb_43a18800_f4ff0afd_82ff1012n,
|
|
115
|
+
0x07192b95_ffc8da78_631011ed_6b24cdd5_73f977a1_1e794811n
|
|
116
|
+
],
|
|
117
|
+
n: 0xffffffff_ffffffff_ffffffff_99def836_146bc9b1_b4d22831n,
|
|
118
|
+
},
|
|
119
|
+
}
|
package/secp/test.f.cjs
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
const m = require('./module.f.cjs')
|
|
2
|
+
const { curve, secp256k1, secp192r1, eq } = m
|
|
3
|
+
|
|
4
|
+
module.exports = {
|
|
5
|
+
test: () => {
|
|
6
|
+
/** @type {(c: m.Init) => void} */
|
|
7
|
+
const test_curve = c => {
|
|
8
|
+
const { g } = c
|
|
9
|
+
const { mul, neg, pf: { abs }, y: yf, nf: { p: n } } = curve(c)
|
|
10
|
+
/** @type {(p: m.Point) => void} */
|
|
11
|
+
const point_check = p => {
|
|
12
|
+
if (p === null) { throw 'null' }
|
|
13
|
+
const [x, y] = p
|
|
14
|
+
const ye = yf(x)
|
|
15
|
+
if (ye === null) { throw 'null' }
|
|
16
|
+
if (abs(ye) !== abs(y)) { throw 'ye' }
|
|
17
|
+
}
|
|
18
|
+
point_check(g)
|
|
19
|
+
point_check(neg(g))
|
|
20
|
+
/** @type {(p: m.Point) => void} */
|
|
21
|
+
const test_mul = p => {
|
|
22
|
+
if (mul(p)(0n) !== null) { throw 'O' }
|
|
23
|
+
if (mul(p)(1n) !== p) { throw 'p' }
|
|
24
|
+
if (mul(p)(n) !== null) { throw 'n' }
|
|
25
|
+
const pn = neg(p)
|
|
26
|
+
if (!eq(mul(p)(n - 1n))(pn)) { throw 'n - 1' }
|
|
27
|
+
/** @type {(s: bigint) => void} */
|
|
28
|
+
const f = s => {
|
|
29
|
+
const r = mul(p)(s)
|
|
30
|
+
point_check(r)
|
|
31
|
+
const rn = mul(pn)(s)
|
|
32
|
+
point_check(rn)
|
|
33
|
+
if (!eq(r)(neg(rn))) { throw 'r != -rn' }
|
|
34
|
+
}
|
|
35
|
+
f(2n)
|
|
36
|
+
f(3n)
|
|
37
|
+
f(4n << 128n)
|
|
38
|
+
f((5n << 128n) + 6n)
|
|
39
|
+
f(7n << 128n)
|
|
40
|
+
f((8n << 128n) + 9n)
|
|
41
|
+
}
|
|
42
|
+
test_mul(g)
|
|
43
|
+
test_mul(neg(g))
|
|
44
|
+
}
|
|
45
|
+
test_curve(secp256k1)
|
|
46
|
+
test_curve(secp192r1)
|
|
47
|
+
}
|
|
48
|
+
}
|