@noble/post-quantum 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- package/LICENSE +21 -0
- package/README.md +300 -0
- package/_crystals.d.ts +34 -0
- package/_crystals.d.ts.map +1 -0
- package/_crystals.js +171 -0
- package/_crystals.js.map +1 -0
- package/esm/_crystals.js +167 -0
- package/esm/_crystals.js.map +1 -0
- package/esm/index.js +3 -0
- package/esm/index.js.map +1 -0
- package/esm/ml-dsa.js +529 -0
- package/esm/ml-dsa.js.map +1 -0
- package/esm/ml-kem.js +361 -0
- package/esm/ml-kem.js.map +1 -0
- package/esm/package.json +10 -0
- package/esm/slh-dsa.js +602 -0
- package/esm/slh-dsa.js.map +1 -0
- package/esm/utils.js +86 -0
- package/esm/utils.js.map +1 -0
- package/index.d.ts +1 -0
- package/index.d.ts.map +1 -0
- package/index.js +3 -0
- package/index.js.map +1 -0
- package/ml-dsa.d.ts +37 -0
- package/ml-dsa.d.ts.map +1 -0
- package/ml-dsa.js +532 -0
- package/ml-dsa.js.map +1 -0
- package/ml-kem.d.ts +134 -0
- package/ml-kem.d.ts.map +1 -0
- package/ml-kem.js +364 -0
- package/ml-kem.js.map +1 -0
- package/package.json +100 -0
- package/slh-dsa.d.ts +70 -0
- package/slh-dsa.d.ts.map +1 -0
- package/slh-dsa.js +605 -0
- package/slh-dsa.js.map +1 -0
- package/src/_crystals.ts +197 -0
- package/src/index.ts +1 -0
- package/src/ml-dsa.ts +569 -0
- package/src/ml-kem.ts +403 -0
- package/src/package.json +3 -0
- package/src/slh-dsa.ts +771 -0
- package/src/utils.ts +113 -0
- package/utils.d.ts +38 -0
- package/utils.d.ts.map +1 -0
- package/utils.js +94 -0
- package/utils.js.map +1 -0
package/esm/utils.js
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
/*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */
|
2
|
+
import { bytes as abytes } from '@noble/hashes/_assert';
|
3
|
+
import { randomBytes as randb } from '@noble/hashes/utils';
|
4
|
+
export const ensureBytes = abytes;
|
5
|
+
export const randomBytes = randb;
|
6
|
+
// Compares 2 u8a-s in kinda constant time
|
7
|
+
export function equalBytes(a, b) {
|
8
|
+
if (a.length !== b.length)
|
9
|
+
return false;
|
10
|
+
let diff = 0;
|
11
|
+
for (let i = 0; i < a.length; i++)
|
12
|
+
diff |= a[i] ^ b[i];
|
13
|
+
return diff === 0;
|
14
|
+
}
|
15
|
+
export function splitCoder(...lengths) {
|
16
|
+
const getLength = (c) => (typeof c === 'number' ? c : c.bytesLen);
|
17
|
+
const bytesLen = lengths.reduce((sum, a) => sum + getLength(a), 0);
|
18
|
+
return {
|
19
|
+
bytesLen,
|
20
|
+
encode: (bufs) => {
|
21
|
+
const res = new Uint8Array(bytesLen);
|
22
|
+
for (let i = 0, pos = 0; i < lengths.length; i++) {
|
23
|
+
const c = lengths[i];
|
24
|
+
const l = getLength(c);
|
25
|
+
const b = typeof c === 'number' ? bufs[i] : c.encode(bufs[i]);
|
26
|
+
ensureBytes(b, l);
|
27
|
+
res.set(b, pos);
|
28
|
+
if (typeof c !== 'number')
|
29
|
+
b.fill(0); // clean
|
30
|
+
pos += l;
|
31
|
+
}
|
32
|
+
return res;
|
33
|
+
},
|
34
|
+
decode: (buf) => {
|
35
|
+
ensureBytes(buf, bytesLen);
|
36
|
+
const res = [];
|
37
|
+
for (const c of lengths) {
|
38
|
+
const l = getLength(c);
|
39
|
+
const b = buf.subarray(0, l);
|
40
|
+
res.push(typeof c === 'number' ? b : c.decode(b));
|
41
|
+
buf = buf.subarray(l);
|
42
|
+
}
|
43
|
+
return res;
|
44
|
+
},
|
45
|
+
};
|
46
|
+
}
|
47
|
+
// nano-packed.array (fixed size)
|
48
|
+
export function vecCoder(c, vecLen) {
|
49
|
+
const bytesLen = vecLen * c.bytesLen;
|
50
|
+
return {
|
51
|
+
bytesLen,
|
52
|
+
encode: (u) => {
|
53
|
+
if (u.length !== vecLen)
|
54
|
+
throw new Error(`vecCoder.encode: wrong length=${u.length}. Expected: ${vecLen}`);
|
55
|
+
const res = new Uint8Array(bytesLen);
|
56
|
+
for (let i = 0, pos = 0; i < u.length; i++) {
|
57
|
+
const b = c.encode(u[i]);
|
58
|
+
res.set(b, pos);
|
59
|
+
b.fill(0); // clean
|
60
|
+
pos += b.length;
|
61
|
+
}
|
62
|
+
return res;
|
63
|
+
},
|
64
|
+
decode: (a) => {
|
65
|
+
ensureBytes(a, bytesLen);
|
66
|
+
const r = [];
|
67
|
+
for (let i = 0; i < a.length; i += c.bytesLen)
|
68
|
+
r.push(c.decode(a.subarray(i, i + c.bytesLen)));
|
69
|
+
return r;
|
70
|
+
},
|
71
|
+
};
|
72
|
+
}
|
73
|
+
// cleanBytes(new Uint8Array(), [new Uint16Array(), new Uint32Array()])
|
74
|
+
export function cleanBytes(...list) {
|
75
|
+
for (const t of list) {
|
76
|
+
if (Array.isArray(t))
|
77
|
+
for (const b of t)
|
78
|
+
b.fill(0);
|
79
|
+
else
|
80
|
+
t.fill(0);
|
81
|
+
}
|
82
|
+
}
|
83
|
+
export function getMask(bits) {
|
84
|
+
return (1 << bits) - 1; // 4 -> 0b1111
|
85
|
+
}
|
86
|
+
//# sourceMappingURL=utils.js.map
|
package/esm/utils.js.map
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"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"}
|
package/index.d.ts
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
//# sourceMappingURL=index.d.ts.map
|
package/index.d.ts.map
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":""}
|
package/index.js
ADDED
package/index.js.map
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["src/index.ts"],"names":[],"mappings":";AAAA,MAAM,IAAI,KAAK,CAAC,iEAAiE,CAAC,CAAC"}
|
package/ml-dsa.d.ts
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
import { Signer } from './utils.js';
|
2
|
+
type Param = {
|
3
|
+
K: number;
|
4
|
+
L: number;
|
5
|
+
D: number;
|
6
|
+
GAMMA1: number;
|
7
|
+
GAMMA2: number;
|
8
|
+
TAU: number;
|
9
|
+
ETA: number;
|
10
|
+
OMEGA: number;
|
11
|
+
};
|
12
|
+
export declare const PARAMS: Record<string, Param>;
|
13
|
+
export declare const dilithium_v30: {
|
14
|
+
dilithium2: Signer;
|
15
|
+
dilithium3: Signer;
|
16
|
+
dilithium5: Signer;
|
17
|
+
};
|
18
|
+
export declare const dilithium_v31: {
|
19
|
+
dilithium2: Signer;
|
20
|
+
dilithium3: Signer;
|
21
|
+
dilithium5: Signer;
|
22
|
+
};
|
23
|
+
export declare const dilithium_v30_aes: {
|
24
|
+
dilithium2: Signer;
|
25
|
+
dilithium3: Signer;
|
26
|
+
dilithium5: Signer;
|
27
|
+
};
|
28
|
+
export declare const dilithium_v31_aes: {
|
29
|
+
dilithium2: Signer;
|
30
|
+
dilithium3: Signer;
|
31
|
+
dilithium5: Signer;
|
32
|
+
};
|
33
|
+
export declare const ml_dsa44: Signer;
|
34
|
+
export declare const ml_dsa65: Signer;
|
35
|
+
export declare const ml_dsa87: Signer;
|
36
|
+
export {};
|
37
|
+
//# sourceMappingURL=ml-dsa.d.ts.map
|
package/ml-dsa.d.ts.map
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
{"version":3,"file":"ml-dsa.d.ts","sourceRoot":"","sources":["src/ml-dsa.ts"],"names":[],"mappings":"AAGA,OAAO,EAEL,MAAM,EAOP,MAAM,YAAY,CAAC;AA6BpB,KAAK,KAAK,GAAG;IACX,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,CAAC,EAAE,MAAM,CAAC;IACV,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;IACf,GAAG,EAAE,MAAM,CAAC;IACZ,GAAG,EAAE,MAAM,CAAC;IACZ,KAAK,EAAE,MAAM,CAAC;CACf,CAAC;AAEF,eAAO,MAAM,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,KAAK,CAI/B,CAAC;AA8bX,eAAO,MAAM,aAAa;;;;CAMxB,CAAC;AAEH,eAAO,MAAM,aAAa;;;;CAOxB,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;CAM5B,CAAC;AAEH,eAAO,MAAM,iBAAiB;;;;CAO5B,CAAC;AAGH,eAAO,MAAM,QAAQ,QASnB,CAAC;AAEH,eAAO,MAAM,QAAQ,QASnB,CAAC;AAEH,eAAO,MAAM,QAAQ,QASnB,CAAC"}
|
package/ml-dsa.js
ADDED
@@ -0,0 +1,532 @@
|
|
1
|
+
"use strict";
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
3
|
+
exports.ml_dsa87 = exports.ml_dsa65 = exports.ml_dsa44 = exports.dilithium_v31_aes = exports.dilithium_v30_aes = exports.dilithium_v31 = exports.dilithium_v30 = exports.PARAMS = void 0;
|
4
|
+
/*! noble-post-quantum - MIT License (c) 2024 Paul Miller (paulmillr.com) */
|
5
|
+
const sha3_1 = require("@noble/hashes/sha3");
|
6
|
+
const _crystals_js_1 = require("./_crystals.js");
|
7
|
+
const utils_js_1 = require("./utils.js");
|
8
|
+
/*
|
9
|
+
Lattice-based digital signature algorithm. See
|
10
|
+
[official site](https://www.pq-crystals.org/dilithium/index.shtml),
|
11
|
+
[repo](https://github.com/pq-crystals/dilithium).
|
12
|
+
Dilithium has similar internals to Kyber, but their keys and params are different.
|
13
|
+
|
14
|
+
Three versions are provided:
|
15
|
+
|
16
|
+
1. Dilithium v3.0, v3.0 AES
|
17
|
+
2. Dilithium v3.1, v3.1 AES
|
18
|
+
3. ML-DSA aka [FIPS-204](https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.204.ipd.pdf)
|
19
|
+
*/
|
20
|
+
// Constants
|
21
|
+
const N = 256;
|
22
|
+
// 2**23 − 2**13 + 1, 23 bits: multiply will be 46. We have enough precision in JS to avoid bigints
|
23
|
+
const Q = 8380417;
|
24
|
+
const ROOT_OF_UNITY = 1753;
|
25
|
+
// f = 256**−1 mod q, pow(256, -1, q) = 8347681 (python3)
|
26
|
+
const F = 8347681;
|
27
|
+
const D = 13;
|
28
|
+
// Dilithium is kinda parametrized over GAMMA2, but everything will break with any other value.
|
29
|
+
const GAMMA2_1 = Math.floor((Q - 1) / 88) | 0;
|
30
|
+
const GAMMA2_2 = Math.floor((Q - 1) / 32) | 0;
|
31
|
+
// prettier-ignore
|
32
|
+
exports.PARAMS = {
|
33
|
+
2: { K: 4, L: 4, D, GAMMA1: 2 ** 17, GAMMA2: GAMMA2_1, TAU: 39, ETA: 2, OMEGA: 80 },
|
34
|
+
3: { K: 6, L: 5, D, GAMMA1: 2 ** 19, GAMMA2: GAMMA2_2, TAU: 49, ETA: 4, OMEGA: 55 },
|
35
|
+
5: { K: 8, L: 7, D, GAMMA1: 2 ** 19, GAMMA2: GAMMA2_2, TAU: 60, ETA: 2, OMEGA: 75 },
|
36
|
+
};
|
37
|
+
const newPoly = (n) => new Int32Array(n);
|
38
|
+
const { mod, smod, NTT, bitsCoder } = (0, _crystals_js_1.genCrystals)({
|
39
|
+
N,
|
40
|
+
Q,
|
41
|
+
F,
|
42
|
+
ROOT_OF_UNITY,
|
43
|
+
newPoly,
|
44
|
+
isKyber: false,
|
45
|
+
brvBits: 8,
|
46
|
+
});
|
47
|
+
const polyCoder = (d, compress) => bitsCoder(d, {
|
48
|
+
encode: (i) => (compress ? compress(i) : i),
|
49
|
+
decode: (i) => (compress ? compress(i) : i),
|
50
|
+
});
|
51
|
+
const polyAdd = (a, b) => {
|
52
|
+
for (let i = 0; i < a.length; i++)
|
53
|
+
a[i] = mod(a[i] + b[i]);
|
54
|
+
return a;
|
55
|
+
};
|
56
|
+
const polySub = (a, b) => {
|
57
|
+
for (let i = 0; i < a.length; i++)
|
58
|
+
a[i] = mod(a[i] - b[i]);
|
59
|
+
return a;
|
60
|
+
};
|
61
|
+
const polyShiftl = (p) => {
|
62
|
+
for (let i = 0; i < N; i++)
|
63
|
+
p[i] <<= D;
|
64
|
+
return p;
|
65
|
+
};
|
66
|
+
const polyChknorm = (p, B) => {
|
67
|
+
// Not very sure about this, but FIPS204 doesn't provide any function for that :(
|
68
|
+
for (let i = 0; i < N; i++)
|
69
|
+
if (Math.abs(smod(p[i])) >= B)
|
70
|
+
return true;
|
71
|
+
return false;
|
72
|
+
};
|
73
|
+
const MultiplyNTTs = (a, b) => {
|
74
|
+
// NOTE: we don't use montgomery reduction in code, since it requires 64 bit ints,
|
75
|
+
// which is not available in JS. mod(a[i] * b[i]) is ok, since Q is 23 bit,
|
76
|
+
// which means a[i] * b[i] is 46 bit, which is safe to use in JS. (number is 53 bits).
|
77
|
+
// Barrett reduction is slower than mod :(
|
78
|
+
const c = newPoly(N);
|
79
|
+
for (let i = 0; i < a.length; i++)
|
80
|
+
c[i] = mod(a[i] * b[i]);
|
81
|
+
return c;
|
82
|
+
};
|
83
|
+
// Return poly in NTT representation
|
84
|
+
function RejNTTPoly(xof) {
|
85
|
+
// Samples a polynomial ∈ Tq.
|
86
|
+
const r = newPoly(N);
|
87
|
+
// NOTE: we can represent 3xu24 as 4xu32, but it doesn't improve perf :(
|
88
|
+
for (let j = 0; j < N;) {
|
89
|
+
const b = xof();
|
90
|
+
if (b.length % 3)
|
91
|
+
throw new Error('RejNTTPoly: unaligned block');
|
92
|
+
for (let i = 0; j < N && i <= b.length - 3; i += 3) {
|
93
|
+
const t = (b[i + 0] | (b[i + 1] << 8) | (b[i + 2] << 16)) & 0x7fffff; // 3 bytes
|
94
|
+
if (t < Q)
|
95
|
+
r[j++] = t;
|
96
|
+
}
|
97
|
+
}
|
98
|
+
return r;
|
99
|
+
}
|
100
|
+
function getDilithium(opts) {
|
101
|
+
const { K, L, GAMMA1, GAMMA2, TAU, ETA, OMEGA } = opts;
|
102
|
+
const { FIPS204, V31, CRH_BYTES, TR_BYTES, C_TILDE_BYTES, XOF128, XOF256 } = opts;
|
103
|
+
if (![2, 4].includes(ETA))
|
104
|
+
throw new Error('Wrong ETA');
|
105
|
+
if (![1 << 17, 1 << 19].includes(GAMMA1))
|
106
|
+
throw new Error('Wrong GAMMA1');
|
107
|
+
if (![GAMMA2_1, GAMMA2_2].includes(GAMMA2))
|
108
|
+
throw new Error('Wrong GAMMA2');
|
109
|
+
const BETA = TAU * ETA;
|
110
|
+
const decompose = (r) => {
|
111
|
+
// Decomposes r into (r1, r0) such that r ≡ r1(2γ2) + r0 mod q.
|
112
|
+
const rPlus = mod(r);
|
113
|
+
const r0 = smod(rPlus, 2 * GAMMA2) | 0;
|
114
|
+
if (rPlus - r0 === Q - 1)
|
115
|
+
return { r1: 0 | 0, r0: (r0 - 1) | 0 };
|
116
|
+
const r1 = Math.floor((rPlus - r0) / (2 * GAMMA2)) | 0;
|
117
|
+
return { r1, r0 }; // r1 = HighBits, r0 = LowBits
|
118
|
+
};
|
119
|
+
const HighBits = (r) => decompose(r).r1;
|
120
|
+
const LowBits = (r) => decompose(r).r0;
|
121
|
+
const MakeHint = (z, r) => {
|
122
|
+
// Compute hint bit indicating whether adding z to r alters the high bits of r.
|
123
|
+
// From dilithium code
|
124
|
+
const res0 = z <= GAMMA2 || z > Q - GAMMA2 || (z === Q - GAMMA2 && r === 0) ? 0 : 1;
|
125
|
+
// from FIPS204:
|
126
|
+
// // const r1 = HighBits(r);
|
127
|
+
// // const v1 = HighBits(r + z);
|
128
|
+
// // const res1 = +(r1 !== v1);
|
129
|
+
// But they return different results! However, decompose is same.
|
130
|
+
// So, either there is a bug in Dilithium ref implementation or in FIPS204.
|
131
|
+
// For now, lets use dilithium one, so test vectors can be passed.
|
132
|
+
return res0;
|
133
|
+
};
|
134
|
+
const UseHint = (h, r) => {
|
135
|
+
// Returns the high bits of r adjusted according to hint h
|
136
|
+
const m = Math.floor((Q - 1) / (2 * GAMMA2));
|
137
|
+
const { r1, r0 } = decompose(r);
|
138
|
+
// 3: if h = 1 and r0 > 0 return (r1 + 1) mod m
|
139
|
+
// 4: if h = 1 and r0 ≤ 0 return (r1 − 1) mod m
|
140
|
+
if (h === 1)
|
141
|
+
return r0 > 0 ? mod(r1 + 1, m) | 0 : mod(r1 - 1, m) | 0;
|
142
|
+
return r1 | 0;
|
143
|
+
};
|
144
|
+
const Power2Round = (r) => {
|
145
|
+
// Decomposes r into (r1, r0) such that r ≡ r1*(2**d) + r0 mod q.
|
146
|
+
const rPlus = mod(r);
|
147
|
+
const r0 = smod(rPlus, 2 ** D) | 0;
|
148
|
+
return { r1: Math.floor((rPlus - r0) / 2 ** D) | 0, r0 };
|
149
|
+
};
|
150
|
+
const hintCoder = {
|
151
|
+
bytesLen: OMEGA + K,
|
152
|
+
encode: (h) => {
|
153
|
+
if (h === false)
|
154
|
+
throw new Error('hint.encode: hint is false'); // should never happen
|
155
|
+
const res = new Uint8Array(OMEGA + K);
|
156
|
+
for (let i = 0, k = 0; i < K; i++) {
|
157
|
+
for (let j = 0; j < N; j++)
|
158
|
+
if (h[i][j] !== 0)
|
159
|
+
res[k++] = j;
|
160
|
+
res[OMEGA + i] = k;
|
161
|
+
}
|
162
|
+
return res;
|
163
|
+
},
|
164
|
+
decode: (buf) => {
|
165
|
+
const h = [];
|
166
|
+
let k = 0;
|
167
|
+
for (let i = 0; i < K; i++) {
|
168
|
+
const hi = newPoly(N);
|
169
|
+
if (buf[OMEGA + i] < k || buf[OMEGA + i] > OMEGA)
|
170
|
+
return false;
|
171
|
+
for (let j = k; j < buf[OMEGA + i]; j++) {
|
172
|
+
if (j > k && buf[j] <= buf[j - 1])
|
173
|
+
return false;
|
174
|
+
hi[buf[j]] = 1;
|
175
|
+
}
|
176
|
+
k = buf[OMEGA + i];
|
177
|
+
h.push(hi);
|
178
|
+
}
|
179
|
+
for (let j = k; j < OMEGA; j++)
|
180
|
+
if (buf[j] !== 0)
|
181
|
+
return false;
|
182
|
+
return h;
|
183
|
+
},
|
184
|
+
};
|
185
|
+
const ETACoder = polyCoder(ETA === 2 ? 3 : 4, (i) => ETA - i);
|
186
|
+
const T0Coder = polyCoder(13, (i) => (1 << (D - 1)) - i);
|
187
|
+
const T1Coder = polyCoder(10);
|
188
|
+
// Requires smod. Need to fix!
|
189
|
+
const ZCoder = polyCoder(GAMMA1 === 1 << 17 ? 18 : 20, (i) => smod(GAMMA1 - i));
|
190
|
+
const W1Coder = polyCoder(GAMMA2 === GAMMA2_1 ? 6 : 4);
|
191
|
+
const W1Vec = (0, utils_js_1.vecCoder)(W1Coder, K);
|
192
|
+
// Main structures
|
193
|
+
const publicCoder = (0, utils_js_1.splitCoder)(32, (0, utils_js_1.vecCoder)(T1Coder, K));
|
194
|
+
const secretCoder = (0, utils_js_1.splitCoder)(32, 32, TR_BYTES, (0, utils_js_1.vecCoder)(ETACoder, L), (0, utils_js_1.vecCoder)(ETACoder, K), (0, utils_js_1.vecCoder)(T0Coder, K));
|
195
|
+
const sigCoder = (0, utils_js_1.splitCoder)(C_TILDE_BYTES, (0, utils_js_1.vecCoder)(ZCoder, L), hintCoder);
|
196
|
+
const CoefFromHalfByte = ETA === 2
|
197
|
+
? (n) => (n < 15 ? 2 - (n % 5) : false)
|
198
|
+
: (n) => (n < 9 ? 4 - n : false);
|
199
|
+
// Return poly in NTT representation
|
200
|
+
function RejBoundedPoly(xof) {
|
201
|
+
// Samples an element a ∈ Rq with coeffcients in [−η, η] computed via rejection sampling from ρ.
|
202
|
+
const r = newPoly(N);
|
203
|
+
for (let j = 0; j < N;) {
|
204
|
+
const b = xof();
|
205
|
+
for (let i = 0; j < N && i < b.length; i += 1) {
|
206
|
+
// half byte. Should be superfast with vector instructions. But very slow with js :(
|
207
|
+
const d1 = CoefFromHalfByte(b[i] & 0x0f);
|
208
|
+
const d2 = CoefFromHalfByte((b[i] >> 4) & 0x0f);
|
209
|
+
if (d1 !== false)
|
210
|
+
r[j++] = d1;
|
211
|
+
if (j < N && d2 !== false)
|
212
|
+
r[j++] = d2;
|
213
|
+
}
|
214
|
+
}
|
215
|
+
return r;
|
216
|
+
}
|
217
|
+
const SampleInBall = (seed) => {
|
218
|
+
// Samples a polynomial c ∈ Rq with coeffcients from {−1, 0, 1} and Hamming weight τ
|
219
|
+
const pre = newPoly(N);
|
220
|
+
const s = sha3_1.shake256.create({}).update(seed.slice(0, 32));
|
221
|
+
const buf = new Uint8Array(sha3_1.shake256.blockLen);
|
222
|
+
s.xofInto(buf);
|
223
|
+
const masks = buf.slice(0, 8);
|
224
|
+
for (let i = N - TAU, pos = 8, maskPos = 0, maskBit = 0; i < N; i++) {
|
225
|
+
let b = i + 1;
|
226
|
+
for (; b > i;) {
|
227
|
+
b = buf[pos++];
|
228
|
+
if (pos < sha3_1.shake256.blockLen)
|
229
|
+
continue;
|
230
|
+
s.xofInto(buf);
|
231
|
+
pos = 0;
|
232
|
+
}
|
233
|
+
pre[i] = pre[b];
|
234
|
+
pre[b] = 1 - (((masks[maskPos] >> maskBit++) & 1) << 1);
|
235
|
+
if (maskBit >= 8) {
|
236
|
+
maskPos++;
|
237
|
+
maskBit = 0;
|
238
|
+
}
|
239
|
+
}
|
240
|
+
return pre;
|
241
|
+
};
|
242
|
+
const polyPowerRound = (p) => {
|
243
|
+
const res0 = newPoly(N);
|
244
|
+
const res1 = newPoly(N);
|
245
|
+
for (let i = 0; i < p.length; i++) {
|
246
|
+
const { r0, r1 } = Power2Round(p[i]);
|
247
|
+
res0[i] = r0;
|
248
|
+
res1[i] = r1;
|
249
|
+
}
|
250
|
+
return { r0: res0, r1: res1 };
|
251
|
+
};
|
252
|
+
const polyUseHint = (u, h) => {
|
253
|
+
for (let i = 0; i < N; i++)
|
254
|
+
u[i] = UseHint(h[i], u[i]);
|
255
|
+
return u;
|
256
|
+
};
|
257
|
+
const polyMakeHint = (a, b) => {
|
258
|
+
const v = newPoly(N);
|
259
|
+
let cnt = 0;
|
260
|
+
for (let i = 0; i < N; i++) {
|
261
|
+
const h = MakeHint(a[i], b[i]);
|
262
|
+
v[i] = h;
|
263
|
+
cnt += h;
|
264
|
+
}
|
265
|
+
return { v, cnt };
|
266
|
+
};
|
267
|
+
const signRandBytes = FIPS204 ? 32 : CRH_BYTES;
|
268
|
+
const seedCoder = (0, utils_js_1.splitCoder)(32, V31 ? 64 : 32, 32);
|
269
|
+
const seedXOF = V31 ? XOF256 : XOF128;
|
270
|
+
// API & argument positions are exactly as in FIPS204.
|
271
|
+
return {
|
272
|
+
signRandBytes,
|
273
|
+
keygen: (seed = (0, utils_js_1.randomBytes)(32)) => {
|
274
|
+
const [rho, rhoPrime, K_] = seedCoder.decode((0, sha3_1.shake256)(seed, { dkLen: seedCoder.bytesLen }));
|
275
|
+
const xofPrime = seedXOF(rhoPrime);
|
276
|
+
const s1 = [];
|
277
|
+
for (let i = 0; i < L; i++)
|
278
|
+
s1.push(RejBoundedPoly(xofPrime.get(i & 0xff, (i >> 8) & 0xff)));
|
279
|
+
const s2 = [];
|
280
|
+
for (let i = L; i < L + K; i++)
|
281
|
+
s2.push(RejBoundedPoly(xofPrime.get(i & 0xff, (i >> 8) & 0xff)));
|
282
|
+
const s1Hat = s1.map((i) => NTT.encode(i.slice()));
|
283
|
+
const t0 = [];
|
284
|
+
const t1 = [];
|
285
|
+
const xof = XOF128(rho);
|
286
|
+
const t = newPoly(N);
|
287
|
+
for (let i = 0; i < K; i++) {
|
288
|
+
// t ← NTT−1(A*NTT(s1)) + s2
|
289
|
+
t.fill(0); // don't-reallocate
|
290
|
+
for (let j = 0; j < L; j++) {
|
291
|
+
const aij = RejNTTPoly(xof.get(j, i)); // super slow!
|
292
|
+
polyAdd(t, MultiplyNTTs(aij, s1Hat[j]));
|
293
|
+
}
|
294
|
+
NTT.decode(t);
|
295
|
+
const { r0, r1 } = polyPowerRound(polyAdd(t, s2[i])); // (t1, t0) ← Power2Round(t, d)
|
296
|
+
t0.push(r0);
|
297
|
+
t1.push(r1);
|
298
|
+
}
|
299
|
+
const publicKey = publicCoder.encode([rho, t1]); // pk ← pkEncode(ρ, t1)
|
300
|
+
const tr = (0, sha3_1.shake256)(publicKey, { dkLen: TR_BYTES }); // tr ← H(BytesToBits(pk), 512)
|
301
|
+
const secretKey = secretCoder.encode([rho, K_, tr, s1, s2, t0]); // sk ← skEncode(ρ, K,tr, s1, s2, t0)
|
302
|
+
xof.clean();
|
303
|
+
xofPrime.clean();
|
304
|
+
// STATS
|
305
|
+
// Kyber512: { calls: 4, xofs: 12 }, Kyber768: { calls: 9, xofs: 27 }, Kyber1024: { calls: 16, xofs: 48 }
|
306
|
+
// DSA44: { calls: 24, xofs: 24 }, DSA65: { calls: 41, xofs: 41 }, DSA87: { calls: 71, xofs: 71 }
|
307
|
+
(0, utils_js_1.cleanBytes)(rho, rhoPrime, K_, s1, s2, s1Hat, t, t0, t1, tr);
|
308
|
+
return { publicKey, secretKey };
|
309
|
+
},
|
310
|
+
// NOTE: random is optional.
|
311
|
+
sign: (secretKey, msg, random) => {
|
312
|
+
// This part can be pre-cached per secretKey, but there is only minor performance improvement,
|
313
|
+
// since we re-use a lot of variables to computation.
|
314
|
+
const [rho, _K, tr, s1, s2, t0] = secretCoder.decode(secretKey); // (ρ, K,tr, s1, s2, t0) ← skDecode(sk)
|
315
|
+
// Cache matrix to avoid re-compute later
|
316
|
+
const A = []; // A ← ExpandA(ρ)
|
317
|
+
const xof = XOF128(rho);
|
318
|
+
for (let i = 0; i < K; i++) {
|
319
|
+
const pv = [];
|
320
|
+
for (let j = 0; j < L; j++)
|
321
|
+
pv.push(RejNTTPoly(xof.get(j, i)));
|
322
|
+
A.push(pv);
|
323
|
+
}
|
324
|
+
xof.clean();
|
325
|
+
for (let i = 0; i < L; i++)
|
326
|
+
NTT.encode(s1[i]); // sˆ1 ← NTT(s1)
|
327
|
+
for (let i = 0; i < K; i++) {
|
328
|
+
NTT.encode(s2[i]); // sˆ2 ← NTT(s2)
|
329
|
+
NTT.encode(t0[i]); // tˆ0 ← NTT(t0)
|
330
|
+
}
|
331
|
+
// This part is per msg
|
332
|
+
const mu = sha3_1.shake256.create({ dkLen: CRH_BYTES }).update(tr).update(msg).digest(); // 6: µ ← H(tr||M, 512) ▷ Compute message representative µ
|
333
|
+
let rhoprime; // Compute private random seed
|
334
|
+
if (FIPS204) {
|
335
|
+
const rnd = random ? random : new Uint8Array(32);
|
336
|
+
(0, utils_js_1.ensureBytes)(rnd);
|
337
|
+
rhoprime = sha3_1.shake256.create({ dkLen: CRH_BYTES }).update(_K).update(rnd).update(mu).digest(); // ρ′← H(K||rnd||µ, 512)
|
338
|
+
}
|
339
|
+
else {
|
340
|
+
rhoprime = random
|
341
|
+
? random
|
342
|
+
: sha3_1.shake256.create({ dkLen: CRH_BYTES }).update(_K).update(mu).digest();
|
343
|
+
}
|
344
|
+
(0, utils_js_1.ensureBytes)(rhoprime, CRH_BYTES);
|
345
|
+
const x256 = XOF256(rhoprime, ZCoder.bytesLen);
|
346
|
+
// Rejection sampling loop
|
347
|
+
main_loop: for (let kappa = 0;;) {
|
348
|
+
const y = [];
|
349
|
+
// y ← ExpandMask(ρ , κ)
|
350
|
+
for (let i = 0; i < L; i++, kappa++)
|
351
|
+
y.push(ZCoder.decode(x256.get(kappa & 0xff, kappa >> 8)()));
|
352
|
+
const z = y.map((i) => NTT.encode(i.slice()));
|
353
|
+
const w = [];
|
354
|
+
for (let i = 0; i < K; i++) {
|
355
|
+
// w ← NTT−1(A ◦ NTT(y))
|
356
|
+
const wi = newPoly(N);
|
357
|
+
for (let j = 0; j < L; j++)
|
358
|
+
polyAdd(wi, MultiplyNTTs(A[i][j], z[j]));
|
359
|
+
NTT.decode(wi);
|
360
|
+
w.push(wi);
|
361
|
+
}
|
362
|
+
const w1 = w.map((j) => j.map(HighBits)); // w1 ← HighBits(w)
|
363
|
+
// Commitment hash: c˜ ∈{0, 1 2λ } ← H(µ||w1Encode(w1), 2λ)
|
364
|
+
const cTilde = sha3_1.shake256
|
365
|
+
.create({ dkLen: C_TILDE_BYTES })
|
366
|
+
.update(mu)
|
367
|
+
.update(W1Vec.encode(w1))
|
368
|
+
.digest();
|
369
|
+
// Verifer’s challenge
|
370
|
+
const cHat = NTT.encode(SampleInBall(cTilde.subarray(0, 32))); // c ← SampleInBall(c˜1); cˆ ← NTT(c)
|
371
|
+
// ⟨⟨cs1⟩⟩ ← NTT−1(cˆ◦ sˆ1)
|
372
|
+
const cs1 = s1.map((i) => MultiplyNTTs(i, cHat));
|
373
|
+
for (let i = 0; i < L; i++) {
|
374
|
+
polyAdd(NTT.decode(cs1[i]), y[i]); // z ← y + ⟨⟨cs1⟩⟩
|
375
|
+
if (polyChknorm(cs1[i], GAMMA1 - BETA))
|
376
|
+
continue main_loop; // ||z||∞ ≥ γ1 − β
|
377
|
+
}
|
378
|
+
// cs1 is now z (▷ Signer’s response)
|
379
|
+
let cnt = 0;
|
380
|
+
const h = [];
|
381
|
+
for (let i = 0; i < K; i++) {
|
382
|
+
const cs2 = NTT.decode(MultiplyNTTs(s2[i], cHat)); // ⟨⟨cs2⟩⟩ ← NTT−1(cˆ◦ sˆ2)
|
383
|
+
const r0 = polySub(w[i], cs2).map(LowBits); // r0 ← LowBits(w − ⟨⟨cs2⟩⟩)
|
384
|
+
if (polyChknorm(r0, GAMMA2 - BETA))
|
385
|
+
continue main_loop; // ||r0||∞ ≥ γ2 − β
|
386
|
+
const ct0 = NTT.decode(MultiplyNTTs(t0[i], cHat)); // ⟨⟨ct0⟩⟩ ← NTT−1(cˆ◦ tˆ0)
|
387
|
+
if (polyChknorm(ct0, GAMMA2))
|
388
|
+
continue main_loop;
|
389
|
+
polyAdd(r0, ct0);
|
390
|
+
// ▷ Signer’s hint
|
391
|
+
const hint = polyMakeHint(r0, w1[i]); // h ← MakeHint(−⟨⟨ct0⟩⟩, w− ⟨⟨cs2⟩⟩ + ⟨⟨ct0⟩⟩)
|
392
|
+
h.push(hint.v);
|
393
|
+
cnt += hint.cnt;
|
394
|
+
}
|
395
|
+
if (cnt > OMEGA)
|
396
|
+
continue; // the number of 1’s in h is greater than ω
|
397
|
+
x256.clean();
|
398
|
+
const res = sigCoder.encode([cTilde, cs1, h]); // σ ← sigEncode(c˜, z mod±q, h)
|
399
|
+
// rho, _K, tr is subarray of secretKey, cannot clean.
|
400
|
+
(0, utils_js_1.cleanBytes)(cTilde, cs1, h, cHat, w1, w, z, y, rhoprime, mu, s1, s2, t0, ...A);
|
401
|
+
return res;
|
402
|
+
}
|
403
|
+
// @ts-ignore
|
404
|
+
throw new Error('Unreachable code path reached, report this error');
|
405
|
+
},
|
406
|
+
verify: (publicKey, msg, sig) => {
|
407
|
+
// ML-DSA.Verify(pk, M, σ): Verifes a signature σ for a message M.
|
408
|
+
const [rho, t1] = publicCoder.decode(publicKey); // (ρ, t1) ← pkDecode(pk)
|
409
|
+
const tr = (0, sha3_1.shake256)(publicKey, { dkLen: TR_BYTES }); // 6: tr ← H(BytesToBits(pk), 512)
|
410
|
+
if (sig.length !== sigCoder.bytesLen)
|
411
|
+
return false; // return false instead of exception
|
412
|
+
const [cTilde, z, h] = sigCoder.decode(sig); // (c˜, z, h) ← sigDecode(σ), ▷ Signer’s commitment hash c ˜, response z and hint
|
413
|
+
if (h === false)
|
414
|
+
return false; // if h = ⊥ then return false
|
415
|
+
for (let i = 0; i < L; i++)
|
416
|
+
if (polyChknorm(z[i], GAMMA1 - BETA))
|
417
|
+
return false;
|
418
|
+
const mu = sha3_1.shake256.create({ dkLen: CRH_BYTES }).update(tr).update(msg).digest(); // 7: µ ← H(tr||M, 512)
|
419
|
+
// Compute verifer’s challenge from c˜
|
420
|
+
const c = NTT.encode(SampleInBall(cTilde.subarray(0, 32))); // c ← SampleInBall(c˜1)
|
421
|
+
const zNtt = z.map((i) => i.slice()); // zNtt = NTT(z)
|
422
|
+
for (let i = 0; i < L; i++)
|
423
|
+
NTT.encode(zNtt[i]);
|
424
|
+
const wTick1 = [];
|
425
|
+
const xof = XOF128(rho);
|
426
|
+
for (let i = 0; i < K; i++) {
|
427
|
+
const ct12d = MultiplyNTTs(NTT.encode(polyShiftl(t1[i])), c); //c * t1 * (2**d)
|
428
|
+
const Az = newPoly(N); // // A * z
|
429
|
+
for (let j = 0; j < L; j++) {
|
430
|
+
const aij = RejNTTPoly(xof.get(j, i)); // A[i][j] inplace
|
431
|
+
polyAdd(Az, MultiplyNTTs(aij, zNtt[j]));
|
432
|
+
}
|
433
|
+
// wApprox = A*z - c*t1 * (2**d)
|
434
|
+
const wApprox = NTT.decode(polySub(Az, ct12d));
|
435
|
+
// Reconstruction of signer’s commitment
|
436
|
+
wTick1.push(polyUseHint(wApprox, h[i])); // w ′ ← UseHint(h, w'approx )
|
437
|
+
}
|
438
|
+
xof.clean();
|
439
|
+
// c˜′← H (µ||w1Encode(w′1), 2λ), Hash it; this should match c˜
|
440
|
+
const c2 = sha3_1.shake256
|
441
|
+
.create({ dkLen: C_TILDE_BYTES })
|
442
|
+
.update(mu)
|
443
|
+
.update(W1Vec.encode(wTick1))
|
444
|
+
.digest();
|
445
|
+
if (FIPS204) {
|
446
|
+
// Additional checks in FIPS-204:
|
447
|
+
// [[ ||z||∞ < γ1 − β ]] and [[c ˜ = c˜′]] and [[number of 1’s in h is ≤ ω]]
|
448
|
+
for (const t of h) {
|
449
|
+
const sum = t.reduce((acc, i) => acc + i, 0);
|
450
|
+
if (!(sum <= OMEGA))
|
451
|
+
return false;
|
452
|
+
}
|
453
|
+
for (const t of z)
|
454
|
+
if (polyChknorm(t, GAMMA1 - BETA))
|
455
|
+
return false;
|
456
|
+
}
|
457
|
+
return (0, utils_js_1.equalBytes)(cTilde, c2);
|
458
|
+
},
|
459
|
+
};
|
460
|
+
}
|
461
|
+
function getDilithiumVersions(cfg) {
|
462
|
+
return {
|
463
|
+
dilithium2: getDilithium({ ...exports.PARAMS[2], ...cfg }),
|
464
|
+
dilithium3: getDilithium({ ...exports.PARAMS[3], ...cfg }),
|
465
|
+
dilithium5: getDilithium({ ...exports.PARAMS[5], ...cfg }),
|
466
|
+
};
|
467
|
+
}
|
468
|
+
// v30 is NIST round 3 submission, for original vectors and benchmarking.
|
469
|
+
// v31 is kyber: more secure than v30.
|
470
|
+
// ml-dsa is NIST FIPS 204, but it is still a draft and may change.
|
471
|
+
exports.dilithium_v30 = getDilithiumVersions({
|
472
|
+
CRH_BYTES: 48,
|
473
|
+
TR_BYTES: 48,
|
474
|
+
C_TILDE_BYTES: 32,
|
475
|
+
XOF128: _crystals_js_1.XOF128,
|
476
|
+
XOF256: _crystals_js_1.XOF256,
|
477
|
+
});
|
478
|
+
exports.dilithium_v31 = getDilithiumVersions({
|
479
|
+
CRH_BYTES: 64,
|
480
|
+
TR_BYTES: 32,
|
481
|
+
C_TILDE_BYTES: 32,
|
482
|
+
XOF128: _crystals_js_1.XOF128,
|
483
|
+
XOF256: _crystals_js_1.XOF256,
|
484
|
+
V31: true,
|
485
|
+
});
|
486
|
+
exports.dilithium_v30_aes = getDilithiumVersions({
|
487
|
+
CRH_BYTES: 48,
|
488
|
+
TR_BYTES: 48,
|
489
|
+
C_TILDE_BYTES: 32,
|
490
|
+
XOF128: _crystals_js_1.XOF_AES,
|
491
|
+
XOF256: _crystals_js_1.XOF_AES,
|
492
|
+
});
|
493
|
+
exports.dilithium_v31_aes = getDilithiumVersions({
|
494
|
+
CRH_BYTES: 64,
|
495
|
+
TR_BYTES: 32,
|
496
|
+
C_TILDE_BYTES: 32,
|
497
|
+
XOF128: _crystals_js_1.XOF_AES,
|
498
|
+
XOF256: _crystals_js_1.XOF_AES,
|
499
|
+
V31: true,
|
500
|
+
});
|
501
|
+
// ML-DSA
|
502
|
+
exports.ml_dsa44 = getDilithium({
|
503
|
+
...exports.PARAMS[2],
|
504
|
+
CRH_BYTES: 64,
|
505
|
+
TR_BYTES: 64,
|
506
|
+
C_TILDE_BYTES: 32,
|
507
|
+
XOF128: _crystals_js_1.XOF128,
|
508
|
+
XOF256: _crystals_js_1.XOF256,
|
509
|
+
V31: true,
|
510
|
+
FIPS204: true,
|
511
|
+
});
|
512
|
+
exports.ml_dsa65 = getDilithium({
|
513
|
+
...exports.PARAMS[3],
|
514
|
+
CRH_BYTES: 64,
|
515
|
+
TR_BYTES: 64,
|
516
|
+
C_TILDE_BYTES: 48,
|
517
|
+
XOF128: _crystals_js_1.XOF128,
|
518
|
+
XOF256: _crystals_js_1.XOF256,
|
519
|
+
V31: true,
|
520
|
+
FIPS204: true,
|
521
|
+
});
|
522
|
+
exports.ml_dsa87 = getDilithium({
|
523
|
+
...exports.PARAMS[5],
|
524
|
+
CRH_BYTES: 64,
|
525
|
+
TR_BYTES: 64,
|
526
|
+
C_TILDE_BYTES: 64,
|
527
|
+
XOF128: _crystals_js_1.XOF128,
|
528
|
+
XOF256: _crystals_js_1.XOF256,
|
529
|
+
V31: true,
|
530
|
+
FIPS204: true,
|
531
|
+
});
|
532
|
+
//# sourceMappingURL=ml-dsa.js.map
|