ml_dsa 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.
Files changed (86) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +104 -0
  3. data/LICENSE +14 -0
  4. data/LICENSE-APACHE +185 -0
  5. data/LICENSE-MIT +21 -0
  6. data/README.md +234 -0
  7. data/ext/ml_dsa/extconf.rb +47 -0
  8. data/ext/ml_dsa/fips202.c +933 -0
  9. data/ext/ml_dsa/fips202.h +166 -0
  10. data/ext/ml_dsa/ml-dsa-44/clean/api.h +52 -0
  11. data/ext/ml_dsa/ml-dsa-44/clean/ntt.c +98 -0
  12. data/ext/ml_dsa/ml-dsa-44/clean/ntt.h +10 -0
  13. data/ext/ml_dsa/ml-dsa-44/clean/packing.c +261 -0
  14. data/ext/ml_dsa/ml-dsa-44/clean/packing.h +31 -0
  15. data/ext/ml_dsa/ml-dsa-44/clean/params.h +44 -0
  16. data/ext/ml_dsa/ml-dsa-44/clean/poly.c +848 -0
  17. data/ext/ml_dsa/ml-dsa-44/clean/poly.h +52 -0
  18. data/ext/ml_dsa/ml-dsa-44/clean/polyvec.c +415 -0
  19. data/ext/ml_dsa/ml-dsa-44/clean/polyvec.h +65 -0
  20. data/ext/ml_dsa/ml-dsa-44/clean/reduce.c +69 -0
  21. data/ext/ml_dsa/ml-dsa-44/clean/reduce.h +17 -0
  22. data/ext/ml_dsa/ml-dsa-44/clean/rounding.c +98 -0
  23. data/ext/ml_dsa/ml-dsa-44/clean/rounding.h +14 -0
  24. data/ext/ml_dsa/ml-dsa-44/clean/sign.c +417 -0
  25. data/ext/ml_dsa/ml-dsa-44/clean/sign.h +49 -0
  26. data/ext/ml_dsa/ml-dsa-44/clean/symmetric-shake.c +26 -0
  27. data/ext/ml_dsa/ml-dsa-44/clean/symmetric.h +34 -0
  28. data/ext/ml_dsa/ml-dsa-65/clean/api.h +52 -0
  29. data/ext/ml_dsa/ml-dsa-65/clean/ntt.c +98 -0
  30. data/ext/ml_dsa/ml-dsa-65/clean/ntt.h +10 -0
  31. data/ext/ml_dsa/ml-dsa-65/clean/packing.c +261 -0
  32. data/ext/ml_dsa/ml-dsa-65/clean/packing.h +31 -0
  33. data/ext/ml_dsa/ml-dsa-65/clean/params.h +44 -0
  34. data/ext/ml_dsa/ml-dsa-65/clean/poly.c +799 -0
  35. data/ext/ml_dsa/ml-dsa-65/clean/poly.h +52 -0
  36. data/ext/ml_dsa/ml-dsa-65/clean/polyvec.c +415 -0
  37. data/ext/ml_dsa/ml-dsa-65/clean/polyvec.h +65 -0
  38. data/ext/ml_dsa/ml-dsa-65/clean/reduce.c +69 -0
  39. data/ext/ml_dsa/ml-dsa-65/clean/reduce.h +17 -0
  40. data/ext/ml_dsa/ml-dsa-65/clean/rounding.c +92 -0
  41. data/ext/ml_dsa/ml-dsa-65/clean/rounding.h +14 -0
  42. data/ext/ml_dsa/ml-dsa-65/clean/sign.c +415 -0
  43. data/ext/ml_dsa/ml-dsa-65/clean/sign.h +49 -0
  44. data/ext/ml_dsa/ml-dsa-65/clean/symmetric-shake.c +26 -0
  45. data/ext/ml_dsa/ml-dsa-65/clean/symmetric.h +34 -0
  46. data/ext/ml_dsa/ml-dsa-87/clean/api.h +52 -0
  47. data/ext/ml_dsa/ml-dsa-87/clean/ntt.c +98 -0
  48. data/ext/ml_dsa/ml-dsa-87/clean/ntt.h +10 -0
  49. data/ext/ml_dsa/ml-dsa-87/clean/packing.c +261 -0
  50. data/ext/ml_dsa/ml-dsa-87/clean/packing.h +31 -0
  51. data/ext/ml_dsa/ml-dsa-87/clean/params.h +44 -0
  52. data/ext/ml_dsa/ml-dsa-87/clean/poly.c +823 -0
  53. data/ext/ml_dsa/ml-dsa-87/clean/poly.h +52 -0
  54. data/ext/ml_dsa/ml-dsa-87/clean/polyvec.c +415 -0
  55. data/ext/ml_dsa/ml-dsa-87/clean/polyvec.h +65 -0
  56. data/ext/ml_dsa/ml-dsa-87/clean/reduce.c +69 -0
  57. data/ext/ml_dsa/ml-dsa-87/clean/reduce.h +17 -0
  58. data/ext/ml_dsa/ml-dsa-87/clean/rounding.c +92 -0
  59. data/ext/ml_dsa/ml-dsa-87/clean/rounding.h +14 -0
  60. data/ext/ml_dsa/ml-dsa-87/clean/sign.c +415 -0
  61. data/ext/ml_dsa/ml-dsa-87/clean/sign.h +49 -0
  62. data/ext/ml_dsa/ml-dsa-87/clean/symmetric-shake.c +26 -0
  63. data/ext/ml_dsa/ml-dsa-87/clean/symmetric.h +34 -0
  64. data/ext/ml_dsa/ml_dsa_44_impl.c +10 -0
  65. data/ext/ml_dsa/ml_dsa_65_impl.c +10 -0
  66. data/ext/ml_dsa/ml_dsa_87_impl.c +10 -0
  67. data/ext/ml_dsa/ml_dsa_ext.c +1360 -0
  68. data/ext/ml_dsa/ml_dsa_impl_template.h +35 -0
  69. data/ext/ml_dsa/ml_dsa_internal.h +188 -0
  70. data/ext/ml_dsa/randombytes.c +48 -0
  71. data/ext/ml_dsa/randombytes.h +15 -0
  72. data/lib/ml_dsa/batch_builder.rb +57 -0
  73. data/lib/ml_dsa/config.rb +69 -0
  74. data/lib/ml_dsa/internal.rb +76 -0
  75. data/lib/ml_dsa/key_pair.rb +39 -0
  76. data/lib/ml_dsa/parameter_set.rb +89 -0
  77. data/lib/ml_dsa/public_key.rb +180 -0
  78. data/lib/ml_dsa/requests.rb +96 -0
  79. data/lib/ml_dsa/secret_key.rb +221 -0
  80. data/lib/ml_dsa/version.rb +5 -0
  81. data/lib/ml_dsa.rb +277 -0
  82. data/patches/README.md +55 -0
  83. data/patches/pqclean-explicit-rnd.patch +64 -0
  84. data/sig/ml_dsa.rbs +178 -0
  85. data/test/fixtures/kat_vectors.yaml +16 -0
  86. metadata +194 -0
