@noble/post-quantum 0.1.0
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/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
|