@theqrl/dilithium5 0.1.0 → 0.2.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/dist/{dilithium5.cjs.js → cjs/dilithium5.js} +251 -521
- package/dist/cjs/package.json +3 -0
- package/dist/{dilithium5.esm.js → mjs/dilithium5.js} +252 -503
- package/dist/mjs/package.json +3 -0
- package/package.json +10 -8
- package/src/index.d.ts +194 -0
- package/src/index.js +1 -0
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import
|
|
2
|
-
|
|
3
|
-
import { SHAKE } from 'sha3';
|
|
4
|
-
export { SHAKE } from 'sha3';
|
|
1
|
+
import { shake128, shake256 } from '@noble/hashes/sha3';
|
|
2
|
+
import pkg from 'randombytes';
|
|
5
3
|
|
|
6
4
|
const Shake128Rate = 168;
|
|
7
5
|
const Shake256Rate = 136;
|
|
@@ -10,6 +8,7 @@ const Stream256BlockBytes = Shake256Rate;
|
|
|
10
8
|
|
|
11
9
|
const SeedBytes = 32;
|
|
12
10
|
const CRHBytes = 64;
|
|
11
|
+
const TRBytes = 64;
|
|
13
12
|
const N = 256;
|
|
14
13
|
const Q = 8380417;
|
|
15
14
|
const QInv = 58728449;
|
|
@@ -33,7 +32,7 @@ const PolyW1PackedBytes = 128;
|
|
|
33
32
|
|
|
34
33
|
const CryptoPublicKeyBytes = SeedBytes + K * PolyT1PackedBytes;
|
|
35
34
|
const CryptoSecretKeyBytes =
|
|
36
|
-
|
|
35
|
+
2 * SeedBytes + TRBytes + L * PolyETAPackedBytes + K * PolyETAPackedBytes + K * PolyT0PackedBytes;
|
|
37
36
|
const CryptoBytes = SeedBytes + L * PolyZPackedBytes + PolyVecHPackedBytes;
|
|
38
37
|
|
|
39
38
|
const PolyUniformNBlocks = Math.floor((768 + Stream128BlockBytes - 1) / Stream128BlockBytes);
|
|
@@ -64,452 +63,65 @@ const zetas = [
|
|
|
64
63
|
-1362209, 3937738, 1400424, -846154, 1976782,
|
|
65
64
|
];
|
|
66
65
|
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
0x0000000000008082n,
|
|
72
|
-
0x800000000000808an,
|
|
73
|
-
0x8000000080008000n,
|
|
74
|
-
0x000000000000808bn,
|
|
75
|
-
0x0000000080000001n,
|
|
76
|
-
0x8000000080008081n,
|
|
77
|
-
0x8000000000008009n,
|
|
78
|
-
0x000000000000008an,
|
|
79
|
-
0x0000000000000088n,
|
|
80
|
-
0x0000000080008009n,
|
|
81
|
-
0x000000008000000an,
|
|
82
|
-
0x000000008000808bn,
|
|
83
|
-
0x800000000000008bn,
|
|
84
|
-
0x8000000000008089n,
|
|
85
|
-
0x8000000000008003n,
|
|
86
|
-
0x8000000000008002n,
|
|
87
|
-
0x8000000000000080n,
|
|
88
|
-
0x000000000000800an,
|
|
89
|
-
0x800000008000000an,
|
|
90
|
-
0x8000000080008081n,
|
|
91
|
-
0x8000000000008080n,
|
|
92
|
-
0x0000000080000001n,
|
|
93
|
-
0x8000000080008008n,
|
|
94
|
-
]);
|
|
66
|
+
/**
|
|
67
|
+
* FIPS 202 SHAKE functions using @noble/hashes
|
|
68
|
+
* Provides streaming XOF (extendable output function) interface
|
|
69
|
+
*/
|
|
95
70
|
|
|
71
|
+
|
|
72
|
+
/**
|
|
73
|
+
* Keccak state wrapper for @noble/hashes
|
|
74
|
+
* Maintains hasher instance for streaming operations
|
|
75
|
+
*/
|
|
96
76
|
class KeccakState {
|
|
97
77
|
constructor() {
|
|
98
|
-
this.
|
|
99
|
-
this.
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
function ROL(a, offset) {
|
|
104
|
-
return BigInt.asUintN(64, BigInt.asUintN(64, a << offset) ^ (a >> (64n - offset)));
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
function load64(x, xOffset) {
|
|
108
|
-
let r = BigInt(0);
|
|
109
|
-
|
|
110
|
-
for (let i = 0; i < 8; i++) r = BigInt.asUintN(64, r | BigInt.asUintN(64, BigInt(x[xOffset + i]) << BigInt(8 * i)));
|
|
111
|
-
|
|
112
|
-
return r;
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
function store64(xP, xOffset, u) {
|
|
116
|
-
const x = xP;
|
|
117
|
-
for (let i = 0; i < 8; i++) x[xOffset + i] = Number((u >> BigInt(8 * i)) & 0xffn);
|
|
118
|
-
}
|
|
119
|
-
|
|
120
|
-
function KeccakF1600StatePermute(stateP) {
|
|
121
|
-
const state = stateP;
|
|
122
|
-
// copyFromState(A, state)
|
|
123
|
-
let Aba = state[0];
|
|
124
|
-
let Abe = state[1];
|
|
125
|
-
let Abi = state[2];
|
|
126
|
-
let Abo = state[3];
|
|
127
|
-
let Abu = state[4];
|
|
128
|
-
let Aga = state[5];
|
|
129
|
-
let Age = state[6];
|
|
130
|
-
let Agi = state[7];
|
|
131
|
-
let Ago = state[8];
|
|
132
|
-
let Agu = state[9];
|
|
133
|
-
let Aka = state[10];
|
|
134
|
-
let Ake = state[11];
|
|
135
|
-
let Aki = state[12];
|
|
136
|
-
let Ako = state[13];
|
|
137
|
-
let Aku = state[14];
|
|
138
|
-
let Ama = state[15];
|
|
139
|
-
let Ame = state[16];
|
|
140
|
-
let Ami = state[17];
|
|
141
|
-
let Amo = state[18];
|
|
142
|
-
let Amu = state[19];
|
|
143
|
-
let Asa = state[20];
|
|
144
|
-
let Ase = state[21];
|
|
145
|
-
let Asi = state[22];
|
|
146
|
-
let Aso = state[23];
|
|
147
|
-
let Asu = state[24];
|
|
148
|
-
|
|
149
|
-
for (let round = 0; round < NRounds; round += 2) {
|
|
150
|
-
// prepareTheta
|
|
151
|
-
let BCa = BigInt.asUintN(64, Aba ^ Aga ^ Aka ^ Ama ^ Asa);
|
|
152
|
-
let BCe = BigInt.asUintN(64, Abe ^ Age ^ Ake ^ Ame ^ Ase);
|
|
153
|
-
let BCi = BigInt.asUintN(64, Abi ^ Agi ^ Aki ^ Ami ^ Asi);
|
|
154
|
-
let BCo = BigInt.asUintN(64, Abo ^ Ago ^ Ako ^ Amo ^ Aso);
|
|
155
|
-
let BCu = BigInt.asUintN(64, Abu ^ Agu ^ Aku ^ Amu ^ Asu);
|
|
156
|
-
|
|
157
|
-
// thetaRhoPiChiIotaPrepareTheta(round, A, E)
|
|
158
|
-
let Da = BigInt.asUintN(64, BCu ^ ROL(BCe, 1n));
|
|
159
|
-
let De = BigInt.asUintN(64, BCa ^ ROL(BCi, 1n));
|
|
160
|
-
let Di = BigInt.asUintN(64, BCe ^ ROL(BCo, 1n));
|
|
161
|
-
let Do = BigInt.asUintN(64, BCi ^ ROL(BCu, 1n));
|
|
162
|
-
let Du = BigInt.asUintN(64, BCo ^ ROL(BCa, 1n));
|
|
163
|
-
|
|
164
|
-
Aba = BigInt.asUintN(64, Aba ^ Da);
|
|
165
|
-
BCa = Aba;
|
|
166
|
-
Age = BigInt.asUintN(64, Age ^ De);
|
|
167
|
-
BCe = ROL(Age, 44n);
|
|
168
|
-
Aki = BigInt.asUintN(64, Aki ^ Di);
|
|
169
|
-
BCi = ROL(Aki, 43n);
|
|
170
|
-
Amo = BigInt.asUintN(64, Amo ^ Do);
|
|
171
|
-
BCo = ROL(Amo, 21n);
|
|
172
|
-
Asu = BigInt.asUintN(64, Asu ^ Du);
|
|
173
|
-
BCu = ROL(Asu, 14n);
|
|
174
|
-
let Eba = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
|
|
175
|
-
Eba = BigInt.asUintN(64, Eba ^ KeccakFRoundConstants[round]);
|
|
176
|
-
let Ebe = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
|
|
177
|
-
let Ebi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
|
|
178
|
-
let Ebo = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
|
|
179
|
-
let Ebu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
|
|
180
|
-
|
|
181
|
-
Abo = BigInt.asUintN(64, Abo ^ Do);
|
|
182
|
-
BCa = ROL(Abo, 28n);
|
|
183
|
-
Agu = BigInt.asUintN(64, Agu ^ Du);
|
|
184
|
-
BCe = ROL(Agu, 20n);
|
|
185
|
-
Aka = BigInt.asUintN(64, Aka ^ Da);
|
|
186
|
-
BCi = ROL(Aka, 3n);
|
|
187
|
-
Ame = BigInt.asUintN(64, Ame ^ De);
|
|
188
|
-
BCo = ROL(Ame, 45n);
|
|
189
|
-
Asi = BigInt.asUintN(64, Asi ^ Di);
|
|
190
|
-
BCu = ROL(Asi, 61n);
|
|
191
|
-
let Ega = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
|
|
192
|
-
let Ege = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
|
|
193
|
-
let Egi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
|
|
194
|
-
let Ego = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
|
|
195
|
-
let Egu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
|
|
196
|
-
|
|
197
|
-
Abe = BigInt.asUintN(64, Abe ^ De);
|
|
198
|
-
BCa = ROL(Abe, 1n);
|
|
199
|
-
Agi = BigInt.asUintN(64, Agi ^ Di);
|
|
200
|
-
BCe = ROL(Agi, 6n);
|
|
201
|
-
Ako = BigInt.asUintN(64, Ako ^ Do);
|
|
202
|
-
BCi = ROL(Ako, 25n);
|
|
203
|
-
Amu = BigInt.asUintN(64, Amu ^ Du);
|
|
204
|
-
BCo = ROL(Amu, 8n);
|
|
205
|
-
Asa = BigInt.asUintN(64, Asa ^ Da);
|
|
206
|
-
BCu = ROL(Asa, 18n);
|
|
207
|
-
let Eka = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
|
|
208
|
-
let Eke = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
|
|
209
|
-
let Eki = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
|
|
210
|
-
let Eko = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
|
|
211
|
-
let Eku = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
|
|
212
|
-
|
|
213
|
-
Abu = BigInt.asUintN(64, Abu ^ Du);
|
|
214
|
-
BCa = ROL(Abu, 27n);
|
|
215
|
-
Aga = BigInt.asUintN(64, Aga ^ Da);
|
|
216
|
-
BCe = ROL(Aga, 36n);
|
|
217
|
-
Ake = BigInt.asUintN(64, Ake ^ De);
|
|
218
|
-
BCi = ROL(Ake, 10n);
|
|
219
|
-
Ami = BigInt.asUintN(64, Ami ^ Di);
|
|
220
|
-
BCo = ROL(Ami, 15n);
|
|
221
|
-
Aso = BigInt.asUintN(64, Aso ^ Do);
|
|
222
|
-
BCu = ROL(Aso, 56n);
|
|
223
|
-
let Ema = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
|
|
224
|
-
let Eme = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
|
|
225
|
-
let Emi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
|
|
226
|
-
let Emo = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
|
|
227
|
-
let Emu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
|
|
228
|
-
|
|
229
|
-
Abi = BigInt.asUintN(64, Abi ^ Di);
|
|
230
|
-
BCa = ROL(Abi, 62n);
|
|
231
|
-
Ago = BigInt.asUintN(64, Ago ^ Do);
|
|
232
|
-
BCe = ROL(Ago, 55n);
|
|
233
|
-
Aku = BigInt.asUintN(64, Aku ^ Du);
|
|
234
|
-
BCi = ROL(Aku, 39n);
|
|
235
|
-
Ama = BigInt.asUintN(64, Ama ^ Da);
|
|
236
|
-
BCo = ROL(Ama, 41n);
|
|
237
|
-
Ase = BigInt.asUintN(64, Ase ^ De);
|
|
238
|
-
BCu = ROL(Ase, 2n);
|
|
239
|
-
let Esa = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
|
|
240
|
-
let Ese = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
|
|
241
|
-
let Esi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
|
|
242
|
-
let Eso = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
|
|
243
|
-
let Esu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
|
|
244
|
-
|
|
245
|
-
// prepareTheta
|
|
246
|
-
BCa = BigInt.asUintN(64, Eba ^ Ega ^ Eka ^ Ema ^ Esa);
|
|
247
|
-
BCe = BigInt.asUintN(64, Ebe ^ Ege ^ Eke ^ Eme ^ Ese);
|
|
248
|
-
BCi = BigInt.asUintN(64, Ebi ^ Egi ^ Eki ^ Emi ^ Esi);
|
|
249
|
-
BCo = BigInt.asUintN(64, Ebo ^ Ego ^ Eko ^ Emo ^ Eso);
|
|
250
|
-
BCu = BigInt.asUintN(64, Ebu ^ Egu ^ Eku ^ Emu ^ Esu);
|
|
251
|
-
|
|
252
|
-
// thetaRhoPiChiIotaPrepareTheta(round+1, E, A)
|
|
253
|
-
Da = BigInt.asUintN(64, BCu ^ ROL(BCe, 1n));
|
|
254
|
-
De = BigInt.asUintN(64, BCa ^ ROL(BCi, 1n));
|
|
255
|
-
Di = BigInt.asUintN(64, BCe ^ ROL(BCo, 1n));
|
|
256
|
-
Do = BigInt.asUintN(64, BCi ^ ROL(BCu, 1n));
|
|
257
|
-
Du = BigInt.asUintN(64, BCo ^ ROL(BCa, 1n));
|
|
258
|
-
|
|
259
|
-
Eba = BigInt.asUintN(64, Eba ^ Da);
|
|
260
|
-
BCa = Eba;
|
|
261
|
-
Ege = BigInt.asUintN(64, Ege ^ De);
|
|
262
|
-
BCe = ROL(Ege, 44n);
|
|
263
|
-
Eki = BigInt.asUintN(64, Eki ^ Di);
|
|
264
|
-
BCi = ROL(Eki, 43n);
|
|
265
|
-
Emo = BigInt.asUintN(64, Emo ^ Do);
|
|
266
|
-
BCo = ROL(Emo, 21n);
|
|
267
|
-
Esu = BigInt.asUintN(64, Esu ^ Du);
|
|
268
|
-
BCu = ROL(Esu, 14n);
|
|
269
|
-
Aba = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
|
|
270
|
-
Aba = BigInt.asUintN(64, Aba ^ KeccakFRoundConstants[round + 1]);
|
|
271
|
-
Abe = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
|
|
272
|
-
Abi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
|
|
273
|
-
Abo = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
|
|
274
|
-
Abu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
|
|
275
|
-
|
|
276
|
-
Ebo = BigInt.asUintN(64, Ebo ^ Do);
|
|
277
|
-
BCa = ROL(Ebo, 28n);
|
|
278
|
-
Egu = BigInt.asUintN(64, Egu ^ Du);
|
|
279
|
-
BCe = ROL(Egu, 20n);
|
|
280
|
-
Eka = BigInt.asUintN(64, Eka ^ Da);
|
|
281
|
-
BCi = ROL(Eka, 3n);
|
|
282
|
-
Eme = BigInt.asUintN(64, Eme ^ De);
|
|
283
|
-
BCo = ROL(Eme, 45n);
|
|
284
|
-
Esi = BigInt.asUintN(64, Esi ^ Di);
|
|
285
|
-
BCu = ROL(Esi, 61n);
|
|
286
|
-
Aga = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
|
|
287
|
-
Age = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
|
|
288
|
-
Agi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
|
|
289
|
-
Ago = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
|
|
290
|
-
Agu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
|
|
291
|
-
|
|
292
|
-
Ebe = BigInt.asUintN(64, Ebe ^ De);
|
|
293
|
-
BCa = ROL(Ebe, 1n);
|
|
294
|
-
Egi = BigInt.asUintN(64, Egi ^ Di);
|
|
295
|
-
BCe = ROL(Egi, 6n);
|
|
296
|
-
Eko = BigInt.asUintN(64, Eko ^ Do);
|
|
297
|
-
BCi = ROL(Eko, 25n);
|
|
298
|
-
Emu = BigInt.asUintN(64, Emu ^ Du);
|
|
299
|
-
BCo = ROL(Emu, 8n);
|
|
300
|
-
Esa = BigInt.asUintN(64, Esa ^ Da);
|
|
301
|
-
BCu = ROL(Esa, 18n);
|
|
302
|
-
Aka = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
|
|
303
|
-
Ake = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
|
|
304
|
-
Aki = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
|
|
305
|
-
Ako = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
|
|
306
|
-
Aku = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
|
|
307
|
-
|
|
308
|
-
Ebu = BigInt.asUintN(64, Ebu ^ Du);
|
|
309
|
-
BCa = ROL(Ebu, 27n);
|
|
310
|
-
Ega = BigInt.asUintN(64, Ega ^ Da);
|
|
311
|
-
BCe = ROL(Ega, 36n);
|
|
312
|
-
Eke = BigInt.asUintN(64, Eke ^ De);
|
|
313
|
-
BCi = ROL(Eke, 10n);
|
|
314
|
-
Emi = BigInt.asUintN(64, Emi ^ Di);
|
|
315
|
-
BCo = ROL(Emi, 15n);
|
|
316
|
-
Eso = BigInt.asUintN(64, Eso ^ Do);
|
|
317
|
-
BCu = ROL(Eso, 56n);
|
|
318
|
-
Ama = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
|
|
319
|
-
Ame = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
|
|
320
|
-
Ami = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
|
|
321
|
-
Amo = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
|
|
322
|
-
Amu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
|
|
323
|
-
|
|
324
|
-
Ebi = BigInt.asUintN(64, Ebi ^ Di);
|
|
325
|
-
BCa = ROL(Ebi, 62n);
|
|
326
|
-
Ego = BigInt.asUintN(64, Ego ^ Do);
|
|
327
|
-
BCe = ROL(Ego, 55n);
|
|
328
|
-
Eku = BigInt.asUintN(64, Eku ^ Du);
|
|
329
|
-
BCi = ROL(Eku, 39n);
|
|
330
|
-
Ema = BigInt.asUintN(64, Ema ^ Da);
|
|
331
|
-
BCo = ROL(Ema, 41n);
|
|
332
|
-
Ese = BigInt.asUintN(64, Ese ^ De);
|
|
333
|
-
BCu = ROL(Ese, 2n);
|
|
334
|
-
Asa = BigInt.asUintN(64, BCa ^ (~BCe & BCi));
|
|
335
|
-
Ase = BigInt.asUintN(64, BCe ^ (~BCi & BCo));
|
|
336
|
-
Asi = BigInt.asUintN(64, BCi ^ (~BCo & BCu));
|
|
337
|
-
Aso = BigInt.asUintN(64, BCo ^ (~BCu & BCa));
|
|
338
|
-
Asu = BigInt.asUintN(64, BCu ^ (~BCa & BCe));
|
|
339
|
-
}
|
|
340
|
-
|
|
341
|
-
state[0] = Aba;
|
|
342
|
-
state[1] = Abe;
|
|
343
|
-
state[2] = Abi;
|
|
344
|
-
state[3] = Abo;
|
|
345
|
-
state[4] = Abu;
|
|
346
|
-
state[5] = Aga;
|
|
347
|
-
state[6] = Age;
|
|
348
|
-
state[7] = Agi;
|
|
349
|
-
state[8] = Ago;
|
|
350
|
-
state[9] = Agu;
|
|
351
|
-
state[10] = Aka;
|
|
352
|
-
state[11] = Ake;
|
|
353
|
-
state[12] = Aki;
|
|
354
|
-
state[13] = Ako;
|
|
355
|
-
state[14] = Aku;
|
|
356
|
-
state[15] = Ama;
|
|
357
|
-
state[16] = Ame;
|
|
358
|
-
state[17] = Ami;
|
|
359
|
-
state[18] = Amo;
|
|
360
|
-
state[19] = Amu;
|
|
361
|
-
state[20] = Asa;
|
|
362
|
-
state[21] = Ase;
|
|
363
|
-
state[22] = Asi;
|
|
364
|
-
state[23] = Aso;
|
|
365
|
-
state[24] = Asu;
|
|
366
|
-
}
|
|
367
|
-
|
|
368
|
-
function keccakInit(sP) {
|
|
369
|
-
const s = sP;
|
|
370
|
-
for (let i = 0; i < 25; i++) s[i] = 0n;
|
|
371
|
-
}
|
|
372
|
-
|
|
373
|
-
function keccakAbsorb(sP, posP, r, input) {
|
|
374
|
-
const s = sP;
|
|
375
|
-
let pos = posP;
|
|
376
|
-
let inLen = input.length;
|
|
377
|
-
let i;
|
|
378
|
-
let inputOffset = 0;
|
|
379
|
-
while (pos + inLen >= r) {
|
|
380
|
-
for (i = pos; i < r; i++)
|
|
381
|
-
s[Math.floor(i / 8)] = BigInt.asUintN(
|
|
382
|
-
64,
|
|
383
|
-
s[Math.floor(i / 8)] ^ (BigInt(input[inputOffset++]) << BigInt(8 * (i % 8)))
|
|
384
|
-
);
|
|
385
|
-
inLen -= r - pos;
|
|
386
|
-
KeccakF1600StatePermute(s);
|
|
387
|
-
pos = 0;
|
|
388
|
-
}
|
|
389
|
-
|
|
390
|
-
for (i = pos; i < pos + inLen; i++) {
|
|
391
|
-
s[Math.floor(i / 8)] = BigInt.asUintN(
|
|
392
|
-
64,
|
|
393
|
-
s[Math.floor(i / 8)] ^ (BigInt(input[inputOffset++]) << BigInt(8 * (i % 8)))
|
|
394
|
-
);
|
|
395
|
-
}
|
|
396
|
-
|
|
397
|
-
return i;
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
function keccakFinalize(sP, pos, r, p) {
|
|
401
|
-
const s = sP;
|
|
402
|
-
s[Math.floor(pos / 8)] = BigInt.asUintN(64, s[Math.floor(pos / 8)] ^ (BigInt(p) << BigInt(8 * (pos % 8))));
|
|
403
|
-
s[Math.floor(r / 8) - 1] = BigInt.asUintN(64, s[Math.floor(r / 8) - 1] ^ (1n << 63n));
|
|
404
|
-
}
|
|
405
|
-
|
|
406
|
-
function keccakSqueeze(outP, s, posP, r) {
|
|
407
|
-
let pos = posP;
|
|
408
|
-
const out = outP;
|
|
409
|
-
let outLen = out.length;
|
|
410
|
-
let outputOffset = 0;
|
|
411
|
-
let i = 0;
|
|
412
|
-
|
|
413
|
-
while (outLen) {
|
|
414
|
-
if (pos === r) {
|
|
415
|
-
KeccakF1600StatePermute(s);
|
|
416
|
-
pos = 0;
|
|
417
|
-
}
|
|
418
|
-
for (i = pos; i < r && i < pos + outLen; i++) out[outputOffset++] = s[Math.floor(i / 8)] >> BigInt(8 * (i % 8));
|
|
419
|
-
outLen -= i - pos;
|
|
420
|
-
pos = i;
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
return pos;
|
|
424
|
-
}
|
|
425
|
-
|
|
426
|
-
function keccakAbsorbOnce(sP, r, input, p) {
|
|
427
|
-
const s = sP;
|
|
428
|
-
let inLen = input.length;
|
|
429
|
-
let inputOffset = 0;
|
|
430
|
-
let i;
|
|
431
|
-
|
|
432
|
-
for (i = 0; i < 25; i++) s[i] = 0;
|
|
433
|
-
|
|
434
|
-
while (inLen >= r) {
|
|
435
|
-
for (i = 0; i < Math.floor(r / 8); i++) s[i] = BigInt.asUintN(64, s[i] ^ load64(input, inputOffset + 8 * i));
|
|
436
|
-
inputOffset += r;
|
|
437
|
-
inLen -= r;
|
|
438
|
-
KeccakF1600StatePermute(s);
|
|
439
|
-
}
|
|
440
|
-
|
|
441
|
-
for (i = 0; i < inLen; i++)
|
|
442
|
-
s[Math.floor(i / 8)] = BigInt.asUintN(
|
|
443
|
-
64,
|
|
444
|
-
s[Math.floor(i / 8)] ^ (BigInt(input[inputOffset + i]) << BigInt(8 * (i % 8)))
|
|
445
|
-
);
|
|
446
|
-
|
|
447
|
-
s[Math.floor(i / 8)] = BigInt.asUintN(64, s[Math.floor(i / 8)] ^ (BigInt(p) << BigInt(8 * (i % 8))));
|
|
448
|
-
s[Math.floor((r - 1) / 8)] = BigInt.asUintN(64, s[Math.floor((r - 1) / 8)] ^ (1n << 63n));
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
function keccakSqueezeBlocks(output, outputOffsetP, nBlocksP, s, r) {
|
|
452
|
-
let nBlocks = nBlocksP;
|
|
453
|
-
let outputOffset = outputOffsetP;
|
|
454
|
-
while (nBlocks) {
|
|
455
|
-
KeccakF1600StatePermute(s);
|
|
456
|
-
for (let i = 0; i < Math.floor(r / 8); i++) store64(output, outputOffset + 8 * i, s[i]);
|
|
457
|
-
outputOffset += r;
|
|
458
|
-
nBlocks -= 1;
|
|
78
|
+
this.hasher = null;
|
|
79
|
+
this.finalized = false;
|
|
459
80
|
}
|
|
460
81
|
}
|
|
461
82
|
|
|
462
|
-
|
|
463
|
-
const state = stateP;
|
|
464
|
-
keccakInit(state.s);
|
|
465
|
-
state.pos = 0;
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
function shake128Absorb(stateP, input) {
|
|
469
|
-
const state = stateP;
|
|
470
|
-
state.pos = keccakAbsorb(state.s, state.pos, Shake128Rate, input);
|
|
471
|
-
}
|
|
83
|
+
// SHAKE-128 functions
|
|
472
84
|
|
|
473
|
-
function
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
state.pos = Shake128Rate;
|
|
85
|
+
function shake128Init(state) {
|
|
86
|
+
state.hasher = shake128.create({});
|
|
87
|
+
state.finalized = false;
|
|
477
88
|
}
|
|
478
89
|
|
|
479
|
-
function
|
|
480
|
-
|
|
481
|
-
state.pos = keccakSqueeze(out, state.s, state.pos, Shake128Rate);
|
|
90
|
+
function shake128Absorb(state, input) {
|
|
91
|
+
state.hasher.update(input);
|
|
482
92
|
}
|
|
483
93
|
|
|
484
|
-
function
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
state.pos = Shake128Rate;
|
|
94
|
+
function shake128Finalize(state) {
|
|
95
|
+
// Mark as finalized - actual finalization happens on first xofInto call
|
|
96
|
+
state.finalized = true;
|
|
488
97
|
}
|
|
489
98
|
|
|
490
99
|
function shake128SqueezeBlocks(out, outputOffset, nBlocks, state) {
|
|
491
|
-
|
|
100
|
+
const len = nBlocks * Shake128Rate;
|
|
101
|
+
const output = out.subarray(outputOffset, outputOffset + len);
|
|
102
|
+
state.hasher.xofInto(output);
|
|
492
103
|
}
|
|
493
104
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
state.
|
|
105
|
+
// SHAKE-256 functions
|
|
106
|
+
|
|
107
|
+
function shake256Init(state) {
|
|
108
|
+
state.hasher = shake256.create({});
|
|
109
|
+
state.finalized = false;
|
|
498
110
|
}
|
|
499
111
|
|
|
500
|
-
function shake256Absorb(
|
|
501
|
-
|
|
502
|
-
state.pos = keccakAbsorb(state.s, state.pos, Shake256Rate, input);
|
|
112
|
+
function shake256Absorb(state, input) {
|
|
113
|
+
state.hasher.update(input);
|
|
503
114
|
}
|
|
504
115
|
|
|
505
|
-
function shake256Finalize(
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
state.pos = Shake256Rate;
|
|
116
|
+
function shake256Finalize(state) {
|
|
117
|
+
// Mark as finalized - actual finalization happens on first xofInto call
|
|
118
|
+
state.finalized = true;
|
|
509
119
|
}
|
|
510
120
|
|
|
511
121
|
function shake256SqueezeBlocks(out, outputOffset, nBlocks, state) {
|
|
512
|
-
|
|
122
|
+
const len = nBlocks * Shake256Rate;
|
|
123
|
+
const output = out.subarray(outputOffset, outputOffset + len);
|
|
124
|
+
state.hasher.xofInto(output);
|
|
513
125
|
}
|
|
514
126
|
|
|
515
127
|
function dilithiumShake128StreamInit(state, seed, nonce) {
|
|
@@ -567,9 +179,8 @@ function ntt(a) {
|
|
|
567
179
|
const zeta = zetas[++k];
|
|
568
180
|
for (j = start; j < start + len; ++j) {
|
|
569
181
|
const t = Number(montgomeryReduce(BigInt.asIntN(64, BigInt(zeta) * BigInt(a[j + len]))));
|
|
570
|
-
a[j + len] = a[j] - t;
|
|
571
|
-
|
|
572
|
-
a[j] = a[j] + t;
|
|
182
|
+
a[j + len] = a[j] - t;
|
|
183
|
+
a[j] += t;
|
|
573
184
|
}
|
|
574
185
|
}
|
|
575
186
|
}
|
|
@@ -585,15 +196,14 @@ function invNTTToMont(a) {
|
|
|
585
196
|
const zeta = BigInt.asIntN(32, BigInt(-zetas[--k]));
|
|
586
197
|
for (j = start; j < start + len; ++j) {
|
|
587
198
|
const t = a[j];
|
|
588
|
-
a[j] = t + a[j + len];
|
|
589
|
-
a[j + len] = t - a[j + len];
|
|
590
|
-
a[j + len] = Number(montgomeryReduce(BigInt.asIntN(64, zeta * BigInt(a[j + len]))));
|
|
199
|
+
a[j] = t + a[j + len];
|
|
200
|
+
a[j + len] = t - a[j + len];
|
|
201
|
+
a[j + len] = Number(montgomeryReduce(BigInt.asIntN(64, zeta * BigInt(a[j + len]))));
|
|
591
202
|
}
|
|
592
203
|
}
|
|
593
204
|
}
|
|
594
|
-
// eslint-disable-next-line no-shadow
|
|
595
205
|
for (let j = 0; j < N; ++j) {
|
|
596
|
-
a[j] = Number(montgomeryReduce(BigInt.asIntN(64, f * BigInt(a[j]))));
|
|
206
|
+
a[j] = Number(montgomeryReduce(BigInt.asIntN(64, f * BigInt(a[j]))));
|
|
597
207
|
}
|
|
598
208
|
}
|
|
599
209
|
|
|
@@ -946,7 +556,7 @@ function polyT0Pack(rP, rOffset, a) {
|
|
|
946
556
|
t[6] = (1 << (D - 1)) - a.coeffs[8 * i + 6];
|
|
947
557
|
t[7] = (1 << (D - 1)) - a.coeffs[8 * i + 7];
|
|
948
558
|
|
|
949
|
-
r[rOffset + 13 * i] = t[0];
|
|
559
|
+
r[rOffset + 13 * i] = t[0];
|
|
950
560
|
r[rOffset + 13 * i + 1] = t[0] >> 8;
|
|
951
561
|
r[rOffset + 13 * i + 1] |= t[1] << 5;
|
|
952
562
|
r[rOffset + 13 * i + 2] = t[1] >> 3;
|
|
@@ -1026,7 +636,7 @@ function polyZPack(rP, rOffset, a) {
|
|
|
1026
636
|
t[0] = GAMMA1 - a.coeffs[2 * i];
|
|
1027
637
|
t[1] = GAMMA1 - a.coeffs[2 * i + 1];
|
|
1028
638
|
|
|
1029
|
-
r[rOffset + 5 * i] = t[0];
|
|
639
|
+
r[rOffset + 5 * i] = t[0];
|
|
1030
640
|
r[rOffset + 5 * i + 1] = t[0] >> 8;
|
|
1031
641
|
r[rOffset + 5 * i + 2] = t[0] >> 16;
|
|
1032
642
|
r[rOffset + 5 * i + 2] |= t[1] << 4;
|
|
@@ -1073,7 +683,7 @@ function polyVecMatrixExpand(mat, rho) {
|
|
|
1073
683
|
|
|
1074
684
|
function polyVecMatrixPointWiseMontgomery(t, mat, v) {
|
|
1075
685
|
for (let i = 0; i < K; ++i) {
|
|
1076
|
-
polyVecLPointWiseAccMontgomery(t.vec[i], mat[i], v);
|
|
686
|
+
polyVecLPointWiseAccMontgomery(t.vec[i], mat[i], v);
|
|
1077
687
|
}
|
|
1078
688
|
}
|
|
1079
689
|
|
|
@@ -1274,10 +884,10 @@ function packSk(skp, rho, tr, key, t0, s1, s2) {
|
|
|
1274
884
|
}
|
|
1275
885
|
skOffset += SeedBytes;
|
|
1276
886
|
|
|
1277
|
-
for (let i = 0; i <
|
|
887
|
+
for (let i = 0; i < TRBytes; ++i) {
|
|
1278
888
|
sk[skOffset + i] = tr[i];
|
|
1279
889
|
}
|
|
1280
|
-
skOffset +=
|
|
890
|
+
skOffset += TRBytes;
|
|
1281
891
|
|
|
1282
892
|
for (let i = 0; i < L; ++i) {
|
|
1283
893
|
polyEtaPack(sk, skOffset + i * PolyETAPackedBytes, s1.vec[i]);
|
|
@@ -1309,10 +919,10 @@ function unpackSk(rhoP, trP, keyP, t0, s1, s2, sk) {
|
|
|
1309
919
|
}
|
|
1310
920
|
skOffset += SeedBytes;
|
|
1311
921
|
|
|
1312
|
-
for (let i = 0; i <
|
|
922
|
+
for (let i = 0; i < TRBytes; ++i) {
|
|
1313
923
|
tr[i] = sk[skOffset + i];
|
|
1314
924
|
}
|
|
1315
|
-
skOffset +=
|
|
925
|
+
skOffset += TRBytes;
|
|
1316
926
|
|
|
1317
927
|
for (let i = 0; i < L; ++i) {
|
|
1318
928
|
polyEtaUnpack(s1.vec[i], sk, skOffset + i * PolyETAPackedBytes);
|
|
@@ -1404,8 +1014,38 @@ function unpackSig(cP, z, hP, sig) {
|
|
|
1404
1014
|
return 0;
|
|
1405
1015
|
}
|
|
1406
1016
|
|
|
1407
|
-
const randomBytes =
|
|
1408
|
-
|
|
1017
|
+
const randomBytes = pkg;
|
|
1018
|
+
|
|
1019
|
+
/**
|
|
1020
|
+
* Convert hex string to Uint8Array
|
|
1021
|
+
* @param {string} hex - Hex-encoded string
|
|
1022
|
+
* @returns {Uint8Array} Decoded bytes
|
|
1023
|
+
* @private
|
|
1024
|
+
*/
|
|
1025
|
+
function hexToBytes(hex) {
|
|
1026
|
+
const len = hex.length / 2;
|
|
1027
|
+
const result = new Uint8Array(len);
|
|
1028
|
+
for (let i = 0; i < len; i++) {
|
|
1029
|
+
result[i] = parseInt(hex.substr(i * 2, 2), 16);
|
|
1030
|
+
}
|
|
1031
|
+
return result;
|
|
1032
|
+
}
|
|
1033
|
+
|
|
1034
|
+
/**
|
|
1035
|
+
* Generate a Dilithium-5 key pair.
|
|
1036
|
+
*
|
|
1037
|
+
* @param {Uint8Array|null} passedSeed - Optional 32-byte seed for deterministic key generation.
|
|
1038
|
+
* Pass null for random key generation.
|
|
1039
|
+
* @param {Uint8Array} pk - Output buffer for public key (must be CryptoPublicKeyBytes = 2592 bytes)
|
|
1040
|
+
* @param {Uint8Array} sk - Output buffer for secret key (must be CryptoSecretKeyBytes = 4896 bytes)
|
|
1041
|
+
* @returns {Uint8Array} The seed used for key generation (useful when passedSeed is null)
|
|
1042
|
+
* @throws {Error} If pk/sk buffers are null or wrong size, or if seed is wrong size
|
|
1043
|
+
*
|
|
1044
|
+
* @example
|
|
1045
|
+
* const pk = new Uint8Array(CryptoPublicKeyBytes);
|
|
1046
|
+
* const sk = new Uint8Array(CryptoSecretKeyBytes);
|
|
1047
|
+
* const seed = cryptoSignKeypair(null, pk, sk);
|
|
1048
|
+
*/
|
|
1409
1049
|
function cryptoSignKeypair(passedSeed, pk, sk) {
|
|
1410
1050
|
try {
|
|
1411
1051
|
if (pk.length !== CryptoPublicKeyBytes) {
|
|
@@ -1421,8 +1061,15 @@ function cryptoSignKeypair(passedSeed, pk, sk) {
|
|
|
1421
1061
|
throw new Error(`${e.message}`);
|
|
1422
1062
|
}
|
|
1423
1063
|
}
|
|
1424
|
-
|
|
1425
|
-
|
|
1064
|
+
|
|
1065
|
+
// Validate seed length if provided
|
|
1066
|
+
if (passedSeed !== null && passedSeed !== undefined) {
|
|
1067
|
+
if (passedSeed.length !== SeedBytes) {
|
|
1068
|
+
throw new Error(`invalid seed length ${passedSeed.length} | Expected length ${SeedBytes}`);
|
|
1069
|
+
}
|
|
1070
|
+
}
|
|
1071
|
+
|
|
1072
|
+
const mat = new Array(K).fill().map(() => new PolyVecL());
|
|
1426
1073
|
const s1 = new PolyVecL();
|
|
1427
1074
|
const s2 = new PolyVecK();
|
|
1428
1075
|
const t1 = new PolyVecK();
|
|
@@ -1431,10 +1078,8 @@ function cryptoSignKeypair(passedSeed, pk, sk) {
|
|
|
1431
1078
|
// Get randomness for rho, rhoPrime and key
|
|
1432
1079
|
const seed = passedSeed || randomBytes(SeedBytes);
|
|
1433
1080
|
|
|
1434
|
-
const
|
|
1435
|
-
|
|
1436
|
-
state.update(seed);
|
|
1437
|
-
const seedBuf = state.digest({ buffer: Buffer.alloc(outputLength) });
|
|
1081
|
+
const outputLength = 2 * SeedBytes + CRHBytes;
|
|
1082
|
+
const seedBuf = shake256.create({}).update(seed).xof(outputLength);
|
|
1438
1083
|
const rho = seedBuf.slice(0, SeedBytes);
|
|
1439
1084
|
const rhoPrime = seedBuf.slice(SeedBytes, SeedBytes + CRHBytes);
|
|
1440
1085
|
const key = seedBuf.slice(SeedBytes + CRHBytes);
|
|
@@ -1463,30 +1108,42 @@ function cryptoSignKeypair(passedSeed, pk, sk) {
|
|
|
1463
1108
|
packPk(pk, rho, t1);
|
|
1464
1109
|
|
|
1465
1110
|
// Compute H(rho, t1) and write secret key
|
|
1466
|
-
const
|
|
1467
|
-
outputLength = SeedBytes;
|
|
1468
|
-
hasher.update(Buffer.from(pk, 'hex'));
|
|
1469
|
-
const tr = new Uint8Array(hasher.digest());
|
|
1111
|
+
const tr = shake256.create({}).update(pk).xof(TRBytes);
|
|
1470
1112
|
packSk(sk, rho, tr, key, t0, s1, s2);
|
|
1471
1113
|
|
|
1472
1114
|
return seed;
|
|
1473
1115
|
}
|
|
1474
1116
|
|
|
1117
|
+
/**
|
|
1118
|
+
* Create a detached signature for a message.
|
|
1119
|
+
*
|
|
1120
|
+
* Uses the Dilithium-5 (Round 3) signing algorithm with rejection sampling.
|
|
1121
|
+
*
|
|
1122
|
+
* @param {Uint8Array} sig - Output buffer for signature (must be at least CryptoBytes = 4595 bytes)
|
|
1123
|
+
* @param {string|Uint8Array} m - Message to sign (hex string or Uint8Array)
|
|
1124
|
+
* @param {Uint8Array} sk - Secret key (must be CryptoSecretKeyBytes = 4896 bytes)
|
|
1125
|
+
* @param {boolean} randomizedSigning - If true, use random nonce for hedged signing.
|
|
1126
|
+
* If false, use deterministic nonce derived from message and key.
|
|
1127
|
+
* @returns {number} 0 on success
|
|
1128
|
+
* @throws {Error} If sk is wrong size
|
|
1129
|
+
*
|
|
1130
|
+
* @example
|
|
1131
|
+
* const sig = new Uint8Array(CryptoBytes);
|
|
1132
|
+
* cryptoSignSignature(sig, message, sk, false);
|
|
1133
|
+
*/
|
|
1475
1134
|
function cryptoSignSignature(sig, m, sk, randomizedSigning) {
|
|
1476
1135
|
if (sk.length !== CryptoSecretKeyBytes) {
|
|
1477
1136
|
throw new Error(`invalid sk length ${sk.length} | Expected length ${CryptoSecretKeyBytes}`);
|
|
1478
1137
|
}
|
|
1479
1138
|
|
|
1480
1139
|
const rho = new Uint8Array(SeedBytes);
|
|
1481
|
-
const tr = new Uint8Array(
|
|
1140
|
+
const tr = new Uint8Array(TRBytes);
|
|
1482
1141
|
const key = new Uint8Array(SeedBytes);
|
|
1483
1142
|
let rhoPrime = new Uint8Array(CRHBytes);
|
|
1484
1143
|
let nonce = 0;
|
|
1485
|
-
let state = null;
|
|
1486
1144
|
const mat = Array(K)
|
|
1487
1145
|
.fill()
|
|
1488
|
-
|
|
1489
|
-
.map((_) => new PolyVecL());
|
|
1146
|
+
.map(() => new PolyVecL());
|
|
1490
1147
|
const s1 = new PolyVecL();
|
|
1491
1148
|
const y = new PolyVecL();
|
|
1492
1149
|
const z = new PolyVecL();
|
|
@@ -1499,19 +1156,14 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
|
|
|
1499
1156
|
|
|
1500
1157
|
unpackSk(rho, tr, key, t0, s1, s2, sk);
|
|
1501
1158
|
|
|
1502
|
-
|
|
1503
|
-
|
|
1504
|
-
|
|
1505
|
-
state.update(Buffer.from(m, 'hex'));
|
|
1506
|
-
const mu = new Uint8Array(state.digest({ buffer: Buffer.alloc(outputLength) }));
|
|
1159
|
+
// Convert hex message to bytes
|
|
1160
|
+
const mBytes = typeof m === 'string' ? hexToBytes(m) : m;
|
|
1161
|
+
const mu = shake256.create({}).update(tr).update(mBytes).xof(CRHBytes);
|
|
1507
1162
|
|
|
1508
|
-
if (randomizedSigning)
|
|
1509
|
-
|
|
1510
|
-
|
|
1511
|
-
|
|
1512
|
-
state.update(Buffer.from(key, 'hex'));
|
|
1513
|
-
state.update(Buffer.from(mu, 'hex'));
|
|
1514
|
-
rhoPrime.set(state.digest({ buffer: Buffer.alloc(outputLength) }));
|
|
1163
|
+
if (randomizedSigning) {
|
|
1164
|
+
rhoPrime = new Uint8Array(randomBytes(CRHBytes));
|
|
1165
|
+
} else {
|
|
1166
|
+
rhoPrime = shake256.create({}).update(key).update(mu).xof(CRHBytes);
|
|
1515
1167
|
}
|
|
1516
1168
|
|
|
1517
1169
|
polyVecMatrixExpand(mat, rho);
|
|
@@ -1519,7 +1171,6 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
|
|
|
1519
1171
|
polyVecKNTT(s2);
|
|
1520
1172
|
polyVecKNTT(t0);
|
|
1521
1173
|
|
|
1522
|
-
// eslint-disable-next-line no-constant-condition
|
|
1523
1174
|
while (true) {
|
|
1524
1175
|
polyVecLUniformGamma1(y, rhoPrime, nonce++);
|
|
1525
1176
|
// Matrix-vector multiplication
|
|
@@ -1534,11 +1185,12 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
|
|
|
1534
1185
|
polyVecKDecompose(w1, w0, w1);
|
|
1535
1186
|
polyVecKPackW1(sig, w1);
|
|
1536
1187
|
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1188
|
+
const cHash = shake256
|
|
1189
|
+
.create({})
|
|
1190
|
+
.update(mu)
|
|
1191
|
+
.update(sig.slice(0, K * PolyW1PackedBytes))
|
|
1192
|
+
.xof(SeedBytes);
|
|
1193
|
+
sig.set(cHash);
|
|
1542
1194
|
|
|
1543
1195
|
polyChallenge(cp, sig);
|
|
1544
1196
|
polyNTT(cp);
|
|
@@ -1549,7 +1201,7 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
|
|
|
1549
1201
|
polyVecLAdd(z, z, y);
|
|
1550
1202
|
polyVecLReduce(z);
|
|
1551
1203
|
if (polyVecLChkNorm(z, GAMMA1 - BETA) !== 0) {
|
|
1552
|
-
continue;
|
|
1204
|
+
continue;
|
|
1553
1205
|
}
|
|
1554
1206
|
|
|
1555
1207
|
polyVecKPointWisePolyMontgomery(h, cp, s2);
|
|
@@ -1557,20 +1209,20 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
|
|
|
1557
1209
|
polyVecKSub(w0, w0, h);
|
|
1558
1210
|
polyVecKReduce(w0);
|
|
1559
1211
|
if (polyVecKChkNorm(w0, GAMMA2 - BETA) !== 0) {
|
|
1560
|
-
continue;
|
|
1212
|
+
continue;
|
|
1561
1213
|
}
|
|
1562
1214
|
|
|
1563
1215
|
polyVecKPointWisePolyMontgomery(h, cp, t0);
|
|
1564
1216
|
polyVecKInvNTTToMont(h);
|
|
1565
1217
|
polyVecKReduce(h);
|
|
1566
1218
|
if (polyVecKChkNorm(h, GAMMA2) !== 0) {
|
|
1567
|
-
continue;
|
|
1219
|
+
continue;
|
|
1568
1220
|
}
|
|
1569
1221
|
|
|
1570
1222
|
polyVecKAdd(w0, w0, h);
|
|
1571
1223
|
const n = polyVecKMakeHint(h, w0, w1);
|
|
1572
1224
|
if (n > OMEGA) {
|
|
1573
|
-
continue;
|
|
1225
|
+
continue;
|
|
1574
1226
|
}
|
|
1575
1227
|
|
|
1576
1228
|
packSig(sig, sig, z, h);
|
|
@@ -1578,6 +1230,22 @@ function cryptoSignSignature(sig, m, sk, randomizedSigning) {
|
|
|
1578
1230
|
}
|
|
1579
1231
|
}
|
|
1580
1232
|
|
|
1233
|
+
/**
|
|
1234
|
+
* Sign a message, returning signature concatenated with message.
|
|
1235
|
+
*
|
|
1236
|
+
* This is the combined sign operation that produces a "signed message" containing
|
|
1237
|
+
* both the signature and the original message (signature || message).
|
|
1238
|
+
*
|
|
1239
|
+
* @param {Uint8Array} msg - Message to sign
|
|
1240
|
+
* @param {Uint8Array} sk - Secret key (must be CryptoSecretKeyBytes = 4896 bytes)
|
|
1241
|
+
* @param {boolean} randomizedSigning - If true, use random nonce; if false, deterministic
|
|
1242
|
+
* @returns {Uint8Array} Signed message (CryptoBytes + msg.length bytes)
|
|
1243
|
+
* @throws {Error} If signing fails
|
|
1244
|
+
*
|
|
1245
|
+
* @example
|
|
1246
|
+
* const signedMsg = cryptoSign(message, sk, false);
|
|
1247
|
+
* // signedMsg contains: signature (4595 bytes) || message
|
|
1248
|
+
*/
|
|
1581
1249
|
function cryptoSign(msg, sk, randomizedSigning) {
|
|
1582
1250
|
const sm = new Uint8Array(CryptoBytes + msg.length);
|
|
1583
1251
|
const mLen = msg.length;
|
|
@@ -1592,6 +1260,22 @@ function cryptoSign(msg, sk, randomizedSigning) {
|
|
|
1592
1260
|
return sm;
|
|
1593
1261
|
}
|
|
1594
1262
|
|
|
1263
|
+
/**
|
|
1264
|
+
* Verify a detached signature.
|
|
1265
|
+
*
|
|
1266
|
+
* Performs constant-time verification to prevent timing side-channel attacks.
|
|
1267
|
+
*
|
|
1268
|
+
* @param {Uint8Array} sig - Signature to verify (must be CryptoBytes = 4595 bytes)
|
|
1269
|
+
* @param {string|Uint8Array} m - Message that was signed (hex string or Uint8Array)
|
|
1270
|
+
* @param {Uint8Array} pk - Public key (must be CryptoPublicKeyBytes = 2592 bytes)
|
|
1271
|
+
* @returns {boolean} true if signature is valid, false otherwise
|
|
1272
|
+
*
|
|
1273
|
+
* @example
|
|
1274
|
+
* const isValid = cryptoSignVerify(signature, message, pk);
|
|
1275
|
+
* if (!isValid) {
|
|
1276
|
+
* throw new Error('Invalid signature');
|
|
1277
|
+
* }
|
|
1278
|
+
*/
|
|
1595
1279
|
function cryptoSignVerify(sig, m, pk) {
|
|
1596
1280
|
let i;
|
|
1597
1281
|
const buf = new Uint8Array(K * PolyW1PackedBytes);
|
|
@@ -1600,8 +1284,7 @@ function cryptoSignVerify(sig, m, pk) {
|
|
|
1600
1284
|
const c = new Uint8Array(SeedBytes);
|
|
1601
1285
|
const c2 = new Uint8Array(SeedBytes);
|
|
1602
1286
|
const cp = new Poly();
|
|
1603
|
-
|
|
1604
|
-
const mat = new Array(K).fill().map((_) => new PolyVecL());
|
|
1287
|
+
const mat = new Array(K).fill().map(() => new PolyVecL());
|
|
1605
1288
|
const z = new PolyVecL();
|
|
1606
1289
|
const t1 = new PolyVecK();
|
|
1607
1290
|
const w1 = new PolyVecK();
|
|
@@ -1623,16 +1306,13 @@ function cryptoSignVerify(sig, m, pk) {
|
|
|
1623
1306
|
}
|
|
1624
1307
|
|
|
1625
1308
|
/* Compute CRH(H(rho, t1), msg) */
|
|
1626
|
-
|
|
1627
|
-
|
|
1628
|
-
state.update(pk.slice(0, CryptoPublicKeyBytes));
|
|
1629
|
-
mu.set(state.digest({ buffer: Buffer.alloc(outputLength) }));
|
|
1309
|
+
const tr = shake256.create({}).update(pk).xof(TRBytes);
|
|
1310
|
+
mu.set(tr);
|
|
1630
1311
|
|
|
1631
|
-
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
mu.set(state.digest({ buffer: Buffer.alloc(outputLength) }));
|
|
1312
|
+
// Convert hex message to bytes
|
|
1313
|
+
const mBytes = typeof m === 'string' ? hexToBytes(m) : m;
|
|
1314
|
+
const muFull = shake256.create({}).update(mu.slice(0, TRBytes)).update(mBytes).xof(CRHBytes);
|
|
1315
|
+
mu.set(muFull);
|
|
1636
1316
|
|
|
1637
1317
|
/* Matrix-vector multiplication; compute Az - c2^dt1 */
|
|
1638
1318
|
polyChallenge(cp, c);
|
|
@@ -1656,16 +1336,33 @@ function cryptoSignVerify(sig, m, pk) {
|
|
|
1656
1336
|
polyVecKPackW1(buf, w1);
|
|
1657
1337
|
|
|
1658
1338
|
/* Call random oracle and verify challenge */
|
|
1659
|
-
|
|
1660
|
-
|
|
1661
|
-
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
|
|
1666
|
-
|
|
1667
|
-
|
|
1668
|
-
|
|
1339
|
+
const c2Hash = shake256.create({}).update(mu).update(buf).xof(SeedBytes);
|
|
1340
|
+
c2.set(c2Hash);
|
|
1341
|
+
|
|
1342
|
+
// Constant-time comparison to prevent timing attacks
|
|
1343
|
+
let diff = 0;
|
|
1344
|
+
for (i = 0; i < SeedBytes; ++i) {
|
|
1345
|
+
diff |= c[i] ^ c2[i];
|
|
1346
|
+
}
|
|
1347
|
+
return diff === 0;
|
|
1348
|
+
}
|
|
1349
|
+
|
|
1350
|
+
/**
|
|
1351
|
+
* Open a signed message (verify and extract message).
|
|
1352
|
+
*
|
|
1353
|
+
* This is the counterpart to cryptoSign(). It verifies the signature and
|
|
1354
|
+
* extracts the original message from a signed message.
|
|
1355
|
+
*
|
|
1356
|
+
* @param {Uint8Array} sm - Signed message (signature || message)
|
|
1357
|
+
* @param {Uint8Array} pk - Public key (must be CryptoPublicKeyBytes = 2592 bytes)
|
|
1358
|
+
* @returns {Uint8Array|undefined} The original message if valid, undefined if verification fails
|
|
1359
|
+
*
|
|
1360
|
+
* @example
|
|
1361
|
+
* const message = cryptoSignOpen(signedMsg, pk);
|
|
1362
|
+
* if (message === undefined) {
|
|
1363
|
+
* throw new Error('Invalid signature');
|
|
1364
|
+
* }
|
|
1365
|
+
*/
|
|
1669
1366
|
function cryptoSignOpen(sm, pk) {
|
|
1670
1367
|
if (sm.length < CryptoBytes) {
|
|
1671
1368
|
return undefined;
|
|
@@ -1680,4 +1377,56 @@ function cryptoSignOpen(sm, pk) {
|
|
|
1680
1377
|
return msg;
|
|
1681
1378
|
}
|
|
1682
1379
|
|
|
1683
|
-
|
|
1380
|
+
/**
|
|
1381
|
+
* Security utilities for Dilithium5
|
|
1382
|
+
*
|
|
1383
|
+
* IMPORTANT: JavaScript cannot guarantee secure memory zeroization.
|
|
1384
|
+
* See SECURITY.md for details on limitations.
|
|
1385
|
+
*/
|
|
1386
|
+
|
|
1387
|
+
/**
|
|
1388
|
+
* Attempts to zero out a Uint8Array buffer.
|
|
1389
|
+
*
|
|
1390
|
+
* WARNING: This is a BEST-EFFORT operation. Due to JavaScript/JIT limitations:
|
|
1391
|
+
* - The write may be optimized away if the buffer is unused afterward
|
|
1392
|
+
* - Copies may exist in garbage collector memory
|
|
1393
|
+
* - Data may have been swapped to disk
|
|
1394
|
+
*
|
|
1395
|
+
* For high-security applications, consider native implementations (go-qrllib)
|
|
1396
|
+
* or hardware security modules.
|
|
1397
|
+
*
|
|
1398
|
+
* @param {Uint8Array} buffer - The buffer to zero
|
|
1399
|
+
* @returns {void}
|
|
1400
|
+
*/
|
|
1401
|
+
function zeroize(buffer) {
|
|
1402
|
+
if (!(buffer instanceof Uint8Array)) {
|
|
1403
|
+
throw new TypeError('zeroize requires a Uint8Array');
|
|
1404
|
+
}
|
|
1405
|
+
// Use fill(0) for zeroing - best effort
|
|
1406
|
+
buffer.fill(0);
|
|
1407
|
+
// Additional volatile-like access to discourage optimization
|
|
1408
|
+
// (This is a hint to the JIT, not a guarantee)
|
|
1409
|
+
if (buffer.length > 0 && buffer[0] !== 0) {
|
|
1410
|
+
throw new Error('zeroize failed'); // Should never happen
|
|
1411
|
+
}
|
|
1412
|
+
}
|
|
1413
|
+
|
|
1414
|
+
/**
|
|
1415
|
+
* Checks if a buffer is all zeros.
|
|
1416
|
+
* Uses constant-time comparison to avoid timing leaks.
|
|
1417
|
+
*
|
|
1418
|
+
* @param {Uint8Array} buffer - The buffer to check
|
|
1419
|
+
* @returns {boolean} True if all bytes are zero
|
|
1420
|
+
*/
|
|
1421
|
+
function isZero(buffer) {
|
|
1422
|
+
if (!(buffer instanceof Uint8Array)) {
|
|
1423
|
+
throw new TypeError('isZero requires a Uint8Array');
|
|
1424
|
+
}
|
|
1425
|
+
let acc = 0;
|
|
1426
|
+
for (let i = 0; i < buffer.length; i++) {
|
|
1427
|
+
acc |= buffer[i];
|
|
1428
|
+
}
|
|
1429
|
+
return acc === 0;
|
|
1430
|
+
}
|
|
1431
|
+
|
|
1432
|
+
export { BETA, CRHBytes, CryptoBytes, CryptoPublicKeyBytes, CryptoSecretKeyBytes, D, ETA, GAMMA1, GAMMA2, K, KeccakState, L, N, OMEGA, Poly, PolyETAPackedBytes, PolyT0PackedBytes, PolyT1PackedBytes, PolyUniformETANBlocks, PolyUniformGamma1NBlocks, PolyUniformNBlocks, PolyVecHPackedBytes, PolyVecK, PolyVecL, PolyW1PackedBytes, PolyZPackedBytes, Q, QInv, SeedBytes, Shake128Rate, Shake256Rate, Stream128BlockBytes, Stream256BlockBytes, TAU, TRBytes, cAddQ, cryptoSign, cryptoSignKeypair, cryptoSignOpen, cryptoSignSignature, cryptoSignVerify, decompose, dilithiumShake128StreamInit, dilithiumShake256StreamInit, invNTTToMont, isZero, makeHint, montgomeryReduce, ntt, packPk, packSig, packSk, polyAdd, polyCAddQ, polyChallenge, polyChkNorm, polyDecompose, polyEtaPack, polyEtaUnpack, polyInvNTTToMont, polyMakeHint, polyNTT, polyPointWiseMontgomery, polyPower2round, polyReduce, polyShiftL, polySub, polyT0Pack, polyT0Unpack, polyT1Pack, polyT1Unpack, polyUniform, polyUniformEta, polyUniformGamma1, polyUseHint, polyVecKAdd, polyVecKCAddQ, polyVecKChkNorm, polyVecKDecompose, polyVecKInvNTTToMont, polyVecKMakeHint, polyVecKNTT, polyVecKPackW1, polyVecKPointWisePolyMontgomery, polyVecKPower2round, polyVecKReduce, polyVecKShiftL, polyVecKSub, polyVecKUniformEta, polyVecKUseHint, polyVecLAdd, polyVecLChkNorm, polyVecLInvNTTToMont, polyVecLNTT, polyVecLPointWiseAccMontgomery, polyVecLPointWisePolyMontgomery, polyVecLReduce, polyVecLUniformEta, polyVecLUniformGamma1, polyVecMatrixExpand, polyVecMatrixPointWiseMontgomery, polyW1Pack, polyZPack, polyZUnpack, power2round, reduce32, rejEta, rejUniform, shake128Absorb, shake128Finalize, shake128Init, shake128SqueezeBlocks, shake256Absorb, shake256Finalize, shake256Init, shake256SqueezeBlocks, unpackPk, unpackSig, unpackSk, useHint, zeroize, zetas };
|