@@ -0,0 +1,933 @@
1
+ /* Based on the public domain implementation in
2
+ * crypto_hash/keccakc512/simple/ from http://bench.cr.yp.to/supercop.html
3
+ * by Ronny Van Keer
4
+ * and the public domain "TweetFips202" implementation
5
+ * from https://twitter.com/tweetfips202
6
+ * by Gilles Van Assche, Daniel J. Bernstein, and Peter Schwabe
7
+ *
8
+ * NOTE (ml_dsa gem): This is a vendored PQClean file. malloc() failures
9
+ * in the incremental SHAKE context allocators call exit(111), which is
10
+ * treated as a fatal, unrecoverable error. In practice, these allocations
11
+ * are small (~200 bytes) and OOM is extremely unlikely. */
12
+
13
+ #include <stddef.h>
14
+ #include <stdint.h>
15
+ #include <stdlib.h>
16
+ #include <string.h>
17
+
18
+ #include "fips202.h"
19
+
20
+ #define NROUNDS 24
21
+ #define ROL(a, offset) (((a) << (offset)) ^ ((a) >> (64 - (offset))))
22
+
23
+ /*************************************************
24
+ * Name: load64
25
+ *
26
+ * Description: Load 8 bytes into uint64_t in little-endian order
27
+ *
28
+ * Arguments: - const uint8_t *x: pointer to input byte array
29
+ *
30
+ * Returns the loaded 64-bit unsigned integer
31
+ **************************************************/
32
+ static uint64_t load64(const uint8_t *x) {
33
+ uint64_t r = 0;
34
+ for (size_t i = 0; i < 8; ++i) {
35
+ r |= (uint64_t)x[i] << 8 * i;
36
+ }
37
+
38
+ return r;
39
+ }
40
+
41
+ /*************************************************
42
+ * Name: store64
43
+ *
44
+ * Description: Store a 64-bit integer to a byte array in little-endian order
45
+ *
46
+ * Arguments: - uint8_t *x: pointer to the output byte array
47
+ * - uint64_t u: input 64-bit unsigned integer
48
+ **************************************************/
49
+ static void store64(uint8_t *x, uint64_t u) {
50
+ for (size_t i = 0; i < 8; ++i) {
51
+ x[i] = (uint8_t) (u >> 8 * i);
52
+ }
53
+ }
54
+
55
+ /* Keccak round constants */
56
+ static const uint64_t KeccakF_RoundConstants[NROUNDS] = {
57
+ 0x0000000000000001ULL, 0x0000000000008082ULL,
58
+ 0x800000000000808aULL, 0x8000000080008000ULL,
59
+ 0x000000000000808bULL, 0x0000000080000001ULL,
60
+ 0x8000000080008081ULL, 0x8000000000008009ULL,
61
+ 0x000000000000008aULL, 0x0000000000000088ULL,
62
+ 0x0000000080008009ULL, 0x000000008000000aULL,
63
+ 0x000000008000808bULL, 0x800000000000008bULL,
64
+ 0x8000000000008089ULL, 0x8000000000008003ULL,
65
+ 0x8000000000008002ULL, 0x8000000000000080ULL,
66
+ 0x000000000000800aULL, 0x800000008000000aULL,
67
+ 0x8000000080008081ULL, 0x8000000000008080ULL,
68
+ 0x0000000080000001ULL, 0x8000000080008008ULL
69
+ };
70
+
71
+ /*************************************************
72
+ * Name: KeccakF1600_StatePermute
73
+ *
74
+ * Description: The Keccak F1600 Permutation
75
+ *
76
+ * Arguments: - uint64_t *state: pointer to input/output Keccak state
77
+ **************************************************/
78
+ static void KeccakF1600_StatePermute(uint64_t *state) {
79
+ int round;
80
+
81
+ uint64_t Aba, Abe, Abi, Abo, Abu;
82
+ uint64_t Aga, Age, Agi, Ago, Agu;
83
+ uint64_t Aka, Ake, Aki, Ako, Aku;
84
+ uint64_t Ama, Ame, Ami, Amo, Amu;
85
+ uint64_t Asa, Ase, Asi, Aso, Asu;
86
+ uint64_t BCa, BCe, BCi, BCo, BCu;
87
+ uint64_t Da, De, Di, Do, Du;
88
+ uint64_t Eba, Ebe, Ebi, Ebo, Ebu;
89
+ uint64_t Ega, Ege, Egi, Ego, Egu;
90
+ uint64_t Eka, Eke, Eki, Eko, Eku;
91
+ uint64_t Ema, Eme, Emi, Emo, Emu;
92
+ uint64_t Esa, Ese, Esi, Eso, Esu;
93
+
94
+ // copyFromState(A, state)
95
+ Aba = state[0];
96
+ Abe = state[1];
97
+ Abi = state[2];
98
+ Abo = state[3];
99
+ Abu = state[4];
100
+ Aga = state[5];
101
+ Age = state[6];
102
+ Agi = state[7];
103
+ Ago = state[8];
104
+ Agu = state[9];
105
+ Aka = state[10];
106
+ Ake = state[11];
107
+ Aki = state[12];
108
+ Ako = state[13];
109
+ Aku = state[14];
110
+ Ama = state[15];
111
+ Ame = state[16];
112
+ Ami = state[17];
113
+ Amo = state[18];
114
+ Amu = state[19];
115
+ Asa = state[20];
116
+ Ase = state[21];
117
+ Asi = state[22];
118
+ Aso = state[23];
119
+ Asu = state[24];
120
+
121
+ for (round = 0; round < NROUNDS; round += 2) {
122
+ // prepareTheta
123
+ BCa = Aba ^ Aga ^ Aka ^ Ama ^ Asa;
124
+ BCe = Abe ^ Age ^ Ake ^ Ame ^ Ase;
125
+ BCi = Abi ^ Agi ^ Aki ^ Ami ^ Asi;
126
+ BCo = Abo ^ Ago ^ Ako ^ Amo ^ Aso;
127
+ BCu = Abu ^ Agu ^ Aku ^ Amu ^ Asu;
128
+
129
+ // thetaRhoPiChiIotaPrepareTheta(round , A, E)
130
+ Da = BCu ^ ROL(BCe, 1);
131
+ De = BCa ^ ROL(BCi, 1);
132
+ Di = BCe ^ ROL(BCo, 1);
133
+ Do = BCi ^ ROL(BCu, 1);
134
+ Du = BCo ^ ROL(BCa, 1);
135
+
136
+ Aba ^= Da;
137
+ BCa = Aba;
138
+ Age ^= De;
139
+ BCe = ROL(Age, 44);
140
+ Aki ^= Di;
141
+ BCi = ROL(Aki, 43);
142
+ Amo ^= Do;
143
+ BCo = ROL(Amo, 21);
144
+ Asu ^= Du;
145
+ BCu = ROL(Asu, 14);
146
+ Eba = BCa ^ ((~BCe) & BCi);
147
+ Eba ^= KeccakF_RoundConstants[round];
148
+ Ebe = BCe ^ ((~BCi) & BCo);
149
+ Ebi = BCi ^ ((~BCo) & BCu);
150
+ Ebo = BCo ^ ((~BCu) & BCa);
151
+ Ebu = BCu ^ ((~BCa) & BCe);
152
+
153
+ Abo ^= Do;
154
+ BCa = ROL(Abo, 28);
155
+ Agu ^= Du;
156
+ BCe = ROL(Agu, 20);
157
+ Aka ^= Da;
158
+ BCi = ROL(Aka, 3);
159
+ Ame ^= De;
160
+ BCo = ROL(Ame, 45);
161
+ Asi ^= Di;
162
+ BCu = ROL(Asi, 61);
163
+ Ega = BCa ^ ((~BCe) & BCi);
164
+ Ege = BCe ^ ((~BCi) & BCo);
165
+ Egi = BCi ^ ((~BCo) & BCu);
166
+ Ego = BCo ^ ((~BCu) & BCa);
167
+ Egu = BCu ^ ((~BCa) & BCe);
168
+
169
+ Abe ^= De;
170
+ BCa = ROL(Abe, 1);
171
+ Agi ^= Di;
172
+ BCe = ROL(Agi, 6);
173
+ Ako ^= Do;
174
+ BCi = ROL(Ako, 25);
175
+ Amu ^= Du;
176
+ BCo = ROL(Amu, 8);
177
+ Asa ^= Da;
178
+ BCu = ROL(Asa, 18);
179
+ Eka = BCa ^ ((~BCe) & BCi);
180
+ Eke = BCe ^ ((~BCi) & BCo);
181
+ Eki = BCi ^ ((~BCo) & BCu);
182
+ Eko = BCo ^ ((~BCu) & BCa);
183
+ Eku = BCu ^ ((~BCa) & BCe);
184
+
185
+ Abu ^= Du;
186
+ BCa = ROL(Abu, 27);
187
+ Aga ^= Da;
188
+ BCe = ROL(Aga, 36);
189
+ Ake ^= De;
190
+ BCi = ROL(Ake, 10);
191
+ Ami ^= Di;
192
+ BCo = ROL(Ami, 15);
193
+ Aso ^= Do;
194
+ BCu = ROL(Aso, 56);
195
+ Ema = BCa ^ ((~BCe) & BCi);
196
+ Eme = BCe ^ ((~BCi) & BCo);
197
+ Emi = BCi ^ ((~BCo) & BCu);
198
+ Emo = BCo ^ ((~BCu) & BCa);
199
+ Emu = BCu ^ ((~BCa) & BCe);
200
+
201
+ Abi ^= Di;
202
+ BCa = ROL(Abi, 62);
203
+ Ago ^= Do;
204
+ BCe = ROL(Ago, 55);
205
+ Aku ^= Du;
206
+ BCi = ROL(Aku, 39);
207
+ Ama ^= Da;
208
+ BCo = ROL(Ama, 41);
209
+ Ase ^= De;
210
+ BCu = ROL(Ase, 2);
211
+ Esa = BCa ^ ((~BCe) & BCi);
212
+ Ese = BCe ^ ((~BCi) & BCo);
213
+ Esi = BCi ^ ((~BCo) & BCu);
214
+ Eso = BCo ^ ((~BCu) & BCa);
215
+ Esu = BCu ^ ((~BCa) & BCe);
216
+
217
+ // prepareTheta
218
+ BCa = Eba ^ Ega ^ Eka ^ Ema ^ Esa;
219
+ BCe = Ebe ^ Ege ^ Eke ^ Eme ^ Ese;
220
+ BCi = Ebi ^ Egi ^ Eki ^ Emi ^ Esi;
221
+ BCo = Ebo ^ Ego ^ Eko ^ Emo ^ Eso;
222
+ BCu = Ebu ^ Egu ^ Eku ^ Emu ^ Esu;
223
+
224
+ // thetaRhoPiChiIotaPrepareTheta(round+1, E, A)
225
+ Da = BCu ^ ROL(BCe, 1);
226
+ De = BCa ^ ROL(BCi, 1);
227
+ Di = BCe ^ ROL(BCo, 1);
228
+ Do = BCi ^ ROL(BCu, 1);
229
+ Du = BCo ^ ROL(BCa, 1);
230
+
231
+ Eba ^= Da;
232
+ BCa = Eba;
233
+ Ege ^= De;
234
+ BCe = ROL(Ege, 44);
235
+ Eki ^= Di;
236
+ BCi = ROL(Eki, 43);
237
+ Emo ^= Do;
238
+ BCo = ROL(Emo, 21);
239
+ Esu ^= Du;
240
+ BCu = ROL(Esu, 14);
241
+ Aba = BCa ^ ((~BCe) & BCi);
242
+ Aba ^= KeccakF_RoundConstants[round + 1];
243
+ Abe = BCe ^ ((~BCi) & BCo);
244
+ Abi = BCi ^ ((~BCo) & BCu);
245
+ Abo = BCo ^ ((~BCu) & BCa);
246
+ Abu = BCu ^ ((~BCa) & BCe);
247
+
248
+ Ebo ^= Do;
249
+ BCa = ROL(Ebo, 28);
250
+ Egu ^= Du;
251
+ BCe = ROL(Egu, 20);
252
+ Eka ^= Da;
253
+ BCi = ROL(Eka, 3);
254
+ Eme ^= De;
255
+ BCo = ROL(Eme, 45);
256
+ Esi ^= Di;
257
+ BCu = ROL(Esi, 61);
258
+ Aga = BCa ^ ((~BCe) & BCi);
259
+ Age = BCe ^ ((~BCi) & BCo);
260
+ Agi = BCi ^ ((~BCo) & BCu);
261
+ Ago = BCo ^ ((~BCu) & BCa);
262
+ Agu = BCu ^ ((~BCa) & BCe);
263
+
264
+ Ebe ^= De;
265
+ BCa = ROL(Ebe, 1);
266
+ Egi ^= Di;
267
+ BCe = ROL(Egi, 6);
268
+ Eko ^= Do;
269
+ BCi = ROL(Eko, 25);
270
+ Emu ^= Du;
271
+ BCo = ROL(Emu, 8);
272
+ Esa ^= Da;
273
+ BCu = ROL(Esa, 18);
274
+ Aka = BCa ^ ((~BCe) & BCi);
275
+ Ake = BCe ^ ((~BCi) & BCo);
276
+ Aki = BCi ^ ((~BCo) & BCu);
277
+ Ako = BCo ^ ((~BCu) & BCa);
278
+ Aku = BCu ^ ((~BCa) & BCe);
279
+
280
+ Ebu ^= Du;
281
+ BCa = ROL(Ebu, 27);
282
+ Ega ^= Da;
283
+ BCe = ROL(Ega, 36);
284
+ Eke ^= De;
285
+ BCi = ROL(Eke, 10);
286
+ Emi ^= Di;
287
+ BCo = ROL(Emi, 15);
288
+ Eso ^= Do;
289
+ BCu = ROL(Eso, 56);
290
+ Ama = BCa ^ ((~BCe) & BCi);
291
+ Ame = BCe ^ ((~BCi) & BCo);
292
+ Ami = BCi ^ ((~BCo) & BCu);
293
+ Amo = BCo ^ ((~BCu) & BCa);
294
+ Amu = BCu ^ ((~BCa) & BCe);
295
+
296
+ Ebi ^= Di;
297
+ BCa = ROL(Ebi, 62);
298
+ Ego ^= Do;
299
+ BCe = ROL(Ego, 55);
300
+ Eku ^= Du;
301
+ BCi = ROL(Eku, 39);
302
+ Ema ^= Da;
303
+ BCo = ROL(Ema, 41);
304
+ Ese ^= De;
305
+ BCu = ROL(Ese, 2);
306
+ Asa = BCa ^ ((~BCe) & BCi);
307
+ Ase = BCe ^ ((~BCi) & BCo);
308
+ Asi = BCi ^ ((~BCo) & BCu);
309
+ Aso = BCo ^ ((~BCu) & BCa);
310
+ Asu = BCu ^ ((~BCa) & BCe);
311
+ }
312
+
313
+ // copyToState(state, A)
314
+ state[0] = Aba;
315
+ state[1] = Abe;
316
+ state[2] = Abi;
317
+ state[3] = Abo;
318
+ state[4] = Abu;
319
+ state[5] = Aga;
320
+ state[6] = Age;
321
+ state[7] = Agi;
322
+ state[8] = Ago;
323
+ state[9] = Agu;
324
+ state[10] = Aka;
325
+ state[11] = Ake;
326
+ state[12] = Aki;
327
+ state[13] = Ako;
328
+ state[14] = Aku;
329
+ state[15] = Ama;
330
+ state[16] = Ame;
331
+ state[17] = Ami;
332
+ state[18] = Amo;
333
+ state[19] = Amu;
334
+ state[20] = Asa;
335
+ state[21] = Ase;
336
+ state[22] = Asi;
337
+ state[23] = Aso;
338
+ state[24] = Asu;
339
+ }
340
+
341
+ /*************************************************
342
+ * Name: keccak_absorb
343
+ *
344
+ * Description: Absorb step of Keccak;
345
+ * non-incremental, starts by zeroeing the state.
346
+ *
347
+ * Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state
348
+ * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128)
349
+ * - const uint8_t *m: pointer to input to be absorbed into s
350
+ * - size_t mlen: length of input in bytes
351
+ * - uint8_t p: domain-separation byte for different
352
+ * Keccak-derived functions
353
+ **************************************************/
354
+ static void keccak_absorb(uint64_t *s, uint32_t r, const uint8_t *m,
355
+ size_t mlen, uint8_t p) {
356
+ size_t i;
357
+ uint8_t t[200];
358
+
359
+ /* Zero state */
360
+ for (i = 0; i < 25; ++i) {
361
+ s[i] = 0;
362
+ }
363
+
364
+ while (mlen >= r) {
365
+ for (i = 0; i < r / 8; ++i) {
366
+ s[i] ^= load64(m + 8 * i);
367
+ }
368
+
369
+ KeccakF1600_StatePermute(s);
370
+ mlen -= r;
371
+ m += r;
372
+ }
373
+
374
+ for (i = 0; i < r; ++i) {
375
+ t[i] = 0;
376
+ }
377
+ for (i = 0; i < mlen; ++i) {
378
+ t[i] = m[i];
379
+ }
380
+ t[i] = p;
381
+ t[r - 1] |= 128;
382
+ for (i = 0; i < r / 8; ++i) {
383
+ s[i] ^= load64(t + 8 * i);
384
+ }
385
+ }
386
+
387
+ /*************************************************
388
+ * Name: keccak_squeezeblocks
389
+ *
390
+ * Description: Squeeze step of Keccak. Squeezes full blocks of r bytes each.
391
+ * Modifies the state. Can be called multiple times to keep
392
+ * squeezing, i.e., is incremental.
393
+ *
394
+ * Arguments: - uint8_t *h: pointer to output blocks
395
+ * - size_t nblocks: number of blocks to be
396
+ * squeezed (written to h)
397
+ * - uint64_t *s: pointer to input/output Keccak state
398
+ * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128)
399
+ **************************************************/
400
+ static void keccak_squeezeblocks(uint8_t *h, size_t nblocks,
401
+ uint64_t *s, uint32_t r) {
402
+ while (nblocks > 0) {
403
+ KeccakF1600_StatePermute(s);
404
+ for (size_t i = 0; i < (r >> 3); i++) {
405
+ store64(h + 8 * i, s[i]);
406
+ }
407
+ h += r;
408
+ nblocks--;
409
+ }
410
+ }
411
+
412
+ /*************************************************
413
+ * Name: keccak_inc_init
414
+ *
415
+ * Description: Initializes the incremental Keccak state to zero.
416
+ *
417
+ * Arguments: - uint64_t *s_inc: pointer to input/output incremental state
418
+ * First 25 values represent Keccak state.
419
+ * 26th value represents either the number of absorbed bytes
420
+ * that have not been permuted, or not-yet-squeezed bytes.
421
+ **************************************************/
422
+ static void keccak_inc_init(uint64_t *s_inc) {
423
+ size_t i;
424
+
425
+ for (i = 0; i < 25; ++i) {
426
+ s_inc[i] = 0;
427
+ }
428
+ s_inc[25] = 0;
429
+ }
430
+
431
+ /*************************************************
432
+ * Name: keccak_inc_absorb
433
+ *
434
+ * Description: Incremental keccak absorb
435
+ * Preceded by keccak_inc_init, succeeded by keccak_inc_finalize
436
+ *
437
+ * Arguments: - uint64_t *s_inc: pointer to input/output incremental state
438
+ * First 25 values represent Keccak state.
439
+ * 26th value represents either the number of absorbed bytes
440
+ * that have not been permuted, or not-yet-squeezed bytes.
441
+ * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128)
442
+ * - const uint8_t *m: pointer to input to be absorbed into s
443
+ * - size_t mlen: length of input in bytes
444
+ **************************************************/
445
+ static void keccak_inc_absorb(uint64_t *s_inc, uint32_t r, const uint8_t *m,
446
+ size_t mlen) {
447
+ size_t i;
448
+
449
+ /* Recall that s_inc[25] is the non-absorbed bytes xored into the state */
450
+ while (mlen + s_inc[25] >= r) {
451
+ for (i = 0; i < r - (uint32_t)s_inc[25]; i++) {
452
+ /* Take the i'th byte from message
453
+ xor with the s_inc[25] + i'th byte of the state; little-endian */
454
+ s_inc[(s_inc[25] + i) >> 3] ^= (uint64_t)m[i] << (8 * ((s_inc[25] + i) & 0x07));
455
+ }
456
+ mlen -= (size_t)(r - s_inc[25]);
457
+ m += r - s_inc[25];
458
+ s_inc[25] = 0;
459
+
460
+ KeccakF1600_StatePermute(s_inc);
461
+ }
462
+
463
+ for (i = 0; i < mlen; i++) {
464
+ s_inc[(s_inc[25] + i) >> 3] ^= (uint64_t)m[i] << (8 * ((s_inc[25] + i) & 0x07));
465
+ }
466
+ s_inc[25] += mlen;
467
+ }
468
+
469
+ /*************************************************
470
+ * Name: keccak_inc_finalize
471
+ *
472
+ * Description: Finalizes Keccak absorb phase, prepares for squeezing
473
+ *
474
+ * Arguments: - uint64_t *s_inc: pointer to input/output incremental state
475
+ * First 25 values represent Keccak state.
476
+ * 26th value represents either the number of absorbed bytes
477
+ * that have not been permuted, or not-yet-squeezed bytes.
478
+ * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128)
479
+ * - uint8_t p: domain-separation byte for different
480
+ * Keccak-derived functions
481
+ **************************************************/
482
+ static void keccak_inc_finalize(uint64_t *s_inc, uint32_t r, uint8_t p) {
483
+ /* After keccak_inc_absorb, we are guaranteed that s_inc[25] < r,
484
+ so we can always use one more byte for p in the current state. */
485
+ s_inc[s_inc[25] >> 3] ^= (uint64_t)p << (8 * (s_inc[25] & 0x07));
486
+ s_inc[(r - 1) >> 3] ^= (uint64_t)128 << (8 * ((r - 1) & 0x07));
487
+ s_inc[25] = 0;
488
+ }
489
+
490
+ /*************************************************
491
+ * Name: keccak_inc_squeeze
492
+ *
493
+ * Description: Incremental Keccak squeeze; can be called on byte-level
494
+ *
495
+ * Arguments: - uint8_t *h: pointer to output bytes
496
+ * - size_t outlen: number of bytes to be squeezed
497
+ * - uint64_t *s_inc: pointer to input/output incremental state
498
+ * First 25 values represent Keccak state.
499
+ * 26th value represents either the number of absorbed bytes
500
+ * that have not been permuted, or not-yet-squeezed bytes.
501
+ * - uint32_t r: rate in bytes (e.g., 168 for SHAKE128)
502
+ **************************************************/
503
+ static void keccak_inc_squeeze(uint8_t *h, size_t outlen,
504
+ uint64_t *s_inc, uint32_t r) {
505
+ size_t i;
506
+
507
+ /* First consume any bytes we still have sitting around */
508
+ for (i = 0; i < outlen && i < s_inc[25]; i++) {
509
+ /* There are s_inc[25] bytes left, so r - s_inc[25] is the first
510
+ available byte. We consume from there, i.e., up to r. */
511
+ h[i] = (uint8_t)(s_inc[(r - s_inc[25] + i) >> 3] >> (8 * ((r - s_inc[25] + i) & 0x07)));
512
+ }
513
+ h += i;
514
+ outlen -= i;
515
+ s_inc[25] -= i;
516
+
517
+ /* Then squeeze the remaining necessary blocks */
518
+ while (outlen > 0) {
519
+ KeccakF1600_StatePermute(s_inc);
520
+
521
+ for (i = 0; i < outlen && i < r; i++) {
522
+ h[i] = (uint8_t)(s_inc[i >> 3] >> (8 * (i & 0x07)));
523
+ }
524
+ h += i;
525
+ outlen -= i;
526
+ s_inc[25] = r - i;
527
+ }
528
+ }
529
+
530
+ void shake128_inc_init(shake128incctx *state) {
531
+ state->ctx = malloc(PQC_SHAKEINCCTX_BYTES);
532
+ if (state->ctx == NULL) {
533
+ exit(111);
534
+ }
535
+ keccak_inc_init(state->ctx);
536
+ }
537
+
538
+ void shake128_inc_absorb(shake128incctx *state, const uint8_t *input, size_t inlen) {
539
+ keccak_inc_absorb(state->ctx, SHAKE128_RATE, input, inlen);
540
+ }
541
+
542
+ void shake128_inc_finalize(shake128incctx *state) {
543
+ keccak_inc_finalize(state->ctx, SHAKE128_RATE, 0x1F);
544
+ }
545
+
546
+ void shake128_inc_squeeze(uint8_t *output, size_t outlen, shake128incctx *state) {
547
+ keccak_inc_squeeze(output, outlen, state->ctx, SHAKE128_RATE);
548
+ }
549
+
550
+ void shake128_inc_ctx_clone(shake128incctx *dest, const shake128incctx *src) {
551
+ dest->ctx = malloc(PQC_SHAKEINCCTX_BYTES);
552
+ if (dest->ctx == NULL) {
553
+ exit(111);
554
+ }
555
+ memcpy(dest->ctx, src->ctx, PQC_SHAKEINCCTX_BYTES);
556
+ }
557
+
558
+ void shake128_inc_ctx_release(shake128incctx *state) {
559
+ free(state->ctx);
560
+ }
561
+
562
+ void shake256_inc_init(shake256incctx *state) {
563
+ state->ctx = malloc(PQC_SHAKEINCCTX_BYTES);
564
+ if (state->ctx == NULL) {
565
+ exit(111);
566
+ }
567
+ keccak_inc_init(state->ctx);
568
+ }
569
+
570
+ void shake256_inc_absorb(shake256incctx *state, const uint8_t *input, size_t inlen) {
571
+ keccak_inc_absorb(state->ctx, SHAKE256_RATE, input, inlen);
572
+ }
573
+
574
+ void shake256_inc_finalize(shake256incctx *state) {
575
+ keccak_inc_finalize(state->ctx, SHAKE256_RATE, 0x1F);
576
+ }
577
+
578
+ void shake256_inc_squeeze(uint8_t *output, size_t outlen, shake256incctx *state) {
579
+ keccak_inc_squeeze(output, outlen, state->ctx, SHAKE256_RATE);
580
+ }
581
+
582
+ void shake256_inc_ctx_clone(shake256incctx *dest, const shake256incctx *src) {
583
+ dest->ctx = malloc(PQC_SHAKEINCCTX_BYTES);
584
+ if (dest->ctx == NULL) {
585
+ exit(111);
586
+ }
587
+ memcpy(dest->ctx, src->ctx, PQC_SHAKEINCCTX_BYTES);
588
+ }
589
+
590
+ void shake256_inc_ctx_release(shake256incctx *state) {
591
+ free(state->ctx);
592
+ }
593
+
594
+ /*************************************************
595
+ * Name: shake128_absorb
596
+ *
597
+ * Description: Absorb step of the SHAKE128 XOF.
598
+ * non-incremental, starts by zeroeing the state.
599
+ *
600
+ * Arguments: - uint64_t *s: pointer to (uninitialized) output Keccak state
601
+ * - const uint8_t *input: pointer to input to be absorbed
602
+ * into s
603
+ * - size_t inlen: length of input in bytes
604
+ **************************************************/
605
+ void shake128_absorb(shake128ctx *state, const uint8_t *input, size_t inlen) {
606
+ state->ctx = malloc(PQC_SHAKECTX_BYTES);
607
+ if (state->ctx == NULL) {
608
+ exit(111);
609
+ }
610
+ keccak_absorb(state->ctx, SHAKE128_RATE, input, inlen, 0x1F);
611
+ }
612
+
613
+ /*************************************************
614
+ * Name: shake128_squeezeblocks
615
+ *
616
+ * Description: Squeeze step of SHAKE128 XOF. Squeezes full blocks of
617
+ * SHAKE128_RATE bytes each. Modifies the state. Can be called
618
+ * multiple times to keep squeezing, i.e., is incremental.
619
+ *
620
+ * Arguments: - uint8_t *output: pointer to output blocks
621
+ * - size_t nblocks: number of blocks to be squeezed
622
+ * (written to output)
623
+ * - shake128ctx *state: pointer to input/output Keccak state
624
+ **************************************************/
625
+ void shake128_squeezeblocks(uint8_t *output, size_t nblocks, shake128ctx *state) {
626
+ keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE128_RATE);
627
+ }
628
+
629
+ void shake128_ctx_clone(shake128ctx *dest, const shake128ctx *src) {
630
+ dest->ctx = malloc(PQC_SHAKECTX_BYTES);
631
+ if (dest->ctx == NULL) {
632
+ exit(111);
633
+ }
634
+ memcpy(dest->ctx, src->ctx, PQC_SHAKECTX_BYTES);
635
+ }
636
+
637
+ /** Release the allocated state. Call only once. */
638
+ void shake128_ctx_release(shake128ctx *state) {
639
+ free(state->ctx);
640
+ }
641
+
642
+ /*************************************************
643
+ * Name: shake256_absorb
644
+ *
645
+ * Description: Absorb step of the SHAKE256 XOF.
646
+ * non-incremental, starts by zeroeing the state.
647
+ *
648
+ * Arguments: - shake256ctx *state: pointer to (uninitialized) output Keccak state
649
+ * - const uint8_t *input: pointer to input to be absorbed
650
+ * into s
651
+ * - size_t inlen: length of input in bytes
652
+ **************************************************/
653
+ void shake256_absorb(shake256ctx *state, const uint8_t *input, size_t inlen) {
654
+ state->ctx = malloc(PQC_SHAKECTX_BYTES);
655
+ if (state->ctx == NULL) {
656
+ exit(111);
657
+ }
658
+ keccak_absorb(state->ctx, SHAKE256_RATE, input, inlen, 0x1F);
659
+ }
660
+
661
+ /*************************************************
662
+ * Name: shake256_squeezeblocks
663
+ *
664
+ * Description: Squeeze step of SHAKE256 XOF. Squeezes full blocks of
665
+ * SHAKE256_RATE bytes each. Modifies the state. Can be called
666
+ * multiple times to keep squeezing, i.e., is incremental.
667
+ *
668
+ * Arguments: - uint8_t *output: pointer to output blocks
669
+ * - size_t nblocks: number of blocks to be squeezed
670
+ * (written to output)
671
+ * - shake256ctx *state: pointer to input/output Keccak state
672
+ **************************************************/
673
+ void shake256_squeezeblocks(uint8_t *output, size_t nblocks, shake256ctx *state) {
674
+ keccak_squeezeblocks(output, nblocks, state->ctx, SHAKE256_RATE);
675
+ }
676
+
677
+ void shake256_ctx_clone(shake256ctx *dest, const shake256ctx *src) {
678
+ dest->ctx = malloc(PQC_SHAKECTX_BYTES);
679
+ if (dest->ctx == NULL) {
680
+ exit(111);
681
+ }
682
+ memcpy(dest->ctx, src->ctx, PQC_SHAKECTX_BYTES);
683
+ }
684
+
685
+ /** Release the allocated state. Call only once. */
686
+ void shake256_ctx_release(shake256ctx *state) {
687
+ free(state->ctx);
688
+ }
689
+
690
+ /*************************************************
691
+ * Name: shake128
692
+ *
693
+ * Description: SHAKE128 XOF with non-incremental API
694
+ *
695
+ * Arguments: - uint8_t *output: pointer to output
696
+ * - size_t outlen: requested output length in bytes
697
+ * - const uint8_t *input: pointer to input
698
+ * - size_t inlen: length of input in bytes
699
+ **************************************************/
700
+ void shake128(uint8_t *output, size_t outlen,
701
+ const uint8_t *input, size_t inlen) {
702
+ size_t nblocks = outlen / SHAKE128_RATE;
703
+ uint8_t t[SHAKE128_RATE];
704
+ shake128ctx s;
705
+
706
+ shake128_absorb(&s, input, inlen);
707
+ shake128_squeezeblocks(output, nblocks, &s);
708
+
709
+ output += nblocks * SHAKE128_RATE;
710
+ outlen -= nblocks * SHAKE128_RATE;
711
+
712
+ if (outlen) {
713
+ shake128_squeezeblocks(t, 1, &s);
714
+ for (size_t i = 0; i < outlen; ++i) {
715
+ output[i] = t[i];
716
+ }
717
+ }
718
+ shake128_ctx_release(&s);
719
+ }
720
+
721
+ /*************************************************
722
+ * Name: shake256
723
+ *
724
+ * Description: SHAKE256 XOF with non-incremental API
725
+ *
726
+ * Arguments: - uint8_t *output: pointer to output
727
+ * - size_t outlen: requested output length in bytes
728
+ * - const uint8_t *input: pointer to input
729
+ * - size_t inlen: length of input in bytes
730
+ **************************************************/
731
+ void shake256(uint8_t *output, size_t outlen,
732
+ const uint8_t *input, size_t inlen) {
733
+ size_t nblocks = outlen / SHAKE256_RATE;
734
+ uint8_t t[SHAKE256_RATE];
735
+ shake256ctx s;
736
+
737
+ shake256_absorb(&s, input, inlen);
738
+ shake256_squeezeblocks(output, nblocks, &s);
739
+
740
+ output += nblocks * SHAKE256_RATE;
741
+ outlen -= nblocks * SHAKE256_RATE;
742
+
743
+ if (outlen) {
744
+ shake256_squeezeblocks(t, 1, &s);
745
+ for (size_t i = 0; i < outlen; ++i) {
746
+ output[i] = t[i];
747
+ }
748
+ }
749
+ shake256_ctx_release(&s);
750
+ }
751
+
752
+ void sha3_256_inc_init(sha3_256incctx *state) {
753
+ state->ctx = malloc(PQC_SHAKEINCCTX_BYTES);
754
+ if (state->ctx == NULL) {
755
+ exit(111);
756
+ }
757
+ keccak_inc_init(state->ctx);
758
+ }
759
+
760
+ void sha3_256_inc_ctx_clone(sha3_256incctx *dest, const sha3_256incctx *src) {
761
+ dest->ctx = malloc(PQC_SHAKEINCCTX_BYTES);
762
+ if (dest->ctx == NULL) {
763
+ exit(111);
764
+ }
765
+ memcpy(dest->ctx, src->ctx, PQC_SHAKEINCCTX_BYTES);
766
+ }
767
+
768
+ void sha3_256_inc_ctx_release(sha3_256incctx *state) {
769
+ free(state->ctx);
770
+ }
771
+
772
+ void sha3_256_inc_absorb(sha3_256incctx *state, const uint8_t *input, size_t inlen) {
773
+ keccak_inc_absorb(state->ctx, SHA3_256_RATE, input, inlen);
774
+ }
775
+
776
+ void sha3_256_inc_finalize(uint8_t *output, sha3_256incctx *state) {
777
+ uint8_t t[SHA3_256_RATE];
778
+ keccak_inc_finalize(state->ctx, SHA3_256_RATE, 0x06);
779
+
780
+ keccak_squeezeblocks(t, 1, state->ctx, SHA3_256_RATE);
781
+
782
+ sha3_256_inc_ctx_release(state);
783
+
784
+ for (size_t i = 0; i < 32; i++) {
785
+ output[i] = t[i];
786
+ }
787
+ }
788
+
789
+ /*************************************************
790
+ * Name: sha3_256
791
+ *
792
+ * Description: SHA3-256 with non-incremental API
793
+ *
794
+ * Arguments: - uint8_t *output: pointer to output
795
+ * - const uint8_t *input: pointer to input
796
+ * - size_t inlen: length of input in bytes
797
+ **************************************************/
798
+ void sha3_256(uint8_t *output, const uint8_t *input, size_t inlen) {
799
+ uint64_t s[25];
800
+ uint8_t t[SHA3_256_RATE];
801
+
802
+ /* Absorb input */
803
+ keccak_absorb(s, SHA3_256_RATE, input, inlen, 0x06);
804
+
805
+ /* Squeeze output */
806
+ keccak_squeezeblocks(t, 1, s, SHA3_256_RATE);
807
+
808
+ for (size_t i = 0; i < 32; i++) {
809
+ output[i] = t[i];
810
+ }
811
+ }
812
+
813
+ void sha3_384_inc_init(sha3_384incctx *state) {
814
+ state->ctx = malloc(PQC_SHAKEINCCTX_BYTES);
815
+ if (state->ctx == NULL) {
816
+ exit(111);
817
+ }
818
+ keccak_inc_init(state->ctx);
819
+ }
820
+
821
+ void sha3_384_inc_ctx_clone(sha3_384incctx *dest, const sha3_384incctx *src) {
822
+ dest->ctx = malloc(PQC_SHAKEINCCTX_BYTES);
823
+ if (dest->ctx == NULL) {
824
+ exit(111);
825
+ }
826
+ memcpy(dest->ctx, src->ctx, PQC_SHAKEINCCTX_BYTES);
827
+ }
828
+
829
+ void sha3_384_inc_absorb(sha3_384incctx *state, const uint8_t *input, size_t inlen) {
830
+ keccak_inc_absorb(state->ctx, SHA3_384_RATE, input, inlen);
831
+ }
832
+
833
+ void sha3_384_inc_ctx_release(sha3_384incctx *state) {
834
+ free(state->ctx);
835
+ }
836
+
837
+ void sha3_384_inc_finalize(uint8_t *output, sha3_384incctx *state) {
838
+ uint8_t t[SHA3_384_RATE];
839
+ keccak_inc_finalize(state->ctx, SHA3_384_RATE, 0x06);
840
+
841
+ keccak_squeezeblocks(t, 1, state->ctx, SHA3_384_RATE);
842
+
843
+ sha3_384_inc_ctx_release(state);
844
+
845
+ for (size_t i = 0; i < 48; i++) {
846
+ output[i] = t[i];
847
+ }
848
+ }
849
+
850
+ /*************************************************
851
+ * Name: sha3_384
852
+ *
853
+ * Description: SHA3-256 with non-incremental API
854
+ *
855
+ * Arguments: - uint8_t *output: pointer to output
856
+ * - const uint8_t *input: pointer to input
857
+ * - size_t inlen: length of input in bytes
858
+ **************************************************/
859
+ void sha3_384(uint8_t *output, const uint8_t *input, size_t inlen) {
860
+ uint64_t s[25];
861
+ uint8_t t[SHA3_384_RATE];
862
+
863
+ /* Absorb input */
864
+ keccak_absorb(s, SHA3_384_RATE, input, inlen, 0x06);
865
+
866
+ /* Squeeze output */
867
+ keccak_squeezeblocks(t, 1, s, SHA3_384_RATE);
868
+
869
+ for (size_t i = 0; i < 48; i++) {
870
+ output[i] = t[i];
871
+ }
872
+ }
873
+
874
+ void sha3_512_inc_init(sha3_512incctx *state) {
875
+ state->ctx = malloc(PQC_SHAKEINCCTX_BYTES);
876
+ if (state->ctx == NULL) {
877
+ exit(111);
878
+ }
879
+ keccak_inc_init(state->ctx);
880
+ }
881
+
882
+ void sha3_512_inc_ctx_clone(sha3_512incctx *dest, const sha3_512incctx *src) {
883
+ dest->ctx = malloc(PQC_SHAKEINCCTX_BYTES);
884
+ if (dest->ctx == NULL) {
885
+ exit(111);
886
+ }
887
+ memcpy(dest->ctx, src->ctx, PQC_SHAKEINCCTX_BYTES);
888
+ }
889
+
890
+ void sha3_512_inc_absorb(sha3_512incctx *state, const uint8_t *input, size_t inlen) {
891
+ keccak_inc_absorb(state->ctx, SHA3_512_RATE, input, inlen);
892
+ }
893
+
894
+ void sha3_512_inc_ctx_release(sha3_512incctx *state) {
895
+ free(state->ctx);
896
+ }
897
+
898
+ void sha3_512_inc_finalize(uint8_t *output, sha3_512incctx *state) {
899
+ uint8_t t[SHA3_512_RATE];
900
+ keccak_inc_finalize(state->ctx, SHA3_512_RATE, 0x06);
901
+
902
+ keccak_squeezeblocks(t, 1, state->ctx, SHA3_512_RATE);
903
+
904
+ sha3_512_inc_ctx_release(state);
905
+
906
+ for (size_t i = 0; i < 64; i++) {
907
+ output[i] = t[i];
908
+ }
909
+ }
910
+
911
+ /*************************************************
912
+ * Name: sha3_512
913
+ *
914
+ * Description: SHA3-512 with non-incremental API
915
+ *
916
+ * Arguments: - uint8_t *output: pointer to output
917
+ * - const uint8_t *input: pointer to input
918
+ * - size_t inlen: length of input in bytes
919
+ **************************************************/
920
+ void sha3_512(uint8_t *output, const uint8_t *input, size_t inlen) {
921
+ uint64_t s[25];
922
+ uint8_t t[SHA3_512_RATE];
923
+
924
+ /* Absorb input */
925
+ keccak_absorb(s, SHA3_512_RATE, input, inlen, 0x06);
926
+
927
+ /* Squeeze output */
928
+ keccak_squeezeblocks(t, 1, s, SHA3_512_RATE);
929
+
930
+ for (size_t i = 0; i < 64; i++) {
931
+ output[i] = t[i];
932
+ }
933
+ }