functionalscript 0.8.1 → 0.8.2

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.
@@ -1,5 +1,5 @@
1
1
  import type { Equal, Fold, Reduce } from '../../types/function/operator/module.f.ts';
2
- import { type PrimeField } from '../prime_field/module.f.ts';
2
+ import { type PrimeField } from '../../types/prime_field/module.f.ts';
3
3
  /**
4
4
  * A 2D point represented as a pair of `bigint` values `[x, y]`.
5
5
  */
@@ -24,6 +24,7 @@ export type Init = {
24
24
  export type Curve = {
25
25
  readonly pf: PrimeField;
26
26
  readonly nf: PrimeField;
27
+ readonly g: Point;
27
28
  readonly y2: (x: bigint) => bigint;
28
29
  readonly y: (x: bigint) => bigint | null;
29
30
  readonly neg: (a: Point) => Point;
@@ -50,27 +51,29 @@ export type Curve = {
50
51
  * const mulPoint = curveInstance.mul([1n, 1n])(3n); // Multiply a point by 3
51
52
  * ```
52
53
  */
53
- export declare const curve: ({ p, a: [a0, a1], n }: Init) => Curve;
54
+ export declare const curve: ({ p, a: [a0, a1], n, g }: Init) => Curve;
54
55
  export declare const eq: Equal<Point>;
55
56
  /**
56
57
  * https://neuromancer.sk/std/secg/secp192r1
58
+ * NIST P-192
57
59
  */
58
- export declare const secp192r1: Init;
60
+ export declare const secp192r1: Curve;
59
61
  /**
60
62
  * https://en.bitcoin.it/wiki/Secp256k1
61
63
  * https://neuromancer.sk/std/secg/secp256k1
62
64
  */
63
- export declare const secp256k1: Init;
65
+ export declare const secp256k1: Curve;
64
66
  /**
65
67
  * https://neuromancer.sk/std/secg/secp256r1
68
+ * NIST P-256
66
69
  */
67
- export declare const secp256r1: Init;
70
+ export declare const secp256r1: Curve;
68
71
  /**
69
72
  * https://neuromancer.sk/std/secg/secp384r1
70
73
  */
71
- export declare const secp384r1: Init;
74
+ export declare const secp384r1: Curve;
72
75
  /**
73
76
  * https://neuromancer.sk/std/secg/secp521r1
74
77
  */
75
- export declare const secp521r1: Init;
78
+ export declare const secp521r1: Curve;
76
79
  export {};
@@ -1,4 +1,4 @@
1
- import { prime_field, sqrt } from "../prime_field/module.f.js";
1
+ import { prime_field, sqrt } from "../../types/prime_field/module.f.js";
2
2
  import { repeat } from "../../types/monoid/module.f.js";
3
3
  /**
4
4
  * Constructs an elliptic curve with the given initialization parameters.
@@ -20,7 +20,7 @@ import { repeat } from "../../types/monoid/module.f.js";
20
20
  * const mulPoint = curveInstance.mul([1n, 1n])(3n); // Multiply a point by 3
21
21
  * ```
22
22
  */
23
- export const curve = ({ p, a: [a0, a1], n }) => {
23
+ export const curve = ({ p, a: [a0, a1], n, g }) => {
24
24
  const pf = prime_field(p);
25
25
  const { pow2, pow3, sub, add, mul, neg, div } = pf;
26
26
  const mul3 = mul(3n);
@@ -60,6 +60,7 @@ export const curve = ({ p, a: [a0, a1], n }) => {
60
60
  return {
61
61
  pf,
62
62
  nf: prime_field(n),
63
+ g,
63
64
  y2,
64
65
  y: x => sqrt_p(y2(x)),
65
66
  neg: p => {
@@ -83,8 +84,9 @@ export const eq = a => b => {
83
84
  };
84
85
  /**
85
86
  * https://neuromancer.sk/std/secg/secp192r1
87
+ * NIST P-192
86
88
  */
87
- export const secp192r1 = {
89
+ export const secp192r1 = curve({
88
90
  p: 0xfffffffffffffffffffffffffffffffeffffffffffffffffn,
89
91
  a: [
90
92
  0x64210519e59c80e70fa7e9ab72243049feb8deecc146b9b1n,
@@ -95,12 +97,29 @@ export const secp192r1 = {
95
97
  0x07192b95ffc8da78631011ed6b24cdd573f977a11e794811n
96
98
  ],
97
99
  n: 0xffffffffffffffffffffffff99def836146bc9b1b4d22831n,
98
- };
100
+ });
101
+ // The curve doesn't have a simple square root function.
102
+ // /**
103
+ // * https://std.neuromancer.sk/nist/P-224
104
+ // * NIST P-224
105
+ // */
106
+ // export const secp224r1: Curve = curve({
107
+ // p: 0xffffffff_ffffffff_ffffffff_ffffffff_00000000_00000000_00000001n,
108
+ // a: [
109
+ // 0xb4050a85_0c04b3ab_f5413256_5044b0b7_d7bfd8ba_270b3943_2355ffb4n,
110
+ // 0xffffffff_ffffffff_ffffffff_fffffffe_ffffffff_ffffffff_fffffffen,
111
+ // ],
112
+ // g: [
113
+ // 0xb70e0cbd_6bb4bf7f_321390b9_4a03c1d3_56c21122_343280d6_115c1d21n,
114
+ // 0xbd376388_b5f723fb_4c22dfe6_cd4375a0_5a074764_44d58199_85007e34n,
115
+ // ],
116
+ // n: 0xffffffff_ffffffff_ffffffff_ffff16a2_e0b8f03e_13dd2945_5c5c2a3dn,
117
+ // })
99
118
  /**
100
119
  * https://en.bitcoin.it/wiki/Secp256k1
101
120
  * https://neuromancer.sk/std/secg/secp256k1
102
121
  */
103
- export const secp256k1 = {
122
+ export const secp256k1 = curve({
104
123
  p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffefffffc2fn,
105
124
  a: [7n, 0n],
106
125
  g: [
@@ -108,11 +127,12 @@ export const secp256k1 = {
108
127
  0x483ada7726a3c4655da4fbfc0e1108a8fd17b448a68554199c47d08ffb10d4b8n
109
128
  ],
110
129
  n: 0xfffffffffffffffffffffffffffffffebaaedce6af48a03bbfd25e8cd0364141n,
111
- };
130
+ });
112
131
  /**
113
132
  * https://neuromancer.sk/std/secg/secp256r1
133
+ * NIST P-256
114
134
  */
115
- export const secp256r1 = {
135
+ export const secp256r1 = curve({
116
136
  p: 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffffn,
117
137
  a: [
118
138
  0x5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604bn, //< b
@@ -123,11 +143,11 @@ export const secp256r1 = {
123
143
  0x4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5n, //< y
124
144
  ],
125
145
  n: 0xffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551n,
126
- };
146
+ });
127
147
  /**
128
148
  * https://neuromancer.sk/std/secg/secp384r1
129
149
  */
130
- export const secp384r1 = {
150
+ export const secp384r1 = curve({
131
151
  p: 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffffn,
132
152
  a: [
133
153
  0xb3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088f5013875ac656398d8a2ed19d2a85c8edd3ec2aefn, //< b
@@ -138,11 +158,11 @@ export const secp384r1 = {
138
158
  0x3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5fn, //< y
139
159
  ],
140
160
  n: 0xffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973n,
141
- };
161
+ });
142
162
  /**
143
163
  * https://neuromancer.sk/std/secg/secp521r1
144
164
  */
145
- export const secp521r1 = {
165
+ export const secp521r1 = curve({
146
166
  p: 0x01ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffn,
147
167
  a: [
148
168
  0x0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef451fd46b503f00n, //< b
@@ -153,4 +173,4 @@ export const secp521r1 = {
153
173
  0x011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16650n,
154
174
  ],
155
175
  n: 0x01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409n
156
- };
176
+ });
@@ -1,10 +1,10 @@
1
- import { prime_field } from "../prime_field/module.f.js";
1
+ import { prime_field } from "../../types/prime_field/module.f.js";
2
2
  import { curve, secp256k1, secp192r1, secp256r1, eq, secp384r1, secp521r1 } from "./module.f.js";
3
3
  const poker = (param) => () => {
4
4
  // (c ^ x) ^ y = c ^ (x * y)
5
5
  // c ^ ((x * y) * (1/x * 1/y)) = c
6
- const { g, n } = param;
7
- const { mul, y } = curve(param);
6
+ // const { g, n } = param
7
+ const { mul, y, nf: { p: n } } = param;
8
8
  const f = (m) => (pList) => pList.map(mul(m));
9
9
  //
10
10
  const pf = prime_field(n);
@@ -69,8 +69,7 @@ export default {
69
69
  },
70
70
  test: () => {
71
71
  const test_curve = c => {
72
- const { g } = c;
73
- const { mul, neg, pf: { abs }, y: yf, nf: { p: n } } = curve(c);
72
+ const { mul, neg, pf: { abs }, y: yf, nf: { p: n }, g } = c;
74
73
  const point_check = (p) => {
75
74
  if (p === null) {
76
75
  throw 'p === null';
@@ -1,5 +1,18 @@
1
+ import type { Array2 } from '../../types/array/module.f.ts';
1
2
  import { type Vec } from '../../types/bit_vec/module.f.ts';
2
- import { type Init } from '../secp/module.f.ts';
3
- import type { Sha2 } from '../sha2/module.f.ts';
4
- export declare const newPrivateKey: (i: Init) => (random: Vec) => bigint;
5
- export declare const sign: (sha2: Sha2) => (curveInit: Init) => (privateKey: Vec) => (messageHash: Vec) => readonly [bigint, bigint];
3
+ import type { Curve } from '../secp/module.f.ts';
4
+ import { type Sha2 } from '../sha2/module.f.ts';
5
+ export type All = {
6
+ readonly q: bigint;
7
+ readonly qlen: bigint;
8
+ readonly bits2int: (b: Vec) => bigint;
9
+ readonly int2octets: (x: bigint) => Vec;
10
+ readonly bits2octets: (b: Vec) => Vec;
11
+ };
12
+ export declare const all: (q: bigint) => All;
13
+ export declare const fromCurve: (c: Curve) => All;
14
+ export declare const concat: (...x: readonly Vec[]) => Vec;
15
+ export declare const computeK: (_: All) => (_: Sha2) => (x: bigint) => (m: Vec) => bigint;
16
+ type Signature = Array2<bigint>;
17
+ export declare const sign: (c: Curve) => (hf: Sha2) => (x: bigint) => (m: Vec) => Signature;
18
+ export {};
@@ -1,54 +1,148 @@
1
- import { bitLength } from "../../types/bigint/module.f.js";
2
- import { listToVec, msb, uint, vec, vec8, length } from "../../types/bit_vec/module.f.js";
1
+ import { bitLength, divUp, roundUp } from "../../types/bigint/module.f.js";
2
+ import { empty, length, listToVec, msb, repeat, unpack, vec, vec8 } from "../../types/bit_vec/module.f.js";
3
3
  import { hmac } from "../hmac/module.f.js";
4
- import { curve } from "../secp/module.f.js";
5
- const concat = listToVec(msb);
6
- const v00 = vec8(0x00n);
7
- const v01 = vec8(0x01n);
8
- /**
9
- * The size of the result equals the size of the hash.
10
- *
11
- * @param sha2 SHA2 hash function
12
- * @returns A function that accepts a private key, a message hash and returns `k`.
13
- */
14
- const createK = (sha2) => {
15
- const h = hmac(sha2);
16
- let vs = vec(sha2.hashLength);
17
- let k0 = vs(0x00n);
18
- let v0 = vs(0x01n);
19
- return (privateKey) => (messageHash) => {
20
- const pm = concat([privateKey, messageHash]);
21
- let k = k0;
4
+ import { computeSync } from "../sha2/module.f.js";
5
+ // qlen to rlen
6
+ const roundUp8 = roundUp(8n);
7
+ const divUp8 = divUp(8n);
8
+ export const all = (q) => {
9
+ const qlen = bitLength(q);
10
+ const bits2int = (b) => {
11
+ const { length, uint } = unpack(b);
12
+ const diff = length - qlen;
13
+ return diff > 0n ? uint >> diff : uint;
14
+ };
15
+ const int2octets = vec(roundUp8(qlen));
16
+ return {
17
+ q,
18
+ qlen,
19
+ bits2int,
20
+ int2octets,
21
+ // since z2 < 2*q, we can use simple mod with `z1 < q ? z1 : z1 - q`
22
+ bits2octets: b => int2octets(bits2int(b) % q),
23
+ };
24
+ };
25
+ export const fromCurve = (c) => all(c.nf.p);
26
+ const x01 = vec8(0x01n);
27
+ const x00 = vec8(0x00n);
28
+ const ltov = listToVec(msb);
29
+ export const concat = (...x) => ltov(x);
30
+ export const computeK = ({ q, bits2int, qlen, int2octets, bits2octets }) => hf => {
31
+ // TODO: Look at https://www.rfc-editor.org/rfc/rfc6979#section-3.3 to reformulate
32
+ // it using `HMAC_DRBG`.
33
+ const hmacf = hmac(hf);
34
+ // b. Set:
35
+ // V = 0x01 0x01 0x01 ... 0x01
36
+ // such that the length of V, in bits, is equal to 8*ceil(hlen/8).
37
+ // For instance, on an octet-based system, if H is SHA-256, then V
38
+ // is set to a sequence of 32 octets of value 1. Note that in this
39
+ // step and all subsequent steps, we use the same H function as the
40
+ // one used in step 'a' to process the input message; this choice
41
+ // will be discussed in more detail in Section 3.6.
42
+ const rep = repeat(divUp8(hf.hashLength));
43
+ const v0 = rep(x01);
44
+ // c. Set:
45
+ // K = 0x00 0x00 0x00 ... 0x00
46
+ // such that the length of K, in bits, is equal to 8*ceil(hlen/8).
47
+ const k0 = rep(x00);
48
+ //
49
+ return x => m => {
22
50
  let v = v0;
23
- k = h(k)(concat([v, v00, pm]));
24
- v = h(k)(v);
25
- k = h(k)(concat([v, v01, pm]));
26
- v = h(k)(v);
27
- return uint(h(k)(v));
51
+ let k = k0;
52
+ // a. Process m through the hash function H, yielding:
53
+ // h1 = H(m)
54
+ // (h1 is a sequence of hlen bits).
55
+ const h1 = computeSync(hf)([m]);
56
+ // d. Set:
57
+ // K = HMAC_K(V || 0x00 || int2octets(x) || bits2octets(h1))
58
+ // where '||' denotes concatenation.
59
+ const xh1 = concat(int2octets(x), bits2octets(h1));
60
+ k = hmacf(k)(concat(v, x00, xh1));
61
+ // e. Set:
62
+ // V = HMAC_K(V)
63
+ v = hmacf(k)(v);
64
+ // f. Set:
65
+ // K = HMAC_K(V || 0x01 || int2octets(x) || bits2octets(h1))
66
+ k = hmacf(k)(concat(v, x01, xh1));
67
+ // g. Set:
68
+ // V = HMAC_K(V)
69
+ v = hmacf(k)(v);
70
+ // h. Apply the following algorithm until a proper value is for `k`:
71
+ while (true) {
72
+ // h. Apply the following algorithm until a proper value is for `k`:
73
+ // 1. Set `T` to the empty sequence, so `tlen = 0`.
74
+ let t = empty;
75
+ // 2. while `tlen < qlen` do:
76
+ // - `V = HMAC_K(V)`
77
+ // - `T = T || V`
78
+ // Possible optimizations:
79
+ // - precompute number of iterations
80
+ // - `qlen` can't be 0, so we can avoid the first check and
81
+ // first concatenation.
82
+ while (length(t) < qlen) {
83
+ v = hmacf(k)(v);
84
+ t = concat(t, v);
85
+ }
86
+ // 3. Compute `k = bits2int(T)`. If `k` is not in `[1, q-1]` or `kG = 0` then
87
+ // - `K = HMAC_K(V || 0x00)`
88
+ // - `V = HMAC_K(V)`
89
+ // and loop (try to generate a new `T`, and so on). Return to step `1`.
90
+ const result = bits2int(t);
91
+ if (0n < result && result < q) {
92
+ return result;
93
+ }
94
+ k = hmacf(k)(concat(v, x00));
95
+ v = hmacf(k)(v);
96
+ }
28
97
  };
29
98
  };
30
- export const newPrivateKey = (i) => (random) => {
31
- const { nf } = curve(i);
32
- if (bitLength(nf.max) < length(random)) {
33
- throw "need more random bits";
99
+ export const sign = (c) => (hf) => (x) => (m) => {
100
+ // 2.4 Signature Generation
101
+ const { nf: { p: q, div }, g } = c;
102
+ const a = all(q);
103
+ const { bits2int } = a;
104
+ // The following steps are then applied:
105
+ //
106
+ // 1. H(m) is transformed into an integer modulo q using the bits2int
107
+ // transform and an extra modular reduction:
108
+ //
109
+ // h = bits2int(H(m)) mod q
110
+ //
111
+ // As was noted in the description of bits2octets, the extra modular
112
+ // reduction is no more than a conditional subtraction.
113
+ const hm = computeSync(hf)([m]);
114
+ const h = bits2int(hm) % q;
115
+ // 2. A random value modulo q, dubbed k, is generated. That value
116
+ // shall not be 0; hence, it lies in the [1, q-1] range. Most of
117
+ // the remainder of this document will revolve around the process
118
+ // used to generate k. In plain DSA or ECDSA, k should be selected
119
+ // through a random selection that chooses a value among the q-1
120
+ // possible values with uniform probability.
121
+ const k = computeK(a)(hf)(x)(m);
122
+ // 3. A value r (modulo q) is computed from k and the key parameters:
123
+ //
124
+ // * For ECDSA: the point kG is computed; its X coordinate (a
125
+ // member of the field over which E is defined) is converted to
126
+ // an integer, which is reduced modulo q, yielding r.
127
+ //
128
+ // If r turns out to be zero, a new k should be selected and r
129
+ // computed again (this is an utterly improbable occurrence).
130
+ const rxy = c.mul(k)(g);
131
+ // TODO: implement the loop. `computeK` should either
132
+ // - accept a state (current `k`).
133
+ // - accept a `is_valid` function.
134
+ if (rxy === null) {
135
+ throw 'rxy === null';
34
136
  }
35
- return uint(random) % nf.p;
36
- };
37
- export const sign = (sha2) => (curveInit) => (privateKey) => (messageHash) => {
38
- const { mul, pf } = curve(curveInit);
39
- // const curveVec = vec(length(pf.max))
40
- //`k` is a unique for each `z` and secret.
41
- const k = createK(sha2)(privateKey)(messageHash) % pf.p;
42
- // `R = G * k`.
43
- const rp = mul(k)(curveInit.g);
44
- // `r = R.x`
45
- const r = rp === null ? 0n : rp[0];
46
- // `s = ((z + r * d) / k)`.
47
- const d = uint(privateKey);
48
- const z = uint(messageHash);
49
- const rd = pf.mul(r)(d);
50
- const zrd = pf.add(z)(rd);
51
- const kn1 = pf.reciprocal(k);
52
- const s = pf.mul(zrd)(kn1);
137
+ const [r] = rxy;
138
+ // 4. The value s (modulo q) is computed:
139
+ //
140
+ // s = (h+x*r)/k mod q
141
+ //
142
+ // The pair (r, s) is the signature. How a signature is to be
143
+ // encoded is not covered by the DSA and ECDSA standards themselves;
144
+ // a common way is to use a DER-encoded ASN.1 structure (a SEQUENCE
145
+ // of two INTEGERs, for r and s, in that order).
146
+ const s = div(h + x * r)(k);
53
147
  return [r, s];
54
148
  };
@@ -1,2 +1,12 @@
1
- declare const _default: {};
1
+ declare const _default: {
2
+ bits2int: () => void;
3
+ int2octets: () => void;
4
+ bit2octets: () => void;
5
+ k: () => void;
6
+ computeK: () => void;
7
+ investigate: () => void;
8
+ kk: () => void;
9
+ a2: () => void;
10
+ a2s: () => void;
11
+ };
2
12
  export default _default;