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,92 @@
1
+ #include "params.h"
2
+ #include "rounding.h"
3
+ #include <stdint.h>
4
+
5
+ /*************************************************
6
+ * Name: PQCLEAN_MLDSA87_CLEAN_power2round
7
+ *
8
+ * Description: For finite field element a, compute a0, a1 such that
9
+ * a mod^+ Q = a1*2^D + a0 with -2^{D-1} < a0 <= 2^{D-1}.
10
+ * Assumes a to be standard representative.
11
+ *
12
+ * Arguments: - int32_t a: input element
13
+ * - int32_t *a0: pointer to output element a0
14
+ *
15
+ * Returns a1.
16
+ **************************************************/
17
+ int32_t PQCLEAN_MLDSA87_CLEAN_power2round(int32_t *a0, int32_t a) {
18
+ int32_t a1;
19
+
20
+ a1 = (a + (1 << (D - 1)) - 1) >> D;
21
+ *a0 = a - (a1 << D);
22
+ return a1;
23
+ }
24
+
25
+ /*************************************************
26
+ * Name: PQCLEAN_MLDSA87_CLEAN_decompose
27
+ *
28
+ * Description: For finite field element a, compute high and low bits a0, a1 such
29
+ * that a mod^+ Q = a1*ALPHA + a0 with -ALPHA/2 < a0 <= ALPHA/2 except
30
+ * if a1 = (Q-1)/ALPHA where we set a1 = 0 and
31
+ * -ALPHA/2 <= a0 = a mod^+ Q - Q < 0. Assumes a to be standard
32
+ * representative.
33
+ *
34
+ * Arguments: - int32_t a: input element
35
+ * - int32_t *a0: pointer to output element a0
36
+ *
37
+ * Returns a1.
38
+ **************************************************/
39
+ int32_t PQCLEAN_MLDSA87_CLEAN_decompose(int32_t *a0, int32_t a) {
40
+ int32_t a1;
41
+
42
+ a1 = (a + 127) >> 7;
43
+ a1 = (a1 * 1025 + (1 << 21)) >> 22;
44
+ a1 &= 15;
45
+
46
+ *a0 = a - a1 * 2 * GAMMA2;
47
+ *a0 -= (((Q - 1) / 2 - *a0) >> 31) & Q;
48
+ return a1;
49
+ }
50
+
51
+ /*************************************************
52
+ * Name: PQCLEAN_MLDSA87_CLEAN_make_hint
53
+ *
54
+ * Description: Compute hint bit indicating whether the low bits of the
55
+ * input element overflow into the high bits.
56
+ *
57
+ * Arguments: - int32_t a0: low bits of input element
58
+ * - int32_t a1: high bits of input element
59
+ *
60
+ * Returns 1 if overflow.
61
+ **************************************************/
62
+ unsigned int PQCLEAN_MLDSA87_CLEAN_make_hint(int32_t a0, int32_t a1) {
63
+ if (a0 > GAMMA2 || a0 < -GAMMA2 || (a0 == -GAMMA2 && a1 != 0)) {
64
+ return 1;
65
+ }
66
+
67
+ return 0;
68
+ }
69
+
70
+ /*************************************************
71
+ * Name: PQCLEAN_MLDSA87_CLEAN_use_hint
72
+ *
73
+ * Description: Correct high bits according to hint.
74
+ *
75
+ * Arguments: - int32_t a: input element
76
+ * - unsigned int hint: hint bit
77
+ *
78
+ * Returns corrected high bits.
79
+ **************************************************/
80
+ int32_t PQCLEAN_MLDSA87_CLEAN_use_hint(int32_t a, unsigned int hint) {
81
+ int32_t a0, a1;
82
+
83
+ a1 = PQCLEAN_MLDSA87_CLEAN_decompose(&a0, a);
84
+ if (hint == 0) {
85
+ return a1;
86
+ }
87
+
88
+ if (a0 > 0) {
89
+ return (a1 + 1) & 15;
90
+ }
91
+ return (a1 - 1) & 15;
92
+ }
@@ -0,0 +1,14 @@
1
+ #ifndef PQCLEAN_MLDSA87_CLEAN_ROUNDING_H
2
+ #define PQCLEAN_MLDSA87_CLEAN_ROUNDING_H
3
+ #include "params.h"
4
+ #include <stdint.h>
5
+
6
+ int32_t PQCLEAN_MLDSA87_CLEAN_power2round(int32_t *a0, int32_t a);
7
+
8
+ int32_t PQCLEAN_MLDSA87_CLEAN_decompose(int32_t *a0, int32_t a);
9
+
10
+ unsigned int PQCLEAN_MLDSA87_CLEAN_make_hint(int32_t a0, int32_t a1);
11
+
12
+ int32_t PQCLEAN_MLDSA87_CLEAN_use_hint(int32_t a, unsigned int hint);
13
+
14
+ #endif
@@ -0,0 +1,415 @@
1
+ #include "fips202.h"
2
+ #include "packing.h"
3
+ #include "params.h"
4
+ #include "poly.h"
5
+ #include "polyvec.h"
6
+ #include "randombytes.h"
7
+ #include "sign.h"
8
+ #include "symmetric.h"
9
+ #include <stdint.h>
10
+ #include <string.h>
11
+
12
+ /*************************************************
13
+ * Name: PQCLEAN_MLDSA87_CLEAN_crypto_sign_keypair
14
+ *
15
+ * Description: Generates public and private key.
16
+ *
17
+ * Arguments: - uint8_t *pk: pointer to output public key (allocated
18
+ * array of PQCLEAN_MLDSA87_CLEAN_CRYPTO_PUBLICKEYBYTES bytes)
19
+ * - uint8_t *sk: pointer to output private key (allocated
20
+ * array of PQCLEAN_MLDSA87_CLEAN_CRYPTO_SECRETKEYBYTES bytes)
21
+ *
22
+ * Returns 0 (success)
23
+ **************************************************/
24
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk,
25
+ const uint8_t *seed_in) {
26
+ uint8_t seedbuf[2 * SEEDBYTES + CRHBYTES];
27
+ uint8_t tr[TRBYTES];
28
+ const uint8_t *rho, *rhoprime, *key;
29
+ polyvecl mat[K];
30
+ polyvecl s1, s1hat;
31
+ polyveck s2, t1, t0;
32
+
33
+ /* Caller provides the seed: OS-random for normal keygen,
34
+ * or a user-supplied seed for deterministic keygen. */
35
+ memcpy(seedbuf, seed_in, SEEDBYTES);
36
+ seedbuf[SEEDBYTES + 0] = K;
37
+ seedbuf[SEEDBYTES + 1] = L;
38
+ shake256(seedbuf, 2 * SEEDBYTES + CRHBYTES, seedbuf, SEEDBYTES + 2);
39
+ rho = seedbuf;
40
+ rhoprime = rho + SEEDBYTES;
41
+ key = rhoprime + CRHBYTES;
42
+
43
+ /* Expand matrix */
44
+ PQCLEAN_MLDSA87_CLEAN_polyvec_matrix_expand(mat, rho);
45
+
46
+ /* Sample short vectors s1 and s2 */
47
+ PQCLEAN_MLDSA87_CLEAN_polyvecl_uniform_eta(&s1, rhoprime, 0);
48
+ PQCLEAN_MLDSA87_CLEAN_polyveck_uniform_eta(&s2, rhoprime, L);
49
+
50
+ /* Matrix-vector multiplication */
51
+ s1hat = s1;
52
+ PQCLEAN_MLDSA87_CLEAN_polyvecl_ntt(&s1hat);
53
+ PQCLEAN_MLDSA87_CLEAN_polyvec_matrix_pointwise_montgomery(&t1, mat, &s1hat);
54
+ PQCLEAN_MLDSA87_CLEAN_polyveck_reduce(&t1);
55
+ PQCLEAN_MLDSA87_CLEAN_polyveck_invntt_tomont(&t1);
56
+
57
+ /* Add error vector s2 */
58
+ PQCLEAN_MLDSA87_CLEAN_polyveck_add(&t1, &t1, &s2);
59
+
60
+ /* Extract t1 and write public key */
61
+ PQCLEAN_MLDSA87_CLEAN_polyveck_caddq(&t1);
62
+ PQCLEAN_MLDSA87_CLEAN_polyveck_power2round(&t1, &t0, &t1);
63
+ PQCLEAN_MLDSA87_CLEAN_pack_pk(pk, rho, &t1);
64
+
65
+ /* Compute H(rho, t1) and write secret key */
66
+ shake256(tr, TRBYTES, pk, PQCLEAN_MLDSA87_CLEAN_CRYPTO_PUBLICKEYBYTES);
67
+ PQCLEAN_MLDSA87_CLEAN_pack_sk(sk, rho, tr, key, &t0, &s1, &s2);
68
+
69
+ return 0;
70
+ }
71
+
72
+ /*************************************************
73
+ * Name: crypto_sign_signature
74
+ *
75
+ * Description: Computes signature.
76
+ *
77
+ * Arguments: - uint8_t *sig: pointer to output signature (of length PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES)
78
+ * - size_t *siglen: pointer to output length of signature
79
+ * - uint8_t *m: pointer to message to be signed
80
+ * - size_t mlen: length of message
81
+ * - uint8_t *ctx: pointer to context string
82
+ * - size_t ctxlen: length of context string
83
+ * - uint8_t *sk: pointer to bit-packed secret key
84
+ *
85
+ * Returns 0 (success) or -1 (context string too long)
86
+ **************************************************/
87
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_signature_ctx(uint8_t *sig,
88
+ size_t *siglen,
89
+ const uint8_t *m,
90
+ size_t mlen,
91
+ const uint8_t *ctx,
92
+ size_t ctxlen,
93
+ const uint8_t *sk,
94
+ const uint8_t *rnd_in) {
95
+ unsigned int n;
96
+ uint8_t seedbuf[2 * SEEDBYTES + TRBYTES + RNDBYTES + 2 * CRHBYTES];
97
+ uint8_t *rho, *tr, *key, *mu, *rhoprime, *rnd;
98
+ uint16_t nonce = 0;
99
+ polyvecl mat[K], s1, y, z;
100
+ polyveck t0, s2, w1, w0, h;
101
+ poly cp;
102
+ shake256incctx state;
103
+
104
+ if (ctxlen > 255) {
105
+ return -1;
106
+ }
107
+
108
+ rho = seedbuf;
109
+ tr = rho + SEEDBYTES;
110
+ key = tr + TRBYTES;
111
+ rnd = key + SEEDBYTES;
112
+ mu = rnd + RNDBYTES;
113
+ rhoprime = mu + CRHBYTES;
114
+ PQCLEAN_MLDSA87_CLEAN_unpack_sk(rho, tr, key, &t0, &s1, &s2, sk);
115
+
116
+ /* Compute mu = CRH(tr, 0, ctxlen, ctx, msg) */
117
+ mu[0] = 0;
118
+ mu[1] = (uint8_t)ctxlen;
119
+ shake256_inc_init(&state);
120
+ shake256_inc_absorb(&state, tr, TRBYTES);
121
+ shake256_inc_absorb(&state, mu, 2);
122
+ shake256_inc_absorb(&state, ctx, ctxlen);
123
+ shake256_inc_absorb(&state, m, mlen);
124
+ shake256_inc_finalize(&state);
125
+ shake256_inc_squeeze(mu, CRHBYTES, &state);
126
+ shake256_inc_ctx_release(&state);
127
+
128
+ memcpy(rnd, rnd_in, RNDBYTES);
129
+ shake256(rhoprime, CRHBYTES, key, SEEDBYTES + RNDBYTES + CRHBYTES);
130
+
131
+ /* Expand matrix and transform vectors */
132
+ PQCLEAN_MLDSA87_CLEAN_polyvec_matrix_expand(mat, rho);
133
+ PQCLEAN_MLDSA87_CLEAN_polyvecl_ntt(&s1);
134
+ PQCLEAN_MLDSA87_CLEAN_polyveck_ntt(&s2);
135
+ PQCLEAN_MLDSA87_CLEAN_polyveck_ntt(&t0);
136
+
137
+ rej:
138
+ /* Sample intermediate vector y */
139
+ PQCLEAN_MLDSA87_CLEAN_polyvecl_uniform_gamma1(&y, rhoprime, nonce++);
140
+
141
+ /* Matrix-vector multiplication */
142
+ z = y;
143
+ PQCLEAN_MLDSA87_CLEAN_polyvecl_ntt(&z);
144
+ PQCLEAN_MLDSA87_CLEAN_polyvec_matrix_pointwise_montgomery(&w1, mat, &z);
145
+ PQCLEAN_MLDSA87_CLEAN_polyveck_reduce(&w1);
146
+ PQCLEAN_MLDSA87_CLEAN_polyveck_invntt_tomont(&w1);
147
+
148
+ /* Decompose w and call the random oracle */
149
+ PQCLEAN_MLDSA87_CLEAN_polyveck_caddq(&w1);
150
+ PQCLEAN_MLDSA87_CLEAN_polyveck_decompose(&w1, &w0, &w1);
151
+ PQCLEAN_MLDSA87_CLEAN_polyveck_pack_w1(sig, &w1);
152
+
153
+ shake256_inc_init(&state);
154
+ shake256_inc_absorb(&state, mu, CRHBYTES);
155
+ shake256_inc_absorb(&state, sig, K * POLYW1_PACKEDBYTES);
156
+ shake256_inc_finalize(&state);
157
+ shake256_inc_squeeze(sig, CTILDEBYTES, &state);
158
+ shake256_inc_ctx_release(&state);
159
+ PQCLEAN_MLDSA87_CLEAN_poly_challenge(&cp, sig);
160
+ PQCLEAN_MLDSA87_CLEAN_poly_ntt(&cp);
161
+
162
+ /* Compute z, reject if it reveals secret */
163
+ PQCLEAN_MLDSA87_CLEAN_polyvecl_pointwise_poly_montgomery(&z, &cp, &s1);
164
+ PQCLEAN_MLDSA87_CLEAN_polyvecl_invntt_tomont(&z);
165
+ PQCLEAN_MLDSA87_CLEAN_polyvecl_add(&z, &z, &y);
166
+ PQCLEAN_MLDSA87_CLEAN_polyvecl_reduce(&z);
167
+ if (PQCLEAN_MLDSA87_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) {
168
+ goto rej;
169
+ }
170
+
171
+ /* Check that subtracting cs2 does not change high bits of w and low bits
172
+ * do not reveal secret information */
173
+ PQCLEAN_MLDSA87_CLEAN_polyveck_pointwise_poly_montgomery(&h, &cp, &s2);
174
+ PQCLEAN_MLDSA87_CLEAN_polyveck_invntt_tomont(&h);
175
+ PQCLEAN_MLDSA87_CLEAN_polyveck_sub(&w0, &w0, &h);
176
+ PQCLEAN_MLDSA87_CLEAN_polyveck_reduce(&w0);
177
+ if (PQCLEAN_MLDSA87_CLEAN_polyveck_chknorm(&w0, GAMMA2 - BETA)) {
178
+ goto rej;
179
+ }
180
+
181
+ /* Compute hints for w1 */
182
+ PQCLEAN_MLDSA87_CLEAN_polyveck_pointwise_poly_montgomery(&h, &cp, &t0);
183
+ PQCLEAN_MLDSA87_CLEAN_polyveck_invntt_tomont(&h);
184
+ PQCLEAN_MLDSA87_CLEAN_polyveck_reduce(&h);
185
+ if (PQCLEAN_MLDSA87_CLEAN_polyveck_chknorm(&h, GAMMA2)) {
186
+ goto rej;
187
+ }
188
+
189
+ PQCLEAN_MLDSA87_CLEAN_polyveck_add(&w0, &w0, &h);
190
+ n = PQCLEAN_MLDSA87_CLEAN_polyveck_make_hint(&h, &w0, &w1);
191
+ if (n > OMEGA) {
192
+ goto rej;
193
+ }
194
+
195
+ /* Write signature */
196
+ PQCLEAN_MLDSA87_CLEAN_pack_sig(sig, sig, &z, &h);
197
+ *siglen = PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES;
198
+ return 0;
199
+ }
200
+
201
+ /*************************************************
202
+ * Name: crypto_sign
203
+ *
204
+ * Description: Compute signed message.
205
+ *
206
+ * Arguments: - uint8_t *sm: pointer to output signed message (allocated
207
+ * array with PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES + mlen bytes),
208
+ * can be equal to m
209
+ * - size_t *smlen: pointer to output length of signed
210
+ * message
211
+ * - const uint8_t *m: pointer to message to be signed
212
+ * - size_t mlen: length of message
213
+ * - const uint8_t *ctx: pointer to context string
214
+ * - size_t ctxlen: length of context string
215
+ * - const uint8_t *sk: pointer to bit-packed secret key
216
+ *
217
+ * Returns 0 (success) or -1 (context string too long)
218
+ **************************************************/
219
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_ctx(uint8_t *sm,
220
+ size_t *smlen,
221
+ const uint8_t *m,
222
+ size_t mlen,
223
+ const uint8_t *ctx,
224
+ size_t ctxlen,
225
+ const uint8_t *sk) {
226
+ int ret;
227
+ size_t i;
228
+ uint8_t rnd[RNDBYTES];
229
+
230
+ randombytes(rnd, RNDBYTES);
231
+ for (i = 0; i < mlen; ++i) {
232
+ sm[PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES + mlen - 1 - i] = m[mlen - 1 - i];
233
+ }
234
+ ret = PQCLEAN_MLDSA87_CLEAN_crypto_sign_signature_ctx(sm, smlen, sm + PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES, mlen, ctx, ctxlen, sk, rnd);
235
+ *smlen += mlen;
236
+ return ret;
237
+ }
238
+
239
+ /*************************************************
240
+ * Name: crypto_sign_verify
241
+ *
242
+ * Description: Verifies signature.
243
+ *
244
+ * Arguments: - uint8_t *m: pointer to input signature
245
+ * - size_t siglen: length of signature
246
+ * - const uint8_t *m: pointer to message
247
+ * - size_t mlen: length of message
248
+ * - const uint8_t *ctx: pointer to context string
249
+ * - size_t ctxlen: length of context string
250
+ * - const uint8_t *pk: pointer to bit-packed public key
251
+ *
252
+ * Returns 0 if signature could be verified correctly and -1 otherwise
253
+ **************************************************/
254
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_verify_ctx(const uint8_t *sig,
255
+ size_t siglen,
256
+ const uint8_t *m,
257
+ size_t mlen,
258
+ const uint8_t *ctx,
259
+ size_t ctxlen,
260
+ const uint8_t *pk) {
261
+ unsigned int i;
262
+ uint8_t buf[K * POLYW1_PACKEDBYTES];
263
+ uint8_t rho[SEEDBYTES];
264
+ uint8_t mu[CRHBYTES];
265
+ uint8_t c[CTILDEBYTES];
266
+ uint8_t c2[CTILDEBYTES];
267
+ poly cp;
268
+ polyvecl mat[K], z;
269
+ polyveck t1, w1, h;
270
+ shake256incctx state;
271
+
272
+ if (ctxlen > 255 || siglen != PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES) {
273
+ return -1;
274
+ }
275
+
276
+ PQCLEAN_MLDSA87_CLEAN_unpack_pk(rho, &t1, pk);
277
+ if (PQCLEAN_MLDSA87_CLEAN_unpack_sig(c, &z, &h, sig)) {
278
+ return -1;
279
+ }
280
+ if (PQCLEAN_MLDSA87_CLEAN_polyvecl_chknorm(&z, GAMMA1 - BETA)) {
281
+ return -1;
282
+ }
283
+
284
+ /* Compute CRH(H(rho, t1), msg) */
285
+ shake256(mu, TRBYTES, pk, PQCLEAN_MLDSA87_CLEAN_CRYPTO_PUBLICKEYBYTES);
286
+ shake256_inc_init(&state);
287
+ shake256_inc_absorb(&state, mu, TRBYTES);
288
+ mu[0] = 0;
289
+ mu[1] = (uint8_t)ctxlen;
290
+ shake256_inc_absorb(&state, mu, 2);
291
+ shake256_inc_absorb(&state, ctx, ctxlen);
292
+ shake256_inc_absorb(&state, m, mlen);
293
+ shake256_inc_finalize(&state);
294
+ shake256_inc_squeeze(mu, CRHBYTES, &state);
295
+ shake256_inc_ctx_release(&state);
296
+
297
+ /* Matrix-vector multiplication; compute Az - c2^dt1 */
298
+ PQCLEAN_MLDSA87_CLEAN_poly_challenge(&cp, c);
299
+ PQCLEAN_MLDSA87_CLEAN_polyvec_matrix_expand(mat, rho);
300
+
301
+ PQCLEAN_MLDSA87_CLEAN_polyvecl_ntt(&z);
302
+ PQCLEAN_MLDSA87_CLEAN_polyvec_matrix_pointwise_montgomery(&w1, mat, &z);
303
+
304
+ PQCLEAN_MLDSA87_CLEAN_poly_ntt(&cp);
305
+ PQCLEAN_MLDSA87_CLEAN_polyveck_shiftl(&t1);
306
+ PQCLEAN_MLDSA87_CLEAN_polyveck_ntt(&t1);
307
+ PQCLEAN_MLDSA87_CLEAN_polyveck_pointwise_poly_montgomery(&t1, &cp, &t1);
308
+
309
+ PQCLEAN_MLDSA87_CLEAN_polyveck_sub(&w1, &w1, &t1);
310
+ PQCLEAN_MLDSA87_CLEAN_polyveck_reduce(&w1);
311
+ PQCLEAN_MLDSA87_CLEAN_polyveck_invntt_tomont(&w1);
312
+
313
+ /* Reconstruct w1 */
314
+ PQCLEAN_MLDSA87_CLEAN_polyveck_caddq(&w1);
315
+ PQCLEAN_MLDSA87_CLEAN_polyveck_use_hint(&w1, &w1, &h);
316
+ PQCLEAN_MLDSA87_CLEAN_polyveck_pack_w1(buf, &w1);
317
+
318
+ /* Call random oracle and verify challenge */
319
+ shake256_inc_init(&state);
320
+ shake256_inc_absorb(&state, mu, CRHBYTES);
321
+ shake256_inc_absorb(&state, buf, K * POLYW1_PACKEDBYTES);
322
+ shake256_inc_finalize(&state);
323
+ shake256_inc_squeeze(c2, CTILDEBYTES, &state);
324
+ shake256_inc_ctx_release(&state);
325
+ for (i = 0; i < CTILDEBYTES; ++i) {
326
+ if (c[i] != c2[i]) {
327
+ return -1;
328
+ }
329
+ }
330
+
331
+ return 0;
332
+ }
333
+
334
+ /*************************************************
335
+ * Name: crypto_sign_open
336
+ *
337
+ * Description: Verify signed message.
338
+ *
339
+ * Arguments: - uint8_t *m: pointer to output message (allocated
340
+ * array with smlen bytes), can be equal to sm
341
+ * - size_t *mlen: pointer to output length of message
342
+ * - const uint8_t *sm: pointer to signed message
343
+ * - size_t smlen: length of signed message
344
+ * - const uint8_t *ctx: pointer to context tring
345
+ * - size_t ctxlen: length of context string
346
+ * - const uint8_t *pk: pointer to bit-packed public key
347
+ *
348
+ * Returns 0 if signed message could be verified correctly and -1 otherwise
349
+ **************************************************/
350
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_open_ctx(uint8_t *m,
351
+ size_t *mlen,
352
+ const uint8_t *sm,
353
+ size_t smlen,
354
+ const uint8_t *ctx,
355
+ size_t ctxlen,
356
+ const uint8_t *pk) {
357
+ size_t i;
358
+
359
+ if (smlen < PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES) {
360
+ goto badsig;
361
+ }
362
+
363
+ *mlen = smlen - PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES;
364
+ if (PQCLEAN_MLDSA87_CLEAN_crypto_sign_verify_ctx(sm, PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES, sm + PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES, *mlen, ctx, ctxlen, pk)) {
365
+ goto badsig;
366
+ } else {
367
+ /* All good, copy msg, return 0 */
368
+ for (i = 0; i < *mlen; ++i) {
369
+ m[i] = sm[PQCLEAN_MLDSA87_CLEAN_CRYPTO_BYTES + i];
370
+ }
371
+ return 0;
372
+ }
373
+
374
+ badsig:
375
+ /* Signature verification failed */
376
+ *mlen = 0;
377
+ for (i = 0; i < smlen; ++i) {
378
+ m[i] = 0;
379
+ }
380
+
381
+ return -1;
382
+ }
383
+
384
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_signature(uint8_t *sig,
385
+ size_t *siglen,
386
+ const uint8_t *m,
387
+ size_t mlen,
388
+ const uint8_t *sk) {
389
+ uint8_t rnd[RNDBYTES];
390
+ randombytes(rnd, RNDBYTES);
391
+ return PQCLEAN_MLDSA87_CLEAN_crypto_sign_signature_ctx(sig, siglen, m, mlen, NULL, 0, sk, rnd);
392
+ }
393
+
394
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign(uint8_t *sm,
395
+ size_t *smlen,
396
+ const uint8_t *m,
397
+ size_t mlen,
398
+ const uint8_t *sk) {
399
+ return PQCLEAN_MLDSA87_CLEAN_crypto_sign_ctx(sm, smlen, m, mlen, NULL, 0, sk);
400
+ }
401
+
402
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_verify(const uint8_t *sig,
403
+ size_t siglen,
404
+ const uint8_t *m,
405
+ size_t mlen,
406
+ const uint8_t *pk) {
407
+ return PQCLEAN_MLDSA87_CLEAN_crypto_sign_verify_ctx(sig, siglen, m, mlen, NULL, 0, pk);
408
+ }
409
+
410
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_open(uint8_t *m,
411
+ size_t *mlen,
412
+ const uint8_t *sm, size_t smlen,
413
+ const uint8_t *pk) {
414
+ return PQCLEAN_MLDSA87_CLEAN_crypto_sign_open_ctx(m, mlen, sm, smlen, NULL, 0, pk);
415
+ }
@@ -0,0 +1,49 @@
1
+ #ifndef PQCLEAN_MLDSA87_CLEAN_SIGN_H
2
+ #define PQCLEAN_MLDSA87_CLEAN_SIGN_H
3
+ #include "params.h"
4
+ #include "poly.h"
5
+ #include "polyvec.h"
6
+ #include <stddef.h>
7
+ #include <stdint.h>
8
+
9
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_keypair(uint8_t *pk, uint8_t *sk,
10
+ const uint8_t *seed_in);
11
+
12
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_signature_ctx(uint8_t *sig, size_t *siglen,
13
+ const uint8_t *m, size_t mlen,
14
+ const uint8_t *ctx, size_t ctxlen,
15
+ const uint8_t *sk,
16
+ const uint8_t *rnd_in);
17
+
18
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_ctx(uint8_t *sm, size_t *smlen,
19
+ const uint8_t *m, size_t mlen,
20
+ const uint8_t *ctx, size_t ctxlen,
21
+ const uint8_t *sk);
22
+
23
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_verify_ctx(const uint8_t *sig, size_t siglen,
24
+ const uint8_t *m, size_t mlen,
25
+ const uint8_t *ctx, size_t ctxlen,
26
+ const uint8_t *pk);
27
+
28
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_open_ctx(uint8_t *m, size_t *mlen,
29
+ const uint8_t *sm, size_t smlen,
30
+ const uint8_t *ctx, size_t ctxlen,
31
+ const uint8_t *pk);
32
+
33
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_signature(uint8_t *sig, size_t *siglen,
34
+ const uint8_t *m, size_t mlen,
35
+ const uint8_t *sk);
36
+
37
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign(uint8_t *sm, size_t *smlen,
38
+ const uint8_t *m, size_t mlen,
39
+ const uint8_t *sk);
40
+
41
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_verify(const uint8_t *sig, size_t siglen,
42
+ const uint8_t *m, size_t mlen,
43
+ const uint8_t *pk);
44
+
45
+ int PQCLEAN_MLDSA87_CLEAN_crypto_sign_open(uint8_t *m, size_t *mlen,
46
+ const uint8_t *sm, size_t smlen,
47
+ const uint8_t *pk);
48
+
49
+ #endif
@@ -0,0 +1,26 @@
1
+ #include "fips202.h"
2
+ #include "params.h"
3
+ #include "symmetric.h"
4
+ #include <stdint.h>
5
+
6
+ void PQCLEAN_MLDSA87_CLEAN_dilithium_shake128_stream_init(shake128incctx *state, const uint8_t seed[SEEDBYTES], uint16_t nonce) {
7
+ uint8_t t[2];
8
+ t[0] = (uint8_t) nonce;
9
+ t[1] = (uint8_t) (nonce >> 8);
10
+
11
+ shake128_inc_init(state);
12
+ shake128_inc_absorb(state, seed, SEEDBYTES);
13
+ shake128_inc_absorb(state, t, 2);
14
+ shake128_inc_finalize(state);
15
+ }
16
+
17
+ void PQCLEAN_MLDSA87_CLEAN_dilithium_shake256_stream_init(shake256incctx *state, const uint8_t seed[CRHBYTES], uint16_t nonce) {
18
+ uint8_t t[2];
19
+ t[0] = (uint8_t) nonce;
20
+ t[1] = (uint8_t) (nonce >> 8);
21
+
22
+ shake256_inc_init(state);
23
+ shake256_inc_absorb(state, seed, CRHBYTES);
24
+ shake256_inc_absorb(state, t, 2);
25
+ shake256_inc_finalize(state);
26
+ }
@@ -0,0 +1,34 @@
1
+ #ifndef PQCLEAN_MLDSA87_CLEAN_SYMMETRIC_H
2
+ #define PQCLEAN_MLDSA87_CLEAN_SYMMETRIC_H
3
+ #include "fips202.h"
4
+ #include "params.h"
5
+ #include <stdint.h>
6
+
7
+
8
+ typedef shake128incctx stream128_state;
9
+ typedef shake256incctx stream256_state;
10
+
11
+ void PQCLEAN_MLDSA87_CLEAN_dilithium_shake128_stream_init(shake128incctx *state,
12
+ const uint8_t seed[SEEDBYTES],
13
+ uint16_t nonce);
14
+
15
+ void PQCLEAN_MLDSA87_CLEAN_dilithium_shake256_stream_init(shake256incctx *state,
16
+ const uint8_t seed[CRHBYTES],
17
+ uint16_t nonce);
18
+
19
+ #define STREAM128_BLOCKBYTES SHAKE128_RATE
20
+ #define STREAM256_BLOCKBYTES SHAKE256_RATE
21
+
22
+ #define stream128_init(STATE, SEED, NONCE) \
23
+ PQCLEAN_MLDSA87_CLEAN_dilithium_shake128_stream_init(STATE, SEED, NONCE)
24
+ #define stream128_squeezeblocks(OUT, OUTBLOCKS, STATE) \
25
+ shake128_inc_squeeze(OUT, (OUTBLOCKS)*(SHAKE128_RATE), STATE)
26
+ #define stream128_release(STATE) shake128_inc_ctx_release(STATE)
27
+
28
+ #define stream256_init(STATE, SEED, NONCE) \
29
+ PQCLEAN_MLDSA87_CLEAN_dilithium_shake256_stream_init(STATE, SEED, NONCE)
30
+ #define stream256_squeezeblocks(OUT, OUTBLOCKS, STATE) \
31
+ shake256_inc_squeeze(OUT, (OUTBLOCKS)*(SHAKE256_RATE), STATE)
32
+ #define stream256_release(STATE) shake256_inc_ctx_release(STATE)
33
+
34
+ #endif
@@ -0,0 +1,10 @@
1
+ /*
2
+ * ml_dsa_44_impl.c — ML-DSA-44 amalgamation (PQClean clean implementation).
3
+ *
4
+ * AUTO-GENERATED by `rake generate:impl` — do not edit by hand.
5
+ * Uses the parametric template: all PQClean sources are listed once
6
+ * in ml_dsa_impl_template.h; this file just selects the parameter set.
7
+ */
8
+
9
+ #define ML_DSA_PS 44
10
+ #include "ml_dsa_impl_template.h"
@@ -0,0 +1,10 @@
1
+ /*
2
+ * ml_dsa_65_impl.c — ML-DSA-65 amalgamation (PQClean clean implementation).
3
+ *
4
+ * AUTO-GENERATED by `rake generate:impl` — do not edit by hand.
5
+ * Uses the parametric template: all PQClean sources are listed once
6
+ * in ml_dsa_impl_template.h; this file just selects the parameter set.
7
+ */
8
+
9
+ #define ML_DSA_PS 65
10
+ #include "ml_dsa_impl_template.h"
@@ -0,0 +1,10 @@
1
+ /*
2
+ * ml_dsa_87_impl.c — ML-DSA-87 amalgamation (PQClean clean implementation).
3
+ *
4
+ * AUTO-GENERATED by `rake generate:impl` — do not edit by hand.
5
+ * Uses the parametric template: all PQClean sources are listed once
6
+ * in ml_dsa_impl_template.h; this file just selects the parameter set.
7
+ */
8
+
9
+ #define ML_DSA_PS 87
10
+ #include "ml_dsa_impl_template.h"