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 CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "functionalscript",
3
- "version": "0.0.548",
3
+ "version": "0.0.550",
4
4
  "description": "FunctionalScript is a functional subset of JavaScript",
5
5
  "main": "module.f.cjs",
6
6
  "scripts": {
@@ -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
+ }
@@ -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
+ }