/src/boringssl/crypto/fipsmodule/mldsa/mldsa.cc.inc
Line | Count | Source |
1 | | // Copyright 2014 The BoringSSL Authors |
2 | | // |
3 | | // Licensed under the Apache License, Version 2.0 (the "License"); |
4 | | // you may not use this file except in compliance with the License. |
5 | | // You may obtain a copy of the License at |
6 | | // |
7 | | // https://www.apache.org/licenses/LICENSE-2.0 |
8 | | // |
9 | | // Unless required by applicable law or agreed to in writing, software |
10 | | // distributed under the License is distributed on an "AS IS" BASIS, |
11 | | // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
12 | | // See the License for the specific language governing permissions and |
13 | | // limitations under the License. |
14 | | |
15 | | #include <openssl/base.h> |
16 | | |
17 | | #include <memory> |
18 | | |
19 | | #include <assert.h> |
20 | | #include <stdlib.h> |
21 | | |
22 | | #include <openssl/bytestring.h> |
23 | | #include <openssl/mem.h> |
24 | | #include <openssl/rand.h> |
25 | | |
26 | | #include "../../internal.h" |
27 | | #include "../../mem_internal.h" |
28 | | #include "../bcm_interface.h" |
29 | | #include "../keccak/internal.h" |
30 | | |
31 | | namespace mldsa { |
32 | | namespace { |
33 | | |
34 | | namespace fips { |
35 | | void ensure_keygen_self_test(); |
36 | | void ensure_sign_self_test(); |
37 | | void ensure_verify_self_test(); |
38 | | } // namespace fips |
39 | | |
40 | | constexpr int kDegree = 256; |
41 | | constexpr int kRhoBytes = 32; |
42 | | constexpr int kSigmaBytes = 64; |
43 | | constexpr int kKBytes = 32; |
44 | | constexpr int kTrBytes = 64; |
45 | | constexpr int kMuBytes = 64; |
46 | | constexpr int kRhoPrimeBytes = 64; |
47 | | |
48 | | // 2^23 - 2^13 + 1 |
49 | | constexpr uint32_t kPrime = 8380417; |
50 | | // Inverse of -kPrime modulo 2^32 |
51 | | constexpr uint32_t kPrimeNegInverse = 4236238847; |
52 | | constexpr int kDroppedBits = 13; |
53 | | constexpr uint32_t kHalfPrime = (kPrime - 1) / 2; |
54 | | // 256^-1 mod kPrime, in Montgomery form. |
55 | | constexpr uint32_t kInverseDegreeMontgomery = 41978; |
56 | | |
57 | | // Constants that vary depending on ML-DSA size. |
58 | | // |
59 | | // These are implemented as templates which take the K parameter to distinguish |
60 | | // the ML-DSA sizes. |
61 | | |
62 | | template <int K> |
63 | 0 | constexpr size_t public_key_bytes() { |
64 | 0 | if constexpr (K == 6) { |
65 | 0 | return MLDSA65_PUBLIC_KEY_BYTES; |
66 | 0 | } else if constexpr (K == 8) { |
67 | 0 | return MLDSA87_PUBLIC_KEY_BYTES; |
68 | 0 | } else if constexpr (K == 4) { |
69 | 0 | return MLDSA44_PUBLIC_KEY_BYTES; |
70 | 0 | } |
71 | 0 | } Unexecuted instantiation: bcm.cc:unsigned long mldsa::(anonymous namespace)::public_key_bytes<6>() Unexecuted instantiation: bcm.cc:unsigned long mldsa::(anonymous namespace)::public_key_bytes<8>() Unexecuted instantiation: bcm.cc:unsigned long mldsa::(anonymous namespace)::public_key_bytes<4>() |
72 | | |
73 | | template <int K> |
74 | 0 | constexpr size_t signature_bytes() { |
75 | 0 | if constexpr (K == 6) { |
76 | 0 | return MLDSA65_SIGNATURE_BYTES; |
77 | 0 | } else if constexpr (K == 8) { |
78 | 0 | return MLDSA87_SIGNATURE_BYTES; |
79 | 0 | } else if constexpr (K == 4) { |
80 | 0 | return MLDSA44_SIGNATURE_BYTES; |
81 | 0 | } |
82 | 0 | } Unexecuted instantiation: bcm.cc:unsigned long mldsa::(anonymous namespace)::signature_bytes<6>() Unexecuted instantiation: bcm.cc:unsigned long mldsa::(anonymous namespace)::signature_bytes<8>() Unexecuted instantiation: bcm.cc:unsigned long mldsa::(anonymous namespace)::signature_bytes<4>() |
83 | | |
84 | | template <int K> |
85 | 0 | constexpr int tau() { |
86 | 0 | if constexpr (K == 6) { |
87 | 0 | return 49; |
88 | 0 | } else if constexpr (K == 8) { |
89 | 0 | return 60; |
90 | 0 | } else if constexpr (K == 4) { |
91 | 0 | return 39; |
92 | 0 | } |
93 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::tau<6>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::tau<8>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::tau<4>() |
94 | | |
95 | | template <int K> |
96 | 0 | constexpr int lambda_bytes() { |
97 | 0 | if constexpr (K == 6) { |
98 | 0 | return 192 / 8; |
99 | 0 | } else if constexpr (K == 8) { |
100 | 0 | return 256 / 8; |
101 | 0 | } else if constexpr (K == 4) { |
102 | 0 | return 128 / 8; |
103 | 0 | } |
104 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::lambda_bytes<6>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::lambda_bytes<8>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::lambda_bytes<4>() |
105 | | |
106 | | template <int K> |
107 | 0 | constexpr int gamma1_bits() { |
108 | 0 | if constexpr (K == 6 || K == 8) { |
109 | 0 | return 19; |
110 | 0 | } else if constexpr (K == 4) { |
111 | 0 | return 17; |
112 | 0 | } |
113 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::gamma1_bits<6>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::gamma1_bits<8>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::gamma1_bits<4>() |
114 | | |
115 | | template <int K> |
116 | 0 | constexpr int gamma1() { |
117 | 0 | return 1 << gamma1_bits<K>(); |
118 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::gamma1<6>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::gamma1<8>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::gamma1<4>() |
119 | | |
120 | | template <int K> |
121 | 0 | constexpr int scalar_le_gamma1_bytes() { |
122 | 0 | return ((gamma1_bits<K>() + 1) * kDegree) / 8; |
123 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::scalar_le_gamma1_bytes<6>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::scalar_le_gamma1_bytes<8>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::scalar_le_gamma1_bytes<4>() |
124 | | |
125 | | template <int K> |
126 | 0 | constexpr uint32_t w1_coeffs_bits() { |
127 | 0 | if constexpr (K == 6 || K == 8) { |
128 | 0 | return 4; |
129 | 0 | } else if constexpr (K == 4) { |
130 | 0 | return 6; |
131 | 0 | } |
132 | 0 | } Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::w1_coeffs_bits<6>() Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::w1_coeffs_bits<8>() Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::w1_coeffs_bits<4>() |
133 | | |
134 | | template <int K> |
135 | 0 | constexpr uint32_t w1_scalar_bytes() { |
136 | 0 | return (w1_coeffs_bits<K>() * kDegree) / 8; |
137 | 0 | } Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::w1_scalar_bytes<6>() Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::w1_scalar_bytes<8>() Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::w1_scalar_bytes<4>() |
138 | | |
139 | | template <int K> |
140 | 0 | constexpr uint32_t w1_bytes() { |
141 | 0 | return w1_scalar_bytes<K>() * K; |
142 | 0 | } Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::w1_bytes<6>() Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::w1_bytes<8>() Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::w1_bytes<4>() |
143 | | |
144 | | template <int K> |
145 | 0 | constexpr uint32_t prime_minus_one_over_gamma2() { |
146 | 0 | if constexpr (K == 6 || K == 8) { |
147 | 0 | return 32; |
148 | 0 | } else if constexpr (K == 4) { |
149 | 0 | return 88; |
150 | 0 | } |
151 | 0 | } Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::prime_minus_one_over_gamma2<6>() Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::prime_minus_one_over_gamma2<8>() Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::prime_minus_one_over_gamma2<4>() |
152 | | |
153 | | template <int K> |
154 | 0 | constexpr uint32_t gamma2() { |
155 | 0 | return (kPrime - 1) / prime_minus_one_over_gamma2<K>(); |
156 | 0 | } Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::gamma2<6>() Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::gamma2<8>() Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::gamma2<4>() |
157 | | |
158 | | template <int K> |
159 | 0 | constexpr int beta() { |
160 | 0 | if constexpr (K == 6) { |
161 | 0 | return 196; |
162 | 0 | } else if constexpr (K == 8) { |
163 | 0 | return 120; |
164 | 0 | } else if constexpr (K == 4) { |
165 | 0 | return 78; |
166 | 0 | } |
167 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::beta<6>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::beta<8>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::beta<4>() |
168 | | |
169 | | template <int K> |
170 | 0 | constexpr int omega() { |
171 | 0 | if constexpr (K == 6) { |
172 | 0 | return 55; |
173 | 0 | } else if constexpr (K == 8) { |
174 | 0 | return 75; |
175 | 0 | } else if constexpr (K == 4) { |
176 | 0 | return 80; |
177 | 0 | } |
178 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::omega<6>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::omega<8>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::omega<4>() |
179 | | |
180 | | template <int K> |
181 | 0 | constexpr int eta() { |
182 | 0 | if constexpr (K == 6) { |
183 | 0 | return 4; |
184 | 0 | } else if constexpr (K == 8 || K == 4) { |
185 | 0 | return 2; |
186 | 0 | } |
187 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::eta<6>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::eta<8>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::eta<4>() |
188 | | |
189 | | template <int K> |
190 | 0 | constexpr int plus_minus_eta_bitlen() { |
191 | 0 | if constexpr (K == 6) { |
192 | 0 | return 4; |
193 | 0 | } else if constexpr (K == 8 || K == 4) { |
194 | 0 | return 3; |
195 | 0 | } |
196 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::plus_minus_eta_bitlen<6>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::plus_minus_eta_bitlen<8>() Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::plus_minus_eta_bitlen<4>() |
197 | | |
198 | | // Fundamental types. |
199 | | |
200 | | struct scalar { |
201 | | uint32_t c[kDegree]; |
202 | | }; |
203 | | |
204 | | template <int K> |
205 | | struct vector { |
206 | | scalar v[K]; |
207 | | }; |
208 | | |
209 | | template <int K, int L> |
210 | | struct matrix { |
211 | | scalar v[K][L]; |
212 | | }; |
213 | | |
214 | | /* Arithmetic */ |
215 | | |
216 | | // This bit of Python will be referenced in some of the following comments: |
217 | | // |
218 | | // q = 8380417 |
219 | | // # Inverse of -q modulo 2^32 |
220 | | // q_neg_inverse = 4236238847 |
221 | | // # 2^64 modulo q |
222 | | // montgomery_square = 2365951 |
223 | | // |
224 | | // def bitreverse(i): |
225 | | // ret = 0 |
226 | | // for n in range(8): |
227 | | // bit = i & 1 |
228 | | // ret <<= 1 |
229 | | // ret |= bit |
230 | | // i >>= 1 |
231 | | // return ret |
232 | | // |
233 | | // def montgomery_reduce(x): |
234 | | // a = (x * q_neg_inverse) % 2**32 |
235 | | // b = x + a * q |
236 | | // assert b & 0xFFFF_FFFF == 0 |
237 | | // c = b >> 32 |
238 | | // assert c < q |
239 | | // return c |
240 | | // |
241 | | // def montgomery_transform(x): |
242 | | // return montgomery_reduce(x * montgomery_square) |
243 | | |
244 | | // kNTTRootsMontgomery = [ |
245 | | // montgomery_transform(pow(1753, bitreverse(i), q)) for i in range(256) |
246 | | // ] |
247 | | static const uint32_t kNTTRootsMontgomery[256] = { |
248 | | 4193792, 25847, 5771523, 7861508, 237124, 7602457, 7504169, 466468, |
249 | | 1826347, 2353451, 8021166, 6288512, 3119733, 5495562, 3111497, 2680103, |
250 | | 2725464, 1024112, 7300517, 3585928, 7830929, 7260833, 2619752, 6271868, |
251 | | 6262231, 4520680, 6980856, 5102745, 1757237, 8360995, 4010497, 280005, |
252 | | 2706023, 95776, 3077325, 3530437, 6718724, 4788269, 5842901, 3915439, |
253 | | 4519302, 5336701, 3574422, 5512770, 3539968, 8079950, 2348700, 7841118, |
254 | | 6681150, 6736599, 3505694, 4558682, 3507263, 6239768, 6779997, 3699596, |
255 | | 811944, 531354, 954230, 3881043, 3900724, 5823537, 2071892, 5582638, |
256 | | 4450022, 6851714, 4702672, 5339162, 6927966, 3475950, 2176455, 6795196, |
257 | | 7122806, 1939314, 4296819, 7380215, 5190273, 5223087, 4747489, 126922, |
258 | | 3412210, 7396998, 2147896, 2715295, 5412772, 4686924, 7969390, 5903370, |
259 | | 7709315, 7151892, 8357436, 7072248, 7998430, 1349076, 1852771, 6949987, |
260 | | 5037034, 264944, 508951, 3097992, 44288, 7280319, 904516, 3958618, |
261 | | 4656075, 8371839, 1653064, 5130689, 2389356, 8169440, 759969, 7063561, |
262 | | 189548, 4827145, 3159746, 6529015, 5971092, 8202977, 1315589, 1341330, |
263 | | 1285669, 6795489, 7567685, 6940675, 5361315, 4499357, 4751448, 3839961, |
264 | | 2091667, 3407706, 2316500, 3817976, 5037939, 2244091, 5933984, 4817955, |
265 | | 266997, 2434439, 7144689, 3513181, 4860065, 4621053, 7183191, 5187039, |
266 | | 900702, 1859098, 909542, 819034, 495491, 6767243, 8337157, 7857917, |
267 | | 7725090, 5257975, 2031748, 3207046, 4823422, 7855319, 7611795, 4784579, |
268 | | 342297, 286988, 5942594, 4108315, 3437287, 5038140, 1735879, 203044, |
269 | | 2842341, 2691481, 5790267, 1265009, 4055324, 1247620, 2486353, 1595974, |
270 | | 4613401, 1250494, 2635921, 4832145, 5386378, 1869119, 1903435, 7329447, |
271 | | 7047359, 1237275, 5062207, 6950192, 7929317, 1312455, 3306115, 6417775, |
272 | | 7100756, 1917081, 5834105, 7005614, 1500165, 777191, 2235880, 3406031, |
273 | | 7838005, 5548557, 6709241, 6533464, 5796124, 4656147, 594136, 4603424, |
274 | | 6366809, 2432395, 2454455, 8215696, 1957272, 3369112, 185531, 7173032, |
275 | | 5196991, 162844, 1616392, 3014001, 810149, 1652634, 4686184, 6581310, |
276 | | 5341501, 3523897, 3866901, 269760, 2213111, 7404533, 1717735, 472078, |
277 | | 7953734, 1723600, 6577327, 1910376, 6712985, 7276084, 8119771, 4546524, |
278 | | 5441381, 6144432, 7959518, 6094090, 183443, 7403526, 1612842, 4834730, |
279 | | 7826001, 3919660, 8332111, 7018208, 3937738, 1400424, 7534263, 1976782}; |
280 | | |
281 | | // Reduces x mod kPrime in constant time, where 0 <= x < 2*kPrime. |
282 | 0 | uint32_t reduce_once(uint32_t x) { |
283 | 0 | declassify_assert(x < 2 * kPrime); |
284 | | // return x < kPrime ? x : x - kPrime; |
285 | 0 | const uint32_t subtracted = x - kPrime; |
286 | 0 | uint32_t mask = 0u - (subtracted >> 31); |
287 | | // Although this is a constant-time select, we omit a value barrier here. |
288 | | // Value barriers impede auto-vectorization (likely because it forces the |
289 | | // value to transit through a general-purpose register). This is a difference |
290 | | // of 1.4x to 1.5x in signing performance. |
291 | | // |
292 | | // We usually add value barriers to selects because Clang turns consecutive |
293 | | // selects with the same condition into a branch instead of CMOV/CSEL. This |
294 | | // condition does not occur in ML-DSA, so omitting it seems to be generally |
295 | | // safe. However, see |coefficient_from_nibble|. |
296 | 0 | return (mask & x) | (~mask & subtracted); |
297 | 0 | } |
298 | | |
299 | | // Returns the absolute value in constant time, interpreting the high bit as a |
300 | | // sign bit. |
301 | 0 | uint32_t abs_signed(uint32_t x) { |
302 | | // return is_negative(x) ? -x : x; |
303 | 0 | uint32_t mask = 0u - (x >> 31); |
304 | 0 | return constant_time_select_32(mask, 0u - x, x); |
305 | 0 | } |
306 | | |
307 | | // Returns the absolute value modulo kPrime. |
308 | 0 | uint32_t abs_mod_prime(uint32_t x) { |
309 | 0 | declassify_assert(x < kPrime); |
310 | | // return x <= kHalfPrime ? x : kPrime - x; |
311 | 0 | uint32_t mask = x - kHalfPrime - 1; |
312 | 0 | mask = 0u - (mask >> 31); |
313 | 0 | return constant_time_select_32(mask, x, kPrime - x); |
314 | 0 | } |
315 | | |
316 | | // Returns the maximum of two values in constant time. Each value must be less |
317 | | // than kPrime. |
318 | 0 | uint32_t maximum_reduced(uint32_t x, uint32_t y) { |
319 | 0 | declassify_assert(x < kPrime); |
320 | 0 | declassify_assert(y < kPrime); |
321 | | // return x < y ? y : x; |
322 | 0 | uint32_t mask = x - y; |
323 | 0 | mask = 0u - (mask >> 31); |
324 | 0 | return constant_time_select_32(mask, y, x); |
325 | 0 | } |
326 | | |
327 | 0 | uint32_t mod_sub(uint32_t a, uint32_t b) { |
328 | 0 | declassify_assert(a < kPrime); |
329 | 0 | declassify_assert(b < kPrime); |
330 | 0 | uint32_t r = a - b; |
331 | | // return r < 0 ? r + kPrime : r; |
332 | 0 | uint32_t mask = 0u - (r >> 31); |
333 | | // See |reduce_once| for which this does not have a value barrier. |
334 | 0 | return (mask & (r + kPrime)) | (~mask & r); |
335 | 0 | } |
336 | | |
337 | 0 | void scalar_add(scalar *out, const scalar *lhs, const scalar *rhs) { |
338 | 0 | for (int i = 0; i < kDegree; i++) { |
339 | 0 | out->c[i] = reduce_once(lhs->c[i] + rhs->c[i]); |
340 | 0 | } |
341 | 0 | } |
342 | | |
343 | 0 | void scalar_sub(scalar *out, const scalar *lhs, const scalar *rhs) { |
344 | 0 | for (int i = 0; i < kDegree; i++) { |
345 | 0 | out->c[i] = mod_sub(lhs->c[i], rhs->c[i]); |
346 | 0 | } |
347 | 0 | } |
348 | | |
349 | 0 | uint32_t reduce_montgomery(uint64_t x) { |
350 | 0 | declassify_assert(x <= ((uint64_t)kPrime << 32)); |
351 | 0 | uint64_t a = (uint32_t)x * kPrimeNegInverse; |
352 | 0 | uint64_t b = x + a * kPrime; |
353 | 0 | declassify_assert((b & 0xffffffff) == 0); |
354 | 0 | uint32_t c = b >> 32; |
355 | 0 | return reduce_once(c); |
356 | 0 | } |
357 | | |
358 | | // Multiply two scalars in the number theoretically transformed state. |
359 | 0 | void scalar_mult(scalar *out, const scalar *lhs, const scalar *rhs) { |
360 | 0 | for (int i = 0; i < kDegree; i++) { |
361 | 0 | out->c[i] = reduce_montgomery((uint64_t)lhs->c[i] * (uint64_t)rhs->c[i]); |
362 | 0 | } |
363 | 0 | } |
364 | | |
365 | | // In place number theoretic transform of a given scalar. |
366 | | // |
367 | | // FIPS 204, Algorithm 41 (`NTT`). |
368 | 0 | static void scalar_ntt(scalar *s) { |
369 | | // Step: 1, 2, 4, 8, ..., 128 |
370 | | // Offset: 128, 64, 32, 16, ..., 1 |
371 | 0 | int offset = kDegree; |
372 | 0 | for (int step = 1; step < kDegree; step <<= 1) { |
373 | 0 | offset >>= 1; |
374 | 0 | int k = 0; |
375 | 0 | for (int i = 0; i < step; i++) { |
376 | 0 | assert(k == 2 * offset * i); |
377 | 0 | const uint32_t step_root = kNTTRootsMontgomery[step + i]; |
378 | 0 | for (int j = k; j < k + offset; j++) { |
379 | 0 | uint32_t even = s->c[j]; |
380 | | // |reduce_montgomery| works on values up to kPrime*R and R > 2*kPrime. |
381 | | // |step_root| < kPrime because it's static data. |s->c[...]| is < |
382 | | // kPrime by the invariants of that struct. |
383 | 0 | uint32_t odd = |
384 | 0 | reduce_montgomery((uint64_t)step_root * (uint64_t)s->c[j + offset]); |
385 | 0 | s->c[j] = reduce_once(odd + even); |
386 | 0 | s->c[j + offset] = mod_sub(even, odd); |
387 | 0 | } |
388 | 0 | k += 2 * offset; |
389 | 0 | } |
390 | 0 | } |
391 | 0 | } |
392 | | |
393 | | // In place inverse number theoretic transform of a given scalar. |
394 | | // |
395 | | // FIPS 204, Algorithm 42 (`NTT^-1`). |
396 | 0 | void scalar_inverse_ntt(scalar *s) { |
397 | | // Step: 128, 64, 32, 16, ..., 1 |
398 | | // Offset: 1, 2, 4, 8, ..., 128 |
399 | 0 | int step = kDegree; |
400 | 0 | for (int offset = 1; offset < kDegree; offset <<= 1) { |
401 | 0 | step >>= 1; |
402 | 0 | int k = 0; |
403 | 0 | for (int i = 0; i < step; i++) { |
404 | 0 | assert(k == 2 * offset * i); |
405 | 0 | const uint32_t step_root = |
406 | 0 | kPrime - kNTTRootsMontgomery[step + (step - 1 - i)]; |
407 | 0 | for (int j = k; j < k + offset; j++) { |
408 | 0 | uint32_t even = s->c[j]; |
409 | 0 | uint32_t odd = s->c[j + offset]; |
410 | 0 | s->c[j] = reduce_once(odd + even); |
411 | | |
412 | | // |reduce_montgomery| works on values up to kPrime*R and R > 2*kPrime. |
413 | | // kPrime + even < 2*kPrime because |even| < kPrime, by the invariants |
414 | | // of that structure. Thus kPrime + even - odd < 2*kPrime because odd >= |
415 | | // 0, because it's unsigned and less than kPrime. Lastly step_root < |
416 | | // kPrime, because |kNTTRootsMontgomery| is static data. |
417 | 0 | s->c[j + offset] = reduce_montgomery((uint64_t)step_root * |
418 | 0 | (uint64_t)(kPrime + even - odd)); |
419 | 0 | } |
420 | 0 | k += 2 * offset; |
421 | 0 | } |
422 | 0 | } |
423 | 0 | for (int i = 0; i < kDegree; i++) { |
424 | 0 | s->c[i] = reduce_montgomery((uint64_t)s->c[i] * |
425 | 0 | (uint64_t)kInverseDegreeMontgomery); |
426 | 0 | } |
427 | 0 | } |
428 | | |
429 | | template <int X> |
430 | 0 | void vector_zero(vector<X> *out) { |
431 | 0 | OPENSSL_memset(out, 0, sizeof(*out)); |
432 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_zero<6>(mldsa::(anonymous namespace)::vector<6>*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_zero<8>(mldsa::(anonymous namespace)::vector<8>*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_zero<4>(mldsa::(anonymous namespace)::vector<4>*) |
433 | | |
434 | | template <int X> |
435 | 0 | void vector_add(vector<X> *out, const vector<X> *lhs, const vector<X> *rhs) { |
436 | 0 | for (int i = 0; i < X; i++) { |
437 | 0 | scalar_add(&out->v[i], &lhs->v[i], &rhs->v[i]); |
438 | 0 | } |
439 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_add<6>(mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::vector<6> const*, mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_add<5>(mldsa::(anonymous namespace)::vector<5>*, mldsa::(anonymous namespace)::vector<5> const*, mldsa::(anonymous namespace)::vector<5> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_add<8>(mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::vector<8> const*, mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_add<7>(mldsa::(anonymous namespace)::vector<7>*, mldsa::(anonymous namespace)::vector<7> const*, mldsa::(anonymous namespace)::vector<7> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_add<4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4> const*, mldsa::(anonymous namespace)::vector<4> const*) |
440 | | |
441 | | template <int X> |
442 | 0 | void vector_sub(vector<X> *out, const vector<X> *lhs, const vector<X> *rhs) { |
443 | 0 | for (int i = 0; i < X; i++) { |
444 | 0 | scalar_sub(&out->v[i], &lhs->v[i], &rhs->v[i]); |
445 | 0 | } |
446 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_sub<6>(mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::vector<6> const*, mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_sub<8>(mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::vector<8> const*, mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_sub<4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4> const*, mldsa::(anonymous namespace)::vector<4> const*) |
447 | | |
448 | | template <int X> |
449 | | void vector_mult_scalar(vector<X> *out, const vector<X> *lhs, |
450 | 0 | const scalar *rhs) { |
451 | 0 | for (int i = 0; i < X; i++) { |
452 | 0 | scalar_mult(&out->v[i], &lhs->v[i], rhs); |
453 | 0 | } |
454 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_mult_scalar<5>(mldsa::(anonymous namespace)::vector<5>*, mldsa::(anonymous namespace)::vector<5> const*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_mult_scalar<6>(mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::vector<6> const*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_mult_scalar<7>(mldsa::(anonymous namespace)::vector<7>*, mldsa::(anonymous namespace)::vector<7> const*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_mult_scalar<8>(mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::vector<8> const*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_mult_scalar<4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4> const*, mldsa::(anonymous namespace)::scalar const*) |
455 | | |
456 | | template <int X> |
457 | 0 | void vector_ntt(vector<X> *a) { |
458 | 0 | for (int i = 0; i < X; i++) { |
459 | 0 | scalar_ntt(&a->v[i]); |
460 | 0 | } |
461 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_ntt<5>(mldsa::(anonymous namespace)::vector<5>*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_ntt<6>(mldsa::(anonymous namespace)::vector<6>*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_ntt<7>(mldsa::(anonymous namespace)::vector<7>*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_ntt<8>(mldsa::(anonymous namespace)::vector<8>*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_ntt<4>(mldsa::(anonymous namespace)::vector<4>*) |
462 | | |
463 | | template <int X> |
464 | 0 | void vector_inverse_ntt(vector<X> *a) { |
465 | 0 | for (int i = 0; i < X; i++) { |
466 | 0 | scalar_inverse_ntt(&a->v[i]); |
467 | 0 | } |
468 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_inverse_ntt<6>(mldsa::(anonymous namespace)::vector<6>*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_inverse_ntt<5>(mldsa::(anonymous namespace)::vector<5>*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_inverse_ntt<8>(mldsa::(anonymous namespace)::vector<8>*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_inverse_ntt<7>(mldsa::(anonymous namespace)::vector<7>*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_inverse_ntt<4>(mldsa::(anonymous namespace)::vector<4>*) |
469 | | |
470 | | template <int K, int L> |
471 | 0 | void matrix_mult(vector<K> *out, const matrix<K, L> *m, const vector<L> *a) { |
472 | 0 | vector_zero(out); |
473 | 0 | for (int i = 0; i < K; i++) { |
474 | 0 | for (int j = 0; j < L; j++) { |
475 | 0 | scalar product; |
476 | 0 | scalar_mult(&product, &m->v[i][j], &a->v[j]); |
477 | 0 | scalar_add(&out->v[i], &out->v[i], &product); |
478 | 0 | } |
479 | 0 | } |
480 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::matrix_mult<6, 5>(mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::matrix<6, 5> const*, mldsa::(anonymous namespace)::vector<5> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::matrix_mult<8, 7>(mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::matrix<8, 7> const*, mldsa::(anonymous namespace)::vector<7> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::matrix_mult<4, 4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::matrix<4, 4> const*, mldsa::(anonymous namespace)::vector<4> const*) |
481 | | |
482 | | /* Rounding & hints */ |
483 | | |
484 | | // FIPS 204, Algorithm 35 (`Power2Round`). |
485 | 0 | void power2_round(uint32_t *r1, uint32_t *r0, uint32_t r) { |
486 | 0 | *r1 = r >> kDroppedBits; |
487 | 0 | *r0 = r - (*r1 << kDroppedBits); |
488 | |
|
489 | 0 | uint32_t r0_adjusted = mod_sub(*r0, 1 << kDroppedBits); |
490 | 0 | uint32_t r1_adjusted = *r1 + 1; |
491 | | |
492 | | // Mask is set iff r0 > 2^(dropped_bits - 1). |
493 | 0 | crypto_word_t mask = |
494 | 0 | constant_time_lt_w((uint32_t)(1 << (kDroppedBits - 1)), *r0); |
495 | | // r0 = mask ? r0_adjusted : r0 |
496 | 0 | *r0 = constant_time_select_32(mask, r0_adjusted, *r0); |
497 | | // r1 = mask ? r1_adjusted : r1 |
498 | 0 | *r1 = constant_time_select_32(mask, r1_adjusted, *r1); |
499 | 0 | } |
500 | | |
501 | | // Scale back previously rounded value. |
502 | 0 | void scale_power2_round(uint32_t *out, uint32_t r1) { |
503 | | // Pre-condition: 0 <= r1 <= 2^10 - 1 |
504 | 0 | assert(r1 < (1u << 10)); |
505 | | |
506 | 0 | *out = r1 << kDroppedBits; |
507 | | |
508 | | // Post-condition: 0 <= out <= 2^23 - 2^13 = kPrime - 1 |
509 | 0 | assert(*out < kPrime); |
510 | 0 | } |
511 | | |
512 | | // FIPS 204, Algorithm 37 (`HighBits`). |
513 | | template <int K> |
514 | 0 | uint32_t high_bits(uint32_t x) { |
515 | | // Reference description (given 0 <= x < q): |
516 | | // |
517 | | // ``` |
518 | | // int32_t r0 = x mod+- (2 * gamma2); |
519 | | // if (x - r0 == q - 1) { |
520 | | // return 0; |
521 | | // } else { |
522 | | // return (x - r0) / (2 * gamma2); |
523 | | // } |
524 | | // ``` |
525 | | // |
526 | 0 | uint32_t r1 = (x + 127) >> 7; |
527 | 0 | if constexpr (prime_minus_one_over_gamma2<K>() == 32) { |
528 | | // Below is the formula taken from the reference implementation. |
529 | | // |
530 | | // Here, Gamma2 == 2^18 - 2^8 |
531 | | // This returns ((ceil(x / 2^7) * (2^10 + 1) + 2^21) / 2^22) mod 2^4 |
532 | 0 | r1 = (r1 * 1025 + (1 << 21)) >> 22; |
533 | 0 | r1 &= 15; |
534 | 0 | } else if constexpr (prime_minus_one_over_gamma2<K>() == 88) { |
535 | | // 1488/2^24 is close enough to 1/1488 so that r1 becomes x/(2 gamma2) |
536 | | // rounded down. |
537 | 0 | r1 = (r1 * 11275 + (1 << 23)) >> 24; |
538 | | |
539 | | // For corner-case r1 = (Q-1)/(2 gamma2) = 44, we have to set r1=0. |
540 | 0 | r1 ^= ((uint32_t)(((int32_t)(43 - r1)) >> 31)) & r1; |
541 | 0 | } |
542 | 0 | return r1; |
543 | 0 | } Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::high_bits<6>(unsigned int) Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::high_bits<8>(unsigned int) Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::high_bits<4>(unsigned int) |
544 | | |
545 | | // FIPS 204, Algorithm 36 (`Decompose`). |
546 | | template <int K> |
547 | 0 | void decompose(uint32_t *r1, int32_t *r0, uint32_t r) { |
548 | 0 | *r1 = high_bits<K>(r); |
549 | |
|
550 | 0 | *r0 = r; |
551 | 0 | *r0 -= *r1 * 2 * (int32_t)gamma2<K>(); |
552 | 0 | *r0 -= (((int32_t)kHalfPrime - *r0) >> 31) & (int32_t)kPrime; |
553 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::decompose<6>(unsigned int*, int*, unsigned int) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::decompose<8>(unsigned int*, int*, unsigned int) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::decompose<4>(unsigned int*, int*, unsigned int) |
554 | | |
555 | | // FIPS 204, Algorithm 38 (`LowBits`). |
556 | | template <int K> |
557 | 0 | int32_t low_bits(uint32_t x) { |
558 | 0 | uint32_t r1; |
559 | 0 | int32_t r0; |
560 | 0 | decompose<K>(&r1, &r0, x); |
561 | 0 | return r0; |
562 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::low_bits<6>(unsigned int) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::low_bits<8>(unsigned int) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::low_bits<4>(unsigned int) |
563 | | |
564 | | // FIPS 204, Algorithm 39 (`MakeHint`). |
565 | | // |
566 | | // In the spec this takes two arguments, z and r, and is called with |
567 | | // z = -ct0 |
568 | | // r = w - cs2 + ct0 |
569 | | // |
570 | | // It then computes HighBits (algorithm 37) of z and z+r. But z+r is just w - |
571 | | // cs2, so this takes three arguments and saves an addition. |
572 | | template <int K> |
573 | 0 | int32_t make_hint(uint32_t ct0, uint32_t cs2, uint32_t w) { |
574 | 0 | uint32_t r_plus_z = mod_sub(w, cs2); |
575 | 0 | uint32_t r = reduce_once(r_plus_z + ct0); |
576 | 0 | return high_bits<K>(r) != high_bits<K>(r_plus_z); |
577 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::make_hint<6>(unsigned int, unsigned int, unsigned int) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::make_hint<8>(unsigned int, unsigned int, unsigned int) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::make_hint<4>(unsigned int, unsigned int, unsigned int) |
578 | | |
579 | | // FIPS 204, Algorithm 40 (`UseHint`). |
580 | | template <int K> |
581 | 0 | uint32_t use_hint_vartime(uint32_t h, uint32_t r) { |
582 | 0 | uint32_t r1; |
583 | 0 | int32_t r0; |
584 | 0 | decompose<K>(&r1, &r0, r); |
585 | |
|
586 | 0 | if (h) { |
587 | 0 | if constexpr (prime_minus_one_over_gamma2<K>() == 32) { |
588 | 0 | if (r0 > 0) { |
589 | | // (Q-1)/(2 gamma2) = m = 16, thus |mod m| in the spec turns into |& |
590 | | // 15|. |
591 | 0 | return (r1 + 1) & 15; |
592 | 0 | } else { |
593 | 0 | return (r1 - 1) & 15; |
594 | 0 | } |
595 | 0 | } else { |
596 | | // m = 44 |
597 | 0 | static_assert(prime_minus_one_over_gamma2<K>() == 88); |
598 | 0 | if (r0 > 0) { |
599 | 0 | if (r1 == 43) { |
600 | 0 | return 0; |
601 | 0 | } else { |
602 | 0 | return r1 + 1; |
603 | 0 | } |
604 | 0 | } else { |
605 | 0 | if (r1 == 0) { |
606 | 0 | return 43; |
607 | 0 | } else { |
608 | 0 | return r1 - 1; |
609 | 0 | } |
610 | 0 | } |
611 | 0 | } |
612 | 0 | } |
613 | 0 | return r1; |
614 | 0 | } Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::use_hint_vartime<6>(unsigned int, unsigned int) Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::use_hint_vartime<8>(unsigned int, unsigned int) Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::use_hint_vartime<4>(unsigned int, unsigned int) |
615 | | |
616 | 0 | void scalar_power2_round(scalar *s1, scalar *s0, const scalar *s) { |
617 | 0 | for (int i = 0; i < kDegree; i++) { |
618 | 0 | power2_round(&s1->c[i], &s0->c[i], s->c[i]); |
619 | 0 | } |
620 | 0 | } |
621 | | |
622 | 0 | void scalar_scale_power2_round(scalar *out, const scalar *in) { |
623 | 0 | for (int i = 0; i < kDegree; i++) { |
624 | 0 | scale_power2_round(&out->c[i], in->c[i]); |
625 | 0 | } |
626 | 0 | } |
627 | | |
628 | | template <int K> |
629 | 0 | void scalar_high_bits(scalar *out, const scalar *in) { |
630 | 0 | for (int i = 0; i < kDegree; i++) { |
631 | 0 | out->c[i] = high_bits<K>(in->c[i]); |
632 | 0 | } |
633 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_high_bits<6>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_high_bits<8>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_high_bits<4>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*) |
634 | | |
635 | | template <int K> |
636 | 0 | void scalar_low_bits(scalar *out, const scalar *in) { |
637 | 0 | for (int i = 0; i < kDegree; i++) { |
638 | 0 | out->c[i] = low_bits<K>(in->c[i]); |
639 | 0 | } |
640 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_low_bits<6>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_low_bits<8>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_low_bits<4>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*) |
641 | | |
642 | 0 | void scalar_max(uint32_t *max, const scalar *s) { |
643 | 0 | for (int i = 0; i < kDegree; i++) { |
644 | 0 | uint32_t abs = abs_mod_prime(s->c[i]); |
645 | 0 | *max = maximum_reduced(*max, abs); |
646 | 0 | } |
647 | 0 | } |
648 | | |
649 | 0 | void scalar_max_signed(uint32_t *max, const scalar *s) { |
650 | 0 | for (int i = 0; i < kDegree; i++) { |
651 | 0 | uint32_t abs = abs_signed(s->c[i]); |
652 | 0 | *max = maximum_reduced(*max, abs); |
653 | 0 | } |
654 | 0 | } |
655 | | |
656 | | template <int K> |
657 | | void scalar_make_hint(scalar *out, const scalar *ct0, const scalar *cs2, |
658 | 0 | const scalar *w) { |
659 | 0 | for (int i = 0; i < kDegree; i++) { |
660 | 0 | out->c[i] = make_hint<K>(ct0->c[i], cs2->c[i], w->c[i]); |
661 | 0 | } |
662 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_make_hint<6>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*, mldsa::(anonymous namespace)::scalar const*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_make_hint<8>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*, mldsa::(anonymous namespace)::scalar const*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_make_hint<4>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*, mldsa::(anonymous namespace)::scalar const*, mldsa::(anonymous namespace)::scalar const*) |
663 | | |
664 | | template <int K> |
665 | 0 | void scalar_use_hint_vartime(scalar *out, const scalar *h, const scalar *r) { |
666 | 0 | for (int i = 0; i < kDegree; i++) { |
667 | 0 | out->c[i] = use_hint_vartime<K>(h->c[i], r->c[i]); |
668 | 0 | } |
669 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_use_hint_vartime<6>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_use_hint_vartime<8>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*, mldsa::(anonymous namespace)::scalar const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_use_hint_vartime<4>(mldsa::(anonymous namespace)::scalar*, mldsa::(anonymous namespace)::scalar const*, mldsa::(anonymous namespace)::scalar const*) |
670 | | |
671 | | template <int X> |
672 | 0 | void vector_power2_round(vector<X> *t1, vector<X> *t0, const vector<X> *t) { |
673 | 0 | for (int i = 0; i < X; i++) { |
674 | 0 | scalar_power2_round(&t1->v[i], &t0->v[i], &t->v[i]); |
675 | 0 | } |
676 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_power2_round<6>(mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_power2_round<8>(mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_power2_round<4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4> const*) |
677 | | |
678 | | template <int X> |
679 | 0 | void vector_scale_power2_round(vector<X> *out, const vector<X> *in) { |
680 | 0 | for (int i = 0; i < X; i++) { |
681 | 0 | scalar_scale_power2_round(&out->v[i], &in->v[i]); |
682 | 0 | } |
683 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_scale_power2_round<6>(mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_scale_power2_round<8>(mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_scale_power2_round<4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4> const*) |
684 | | |
685 | | template <int K> |
686 | 0 | void vector_high_bits(vector<K> *out, const vector<K> *in) { |
687 | 0 | for (int i = 0; i < K; i++) { |
688 | 0 | scalar_high_bits<K>(&out->v[i], &in->v[i]); |
689 | 0 | } |
690 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_high_bits<6>(mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_high_bits<8>(mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_high_bits<4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4> const*) |
691 | | |
692 | | template <int K> |
693 | 0 | void vector_low_bits(vector<K> *out, const vector<K> *in) { |
694 | 0 | for (int i = 0; i < K; i++) { |
695 | 0 | scalar_low_bits<K>(&out->v[i], &in->v[i]); |
696 | 0 | } |
697 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_low_bits<6>(mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_low_bits<8>(mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_low_bits<4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4> const*) |
698 | | |
699 | | template <int X> |
700 | 0 | uint32_t vector_max(const vector<X> *a) { |
701 | 0 | uint32_t max = 0; |
702 | 0 | for (int i = 0; i < X; i++) { |
703 | 0 | scalar_max(&max, &a->v[i]); |
704 | 0 | } |
705 | 0 | return max; |
706 | 0 | } Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::vector_max<5>(mldsa::(anonymous namespace)::vector<5> const*) Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::vector_max<6>(mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::vector_max<7>(mldsa::(anonymous namespace)::vector<7> const*) Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::vector_max<8>(mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::vector_max<4>(mldsa::(anonymous namespace)::vector<4> const*) |
707 | | |
708 | | template <int X> |
709 | 0 | uint32_t vector_max_signed(const vector<X> *a) { |
710 | 0 | uint32_t max = 0; |
711 | 0 | for (int i = 0; i < X; i++) { |
712 | 0 | scalar_max_signed(&max, &a->v[i]); |
713 | 0 | } |
714 | 0 | return max; |
715 | 0 | } Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::vector_max_signed<6>(mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::vector_max_signed<8>(mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:unsigned int mldsa::(anonymous namespace)::vector_max_signed<4>(mldsa::(anonymous namespace)::vector<4> const*) |
716 | | |
717 | | // The input vector contains only zeroes and ones. |
718 | | template <int X> |
719 | 0 | size_t vector_count_ones(const vector<X> *a) { |
720 | 0 | size_t count = 0; |
721 | 0 | for (int i = 0; i < X; i++) { |
722 | 0 | for (int j = 0; j < kDegree; j++) { |
723 | 0 | count += a->v[i].c[j]; |
724 | 0 | } |
725 | 0 | } |
726 | 0 | return count; |
727 | 0 | } Unexecuted instantiation: bcm.cc:unsigned long mldsa::(anonymous namespace)::vector_count_ones<6>(mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:unsigned long mldsa::(anonymous namespace)::vector_count_ones<8>(mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:unsigned long mldsa::(anonymous namespace)::vector_count_ones<4>(mldsa::(anonymous namespace)::vector<4> const*) |
728 | | |
729 | | template <int K> |
730 | | void vector_make_hint(vector<K> *out, const vector<K> *ct0, |
731 | 0 | const vector<K> *cs2, const vector<K> *w) { |
732 | 0 | for (int i = 0; i < K; i++) { |
733 | 0 | scalar_make_hint<K>(&out->v[i], &ct0->v[i], &cs2->v[i], &w->v[i]); |
734 | 0 | } |
735 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_make_hint<6>(mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::vector<6> const*, mldsa::(anonymous namespace)::vector<6> const*, mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_make_hint<8>(mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::vector<8> const*, mldsa::(anonymous namespace)::vector<8> const*, mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_make_hint<4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4> const*, mldsa::(anonymous namespace)::vector<4> const*, mldsa::(anonymous namespace)::vector<4> const*) |
736 | | |
737 | | template <int K> |
738 | | void vector_use_hint_vartime(vector<K> *out, const vector<K> *h, |
739 | 0 | const vector<K> *r) { |
740 | 0 | for (int i = 0; i < K; i++) { |
741 | 0 | scalar_use_hint_vartime<K>(&out->v[i], &h->v[i], &r->v[i]); |
742 | 0 | } |
743 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_use_hint_vartime<6>(mldsa::(anonymous namespace)::vector<6>*, mldsa::(anonymous namespace)::vector<6> const*, mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_use_hint_vartime<8>(mldsa::(anonymous namespace)::vector<8>*, mldsa::(anonymous namespace)::vector<8> const*, mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_use_hint_vartime<4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4> const*, mldsa::(anonymous namespace)::vector<4> const*) |
744 | | |
745 | | /* Bit packing */ |
746 | | |
747 | | // FIPS 204, Algorithm 16 (`SimpleBitPack`). Specialized to bitlen(b) = 4. |
748 | 0 | static void scalar_encode_4(uint8_t out[128], const scalar *s) { |
749 | | // Every two elements lands on a byte boundary. |
750 | 0 | static_assert(kDegree % 2 == 0, "kDegree must be a multiple of 2"); |
751 | 0 | for (int i = 0; i < kDegree / 2; i++) { |
752 | 0 | uint32_t a = s->c[2 * i]; |
753 | 0 | uint32_t b = s->c[2 * i + 1]; |
754 | 0 | declassify_assert(a < 16); |
755 | 0 | declassify_assert(b < 16); |
756 | 0 | out[i] = a | (b << 4); |
757 | 0 | } |
758 | 0 | } |
759 | | |
760 | | // FIPS 204, Algorithm 16 (`SimpleBitPack`). Specialized to bitlen(b) = 6. |
761 | 0 | void scalar_encode_6(uint8_t out[192], const scalar *s) { |
762 | | // Every four elements lands on a byte boundary. |
763 | 0 | static_assert(kDegree % 4 == 0, "kDegree must be a multiple of 4"); |
764 | 0 | for (int i = 0; i < kDegree / 4; i++) { |
765 | 0 | uint32_t a = s->c[4 * i]; |
766 | 0 | uint32_t b = s->c[4 * i + 1]; |
767 | 0 | uint32_t c = s->c[4 * i + 2]; |
768 | 0 | uint32_t d = s->c[4 * i + 3]; |
769 | 0 | declassify_assert(a < 64); |
770 | 0 | declassify_assert(b < 64); |
771 | 0 | declassify_assert(c < 64); |
772 | 0 | declassify_assert(d < 64); |
773 | 0 | out[3 * i] = a | (b << 6); |
774 | 0 | out[3 * i + 1] = (b >> 2) | (c << 4); |
775 | 0 | out[3 * i + 2] = (c >> 4) | (d << 2); |
776 | 0 | } |
777 | 0 | } |
778 | | |
779 | | // FIPS 204, Algorithm 16 (`SimpleBitPack`). Specialized to bitlen(b) = 10. |
780 | 0 | void scalar_encode_10(uint8_t out[320], const scalar *s) { |
781 | | // Every four elements lands on a byte boundary. |
782 | 0 | static_assert(kDegree % 4 == 0, "kDegree must be a multiple of 4"); |
783 | 0 | for (int i = 0; i < kDegree / 4; i++) { |
784 | 0 | uint32_t a = s->c[4 * i]; |
785 | 0 | uint32_t b = s->c[4 * i + 1]; |
786 | 0 | uint32_t c = s->c[4 * i + 2]; |
787 | 0 | uint32_t d = s->c[4 * i + 3]; |
788 | 0 | declassify_assert(a < 1024); |
789 | 0 | declassify_assert(b < 1024); |
790 | 0 | declassify_assert(c < 1024); |
791 | 0 | declassify_assert(d < 1024); |
792 | 0 | out[5 * i] = (uint8_t)a; |
793 | 0 | out[5 * i + 1] = (uint8_t)((a >> 8) | (b << 2)); |
794 | 0 | out[5 * i + 2] = (uint8_t)((b >> 6) | (c << 4)); |
795 | 0 | out[5 * i + 3] = (uint8_t)((c >> 4) | (d << 6)); |
796 | 0 | out[5 * i + 4] = (uint8_t)(d >> 2); |
797 | 0 | } |
798 | 0 | } |
799 | | |
800 | | // FIPS 204, Algorithm 17 (`BitPack`). Specialized to bitlen(a+b) = 4 and b = 4. |
801 | 0 | void scalar_encode_signed_4_4(uint8_t out[128], const scalar *s) { |
802 | | // Every two elements lands on a byte boundary. |
803 | 0 | static_assert(kDegree % 2 == 0, "kDegree must be a multiple of 2"); |
804 | 0 | for (int i = 0; i < kDegree / 2; i++) { |
805 | 0 | uint32_t a = mod_sub(4, s->c[2 * i]); |
806 | 0 | uint32_t b = mod_sub(4, s->c[2 * i + 1]); |
807 | 0 | declassify_assert(a < 16); |
808 | 0 | declassify_assert(b < 16); |
809 | 0 | out[i] = a | (b << 4); |
810 | 0 | } |
811 | 0 | } |
812 | | |
813 | | // FIPS 204, Algorithm 17 (`BitPack`). Specialized to bitlen(a+b) = 3 and b = 2. |
814 | 0 | static void scalar_encode_signed_3_2(uint8_t out[96], const scalar *s) { |
815 | 0 | static_assert(kDegree % 8 == 0, "kDegree must be a multiple of 8"); |
816 | 0 | for (int i = 0; i < kDegree / 8; i++) { |
817 | 0 | uint32_t a = mod_sub(2, s->c[8 * i]); |
818 | 0 | uint32_t b = mod_sub(2, s->c[8 * i + 1]); |
819 | 0 | uint32_t c = mod_sub(2, s->c[8 * i + 2]); |
820 | 0 | uint32_t d = mod_sub(2, s->c[8 * i + 3]); |
821 | 0 | uint32_t e = mod_sub(2, s->c[8 * i + 4]); |
822 | 0 | uint32_t f = mod_sub(2, s->c[8 * i + 5]); |
823 | 0 | uint32_t g = mod_sub(2, s->c[8 * i + 6]); |
824 | 0 | uint32_t h = mod_sub(2, s->c[8 * i + 7]); |
825 | 0 | uint32_t v = (h << 21) | (g << 18) | (f << 15) | (e << 12) | (d << 9) | |
826 | 0 | (c << 6) | (b << 3) | a; |
827 | 0 | uint8_t v_bytes[sizeof(v)]; |
828 | 0 | CRYPTO_store_u32_le(v_bytes, v); |
829 | 0 | OPENSSL_memcpy(&out[i * 3], v_bytes, 3); |
830 | 0 | } |
831 | 0 | } |
832 | | |
833 | | // FIPS 204, Algorithm 17 (`BitPack`). Specialized to bitlen(a+b) = 13 and b = |
834 | | // 2^12. |
835 | 0 | void scalar_encode_signed_13_12(uint8_t out[416], const scalar *s) { |
836 | 0 | static const uint32_t kMax = 1u << 12; |
837 | | // Every two elements lands on a byte boundary. |
838 | 0 | static_assert(kDegree % 8 == 0, "kDegree must be a multiple of 8"); |
839 | 0 | for (int i = 0; i < kDegree / 8; i++) { |
840 | 0 | uint32_t a = mod_sub(kMax, s->c[8 * i]); |
841 | 0 | uint32_t b = mod_sub(kMax, s->c[8 * i + 1]); |
842 | 0 | uint32_t c = mod_sub(kMax, s->c[8 * i + 2]); |
843 | 0 | uint32_t d = mod_sub(kMax, s->c[8 * i + 3]); |
844 | 0 | uint32_t e = mod_sub(kMax, s->c[8 * i + 4]); |
845 | 0 | uint32_t f = mod_sub(kMax, s->c[8 * i + 5]); |
846 | 0 | uint32_t g = mod_sub(kMax, s->c[8 * i + 6]); |
847 | 0 | uint32_t h = mod_sub(kMax, s->c[8 * i + 7]); |
848 | 0 | declassify_assert(a < (1u << 13)); |
849 | 0 | declassify_assert(b < (1u << 13)); |
850 | 0 | declassify_assert(c < (1u << 13)); |
851 | 0 | declassify_assert(d < (1u << 13)); |
852 | 0 | declassify_assert(e < (1u << 13)); |
853 | 0 | declassify_assert(f < (1u << 13)); |
854 | 0 | declassify_assert(g < (1u << 13)); |
855 | 0 | declassify_assert(h < (1u << 13)); |
856 | 0 | a |= b << 13; |
857 | 0 | a |= c << 26; |
858 | 0 | c >>= 6; |
859 | 0 | c |= d << 7; |
860 | 0 | c |= e << 20; |
861 | 0 | e >>= 12; |
862 | 0 | e |= f << 1; |
863 | 0 | e |= g << 14; |
864 | 0 | e |= h << 27; |
865 | 0 | h >>= 5; |
866 | 0 | CRYPTO_store_u32_le(&out[13 * i], a); |
867 | 0 | CRYPTO_store_u32_le(&out[13 * i + 4], c); |
868 | 0 | CRYPTO_store_u32_le(&out[13 * i + 8], e); |
869 | 0 | out[13 * i + 12] = static_cast<uint8_t>(h); |
870 | 0 | } |
871 | 0 | } |
872 | | |
873 | | // FIPS 204, Algorithm 17 (`BitPack`). Specialized to bitlen(a+b) = 20 and b = |
874 | | // 2^19. |
875 | 0 | void scalar_encode_signed_20_19(uint8_t out[640], const scalar *s) { |
876 | 0 | static const uint32_t kMax = 1u << 19; |
877 | | // Every two elements lands on a byte boundary. |
878 | 0 | static_assert(kDegree % 4 == 0, "kDegree must be a multiple of 4"); |
879 | 0 | for (int i = 0; i < kDegree / 4; i++) { |
880 | 0 | uint32_t a = mod_sub(kMax, s->c[4 * i]); |
881 | 0 | uint32_t b = mod_sub(kMax, s->c[4 * i + 1]); |
882 | 0 | uint32_t c = mod_sub(kMax, s->c[4 * i + 2]); |
883 | 0 | uint32_t d = mod_sub(kMax, s->c[4 * i + 3]); |
884 | 0 | declassify_assert(a < (1u << 20)); |
885 | 0 | declassify_assert(b < (1u << 20)); |
886 | 0 | declassify_assert(c < (1u << 20)); |
887 | 0 | declassify_assert(d < (1u << 20)); |
888 | 0 | a |= b << 20; |
889 | 0 | b >>= 12; |
890 | 0 | b |= c << 8; |
891 | 0 | b |= d << 28; |
892 | 0 | d >>= 4; |
893 | 0 | CRYPTO_store_u32_le(&out[10 * i], a); |
894 | 0 | CRYPTO_store_u32_le(&out[10 * i + 4], b); |
895 | 0 | CRYPTO_store_u16_le(&out[10 * i + 8], static_cast<uint16_t>(d)); |
896 | 0 | } |
897 | 0 | } |
898 | | |
899 | | // FIPS 204, Algorithm 17 (`BitPack`). Specialized to bitlen(a+b) = 18 and b = |
900 | | // 2^17. |
901 | 0 | void scalar_encode_signed_18_17(uint8_t out[576], const scalar *s) { |
902 | 0 | static const uint32_t kMax = 1u << 17; |
903 | 0 | static_assert(kDegree % 4 == 0, "kDegree must be a multiple of 4"); |
904 | 0 | for (int i = 0; i < kDegree / 4; i++) { |
905 | 0 | uint32_t a = mod_sub(kMax, s->c[4 * i]); |
906 | 0 | uint32_t b = mod_sub(kMax, s->c[4 * i + 1]); |
907 | 0 | uint32_t c = mod_sub(kMax, s->c[4 * i + 2]); |
908 | 0 | uint32_t d = mod_sub(kMax, s->c[4 * i + 3]); |
909 | 0 | declassify_assert(a < (1u << 18)); |
910 | 0 | declassify_assert(b < (1u << 18)); |
911 | 0 | declassify_assert(c < (1u << 18)); |
912 | 0 | declassify_assert(d < (1u << 18)); |
913 | 0 | out[9 * i] = (uint8_t)a; |
914 | 0 | out[9 * i + 1] = (uint8_t)(a >> 8); |
915 | 0 | out[9 * i + 2] = (uint8_t)(a >> 16) | (uint8_t)(b << 2); |
916 | 0 | out[9 * i + 3] = (uint8_t)(b >> 6); |
917 | 0 | out[9 * i + 4] = (uint8_t)(b >> 14) | (uint8_t)(c << 4); |
918 | 0 | out[9 * i + 5] = (uint8_t)(c >> 4); |
919 | 0 | out[9 * i + 6] = (uint8_t)(c >> 12) | (uint8_t)(d << 6); |
920 | 0 | out[9 * i + 7] = (uint8_t)(d >> 2); |
921 | 0 | out[9 * i + 8] = (uint8_t)(d >> 10); |
922 | 0 | } |
923 | 0 | } |
924 | | |
925 | | // FIPS 204, Algorithm 17 (`BitPack`). |
926 | | void scalar_encode_signed(uint8_t *out, const scalar *s, int bits, |
927 | 0 | uint32_t max) { |
928 | 0 | if (bits == 3) { |
929 | 0 | assert(max == 2); |
930 | 0 | scalar_encode_signed_3_2(out, s); |
931 | 0 | } else if (bits == 4) { |
932 | 0 | assert(max == 4); |
933 | 0 | scalar_encode_signed_4_4(out, s); |
934 | 0 | } else if (bits == 20) { |
935 | 0 | assert(max == 1u << 19); |
936 | 0 | scalar_encode_signed_20_19(out, s); |
937 | 0 | } else if (bits == 18) { |
938 | 0 | assert(max == 1u << 17); |
939 | 0 | scalar_encode_signed_18_17(out, s); |
940 | 0 | } else { |
941 | 0 | assert(bits == 13); |
942 | 0 | assert(max == 1u << 12); |
943 | 0 | scalar_encode_signed_13_12(out, s); |
944 | 0 | } |
945 | 0 | } |
946 | | |
947 | | // FIPS 204, Algorithm 18 (`SimpleBitUnpack`). Specialized for bitlen(b) == 10. |
948 | 0 | void scalar_decode_10(scalar *out, const uint8_t in[320]) { |
949 | 0 | static_assert(kDegree % 4 == 0, "kDegree must be a multiple of 4"); |
950 | 0 | for (int i = 0; i < kDegree / 4; i++) { |
951 | 0 | uint32_t v = CRYPTO_load_u32_le(&in[5 * i]); |
952 | 0 | out->c[4 * i] = v & 0x3ff; |
953 | 0 | out->c[4 * i + 1] = (v >> 10) & 0x3ff; |
954 | 0 | out->c[4 * i + 2] = (v >> 20) & 0x3ff; |
955 | 0 | out->c[4 * i + 3] = (v >> 30) | (((uint32_t)in[5 * i + 4]) << 2); |
956 | 0 | } |
957 | 0 | } |
958 | | |
959 | | // FIPS 204, Algorithm 19 (`BitUnpack`). Specialized to bitlen(a+b) = 4 and b = |
960 | | // 4. |
961 | 0 | int scalar_decode_signed_4_4(scalar *out, const uint8_t in[128]) { |
962 | 0 | static_assert(kDegree % 8 == 0, "kDegree must be a multiple of 8"); |
963 | 0 | for (int i = 0; i < kDegree / 8; i++) { |
964 | 0 | uint32_t v = CRYPTO_load_u32_le(&in[4 * i]); |
965 | | // None of the nibbles may be >= 9. So if the MSB of any nibble is set, none |
966 | | // of the other bits may be set. First, select all the MSBs. |
967 | 0 | const uint32_t msbs = v & 0x88888888u; |
968 | | // For each nibble where the MSB is set, form a mask of all the other bits. |
969 | 0 | const uint32_t mask = (msbs >> 1) | (msbs >> 2) | (msbs >> 3); |
970 | | // A nibble is only out of range in the case of invalid input, in which case |
971 | | // it is okay to leak the value. |
972 | 0 | if (constant_time_declassify_int((mask & v) != 0)) { |
973 | 0 | return 0; |
974 | 0 | } |
975 | | |
976 | 0 | out->c[i * 8] = mod_sub(4, v & 15); |
977 | 0 | out->c[i * 8 + 1] = mod_sub(4, (v >> 4) & 15); |
978 | 0 | out->c[i * 8 + 2] = mod_sub(4, (v >> 8) & 15); |
979 | 0 | out->c[i * 8 + 3] = mod_sub(4, (v >> 12) & 15); |
980 | 0 | out->c[i * 8 + 4] = mod_sub(4, (v >> 16) & 15); |
981 | 0 | out->c[i * 8 + 5] = mod_sub(4, (v >> 20) & 15); |
982 | 0 | out->c[i * 8 + 6] = mod_sub(4, (v >> 24) & 15); |
983 | 0 | out->c[i * 8 + 7] = mod_sub(4, v >> 28); |
984 | 0 | } |
985 | 0 | return 1; |
986 | 0 | } |
987 | | |
988 | | // FIPS 204, Algorithm 19 (`BitUnpack`). Specialized to bitlen(a+b) = 3 and b = |
989 | | // 2. |
990 | 0 | static int scalar_decode_signed_3_2(scalar *out, const uint8_t in[96]) { |
991 | 0 | uint32_t v; |
992 | 0 | uint8_t v_bytes[sizeof(v)] = {0}; |
993 | 0 | static_assert(kDegree % 8 == 0, "kDegree must be a multiple of 8"); |
994 | 0 | for (int i = 0; i < kDegree / 8; i++) { |
995 | 0 | OPENSSL_memcpy(v_bytes, &in[3 * i], 3); |
996 | 0 | v = CRYPTO_load_u32_le(v_bytes); |
997 | | // v contains 8, 3-bit values in the lower 24 bits. None of the values may |
998 | | // be >= 5. So if the MSB of any triple is set, none of the other bits may |
999 | | // be set. First, select all the MSBs. |
1000 | 0 | const uint32_t msbs = v & 000044444444u; |
1001 | | // For each triple where the MSB is set, form a mask of all the other bits. |
1002 | 0 | const uint32_t mask = (msbs >> 1) | (msbs >> 2); |
1003 | | // A triple is only out of range in the case of invalid input, in which case |
1004 | | // it is okay to leak the value. |
1005 | 0 | if (constant_time_declassify_int((mask & v) != 0)) { |
1006 | 0 | return 0; |
1007 | 0 | } |
1008 | | |
1009 | 0 | out->c[i * 8 + 0] = mod_sub(2, (v >> 0) & 7); |
1010 | 0 | out->c[i * 8 + 1] = mod_sub(2, (v >> 3) & 7); |
1011 | 0 | out->c[i * 8 + 2] = mod_sub(2, (v >> 6) & 7); |
1012 | 0 | out->c[i * 8 + 3] = mod_sub(2, (v >> 9) & 7); |
1013 | 0 | out->c[i * 8 + 4] = mod_sub(2, (v >> 12) & 7); |
1014 | 0 | out->c[i * 8 + 5] = mod_sub(2, (v >> 15) & 7); |
1015 | 0 | out->c[i * 8 + 6] = mod_sub(2, (v >> 18) & 7); |
1016 | 0 | out->c[i * 8 + 7] = mod_sub(2, v >> 21); |
1017 | 0 | } |
1018 | 0 | return 1; |
1019 | 0 | } |
1020 | | |
1021 | | // FIPS 204, Algorithm 19 (`BitUnpack`). Specialized to bitlen(a+b) = 13 and b = |
1022 | | // 2^12. |
1023 | 0 | void scalar_decode_signed_13_12(scalar *out, const uint8_t in[416]) { |
1024 | 0 | static const uint32_t kMax = 1u << 12; |
1025 | 0 | static const uint32_t k13Bits = (1u << 13) - 1; |
1026 | 0 | static const uint32_t k7Bits = (1u << 7) - 1; |
1027 | |
|
1028 | 0 | static_assert(kDegree % 8 == 0, "kDegree must be a multiple of 8"); |
1029 | 0 | for (int i = 0; i < kDegree / 8; i++) { |
1030 | 0 | uint32_t a = CRYPTO_load_u32_le(&in[13 * i]); |
1031 | 0 | uint32_t b = CRYPTO_load_u32_le(&in[13 * i + 4]); |
1032 | 0 | uint32_t c = CRYPTO_load_u32_le(&in[13 * i + 8]); |
1033 | 0 | uint8_t d = in[13 * i + 12]; |
1034 | | |
1035 | | // It's not possible for a 13-bit number to be out of range when the max is |
1036 | | // 2^12. |
1037 | 0 | out->c[i * 8] = mod_sub(kMax, a & k13Bits); |
1038 | 0 | out->c[i * 8 + 1] = mod_sub(kMax, (a >> 13) & k13Bits); |
1039 | 0 | out->c[i * 8 + 2] = mod_sub(kMax, (a >> 26) | ((b & k7Bits) << 6)); |
1040 | 0 | out->c[i * 8 + 3] = mod_sub(kMax, (b >> 7) & k13Bits); |
1041 | 0 | out->c[i * 8 + 4] = mod_sub(kMax, (b >> 20) | ((c & 1) << 12)); |
1042 | 0 | out->c[i * 8 + 5] = mod_sub(kMax, (c >> 1) & k13Bits); |
1043 | 0 | out->c[i * 8 + 6] = mod_sub(kMax, (c >> 14) & k13Bits); |
1044 | 0 | out->c[i * 8 + 7] = mod_sub(kMax, (c >> 27) | ((uint32_t)d) << 5); |
1045 | 0 | } |
1046 | 0 | } |
1047 | | |
1048 | | // FIPS 204, Algorithm 19 (`BitUnpack`). Specialized to bitlen(a+b) = 18 and b = |
1049 | | // 2^17. |
1050 | 0 | void scalar_decode_signed_18_17(scalar *out, const uint8_t in[576]) { |
1051 | 0 | static const uint32_t kMax = 1u << 17; |
1052 | |
|
1053 | 0 | static_assert(kDegree % 4 == 0, "kDegree must be a multiple of 4"); |
1054 | 0 | for (int i = 0; i < kDegree / 4; i++) { |
1055 | 0 | uint32_t a = uint32_t{in[9 * i]} | (uint32_t{in[9 * i + 1]} << 8) | |
1056 | 0 | ((uint32_t{in[9 * i + 2]} & 0x3) << 16); |
1057 | 0 | uint32_t b = (uint32_t{in[9 * i + 2]} >> 2) | |
1058 | 0 | (uint32_t{in[9 * i + 3]} << 6) | |
1059 | 0 | ((uint32_t{in[9 * i + 4]} & 0xf) << 14); |
1060 | 0 | uint32_t c = (uint32_t{in[9 * i + 4]} >> 4) | |
1061 | 0 | (uint32_t{in[9 * i + 5]} << 4) | |
1062 | 0 | ((uint32_t{in[9 * i + 6]} & 0x3f) << 12); |
1063 | 0 | uint32_t d = (uint32_t{in[9 * i + 6]} >> 6) | |
1064 | 0 | (uint32_t{in[9 * i + 7]} << 2) | |
1065 | 0 | (uint32_t{in[9 * i + 8]} << 10); |
1066 | |
|
1067 | 0 | out->c[i * 4] = mod_sub(kMax, a); |
1068 | 0 | out->c[i * 4 + 1] = mod_sub(kMax, b); |
1069 | 0 | out->c[i * 4 + 2] = mod_sub(kMax, c); |
1070 | 0 | out->c[i * 4 + 3] = mod_sub(kMax, d); |
1071 | 0 | } |
1072 | 0 | } |
1073 | | |
1074 | | // FIPS 204, Algorithm 19 (`BitUnpack`). Specialized to bitlen(a+b) = 20 and b = |
1075 | | // 2^19. |
1076 | 0 | void scalar_decode_signed_20_19(scalar *out, const uint8_t in[640]) { |
1077 | 0 | static const uint32_t kMax = 1u << 19; |
1078 | 0 | static const uint32_t k20Bits = (1u << 20) - 1; |
1079 | |
|
1080 | 0 | static_assert(kDegree % 4 == 0, "kDegree must be a multiple of 4"); |
1081 | 0 | for (int i = 0; i < kDegree / 4; i++) { |
1082 | 0 | uint32_t a = CRYPTO_load_u32_le(&in[10 * i]); |
1083 | 0 | uint32_t b = CRYPTO_load_u32_le(&in[10 * i + 4]); |
1084 | 0 | uint16_t c = CRYPTO_load_u16_le(&in[10 * i + 8]); |
1085 | | |
1086 | | // It's not possible for a 20-bit number to be out of range when the max is |
1087 | | // 2^19. |
1088 | 0 | out->c[i * 4] = mod_sub(kMax, a & k20Bits); |
1089 | 0 | out->c[i * 4 + 1] = mod_sub(kMax, (a >> 20) | ((b & 0xff) << 12)); |
1090 | 0 | out->c[i * 4 + 2] = mod_sub(kMax, (b >> 8) & k20Bits); |
1091 | 0 | out->c[i * 4 + 3] = mod_sub(kMax, (b >> 28) | ((uint32_t)c) << 4); |
1092 | 0 | } |
1093 | 0 | } |
1094 | | |
1095 | | // FIPS 204, Algorithm 19 (`BitUnpack`). |
1096 | | int scalar_decode_signed(scalar *out, const uint8_t *in, int bits, |
1097 | 0 | uint32_t max) { |
1098 | 0 | if (bits == 3) { |
1099 | 0 | assert(max == 2); |
1100 | 0 | return scalar_decode_signed_3_2(out, in); |
1101 | 0 | } else if (bits == 4) { |
1102 | 0 | assert(max == 4); |
1103 | 0 | return scalar_decode_signed_4_4(out, in); |
1104 | 0 | } else if (bits == 13) { |
1105 | 0 | assert(max == (1u << 12)); |
1106 | 0 | scalar_decode_signed_13_12(out, in); |
1107 | 0 | return 1; |
1108 | 0 | } else if (bits == 18) { |
1109 | 0 | assert(max == (1u << 17)); |
1110 | 0 | scalar_decode_signed_18_17(out, in); |
1111 | 0 | return 1; |
1112 | 0 | } else if (bits == 20) { |
1113 | 0 | assert(max == (1u << 19)); |
1114 | 0 | scalar_decode_signed_20_19(out, in); |
1115 | 0 | return 1; |
1116 | 0 | } else { |
1117 | 0 | abort(); |
1118 | 0 | } |
1119 | 0 | } |
1120 | | |
1121 | | /* Expansion functions */ |
1122 | | |
1123 | | // FIPS 204, Algorithm 30 (`RejNTTPoly`). |
1124 | | // |
1125 | | // Rejection samples a Keccak stream to get uniformly distributed elements. This |
1126 | | // is used for matrix expansion and only operates on public inputs. |
1127 | | void scalar_from_keccak_vartime(scalar *out, |
1128 | 0 | const uint8_t derived_seed[kRhoBytes + 2]) { |
1129 | 0 | BORINGSSL_keccak_st keccak_ctx; |
1130 | 0 | BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake128); |
1131 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, derived_seed, kRhoBytes + 2); |
1132 | 0 | assert(keccak_ctx.squeeze_offset == 0); |
1133 | 0 | assert(keccak_ctx.rate_bytes == 168); |
1134 | 0 | static_assert(168 % 3 == 0, "block and coefficient boundaries do not align"); |
1135 | |
|
1136 | 0 | int done = 0; |
1137 | 0 | while (done < kDegree) { |
1138 | 0 | uint8_t block[168]; |
1139 | 0 | BORINGSSL_keccak_squeeze(&keccak_ctx, block, sizeof(block)); |
1140 | 0 | for (size_t i = 0; i < sizeof(block) && done < kDegree; i += 3) { |
1141 | | // FIPS 204, Algorithm 14 (`CoeffFromThreeBytes`). |
1142 | 0 | uint32_t value = (uint32_t)block[i] | ((uint32_t)block[i + 1] << 8) | |
1143 | 0 | (((uint32_t)block[i + 2] & 0x7f) << 16); |
1144 | 0 | if (value < kPrime) { |
1145 | 0 | out->c[done++] = value; |
1146 | 0 | } |
1147 | 0 | } |
1148 | 0 | } |
1149 | 0 | } |
1150 | | |
1151 | | template <int ETA> |
1152 | | static bool coefficient_from_nibble(uint32_t nibble, uint32_t *result); |
1153 | | |
1154 | | template <> |
1155 | 0 | bool coefficient_from_nibble<4>(uint32_t nibble, uint32_t *result) { |
1156 | 0 | if (constant_time_declassify_int(nibble < 9)) { |
1157 | | // Knowing bounds on |nibble| seems to tempt some versions of Clang to emit |
1158 | | // a branch, if we don't have a barrier in |mod_sub|. |
1159 | 0 | *result = mod_sub(4, value_barrier_u32(nibble)); |
1160 | 0 | return true; |
1161 | 0 | } |
1162 | 0 | return false; |
1163 | 0 | } |
1164 | | |
1165 | | template <> |
1166 | 0 | bool coefficient_from_nibble<2>(uint32_t nibble, uint32_t *result) { |
1167 | 0 | if (constant_time_declassify_int(nibble < 15)) { |
1168 | | // Knowing bounds on |nibble| seems to tempt some versions of Clang to emit |
1169 | | // a branch, if we don't have a barrier in |mod_sub|. |
1170 | | // Constant time "nibble % 5". |
1171 | 0 | nibble = nibble - 5 * ((205 * nibble) >> 10); |
1172 | 0 | *result = mod_sub(2, value_barrier_u32(nibble)); |
1173 | 0 | return true; |
1174 | 0 | } |
1175 | 0 | return false; |
1176 | 0 | } |
1177 | | |
1178 | | // FIPS 204, Algorithm 31 (`RejBoundedPoly`). |
1179 | | template <int ETA> |
1180 | 0 | void scalar_uniform(scalar *out, const uint8_t derived_seed[kSigmaBytes + 2]) { |
1181 | 0 | BORINGSSL_keccak_st keccak_ctx; |
1182 | 0 | BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake256); |
1183 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, derived_seed, kSigmaBytes + 2); |
1184 | 0 | assert(keccak_ctx.squeeze_offset == 0); |
1185 | 0 | assert(keccak_ctx.rate_bytes == 136); |
1186 | | |
1187 | 0 | int done = 0; |
1188 | 0 | while (done < kDegree) { |
1189 | 0 | uint8_t block[136]; |
1190 | 0 | BORINGSSL_keccak_squeeze(&keccak_ctx, block, sizeof(block)); |
1191 | 0 | for (size_t i = 0; i < sizeof(block) && done < kDegree; ++i) { |
1192 | 0 | uint32_t t0 = block[i] & 0x0F; |
1193 | 0 | uint32_t t1 = block[i] >> 4; |
1194 | | // FIPS 204, Algorithm 15 (`CoefFromHalfByte`). Although both the input |
1195 | | // and output here are secret, it is OK to leak when we rejected a byte. |
1196 | | // Individual bytes of the SHAKE-256 stream are (indistinguishable from) |
1197 | | // independent of each other and the original seed, so leaking information |
1198 | | // about the rejected bytes does not reveal the input or output. |
1199 | 0 | uint32_t v; |
1200 | 0 | if (coefficient_from_nibble<ETA>(t0, &v)) { |
1201 | 0 | out->c[done++] = v; |
1202 | 0 | } |
1203 | 0 | if (done < kDegree && coefficient_from_nibble<ETA>(t1, &v)) { |
1204 | 0 | out->c[done++] = v; |
1205 | 0 | } |
1206 | 0 | } |
1207 | 0 | } |
1208 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_uniform<4>(mldsa::(anonymous namespace)::scalar*, unsigned char const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_uniform<2>(mldsa::(anonymous namespace)::scalar*, unsigned char const*) |
1209 | | |
1210 | | // FIPS 204, Algorithm 34 (`ExpandMask`), but just a single step. |
1211 | | template <int K> |
1212 | | void scalar_sample_mask(scalar *out, |
1213 | 0 | const uint8_t derived_seed[kRhoPrimeBytes + 2]) { |
1214 | 0 | uint8_t buf[scalar_le_gamma1_bytes<K>()]; |
1215 | 0 | BORINGSSL_keccak(buf, sizeof(buf), derived_seed, kRhoPrimeBytes + 2, |
1216 | 0 | boringssl_shake256); |
1217 | |
|
1218 | 0 | scalar_decode_signed(out, buf, gamma1_bits<K>() + 1, gamma1<K>()); |
1219 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_sample_mask<6>(mldsa::(anonymous namespace)::scalar*, unsigned char const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_sample_mask<8>(mldsa::(anonymous namespace)::scalar*, unsigned char const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::scalar_sample_mask<4>(mldsa::(anonymous namespace)::scalar*, unsigned char const*) |
1220 | | |
1221 | | // FIPS 204, Algorithm 29 (`SampleInBall`). |
1222 | | void scalar_sample_in_ball_vartime(scalar *out, const uint8_t *seed, int len, |
1223 | 0 | int tau) { |
1224 | 0 | BORINGSSL_keccak_st keccak_ctx; |
1225 | 0 | BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake256); |
1226 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, seed, len); |
1227 | 0 | assert(keccak_ctx.squeeze_offset == 0); |
1228 | 0 | assert(keccak_ctx.rate_bytes == 136); |
1229 | | |
1230 | 0 | uint8_t block[136]; |
1231 | 0 | BORINGSSL_keccak_squeeze(&keccak_ctx, block, sizeof(block)); |
1232 | |
|
1233 | 0 | uint64_t signs = CRYPTO_load_u64_le(block); |
1234 | 0 | int offset = 8; |
1235 | | // SampleInBall implements a Fisher–Yates shuffle, which unavoidably leaks |
1236 | | // where the zeros are by memory access pattern. Although this leak happens |
1237 | | // before bad signatures are rejected, this is safe. See |
1238 | | // https://boringssl-review.googlesource.com/c/boringssl/+/67747/comment/8d8f01ac_70af3f21/ |
1239 | 0 | CONSTTIME_DECLASSIFY(block + offset, sizeof(block) - offset); |
1240 | |
|
1241 | 0 | OPENSSL_memset(out, 0, sizeof(*out)); |
1242 | 0 | for (size_t i = kDegree - tau; i < kDegree; i++) { |
1243 | 0 | size_t byte; |
1244 | 0 | for (;;) { |
1245 | 0 | if (offset == 136) { |
1246 | 0 | BORINGSSL_keccak_squeeze(&keccak_ctx, block, sizeof(block)); |
1247 | | // See above. |
1248 | 0 | CONSTTIME_DECLASSIFY(block, sizeof(block)); |
1249 | 0 | offset = 0; |
1250 | 0 | } |
1251 | |
|
1252 | 0 | byte = block[offset++]; |
1253 | 0 | if (byte <= i) { |
1254 | 0 | break; |
1255 | 0 | } |
1256 | 0 | } |
1257 | |
|
1258 | 0 | out->c[i] = out->c[byte]; |
1259 | 0 | out->c[byte] = mod_sub(1, 2 * (signs & 1)); |
1260 | 0 | signs >>= 1; |
1261 | 0 | } |
1262 | 0 | } |
1263 | | |
1264 | | // FIPS 204, Algorithm 32 (`ExpandA`). |
1265 | | template <int K, int L> |
1266 | 0 | void matrix_expand(matrix<K, L> *out, const uint8_t rho[kRhoBytes]) { |
1267 | 0 | static_assert(K <= 0x100, "K must fit in 8 bits"); |
1268 | 0 | static_assert(L <= 0x100, "L must fit in 8 bits"); |
1269 | |
|
1270 | 0 | uint8_t derived_seed[kRhoBytes + 2]; |
1271 | 0 | OPENSSL_memcpy(derived_seed, rho, kRhoBytes); |
1272 | 0 | for (int i = 0; i < K; i++) { |
1273 | 0 | for (int j = 0; j < L; j++) { |
1274 | 0 | derived_seed[kRhoBytes + 1] = (uint8_t)i; |
1275 | 0 | derived_seed[kRhoBytes] = (uint8_t)j; |
1276 | 0 | scalar_from_keccak_vartime(&out->v[i][j], derived_seed); |
1277 | 0 | } |
1278 | 0 | } |
1279 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::matrix_expand<6, 5>(mldsa::(anonymous namespace)::matrix<6, 5>*, unsigned char const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::matrix_expand<8, 7>(mldsa::(anonymous namespace)::matrix<8, 7>*, unsigned char const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::matrix_expand<4, 4>(mldsa::(anonymous namespace)::matrix<4, 4>*, unsigned char const*) |
1280 | | |
1281 | | // FIPS 204, Algorithm 33 (`ExpandS`). |
1282 | | template <int K, int L> |
1283 | | void vector_expand_short(vector<L> *s1, vector<K> *s2, |
1284 | 0 | const uint8_t sigma[kSigmaBytes]) { |
1285 | 0 | static_assert(K <= 0x100, "K must fit in 8 bits"); |
1286 | 0 | static_assert(L <= 0x100, "L must fit in 8 bits"); |
1287 | 0 | static_assert(K + L <= 0x100, "K+L must fit in 8 bits"); |
1288 | |
|
1289 | 0 | uint8_t derived_seed[kSigmaBytes + 2]; |
1290 | 0 | OPENSSL_memcpy(derived_seed, sigma, kSigmaBytes); |
1291 | 0 | derived_seed[kSigmaBytes] = 0; |
1292 | 0 | derived_seed[kSigmaBytes + 1] = 0; |
1293 | 0 | for (int i = 0; i < L; i++) { |
1294 | 0 | scalar_uniform<eta<K>()>(&s1->v[i], derived_seed); |
1295 | 0 | ++derived_seed[kSigmaBytes]; |
1296 | 0 | } |
1297 | 0 | for (int i = 0; i < K; i++) { |
1298 | 0 | scalar_uniform<eta<K>()>(&s2->v[i], derived_seed); |
1299 | 0 | ++derived_seed[kSigmaBytes]; |
1300 | 0 | } |
1301 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_expand_short<6, 5>(mldsa::(anonymous namespace)::vector<5>*, mldsa::(anonymous namespace)::vector<6>*, unsigned char const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_expand_short<8, 7>(mldsa::(anonymous namespace)::vector<7>*, mldsa::(anonymous namespace)::vector<8>*, unsigned char const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_expand_short<4, 4>(mldsa::(anonymous namespace)::vector<4>*, mldsa::(anonymous namespace)::vector<4>*, unsigned char const*) |
1302 | | |
1303 | | // FIPS 204, Algorithm 34 (`ExpandMask`). |
1304 | | template <int K, int L> |
1305 | | void vector_expand_mask(vector<L> *out, const uint8_t seed[kRhoPrimeBytes], |
1306 | 0 | size_t kappa) { |
1307 | 0 | assert(kappa + L <= 0x10000); |
1308 | | |
1309 | 0 | uint8_t derived_seed[kRhoPrimeBytes + 2]; |
1310 | 0 | OPENSSL_memcpy(derived_seed, seed, kRhoPrimeBytes); |
1311 | 0 | for (int i = 0; i < L; i++) { |
1312 | 0 | size_t index = kappa + i; |
1313 | 0 | derived_seed[kRhoPrimeBytes] = index & 0xFF; |
1314 | 0 | derived_seed[kRhoPrimeBytes + 1] = (index >> 8) & 0xFF; |
1315 | 0 | scalar_sample_mask<K>(&out->v[i], derived_seed); |
1316 | 0 | } |
1317 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_expand_mask<6, 5>(mldsa::(anonymous namespace)::vector<5>*, unsigned char const*, unsigned long) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_expand_mask<8, 7>(mldsa::(anonymous namespace)::vector<7>*, unsigned char const*, unsigned long) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_expand_mask<4, 4>(mldsa::(anonymous namespace)::vector<4>*, unsigned char const*, unsigned long) |
1318 | | |
1319 | | /* Encoding */ |
1320 | | |
1321 | | // FIPS 204, Algorithm 16 (`SimpleBitPack`). |
1322 | | // |
1323 | | // Encodes an entire vector into 32*K*|bits| bytes. Note that since 256 |
1324 | | // (kDegree) is divisible by 8, the individual vector entries will always fill a |
1325 | | // whole number of bytes, so we do not need to worry about bit packing here. |
1326 | | template <int K> |
1327 | 0 | void vector_encode(uint8_t *out, const vector<K> *a, int bits) { |
1328 | 0 | if (bits == 4) { |
1329 | 0 | for (int i = 0; i < K; i++) { |
1330 | 0 | scalar_encode_4(out + i * bits * kDegree / 8, &a->v[i]); |
1331 | 0 | } |
1332 | 0 | } else if (bits == 6) { |
1333 | 0 | for (int i = 0; i < K; i++) { |
1334 | 0 | scalar_encode_6(out + i * bits * kDegree / 8, &a->v[i]); |
1335 | 0 | } |
1336 | 0 | } else { |
1337 | 0 | assert(bits == 10); |
1338 | 0 | for (int i = 0; i < K; i++) { |
1339 | 0 | scalar_encode_10(out + i * bits * kDegree / 8, &a->v[i]); |
1340 | 0 | } |
1341 | 0 | } |
1342 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_encode<6>(unsigned char*, mldsa::(anonymous namespace)::vector<6> const*, int) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_encode<8>(unsigned char*, mldsa::(anonymous namespace)::vector<8> const*, int) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_encode<4>(unsigned char*, mldsa::(anonymous namespace)::vector<4> const*, int) |
1343 | | |
1344 | | // FIPS 204, Algorithm 18 (`SimpleBitUnpack`). |
1345 | | template <int K> |
1346 | 0 | void vector_decode_10(vector<K> *out, const uint8_t *in) { |
1347 | 0 | for (int i = 0; i < K; i++) { |
1348 | 0 | scalar_decode_10(&out->v[i], in + i * 10 * kDegree / 8); |
1349 | 0 | } |
1350 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_decode_10<6>(mldsa::(anonymous namespace)::vector<6>*, unsigned char const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_decode_10<8>(mldsa::(anonymous namespace)::vector<8>*, unsigned char const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_decode_10<4>(mldsa::(anonymous namespace)::vector<4>*, unsigned char const*) |
1351 | | |
1352 | | // FIPS 204, Algorithm 17 (`BitPack`). |
1353 | | // |
1354 | | // Encodes an entire vector into 32*L*|bits| bytes. Note that since 256 |
1355 | | // (kDegree) is divisible by 8, the individual vector entries will always fill a |
1356 | | // whole number of bytes, so we do not need to worry about bit packing here. |
1357 | | template <int X> |
1358 | | void vector_encode_signed(uint8_t *out, const vector<X> *a, int bits, |
1359 | 0 | uint32_t max) { |
1360 | 0 | for (int i = 0; i < X; i++) { |
1361 | 0 | scalar_encode_signed(out + i * bits * kDegree / 8, &a->v[i], bits, max); |
1362 | 0 | } |
1363 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_encode_signed<5>(unsigned char*, mldsa::(anonymous namespace)::vector<5> const*, int, unsigned int) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_encode_signed<6>(unsigned char*, mldsa::(anonymous namespace)::vector<6> const*, int, unsigned int) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_encode_signed<7>(unsigned char*, mldsa::(anonymous namespace)::vector<7> const*, int, unsigned int) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_encode_signed<8>(unsigned char*, mldsa::(anonymous namespace)::vector<8> const*, int, unsigned int) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::vector_encode_signed<4>(unsigned char*, mldsa::(anonymous namespace)::vector<4> const*, int, unsigned int) |
1364 | | |
1365 | | template <int X> |
1366 | | int vector_decode_signed(vector<X> *out, const uint8_t *in, int bits, |
1367 | 0 | uint32_t max) { |
1368 | 0 | for (int i = 0; i < X; i++) { |
1369 | 0 | if (!scalar_decode_signed(&out->v[i], in + i * bits * kDegree / 8, bits, |
1370 | 0 | max)) { |
1371 | 0 | return 0; |
1372 | 0 | } |
1373 | 0 | } |
1374 | 0 | return 1; |
1375 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::vector_decode_signed<5>(mldsa::(anonymous namespace)::vector<5>*, unsigned char const*, int, unsigned int) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::vector_decode_signed<6>(mldsa::(anonymous namespace)::vector<6>*, unsigned char const*, int, unsigned int) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::vector_decode_signed<7>(mldsa::(anonymous namespace)::vector<7>*, unsigned char const*, int, unsigned int) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::vector_decode_signed<8>(mldsa::(anonymous namespace)::vector<8>*, unsigned char const*, int, unsigned int) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::vector_decode_signed<4>(mldsa::(anonymous namespace)::vector<4>*, unsigned char const*, int, unsigned int) |
1376 | | |
1377 | | // FIPS 204, Algorithm 28 (`w1Encode`). |
1378 | | template <int K> |
1379 | 0 | void w1_encode(uint8_t out[w1_bytes<K>()], const vector<K> *w1) { |
1380 | 0 | vector_encode(out, w1, w1_coeffs_bits<K>()); |
1381 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::w1_encode<6>(unsigned char*, mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::w1_encode<8>(unsigned char*, mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::w1_encode<4>(unsigned char*, mldsa::(anonymous namespace)::vector<4> const*) |
1382 | | |
1383 | | // FIPS 204, Algorithm 20 (`HintBitPack`). |
1384 | | template <int K> |
1385 | 0 | void hint_bit_pack(uint8_t out[omega<K>() + K], const vector<K> *h) { |
1386 | 0 | OPENSSL_memset(out, 0, omega<K>() + K); |
1387 | 0 | int index = 0; |
1388 | 0 | for (int i = 0; i < K; i++) { |
1389 | 0 | for (int j = 0; j < kDegree; j++) { |
1390 | 0 | if (h->v[i].c[j]) { |
1391 | | // h must have at most omega<K>() non-zero coefficients. |
1392 | 0 | BSSL_CHECK(index < omega<K>()); |
1393 | 0 | out[index++] = j; |
1394 | 0 | } |
1395 | 0 | } |
1396 | 0 | out[omega<K>() + i] = index; |
1397 | 0 | } |
1398 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::hint_bit_pack<6>(unsigned char*, mldsa::(anonymous namespace)::vector<6> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::hint_bit_pack<8>(unsigned char*, mldsa::(anonymous namespace)::vector<8> const*) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::hint_bit_pack<4>(unsigned char*, mldsa::(anonymous namespace)::vector<4> const*) |
1399 | | |
1400 | | // FIPS 204, Algorithm 21 (`HintBitUnpack`). |
1401 | | template <int K> |
1402 | 0 | int hint_bit_unpack(vector<K> *h, const uint8_t in[omega<K>() + K]) { |
1403 | 0 | vector_zero(h); |
1404 | 0 | int index = 0; |
1405 | 0 | for (int i = 0; i < K; i++) { |
1406 | 0 | const int limit = in[omega<K>() + i]; |
1407 | 0 | if (limit < index || limit > omega<K>()) { |
1408 | 0 | return 0; |
1409 | 0 | } |
1410 | | |
1411 | 0 | int last = -1; |
1412 | 0 | while (index < limit) { |
1413 | 0 | int byte = in[index++]; |
1414 | 0 | if (last >= 0 && byte <= last) { |
1415 | 0 | return 0; |
1416 | 0 | } |
1417 | 0 | last = byte; |
1418 | 0 | static_assert(kDegree == 256, |
1419 | 0 | "kDegree must be 256 for this write to be in bounds"); |
1420 | 0 | h->v[i].c[byte] = 1; |
1421 | 0 | } |
1422 | 0 | } |
1423 | 0 | for (; index < omega<K>(); index++) { |
1424 | 0 | if (in[index] != 0) { |
1425 | 0 | return 0; |
1426 | 0 | } |
1427 | 0 | } |
1428 | 0 | return 1; |
1429 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::hint_bit_unpack<6>(mldsa::(anonymous namespace)::vector<6>*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::hint_bit_unpack<8>(mldsa::(anonymous namespace)::vector<8>*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::hint_bit_unpack<4>(mldsa::(anonymous namespace)::vector<4>*, unsigned char const*) |
1430 | | |
1431 | | template <int K> |
1432 | | struct public_key { |
1433 | | uint8_t rho[kRhoBytes]; |
1434 | | vector<K> t1; |
1435 | | // Pre-cached value(s). |
1436 | | uint8_t public_key_hash[kTrBytes]; |
1437 | | }; |
1438 | | |
1439 | | template <int K, int L> |
1440 | | struct private_key { |
1441 | | public_key<K> pub; |
1442 | | uint8_t k[kKBytes]; |
1443 | | vector<L> s1; |
1444 | | vector<K> s2; |
1445 | | vector<K> t0; |
1446 | | }; |
1447 | | |
1448 | | template <int K, int L> |
1449 | | struct signature { |
1450 | | uint8_t c_tilde[2 * lambda_bytes<K>()]; |
1451 | | vector<L> z; |
1452 | | vector<K> h; |
1453 | | }; |
1454 | | |
1455 | | // FIPS 204, Algorithm 22 (`pkEncode`). |
1456 | | template <int K> |
1457 | 0 | int mldsa_marshal_public_key(CBB *out, const public_key<K> *pub) { |
1458 | 0 | if (!CBB_add_bytes(out, pub->rho, sizeof(pub->rho))) { |
1459 | 0 | return 0; |
1460 | 0 | } |
1461 | | |
1462 | 0 | uint8_t *vectork_output; |
1463 | 0 | if (!CBB_add_space(out, &vectork_output, 320 * K)) { |
1464 | 0 | return 0; |
1465 | 0 | } |
1466 | 0 | vector_encode(vectork_output, &pub->t1, 10); |
1467 | |
|
1468 | 0 | return 1; |
1469 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_marshal_public_key<6>(cbb_st*, mldsa::(anonymous namespace)::public_key<6> const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_marshal_public_key<8>(cbb_st*, mldsa::(anonymous namespace)::public_key<8> const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_marshal_public_key<4>(cbb_st*, mldsa::(anonymous namespace)::public_key<4> const*) |
1470 | | |
1471 | | // FIPS 204, Algorithm 23 (`pkDecode`). |
1472 | | template <int K> |
1473 | 0 | int mldsa_parse_public_key(public_key<K> *pub, CBS *in) { |
1474 | 0 | const CBS orig_in = *in; |
1475 | |
|
1476 | 0 | if (!CBS_copy_bytes(in, pub->rho, sizeof(pub->rho))) { |
1477 | 0 | return 0; |
1478 | 0 | } |
1479 | | |
1480 | 0 | CBS t1_bytes; |
1481 | 0 | if (!CBS_get_bytes(in, &t1_bytes, 320 * K) || CBS_len(in) != 0) { |
1482 | 0 | return 0; |
1483 | 0 | } |
1484 | 0 | vector_decode_10(&pub->t1, CBS_data(&t1_bytes)); |
1485 | | |
1486 | | // Compute pre-cached values. |
1487 | 0 | BORINGSSL_keccak(pub->public_key_hash, sizeof(pub->public_key_hash), |
1488 | 0 | CBS_data(&orig_in), CBS_len(&orig_in), boringssl_shake256); |
1489 | |
|
1490 | 0 | return 1; |
1491 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_parse_public_key<6>(mldsa::(anonymous namespace)::public_key<6>*, cbs_st*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_parse_public_key<8>(mldsa::(anonymous namespace)::public_key<8>*, cbs_st*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_parse_public_key<4>(mldsa::(anonymous namespace)::public_key<4>*, cbs_st*) |
1492 | | |
1493 | | // FIPS 204, Algorithm 24 (`skEncode`). |
1494 | | template <int K, int L> |
1495 | 0 | int mldsa_marshal_private_key(CBB *out, const private_key<K, L> *priv) { |
1496 | 0 | if (!CBB_add_bytes(out, priv->pub.rho, sizeof(priv->pub.rho)) || |
1497 | 0 | !CBB_add_bytes(out, priv->k, sizeof(priv->k)) || |
1498 | 0 | !CBB_add_bytes(out, priv->pub.public_key_hash, |
1499 | 0 | sizeof(priv->pub.public_key_hash))) { |
1500 | 0 | return 0; |
1501 | 0 | } |
1502 | | |
1503 | 0 | constexpr size_t scalar_bytes = |
1504 | 0 | (kDegree * plus_minus_eta_bitlen<K>() + 7) / 8; |
1505 | 0 | uint8_t *vectorl_output; |
1506 | 0 | if (!CBB_add_space(out, &vectorl_output, scalar_bytes * L)) { |
1507 | 0 | return 0; |
1508 | 0 | } |
1509 | 0 | vector_encode_signed(vectorl_output, &priv->s1, plus_minus_eta_bitlen<K>(), |
1510 | 0 | eta<K>()); |
1511 | |
|
1512 | 0 | uint8_t *s2_output; |
1513 | 0 | if (!CBB_add_space(out, &s2_output, scalar_bytes * K)) { |
1514 | 0 | return 0; |
1515 | 0 | } |
1516 | 0 | vector_encode_signed(s2_output, &priv->s2, plus_minus_eta_bitlen<K>(), |
1517 | 0 | eta<K>()); |
1518 | |
|
1519 | 0 | uint8_t *t0_output; |
1520 | 0 | if (!CBB_add_space(out, &t0_output, 416 * K)) { |
1521 | 0 | return 0; |
1522 | 0 | } |
1523 | 0 | vector_encode_signed(t0_output, &priv->t0, 13, 1 << 12); |
1524 | |
|
1525 | 0 | return 1; |
1526 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_marshal_private_key<6, 5>(cbb_st*, mldsa::(anonymous namespace)::private_key<6, 5> const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_marshal_private_key<8, 7>(cbb_st*, mldsa::(anonymous namespace)::private_key<8, 7> const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_marshal_private_key<4, 4>(cbb_st*, mldsa::(anonymous namespace)::private_key<4, 4> const*) |
1527 | | |
1528 | | // FIPS 204, Algorithm 25 (`skDecode`). This is only used for testing. The |
1529 | | // supported external way to construct ML-DSA keys is to use the input seed. |
1530 | | template <int K, int L> |
1531 | 0 | int mldsa_parse_private_key(private_key<K, L> *priv, CBS *in) { |
1532 | 0 | CBS public_key_hash, s1_bytes, s2_bytes, t0_bytes; |
1533 | 0 | constexpr size_t scalar_bytes = |
1534 | 0 | (kDegree * plus_minus_eta_bitlen<K>() + 7) / 8; |
1535 | 0 | if (!CBS_copy_bytes(in, priv->pub.rho, sizeof(priv->pub.rho)) || |
1536 | 0 | !CBS_copy_bytes(in, priv->k, sizeof(priv->k)) || |
1537 | 0 | !CBS_get_bytes(in, &public_key_hash, kTrBytes) || |
1538 | 0 | !CBS_get_bytes(in, &s1_bytes, scalar_bytes * L) || |
1539 | 0 | !vector_decode_signed(&priv->s1, CBS_data(&s1_bytes), |
1540 | 0 | plus_minus_eta_bitlen<K>(), eta<K>()) || |
1541 | 0 | !CBS_get_bytes(in, &s2_bytes, scalar_bytes * K) || |
1542 | 0 | !vector_decode_signed(&priv->s2, CBS_data(&s2_bytes), |
1543 | 0 | plus_minus_eta_bitlen<K>(), eta<K>()) || |
1544 | 0 | !CBS_get_bytes(in, &t0_bytes, 416 * K) || |
1545 | | // Note: Decoding 13 bits into (-2^12, 2^12] cannot fail. |
1546 | 0 | !vector_decode_signed(&priv->t0, CBS_data(&t0_bytes), 13, 1 << 12)) { |
1547 | 0 | return 0; |
1548 | 0 | } |
1549 | | |
1550 | | // Compute `t1`, which is not in the `skDecode` input. |
1551 | 0 | uint8_t unused[public_key_bytes<K>()]; |
1552 | 0 | if (!mldsa_finish_keygen(unused, priv)) { |
1553 | 0 | return 0; |
1554 | 0 | } |
1555 | | |
1556 | | // As a side effect of computing `t1`, we also compute `t0` and |
1557 | | // `public_key_hash`. Check they match the received bytes. |
1558 | 0 | uint8_t t0_computed[416 * K]; |
1559 | 0 | vector_encode_signed(t0_computed, &priv->t0, 13, 1 << 12); |
1560 | 0 | if (!CBS_mem_equal(&public_key_hash, priv->pub.public_key_hash, |
1561 | 0 | sizeof(priv->pub.public_key_hash)) || |
1562 | 0 | !CBS_mem_equal(&t0_bytes, t0_computed, sizeof(t0_computed))) { |
1563 | 0 | return 0; |
1564 | 0 | } |
1565 | | |
1566 | 0 | return 1; |
1567 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_parse_private_key<6, 5>(mldsa::(anonymous namespace)::private_key<6, 5>*, cbs_st*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_parse_private_key<8, 7>(mldsa::(anonymous namespace)::private_key<8, 7>*, cbs_st*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_parse_private_key<4, 4>(mldsa::(anonymous namespace)::private_key<4, 4>*, cbs_st*) |
1568 | | |
1569 | | // FIPS 204, Algorithm 26 (`sigEncode`). |
1570 | | template <int K, int L> |
1571 | 0 | int mldsa_marshal_signature(CBB *out, const signature<K, L> *sign) { |
1572 | 0 | if (!CBB_add_bytes(out, sign->c_tilde, sizeof(sign->c_tilde))) { |
1573 | 0 | return 0; |
1574 | 0 | } |
1575 | | |
1576 | 0 | uint8_t *vectorl_output; |
1577 | 0 | if (!CBB_add_space(out, &vectorl_output, scalar_le_gamma1_bytes<K>() * L)) { |
1578 | 0 | return 0; |
1579 | 0 | } |
1580 | 0 | vector_encode_signed(vectorl_output, &sign->z, gamma1_bits<K>() + 1, |
1581 | 0 | gamma1<K>()); |
1582 | |
|
1583 | 0 | uint8_t *hint_output; |
1584 | 0 | if (!CBB_add_space(out, &hint_output, omega<K>() + K)) { |
1585 | 0 | return 0; |
1586 | 0 | } |
1587 | 0 | hint_bit_pack(hint_output, &sign->h); |
1588 | |
|
1589 | 0 | return 1; |
1590 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_marshal_signature<6, 5>(cbb_st*, mldsa::(anonymous namespace)::signature<6, 5> const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_marshal_signature<8, 7>(cbb_st*, mldsa::(anonymous namespace)::signature<8, 7> const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_marshal_signature<4, 4>(cbb_st*, mldsa::(anonymous namespace)::signature<4, 4> const*) |
1591 | | |
1592 | | // FIPS 204, Algorithm 27 (`sigDecode`). |
1593 | | template <int K, int L> |
1594 | 0 | int mldsa_parse_signature(signature<K, L> *sign, CBS *in) { |
1595 | 0 | CBS z_bytes; |
1596 | 0 | CBS hint_bytes; |
1597 | 0 | if (!CBS_copy_bytes(in, sign->c_tilde, sizeof(sign->c_tilde)) || |
1598 | 0 | !CBS_get_bytes(in, &z_bytes, scalar_le_gamma1_bytes<K>() * L) || |
1599 | | // Note: Decoding b+1 bits into (-2^b, 2^b] cannot fail. |
1600 | 0 | !vector_decode_signed(&sign->z, CBS_data(&z_bytes), gamma1_bits<K>() + 1, |
1601 | 0 | gamma1<K>()) || |
1602 | 0 | !CBS_get_bytes(in, &hint_bytes, omega<K>() + K) || |
1603 | 0 | !hint_bit_unpack(&sign->h, CBS_data(&hint_bytes))) { |
1604 | 0 | return 0; |
1605 | 0 | }; |
1606 | |
|
1607 | 0 | return 1; |
1608 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_parse_signature<6, 5>(mldsa::(anonymous namespace)::signature<6, 5>*, cbs_st*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_parse_signature<8, 7>(mldsa::(anonymous namespace)::signature<8, 7>*, cbs_st*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_parse_signature<4, 4>(mldsa::(anonymous namespace)::signature<4, 4>*, cbs_st*) |
1609 | | |
1610 | | // FIPS 204, Algorithm 6 (`ML-DSA.KeyGen_internal`), steps 3 and 5–11. |
1611 | | // Returns 1 on success and 0 on failure. |
1612 | | template <int K, int L> |
1613 | | int mldsa_finish_keygen(uint8_t out_encoded_public_key[public_key_bytes<K>()], |
1614 | 0 | private_key<K, L> *priv) { |
1615 | | // Intermediate values, allocated on the heap to allow use when there is a |
1616 | | // limited amount of stack. |
1617 | 0 | struct Values { |
1618 | 0 | enum { kAllowUniquePtr = true }; |
1619 | 0 | matrix<K, L> a_ntt; |
1620 | 0 | vector<L> s1_ntt; |
1621 | 0 | vector<K> t; |
1622 | 0 | }; |
1623 | 0 | auto values = bssl::MakeUnique<Values>(); |
1624 | 0 | if (values == nullptr) { |
1625 | 0 | return 0; |
1626 | 0 | } |
1627 | | |
1628 | | // Step 3. |
1629 | 0 | matrix_expand(&values->a_ntt, priv->pub.rho); |
1630 | | |
1631 | | // Step 5. |
1632 | 0 | OPENSSL_memcpy(&values->s1_ntt, &priv->s1, sizeof(values->s1_ntt)); |
1633 | 0 | vector_ntt(&values->s1_ntt); |
1634 | |
|
1635 | 0 | matrix_mult(&values->t, &values->a_ntt, &values->s1_ntt); |
1636 | 0 | vector_inverse_ntt(&values->t); |
1637 | 0 | vector_add(&values->t, &values->t, &priv->s2); |
1638 | | |
1639 | | // Step 6-7. |
1640 | 0 | vector_power2_round(&priv->pub.t1, &priv->t0, &values->t); |
1641 | | // t1 is public. |
1642 | 0 | CONSTTIME_DECLASSIFY(&priv->pub.t1, sizeof(priv->pub.t1)); |
1643 | | |
1644 | | // Step 8. |
1645 | 0 | CBB cbb; |
1646 | 0 | CBB_init_fixed(&cbb, out_encoded_public_key, public_key_bytes<K>()); |
1647 | 0 | if (!mldsa_marshal_public_key(&cbb, &priv->pub)) { |
1648 | 0 | return 0; |
1649 | 0 | } |
1650 | 0 | assert(CBB_len(&cbb) == public_key_bytes<K>()); |
1651 | | |
1652 | | // Step 9-11. |
1653 | 0 | BORINGSSL_keccak(priv->pub.public_key_hash, sizeof(priv->pub.public_key_hash), |
1654 | 0 | out_encoded_public_key, public_key_bytes<K>(), |
1655 | 0 | boringssl_shake256); |
1656 | |
|
1657 | 0 | return 1; |
1658 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_finish_keygen<6, 5>(unsigned char*, mldsa::(anonymous namespace)::private_key<6, 5>*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_finish_keygen<8, 7>(unsigned char*, mldsa::(anonymous namespace)::private_key<8, 7>*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_finish_keygen<4, 4>(unsigned char*, mldsa::(anonymous namespace)::private_key<4, 4>*) |
1659 | | |
1660 | | // FIPS 204, Algorithm 6 (`ML-DSA.KeyGen_internal`). Returns 1 on success and 0 |
1661 | | // on failure. |
1662 | | template <int K, int L> |
1663 | | int mldsa_generate_key_external_entropy_no_self_test( |
1664 | | uint8_t out_encoded_public_key[public_key_bytes<K>()], |
1665 | 0 | private_key<K, L> *priv, const uint8_t entropy[MLDSA_SEED_BYTES]) { |
1666 | | // Step 1-2. |
1667 | 0 | uint8_t augmented_entropy[MLDSA_SEED_BYTES + 2]; |
1668 | 0 | OPENSSL_memcpy(augmented_entropy, entropy, MLDSA_SEED_BYTES); |
1669 | | // The k and l parameters are appended to the seed. |
1670 | 0 | augmented_entropy[MLDSA_SEED_BYTES] = K; |
1671 | 0 | augmented_entropy[MLDSA_SEED_BYTES + 1] = L; |
1672 | 0 | uint8_t expanded_seed[kRhoBytes + kSigmaBytes + kKBytes]; |
1673 | 0 | BORINGSSL_keccak(expanded_seed, sizeof(expanded_seed), augmented_entropy, |
1674 | 0 | sizeof(augmented_entropy), boringssl_shake256); |
1675 | 0 | const uint8_t *const rho = expanded_seed; |
1676 | 0 | const uint8_t *const sigma = expanded_seed + kRhoBytes; |
1677 | 0 | const uint8_t *const k = expanded_seed + kRhoBytes + kSigmaBytes; |
1678 | | // rho is public. |
1679 | 0 | CONSTTIME_DECLASSIFY(rho, kRhoBytes); |
1680 | 0 | OPENSSL_memcpy(priv->pub.rho, rho, sizeof(priv->pub.rho)); |
1681 | 0 | OPENSSL_memcpy(priv->k, k, sizeof(priv->k)); |
1682 | | // Step 4. This is independent of A (step 3) and can be done first. |
1683 | 0 | vector_expand_short(&priv->s1, &priv->s2, sigma); |
1684 | | // Steps 3 and 5-11. |
1685 | 0 | return mldsa_finish_keygen(out_encoded_public_key, priv); |
1686 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_generate_key_external_entropy_no_self_test<6, 5>(unsigned char*, mldsa::(anonymous namespace)::private_key<6, 5>*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_generate_key_external_entropy_no_self_test<8, 7>(unsigned char*, mldsa::(anonymous namespace)::private_key<8, 7>*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_generate_key_external_entropy_no_self_test<4, 4>(unsigned char*, mldsa::(anonymous namespace)::private_key<4, 4>*, unsigned char const*) |
1687 | | |
1688 | | template <int K, int L> |
1689 | | int mldsa_generate_key_external_entropy( |
1690 | | uint8_t out_encoded_public_key[public_key_bytes<K>()], |
1691 | 0 | private_key<K, L> *priv, const uint8_t entropy[MLDSA_SEED_BYTES]) { |
1692 | 0 | fips::ensure_keygen_self_test(); |
1693 | 0 | return mldsa_generate_key_external_entropy_no_self_test( |
1694 | 0 | out_encoded_public_key, priv, entropy); |
1695 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_generate_key_external_entropy<6, 5>(unsigned char*, mldsa::(anonymous namespace)::private_key<6, 5>*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_generate_key_external_entropy<8, 7>(unsigned char*, mldsa::(anonymous namespace)::private_key<8, 7>*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_generate_key_external_entropy<4, 4>(unsigned char*, mldsa::(anonymous namespace)::private_key<4, 4>*, unsigned char const*) |
1696 | | |
1697 | | // FIPS 204, Algorithm 7 (`ML-DSA.Sign_internal`), using a pre-computed mu. |
1698 | | // Returns 1 on success and 0 on failure. |
1699 | | template <int K, int L> |
1700 | | int mldsa_sign_mu_no_self_test( |
1701 | | uint8_t out_encoded_signature[signature_bytes<K>()], |
1702 | | const private_key<K, L> *priv, const uint8_t mu[kMuBytes], |
1703 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) { |
1704 | 0 | uint8_t rho_prime[kRhoPrimeBytes]; |
1705 | 0 | BORINGSSL_keccak_st keccak_ctx; |
1706 | 0 | BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake256); |
1707 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, priv->k, sizeof(priv->k)); |
1708 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, randomizer, |
1709 | 0 | BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES); |
1710 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, mu, kMuBytes); |
1711 | 0 | BORINGSSL_keccak_squeeze(&keccak_ctx, rho_prime, kRhoPrimeBytes); |
1712 | | |
1713 | | // Intermediate values, allocated on the heap to allow use when there is a |
1714 | | // limited amount of stack. |
1715 | 0 | struct Values { |
1716 | 0 | enum { kAllowUniquePtr = true }; |
1717 | 0 | signature<K, L> sign; |
1718 | 0 | vector<L> s1_ntt; |
1719 | 0 | vector<K> s2_ntt; |
1720 | 0 | vector<K> t0_ntt; |
1721 | 0 | matrix<K, L> a_ntt; |
1722 | 0 | vector<L> y; |
1723 | 0 | vector<K> w; |
1724 | 0 | vector<K> w1; |
1725 | 0 | vector<L> cs1; |
1726 | 0 | vector<K> cs2; |
1727 | 0 | }; |
1728 | 0 | auto values = bssl::MakeUnique<Values>(); |
1729 | 0 | if (values == nullptr) { |
1730 | 0 | return 0; |
1731 | 0 | } |
1732 | 0 | OPENSSL_memcpy(&values->s1_ntt, &priv->s1, sizeof(values->s1_ntt)); |
1733 | 0 | vector_ntt(&values->s1_ntt); |
1734 | |
|
1735 | 0 | OPENSSL_memcpy(&values->s2_ntt, &priv->s2, sizeof(values->s2_ntt)); |
1736 | 0 | vector_ntt(&values->s2_ntt); |
1737 | |
|
1738 | 0 | OPENSSL_memcpy(&values->t0_ntt, &priv->t0, sizeof(values->t0_ntt)); |
1739 | 0 | vector_ntt(&values->t0_ntt); |
1740 | |
|
1741 | 0 | matrix_expand(&values->a_ntt, priv->pub.rho); |
1742 | | |
1743 | | // kappa must not exceed 2**16/L = 13107. But the probability of it |
1744 | | // exceeding even 1000 iterations is vanishingly small. |
1745 | 0 | for (size_t kappa = 0;; kappa += L) { |
1746 | 0 | vector_expand_mask<K, L>(&values->y, rho_prime, kappa); |
1747 | |
|
1748 | 0 | vector<L> *y_ntt = &values->cs1; |
1749 | 0 | OPENSSL_memcpy(y_ntt, &values->y, sizeof(*y_ntt)); |
1750 | 0 | vector_ntt(y_ntt); |
1751 | |
|
1752 | 0 | matrix_mult(&values->w, &values->a_ntt, y_ntt); |
1753 | 0 | vector_inverse_ntt(&values->w); |
1754 | |
|
1755 | 0 | vector_high_bits(&values->w1, &values->w); |
1756 | 0 | uint8_t w1_encoded[w1_bytes<K>()]; |
1757 | 0 | w1_encode(w1_encoded, &values->w1); |
1758 | |
|
1759 | 0 | BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake256); |
1760 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, mu, kMuBytes); |
1761 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, w1_encoded, w1_bytes<K>()); |
1762 | 0 | BORINGSSL_keccak_squeeze(&keccak_ctx, values->sign.c_tilde, |
1763 | 0 | 2 * lambda_bytes<K>()); |
1764 | |
|
1765 | 0 | scalar c_ntt; |
1766 | 0 | scalar_sample_in_ball_vartime(&c_ntt, values->sign.c_tilde, |
1767 | 0 | sizeof(values->sign.c_tilde), tau<K>()); |
1768 | 0 | scalar_ntt(&c_ntt); |
1769 | |
|
1770 | 0 | vector_mult_scalar(&values->cs1, &values->s1_ntt, &c_ntt); |
1771 | 0 | vector_inverse_ntt(&values->cs1); |
1772 | 0 | vector_mult_scalar(&values->cs2, &values->s2_ntt, &c_ntt); |
1773 | 0 | vector_inverse_ntt(&values->cs2); |
1774 | |
|
1775 | 0 | vector_add(&values->sign.z, &values->y, &values->cs1); |
1776 | |
|
1777 | 0 | vector<K> *r0 = &values->w1; |
1778 | 0 | vector_sub(r0, &values->w, &values->cs2); |
1779 | 0 | vector_low_bits(r0, r0); |
1780 | | |
1781 | | // Leaking the fact that a signature was rejected is fine as the next |
1782 | | // attempt at a signature will be (indistinguishable from) independent of |
1783 | | // this one. Note, however, that we additionally leak which of the two |
1784 | | // branches rejected the signature. Section 5.5 of |
1785 | | // https://pq-crystals.org/dilithium/data/dilithium-specification-round3.pdf |
1786 | | // describes this leak as OK. Note we leak less than what is described by |
1787 | | // the paper; we do not reveal which coefficient violated the bound, and |
1788 | | // we hide which of the |z_max| or |r0_max| bound failed. See also |
1789 | | // https://boringssl-review.googlesource.com/c/boringssl/+/67747/comment/2bbab0fa_d241d35a/ |
1790 | 0 | uint32_t z_max = vector_max(&values->sign.z); |
1791 | 0 | uint32_t r0_max = vector_max_signed(r0); |
1792 | 0 | if (constant_time_declassify_w( |
1793 | 0 | constant_time_ge_w(z_max, gamma1<K>() - beta<K>()) | |
1794 | 0 | constant_time_ge_w(r0_max, gamma2<K>() - beta<K>()))) { |
1795 | | #if defined(BORINGSSL_FIPS_BREAK_TESTS) |
1796 | | // In order to show that our self-tests trigger both restart cases in |
1797 | | // this loop, printf-logging is added when built in break-test mode. |
1798 | | printf("MLDSA signature restart case 1.\n"); |
1799 | | #endif |
1800 | 0 | continue; |
1801 | 0 | } |
1802 | | |
1803 | 0 | vector<K> *ct0 = &values->w1; |
1804 | 0 | vector_mult_scalar(ct0, &values->t0_ntt, &c_ntt); |
1805 | 0 | vector_inverse_ntt(ct0); |
1806 | 0 | vector_make_hint(&values->sign.h, ct0, &values->cs2, &values->w); |
1807 | | |
1808 | | // See above. |
1809 | 0 | uint32_t ct0_max = vector_max(ct0); |
1810 | 0 | size_t h_ones = vector_count_ones(&values->sign.h); |
1811 | 0 | if (constant_time_declassify_w(constant_time_ge_w(ct0_max, gamma2<K>()) | |
1812 | 0 | constant_time_lt_w(omega<K>(), h_ones))) { |
1813 | | #if defined(BORINGSSL_FIPS_BREAK_TESTS) |
1814 | | // In order to show that our self-tests trigger both restart cases in |
1815 | | // this loop, printf-logging is added when built in break-test mode. |
1816 | | printf("MLDSA signature restart case 2.\n"); |
1817 | | #endif |
1818 | 0 | continue; |
1819 | 0 | } |
1820 | | |
1821 | | // Although computed with the private key, the signature is public. |
1822 | 0 | CONSTTIME_DECLASSIFY(values->sign.c_tilde, sizeof(values->sign.c_tilde)); |
1823 | 0 | CONSTTIME_DECLASSIFY(&values->sign.z, sizeof(values->sign.z)); |
1824 | 0 | CONSTTIME_DECLASSIFY(&values->sign.h, sizeof(values->sign.h)); |
1825 | |
|
1826 | 0 | CBB cbb; |
1827 | 0 | CBB_init_fixed(&cbb, out_encoded_signature, signature_bytes<K>()); |
1828 | 0 | if (!mldsa_marshal_signature(&cbb, &values->sign)) { |
1829 | 0 | return 0; |
1830 | 0 | } |
1831 | | |
1832 | 0 | BSSL_CHECK(CBB_len(&cbb) == signature_bytes<K>()); |
1833 | 0 | return 1; |
1834 | 0 | } |
1835 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_mu_no_self_test<6, 5>(unsigned char*, mldsa::(anonymous namespace)::private_key<6, 5> const*, unsigned char const*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_mu_no_self_test<8, 7>(unsigned char*, mldsa::(anonymous namespace)::private_key<8, 7> const*, unsigned char const*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_mu_no_self_test<4, 4>(unsigned char*, mldsa::(anonymous namespace)::private_key<4, 4> const*, unsigned char const*, unsigned char const*) |
1836 | | |
1837 | | // FIPS 204, Algorithm 7 (`ML-DSA.Sign_internal`), using a pre-computed mu. |
1838 | | // Returns 1 on success and 0 on failure. |
1839 | | template <int K, int L> |
1840 | | int mldsa_sign_mu( |
1841 | | uint8_t out_encoded_signature[signature_bytes<K>()], |
1842 | | const private_key<K, L> *priv, const uint8_t mu[kMuBytes], |
1843 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) { |
1844 | 0 | fips::ensure_sign_self_test(); |
1845 | 0 | return mldsa_sign_mu_no_self_test(out_encoded_signature, priv, mu, |
1846 | 0 | randomizer); |
1847 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_mu<6, 5>(unsigned char*, mldsa::(anonymous namespace)::private_key<6, 5> const*, unsigned char const*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_mu<8, 7>(unsigned char*, mldsa::(anonymous namespace)::private_key<8, 7> const*, unsigned char const*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_mu<4, 4>(unsigned char*, mldsa::(anonymous namespace)::private_key<4, 4> const*, unsigned char const*, unsigned char const*) |
1848 | | |
1849 | | // FIPS 204, Algorithm 7 (`ML-DSA.Sign_internal`). Returns 1 on success and 0 |
1850 | | // on failure. |
1851 | | template <int K, int L> |
1852 | | int mldsa_sign_internal_no_self_test( |
1853 | | uint8_t out_encoded_signature[signature_bytes<K>()], |
1854 | | const private_key<K, L> *priv, const uint8_t *msg, size_t msg_len, |
1855 | | const uint8_t *context_prefix, size_t context_prefix_len, |
1856 | | const uint8_t *context, size_t context_len, |
1857 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) { |
1858 | 0 | uint8_t mu[kMuBytes]; |
1859 | 0 | BORINGSSL_keccak_st keccak_ctx; |
1860 | 0 | BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake256); |
1861 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, priv->pub.public_key_hash, |
1862 | 0 | sizeof(priv->pub.public_key_hash)); |
1863 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, context_prefix, context_prefix_len); |
1864 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, context, context_len); |
1865 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, msg, msg_len); |
1866 | 0 | BORINGSSL_keccak_squeeze(&keccak_ctx, mu, kMuBytes); |
1867 | |
|
1868 | 0 | return mldsa_sign_mu_no_self_test(out_encoded_signature, priv, mu, |
1869 | 0 | randomizer); |
1870 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_internal_no_self_test<6, 5>(unsigned char*, mldsa::(anonymous namespace)::private_key<6, 5> const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_internal_no_self_test<8, 7>(unsigned char*, mldsa::(anonymous namespace)::private_key<8, 7> const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_internal_no_self_test<4, 4>(unsigned char*, mldsa::(anonymous namespace)::private_key<4, 4> const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*) |
1871 | | |
1872 | | // FIPS 204, Algorithm 7 (`ML-DSA.Sign_internal`). Returns 1 on success and 0 |
1873 | | // on failure. |
1874 | | template <int K, int L> |
1875 | | int mldsa_sign_internal( |
1876 | | uint8_t out_encoded_signature[signature_bytes<K>()], |
1877 | | const private_key<K, L> *priv, const uint8_t *msg, size_t msg_len, |
1878 | | const uint8_t *context_prefix, size_t context_prefix_len, |
1879 | | const uint8_t *context, size_t context_len, |
1880 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) { |
1881 | 0 | fips::ensure_sign_self_test(); |
1882 | 0 | return mldsa_sign_internal_no_self_test( |
1883 | 0 | out_encoded_signature, priv, msg, msg_len, context_prefix, |
1884 | 0 | context_prefix_len, context, context_len, randomizer); |
1885 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_internal<6, 5>(unsigned char*, mldsa::(anonymous namespace)::private_key<6, 5> const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_internal<8, 7>(unsigned char*, mldsa::(anonymous namespace)::private_key<8, 7> const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_sign_internal<4, 4>(unsigned char*, mldsa::(anonymous namespace)::private_key<4, 4> const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*) |
1886 | | |
1887 | | struct prehash_context { |
1888 | | BORINGSSL_keccak_st keccak_ctx; |
1889 | | }; |
1890 | | |
1891 | | template <int K> |
1892 | | void mldsa_prehash_init(prehash_context *out_prehash_ctx, |
1893 | | const public_key<K> *pub, const uint8_t *context_prefix, |
1894 | | size_t context_prefix_len, const uint8_t *context, |
1895 | 0 | size_t context_len) { |
1896 | 0 | BORINGSSL_keccak_init(&out_prehash_ctx->keccak_ctx, boringssl_shake256); |
1897 | 0 | BORINGSSL_keccak_absorb(&out_prehash_ctx->keccak_ctx, pub->public_key_hash, |
1898 | 0 | sizeof(pub->public_key_hash)); |
1899 | 0 | BORINGSSL_keccak_absorb(&out_prehash_ctx->keccak_ctx, context_prefix, |
1900 | 0 | context_prefix_len); |
1901 | 0 | BORINGSSL_keccak_absorb(&out_prehash_ctx->keccak_ctx, context, context_len); |
1902 | 0 | } Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::mldsa_prehash_init<6>(mldsa::(anonymous namespace)::prehash_context*, mldsa::(anonymous namespace)::public_key<6> const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::mldsa_prehash_init<8>(mldsa::(anonymous namespace)::prehash_context*, mldsa::(anonymous namespace)::public_key<8> const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long) Unexecuted instantiation: bcm.cc:void mldsa::(anonymous namespace)::mldsa_prehash_init<4>(mldsa::(anonymous namespace)::prehash_context*, mldsa::(anonymous namespace)::public_key<4> const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long) |
1903 | | |
1904 | | void mldsa_prehash_update(prehash_context *inout_prehash_ctx, |
1905 | 0 | const uint8_t *msg, size_t msg_len) { |
1906 | 0 | BORINGSSL_keccak_absorb(&inout_prehash_ctx->keccak_ctx, msg, msg_len); |
1907 | 0 | } |
1908 | | |
1909 | | void mldsa_prehash_finalize(uint8_t out_msg_rep[kMuBytes], |
1910 | 0 | prehash_context *inout_prehash_ctx) { |
1911 | 0 | BORINGSSL_keccak_squeeze(&inout_prehash_ctx->keccak_ctx, out_msg_rep, |
1912 | 0 | kMuBytes); |
1913 | 0 | } |
1914 | | |
1915 | | // FIPS 204, Algorithm 8 (`ML-DSA.Verify_internal`), using a pre-computed mu. |
1916 | | // Returns 1 on success and 0 on failure. |
1917 | | template <int K, int L> |
1918 | | int mldsa_verify_mu_no_self_test( |
1919 | | const public_key<K> *pub, |
1920 | | const uint8_t encoded_signature[signature_bytes<K>()], |
1921 | 0 | const uint8_t mu[kMuBytes]) { |
1922 | | // Intermediate values, allocated on the heap to allow use when there is a |
1923 | | // limited amount of stack. |
1924 | 0 | struct Values { |
1925 | 0 | enum { kAllowUniquePtr = true }; |
1926 | 0 | signature<K, L> sign; |
1927 | 0 | matrix<K, L> a_ntt; |
1928 | 0 | vector<L> z_ntt; |
1929 | 0 | vector<K> az_ntt; |
1930 | 0 | vector<K> ct1_ntt; |
1931 | 0 | }; |
1932 | 0 | auto values = bssl::MakeUnique<Values>(); |
1933 | 0 | if (values == nullptr) { |
1934 | 0 | return 0; |
1935 | 0 | } |
1936 | | |
1937 | 0 | CBS cbs; |
1938 | 0 | CBS_init(&cbs, encoded_signature, signature_bytes<K>()); |
1939 | 0 | if (!mldsa_parse_signature(&values->sign, &cbs)) { |
1940 | 0 | return 0; |
1941 | 0 | } |
1942 | | |
1943 | 0 | matrix_expand(&values->a_ntt, pub->rho); |
1944 | |
|
1945 | 0 | scalar c_ntt; |
1946 | 0 | scalar_sample_in_ball_vartime(&c_ntt, values->sign.c_tilde, |
1947 | 0 | sizeof(values->sign.c_tilde), tau<K>()); |
1948 | 0 | scalar_ntt(&c_ntt); |
1949 | |
|
1950 | 0 | OPENSSL_memcpy(&values->z_ntt, &values->sign.z, sizeof(values->z_ntt)); |
1951 | 0 | vector_ntt(&values->z_ntt); |
1952 | |
|
1953 | 0 | matrix_mult(&values->az_ntt, &values->a_ntt, &values->z_ntt); |
1954 | |
|
1955 | 0 | vector_scale_power2_round(&values->ct1_ntt, &pub->t1); |
1956 | 0 | vector_ntt(&values->ct1_ntt); |
1957 | |
|
1958 | 0 | vector_mult_scalar(&values->ct1_ntt, &values->ct1_ntt, &c_ntt); |
1959 | |
|
1960 | 0 | vector<K> *const w1 = &values->az_ntt; |
1961 | 0 | vector_sub(w1, &values->az_ntt, &values->ct1_ntt); |
1962 | 0 | vector_inverse_ntt(w1); |
1963 | |
|
1964 | 0 | vector_use_hint_vartime(w1, &values->sign.h, w1); |
1965 | 0 | uint8_t w1_encoded[w1_bytes<K>()]; |
1966 | 0 | w1_encode(w1_encoded, w1); |
1967 | |
|
1968 | 0 | uint8_t c_tilde[2 * lambda_bytes<K>()]; |
1969 | 0 | BORINGSSL_keccak_st keccak_ctx; |
1970 | 0 | BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake256); |
1971 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, mu, kMuBytes); |
1972 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, w1_encoded, w1_bytes<K>()); |
1973 | 0 | BORINGSSL_keccak_squeeze(&keccak_ctx, c_tilde, 2 * lambda_bytes<K>()); |
1974 | |
|
1975 | 0 | uint32_t z_max = vector_max(&values->sign.z); |
1976 | 0 | return z_max < static_cast<uint32_t>(gamma1<K>() - beta<K>()) && |
1977 | 0 | OPENSSL_memcmp(c_tilde, values->sign.c_tilde, 2 * lambda_bytes<K>()) == |
1978 | 0 | 0; |
1979 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_mu_no_self_test<6, 5>(mldsa::(anonymous namespace)::public_key<6> const*, unsigned char const*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_mu_no_self_test<8, 7>(mldsa::(anonymous namespace)::public_key<8> const*, unsigned char const*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_mu_no_self_test<4, 4>(mldsa::(anonymous namespace)::public_key<4> const*, unsigned char const*, unsigned char const*) |
1980 | | |
1981 | | // FIPS 204, Algorithm 8 (`ML-DSA.Verify_internal`), using a pre-computed mu. |
1982 | | // Returns 1 on success and 0 on failure. |
1983 | | template <int K, int L> |
1984 | | int mldsa_verify_mu(const public_key<K> *pub, |
1985 | | const uint8_t encoded_signature[signature_bytes<K>()], |
1986 | 0 | const uint8_t mu[kMuBytes]) { |
1987 | 0 | fips::ensure_verify_self_test(); |
1988 | 0 | return mldsa_verify_mu_no_self_test<K, L>(pub, encoded_signature, mu); |
1989 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_mu<6, 5>(mldsa::(anonymous namespace)::public_key<6> const*, unsigned char const*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_mu<8, 7>(mldsa::(anonymous namespace)::public_key<8> const*, unsigned char const*, unsigned char const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_mu<4, 4>(mldsa::(anonymous namespace)::public_key<4> const*, unsigned char const*, unsigned char const*) |
1990 | | |
1991 | | // FIPS 204, Algorithm 8 (`ML-DSA.Verify_internal`). |
1992 | | template <int K, int L> |
1993 | | int mldsa_verify_internal_no_self_test( |
1994 | | const public_key<K> *pub, |
1995 | | const uint8_t encoded_signature[signature_bytes<K>()], const uint8_t *msg, |
1996 | | size_t msg_len, const uint8_t *context_prefix, size_t context_prefix_len, |
1997 | 0 | const uint8_t *context, size_t context_len) { |
1998 | 0 | uint8_t mu[kMuBytes]; |
1999 | 0 | BORINGSSL_keccak_st keccak_ctx; |
2000 | 0 | BORINGSSL_keccak_init(&keccak_ctx, boringssl_shake256); |
2001 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, pub->public_key_hash, |
2002 | 0 | sizeof(pub->public_key_hash)); |
2003 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, context_prefix, context_prefix_len); |
2004 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, context, context_len); |
2005 | 0 | BORINGSSL_keccak_absorb(&keccak_ctx, msg, msg_len); |
2006 | 0 | BORINGSSL_keccak_squeeze(&keccak_ctx, mu, kMuBytes); |
2007 | |
|
2008 | 0 | return mldsa_verify_mu_no_self_test<K, L>(pub, encoded_signature, mu); |
2009 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_internal_no_self_test<6, 5>(mldsa::(anonymous namespace)::public_key<6> const*, unsigned char const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_internal_no_self_test<8, 7>(mldsa::(anonymous namespace)::public_key<8> const*, unsigned char const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_internal_no_self_test<4, 4>(mldsa::(anonymous namespace)::public_key<4> const*, unsigned char const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long) |
2010 | | |
2011 | | // FIPS 204, Algorithm 8 (`ML-DSA.Verify_internal`). |
2012 | | template <int K, int L> |
2013 | | int mldsa_verify_internal(const public_key<K> *pub, |
2014 | | const uint8_t encoded_signature[signature_bytes<K>()], |
2015 | | const uint8_t *msg, size_t msg_len, |
2016 | | const uint8_t *context_prefix, |
2017 | | size_t context_prefix_len, const uint8_t *context, |
2018 | 0 | size_t context_len) { |
2019 | 0 | fips::ensure_verify_self_test(); |
2020 | 0 | return mldsa_verify_internal_no_self_test<K, L>( |
2021 | 0 | pub, encoded_signature, msg, msg_len, context_prefix, context_prefix_len, |
2022 | 0 | context, context_len); |
2023 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_internal<6, 5>(mldsa::(anonymous namespace)::public_key<6> const*, unsigned char const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_internal<8, 7>(mldsa::(anonymous namespace)::public_key<8> const*, unsigned char const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::mldsa_verify_internal<4, 4>(mldsa::(anonymous namespace)::public_key<4> const*, unsigned char const*, unsigned char const*, unsigned long, unsigned char const*, unsigned long, unsigned char const*, unsigned long) |
2024 | | |
2025 | | static_assert(sizeof(MLDSA65_private_key) == sizeof(private_key<6, 5>)); |
2026 | | static_assert(alignof(MLDSA65_private_key) == alignof(private_key<6, 5>)); |
2027 | | |
2028 | | const private_key<6, 5> *private_key_from_external_65( |
2029 | 0 | const MLDSA65_private_key *external) { |
2030 | 0 | return reinterpret_cast<const private_key<6, 5> *>(external); |
2031 | 0 | } |
2032 | 0 | private_key<6, 5> *private_key_from_external_65(MLDSA65_private_key *external) { |
2033 | 0 | return reinterpret_cast<private_key<6, 5> *>(external); |
2034 | 0 | } |
2035 | | |
2036 | | static_assert(sizeof(MLDSA65_public_key) == sizeof(public_key<6>)); |
2037 | | static_assert(alignof(MLDSA65_public_key) == alignof(public_key<6>)); |
2038 | | |
2039 | | const public_key<6> *public_key_from_external_65( |
2040 | 0 | const MLDSA65_public_key *external) { |
2041 | 0 | return reinterpret_cast<const public_key<6> *>(external); |
2042 | 0 | } |
2043 | 0 | public_key<6> *public_key_from_external_65(MLDSA65_public_key *external) { |
2044 | 0 | return reinterpret_cast<public_key<6> *>(external); |
2045 | 0 | } |
2046 | | |
2047 | 0 | prehash_context *prehash_context_from_external_65(MLDSA65_prehash *external) { |
2048 | 0 | static_assert(sizeof(MLDSA65_prehash) == sizeof(prehash_context)); |
2049 | 0 | static_assert(alignof(MLDSA65_prehash) == alignof(prehash_context)); |
2050 | 0 | return reinterpret_cast<prehash_context *>(external); |
2051 | 0 | } |
2052 | | |
2053 | | static_assert(sizeof(MLDSA87_private_key) == sizeof(private_key<8, 7>)); |
2054 | | static_assert(alignof(MLDSA87_private_key) == alignof(private_key<8, 7>)); |
2055 | | const private_key<8, 7> *private_key_from_external_87( |
2056 | 0 | const MLDSA87_private_key *external) { |
2057 | 0 | return reinterpret_cast<const private_key<8, 7> *>(external); |
2058 | 0 | } |
2059 | 0 | private_key<8, 7> *private_key_from_external_87(MLDSA87_private_key *external) { |
2060 | 0 | return reinterpret_cast<private_key<8, 7> *>(external); |
2061 | 0 | } |
2062 | | |
2063 | | static_assert(sizeof(MLDSA87_public_key) == sizeof(public_key<8>)); |
2064 | | static_assert(alignof(MLDSA87_public_key) == alignof(public_key<8>)); |
2065 | | |
2066 | | const public_key<8> *public_key_from_external_87( |
2067 | 0 | const MLDSA87_public_key *external) { |
2068 | 0 | return reinterpret_cast<const public_key<8> *>(external); |
2069 | 0 | } |
2070 | 0 | public_key<8> *public_key_from_external_87(MLDSA87_public_key *external) { |
2071 | 0 | return reinterpret_cast<public_key<8> *>(external); |
2072 | 0 | } |
2073 | | |
2074 | 0 | prehash_context *prehash_context_from_external_87(MLDSA87_prehash *external) { |
2075 | 0 | static_assert(sizeof(MLDSA87_prehash) == sizeof(prehash_context)); |
2076 | 0 | static_assert(alignof(MLDSA87_prehash) == alignof(prehash_context)); |
2077 | 0 | return reinterpret_cast<prehash_context *>(external); |
2078 | 0 | } |
2079 | | |
2080 | | static_assert(sizeof(MLDSA44_private_key) == sizeof(private_key<4, 4>)); |
2081 | | static_assert(alignof(MLDSA44_private_key) == alignof(private_key<4, 4>)); |
2082 | | |
2083 | | const private_key<4, 4> *private_key_from_external_44( |
2084 | 0 | const MLDSA44_private_key *external) { |
2085 | 0 | return reinterpret_cast<const private_key<4, 4> *>(external); |
2086 | 0 | } |
2087 | 0 | private_key<4, 4> *private_key_from_external_44(MLDSA44_private_key *external) { |
2088 | 0 | return reinterpret_cast<private_key<4, 4> *>(external); |
2089 | 0 | } |
2090 | | |
2091 | | static_assert(sizeof(MLDSA44_public_key) == sizeof(public_key<4>)); |
2092 | | static_assert(alignof(MLDSA44_public_key) == alignof(public_key<4>)); |
2093 | | |
2094 | | const public_key<4> *public_key_from_external_44( |
2095 | 0 | const MLDSA44_public_key *external) { |
2096 | 0 | return reinterpret_cast<const public_key<4> *>(external); |
2097 | 0 | } |
2098 | 0 | public_key<4> *public_key_from_external_44(MLDSA44_public_key *external) { |
2099 | 0 | return reinterpret_cast<public_key<4> *>(external); |
2100 | 0 | } |
2101 | | |
2102 | 0 | prehash_context *prehash_context_from_external_44(MLDSA44_prehash *external) { |
2103 | 0 | static_assert(sizeof(MLDSA44_prehash) == sizeof(prehash_context)); |
2104 | 0 | static_assert(alignof(MLDSA44_prehash) == alignof(prehash_context)); |
2105 | 0 | return reinterpret_cast<prehash_context *>(external); |
2106 | 0 | } |
2107 | | |
2108 | | namespace fips { |
2109 | | |
2110 | | #include "fips_known_values.inc" |
2111 | | |
2112 | 0 | static int keygen_self_test() { |
2113 | 0 | struct Values { |
2114 | 0 | enum { kAllowUniquePtr = true }; |
2115 | 0 | private_key<6, 5> priv; |
2116 | 0 | uint8_t pub_bytes[MLDSA65_PUBLIC_KEY_BYTES]; |
2117 | 0 | uint8_t priv_bytes[BCM_MLDSA65_PRIVATE_KEY_BYTES]; |
2118 | 0 | }; |
2119 | 0 | auto values = bssl::MakeUnique<Values>(); |
2120 | 0 | if (values == nullptr || |
2121 | 0 | !mldsa_generate_key_external_entropy_no_self_test( |
2122 | 0 | values->pub_bytes, &values->priv, kGenerateKeyEntropy)) { |
2123 | 0 | return 0; |
2124 | 0 | } |
2125 | | |
2126 | 0 | CBB cbb; |
2127 | 0 | CBB_init_fixed(&cbb, values->priv_bytes, sizeof(values->priv_bytes)); |
2128 | 0 | if (!mldsa_marshal_private_key(&cbb, &values->priv)) { |
2129 | 0 | return 0; |
2130 | 0 | } |
2131 | | |
2132 | 0 | static_assert(sizeof(values->pub_bytes) == sizeof(kExpectedPublicKey)); |
2133 | 0 | static_assert(sizeof(values->priv_bytes) == sizeof(kExpectedPrivateKey)); |
2134 | 0 | if (!BORINGSSL_check_test(kExpectedPublicKey, values->pub_bytes, |
2135 | 0 | sizeof(values->pub_bytes), |
2136 | 0 | "ML-DSA keygen public key") || |
2137 | 0 | !BORINGSSL_check_test(kExpectedPrivateKey, values->priv_bytes, |
2138 | 0 | sizeof(values->priv_bytes), |
2139 | 0 | "ML-DSA keygen private key")) { |
2140 | 0 | return 0; |
2141 | 0 | } |
2142 | | |
2143 | 0 | return 1; |
2144 | 0 | } |
2145 | | |
2146 | 0 | static int sign_self_test() { |
2147 | 0 | struct Values { |
2148 | 0 | enum { kAllowUniquePtr = true }; |
2149 | 0 | private_key<6, 5> priv; |
2150 | 0 | uint8_t pub_bytes[MLDSA65_PUBLIC_KEY_BYTES]; |
2151 | 0 | uint8_t sig[MLDSA65_SIGNATURE_BYTES]; |
2152 | 0 | }; |
2153 | 0 | auto values = bssl::MakeUnique<Values>(); |
2154 | 0 | if (values == nullptr || |
2155 | 0 | !mldsa_generate_key_external_entropy(values->pub_bytes, &values->priv, |
2156 | 0 | kSignEntropy)) { |
2157 | 0 | return 0; |
2158 | 0 | } |
2159 | | |
2160 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES] = {}; |
2161 | | |
2162 | | // This message triggers the first restart case for signing. |
2163 | 0 | uint8_t message[4] = {0}; |
2164 | 0 | if (!mldsa_sign_internal_no_self_test(values->sig, &values->priv, message, |
2165 | 0 | sizeof(message), nullptr, 0, nullptr, 0, |
2166 | 0 | randomizer)) { |
2167 | 0 | return 0; |
2168 | 0 | } |
2169 | 0 | static_assert(sizeof(kExpectedCase1Signature) == sizeof(values->sig)); |
2170 | 0 | if (!BORINGSSL_check_test(kExpectedCase1Signature, values->sig, |
2171 | 0 | sizeof(values->sig), "ML-DSA sign case 1")) { |
2172 | 0 | return 0; |
2173 | 0 | } |
2174 | | |
2175 | | // This message triggers the second restart case for signing. |
2176 | 0 | message[0] = 123; |
2177 | 0 | if (!mldsa_sign_internal_no_self_test(values->sig, &values->priv, message, |
2178 | 0 | sizeof(message), nullptr, 0, nullptr, 0, |
2179 | 0 | randomizer)) { |
2180 | 0 | return 0; |
2181 | 0 | } |
2182 | 0 | static_assert(sizeof(kExpectedCase2Signature) == sizeof(values->sig)); |
2183 | 0 | if (!BORINGSSL_check_test(kExpectedCase2Signature, values->sig, |
2184 | 0 | sizeof(values->sig), "ML-DSA sign case 2")) { |
2185 | 0 | return 0; |
2186 | 0 | } |
2187 | | |
2188 | 0 | return 1; |
2189 | 0 | } |
2190 | | |
2191 | 0 | static int verify_self_test() { |
2192 | 0 | struct Values { |
2193 | 0 | enum { kAllowUniquePtr = true }; |
2194 | 0 | private_key<6, 5> priv; |
2195 | 0 | uint8_t pub_bytes[MLDSA65_PUBLIC_KEY_BYTES]; |
2196 | 0 | }; |
2197 | 0 | auto values = bssl::MakeUnique<Values>(); |
2198 | 0 | if (values == nullptr) { |
2199 | 0 | return 0; |
2200 | 0 | } |
2201 | | |
2202 | 0 | if (!mldsa_generate_key_external_entropy(values->pub_bytes, &values->priv, |
2203 | 0 | kSignEntropy)) { |
2204 | 0 | return 0; |
2205 | 0 | } |
2206 | | |
2207 | 0 | const uint8_t message[4] = {1, 0}; |
2208 | 0 | if (!mldsa_verify_internal_no_self_test<6, 5>( |
2209 | 0 | &values->priv.pub, kExpectedVerifySignature, message, sizeof(message), |
2210 | 0 | nullptr, 0, nullptr, 0)) { |
2211 | 0 | return 0; |
2212 | 0 | } |
2213 | | |
2214 | 0 | return 1; |
2215 | 0 | } |
2216 | | |
2217 | | template <int K, int L> |
2218 | 0 | int check_key(const private_key<K, L> *priv) { |
2219 | 0 | uint8_t sig[signature_bytes<K>()]; |
2220 | 0 | uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES] = {}; |
2221 | 0 | if (!mldsa_sign_internal_no_self_test(sig, priv, nullptr, 0, nullptr, 0, |
2222 | 0 | nullptr, 0, randomizer)) { |
2223 | 0 | return 0; |
2224 | 0 | } |
2225 | | |
2226 | 0 | if (boringssl_fips_break_test("MLDSA_PWCT")) { |
2227 | 0 | sig[0] ^= 1; |
2228 | 0 | } |
2229 | |
|
2230 | 0 | if (!mldsa_verify_internal_no_self_test<K, L>(&priv->pub, sig, nullptr, 0, |
2231 | 0 | nullptr, 0, nullptr, 0)) { |
2232 | 0 | return 0; |
2233 | 0 | } |
2234 | 0 | return 1; |
2235 | 0 | } Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::fips::check_key<6, 5>(mldsa::(anonymous namespace)::private_key<6, 5> const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::fips::check_key<8, 7>(mldsa::(anonymous namespace)::private_key<8, 7> const*) Unexecuted instantiation: bcm.cc:int mldsa::(anonymous namespace)::fips::check_key<4, 4>(mldsa::(anonymous namespace)::private_key<4, 4> const*) |
2236 | | |
2237 | | #if defined(BORINGSSL_FIPS) |
2238 | | |
2239 | | DEFINE_STATIC_ONCE(g_mldsa_keygen_self_test_once) |
2240 | | |
2241 | | void ensure_keygen_self_test(void) { |
2242 | | CRYPTO_once(g_mldsa_keygen_self_test_once_bss_get(), []() { |
2243 | | if (!keygen_self_test()) { |
2244 | | BORINGSSL_FIPS_abort(); |
2245 | | } |
2246 | | }); |
2247 | | } |
2248 | | |
2249 | | DEFINE_STATIC_ONCE(g_mldsa_sign_self_test_once) |
2250 | | |
2251 | | void ensure_sign_self_test(void) { |
2252 | | CRYPTO_once(g_mldsa_sign_self_test_once_bss_get(), []() { |
2253 | | if (!sign_self_test()) { |
2254 | | BORINGSSL_FIPS_abort(); |
2255 | | } |
2256 | | }); |
2257 | | } |
2258 | | |
2259 | | DEFINE_STATIC_ONCE(g_mldsa_verify_self_test_once) |
2260 | | |
2261 | | void ensure_verify_self_test(void) { |
2262 | | CRYPTO_once(g_mldsa_verify_self_test_once_bss_get(), []() { |
2263 | | if (!verify_self_test()) { |
2264 | | BORINGSSL_FIPS_abort(); |
2265 | | } |
2266 | | }); |
2267 | | } |
2268 | | |
2269 | | #else |
2270 | | |
2271 | 0 | void ensure_keygen_self_test(void) {} |
2272 | 0 | void ensure_sign_self_test(void) {} |
2273 | 0 | void ensure_verify_self_test(void) {} |
2274 | | |
2275 | | #endif |
2276 | | |
2277 | | } // namespace fips |
2278 | | |
2279 | | } // namespace |
2280 | | } // namespace mldsa |
2281 | | |
2282 | | |
2283 | | // ML-DSA-65 specific wrappers. |
2284 | | |
2285 | | bcm_status BCM_mldsa65_parse_public_key(MLDSA65_public_key *public_key, |
2286 | 0 | CBS *in) { |
2287 | 0 | return bcm_as_approved_status(mldsa_parse_public_key( |
2288 | 0 | mldsa::public_key_from_external_65(public_key), in)); |
2289 | 0 | } |
2290 | | |
2291 | | bcm_status BCM_mldsa65_marshal_private_key( |
2292 | 0 | CBB *out, const MLDSA65_private_key *private_key) { |
2293 | 0 | return bcm_as_approved_status(mldsa_marshal_private_key( |
2294 | 0 | out, mldsa::private_key_from_external_65(private_key))); |
2295 | 0 | } |
2296 | | |
2297 | | bcm_status BCM_mldsa65_parse_private_key(MLDSA65_private_key *private_key, |
2298 | 0 | CBS *in) { |
2299 | 0 | return bcm_as_approved_status( |
2300 | 0 | mldsa_parse_private_key(mldsa::private_key_from_external_65(private_key), |
2301 | 0 | in) && |
2302 | 0 | CBS_len(in) == 0); |
2303 | 0 | } |
2304 | | |
2305 | 0 | bcm_status BCM_mldsa65_check_key_fips(MLDSA65_private_key *private_key) { |
2306 | 0 | return bcm_as_approved_status( |
2307 | 0 | mldsa::fips::check_key(mldsa::private_key_from_external_65(private_key))); |
2308 | 0 | } |
2309 | | |
2310 | | // Calls |MLDSA_generate_key_external_entropy| with random bytes from |
2311 | | // |BCM_rand_bytes|. |
2312 | | bcm_status BCM_mldsa65_generate_key( |
2313 | | uint8_t out_encoded_public_key[MLDSA65_PUBLIC_KEY_BYTES], |
2314 | 0 | uint8_t out_seed[MLDSA_SEED_BYTES], MLDSA65_private_key *out_private_key) { |
2315 | 0 | BCM_rand_bytes(out_seed, MLDSA_SEED_BYTES); |
2316 | 0 | CONSTTIME_SECRET(out_seed, MLDSA_SEED_BYTES); |
2317 | 0 | return BCM_mldsa65_generate_key_external_entropy(out_encoded_public_key, |
2318 | 0 | out_private_key, out_seed); |
2319 | 0 | } |
2320 | | |
2321 | | bcm_status BCM_mldsa65_private_key_from_seed( |
2322 | | MLDSA65_private_key *out_private_key, |
2323 | 0 | const uint8_t seed[MLDSA_SEED_BYTES]) { |
2324 | 0 | uint8_t public_key[MLDSA65_PUBLIC_KEY_BYTES]; |
2325 | 0 | return BCM_mldsa65_generate_key_external_entropy(public_key, out_private_key, |
2326 | 0 | seed); |
2327 | 0 | } |
2328 | | |
2329 | | bcm_status BCM_mldsa65_generate_key_external_entropy( |
2330 | | uint8_t out_encoded_public_key[MLDSA65_PUBLIC_KEY_BYTES], |
2331 | | MLDSA65_private_key *out_private_key, |
2332 | 0 | const uint8_t entropy[MLDSA_SEED_BYTES]) { |
2333 | 0 | return bcm_as_not_approved_status(mldsa_generate_key_external_entropy( |
2334 | 0 | out_encoded_public_key, |
2335 | 0 | mldsa::private_key_from_external_65(out_private_key), entropy)); |
2336 | 0 | } |
2337 | | |
2338 | | bcm_status BCM_mldsa65_generate_key_fips( |
2339 | | uint8_t out_encoded_public_key[MLDSA65_PUBLIC_KEY_BYTES], |
2340 | 0 | uint8_t out_seed[MLDSA_SEED_BYTES], MLDSA65_private_key *out_private_key) { |
2341 | 0 | if (out_encoded_public_key == nullptr || out_private_key == nullptr) { |
2342 | 0 | return bcm_status::failure; |
2343 | 0 | } |
2344 | 0 | if (BCM_mldsa65_generate_key(out_encoded_public_key, out_seed, |
2345 | 0 | out_private_key) == bcm_status::failure) { |
2346 | 0 | return bcm_status::failure; |
2347 | 0 | } |
2348 | 0 | return BCM_mldsa65_check_key_fips(out_private_key); |
2349 | 0 | } |
2350 | | |
2351 | | bcm_status BCM_mldsa65_generate_key_external_entropy_fips( |
2352 | | uint8_t out_encoded_public_key[MLDSA65_PUBLIC_KEY_BYTES], |
2353 | | MLDSA65_private_key *out_private_key, |
2354 | 0 | const uint8_t entropy[MLDSA_SEED_BYTES]) { |
2355 | 0 | if (out_encoded_public_key == nullptr || out_private_key == nullptr) { |
2356 | 0 | return bcm_status::failure; |
2357 | 0 | } |
2358 | 0 | if (BCM_mldsa65_generate_key_external_entropy(out_encoded_public_key, |
2359 | 0 | out_private_key, entropy) == |
2360 | 0 | bcm_status::failure) { |
2361 | 0 | return bcm_status::failure; |
2362 | 0 | } |
2363 | 0 | return BCM_mldsa65_check_key_fips(out_private_key); |
2364 | 0 | } |
2365 | | |
2366 | | bcm_status BCM_mldsa65_private_key_from_seed_fips( |
2367 | | MLDSA65_private_key *out_private_key, |
2368 | 0 | const uint8_t seed[MLDSA_SEED_BYTES]) { |
2369 | 0 | uint8_t public_key[MLDSA65_PUBLIC_KEY_BYTES]; |
2370 | 0 | if (BCM_mldsa65_generate_key_external_entropy(public_key, out_private_key, |
2371 | 0 | seed) == bcm_status::failure) { |
2372 | 0 | return bcm_status::failure; |
2373 | 0 | } |
2374 | 0 | return BCM_mldsa65_check_key_fips(out_private_key); |
2375 | 0 | } |
2376 | | |
2377 | | bcm_status BCM_mldsa65_public_from_private( |
2378 | | MLDSA65_public_key *out_public_key, |
2379 | 0 | const MLDSA65_private_key *private_key) { |
2380 | 0 | const auto *priv = mldsa::private_key_from_external_65(private_key); |
2381 | 0 | auto *out_pub = mldsa::public_key_from_external_65(out_public_key); |
2382 | 0 | *out_pub = priv->pub; |
2383 | 0 | return bcm_status::approved; |
2384 | 0 | } |
2385 | | |
2386 | | const MLDSA65_public_key *BCM_mldsa65_public_of_private( |
2387 | 0 | const MLDSA65_private_key *private_key) { |
2388 | 0 | return reinterpret_cast<const MLDSA65_public_key *>( |
2389 | 0 | &mldsa::private_key_from_external_65(private_key)->pub); |
2390 | 0 | } |
2391 | | |
2392 | | bcm_status BCM_mldsa65_sign_internal( |
2393 | | uint8_t out_encoded_signature[MLDSA65_SIGNATURE_BYTES], |
2394 | | const MLDSA65_private_key *private_key, const uint8_t *msg, size_t msg_len, |
2395 | | const uint8_t *context_prefix, size_t context_prefix_len, |
2396 | | const uint8_t *context, size_t context_len, |
2397 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) { |
2398 | 0 | return bcm_as_approved_status(mldsa_sign_internal( |
2399 | 0 | out_encoded_signature, mldsa::private_key_from_external_65(private_key), |
2400 | 0 | msg, msg_len, context_prefix, context_prefix_len, context, context_len, |
2401 | 0 | randomizer)); |
2402 | 0 | } |
2403 | | |
2404 | | bcm_status BCM_mldsa65_sign_mu_internal( |
2405 | | uint8_t out_encoded_signature[MLDSA65_SIGNATURE_BYTES], |
2406 | | const MLDSA65_private_key *private_key, |
2407 | | const uint8_t msg_rep[MLDSA_MU_BYTES], |
2408 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) { |
2409 | 0 | return bcm_as_approved_status(mldsa_sign_mu( |
2410 | 0 | out_encoded_signature, mldsa::private_key_from_external_65(private_key), |
2411 | 0 | msg_rep, randomizer)); |
2412 | 0 | } |
2413 | | |
2414 | | // ML-DSA signature in randomized mode, filling the random bytes with |
2415 | | // |BCM_rand_bytes|. |
2416 | | bcm_status BCM_mldsa65_sign( |
2417 | | uint8_t out_encoded_signature[MLDSA65_SIGNATURE_BYTES], |
2418 | | const MLDSA65_private_key *private_key, const uint8_t *msg, size_t msg_len, |
2419 | 0 | const uint8_t *context, size_t context_len) { |
2420 | 0 | BSSL_CHECK(context_len <= 255); |
2421 | 0 | uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]; |
2422 | 0 | BCM_rand_bytes(randomizer, sizeof(randomizer)); |
2423 | 0 | CONSTTIME_SECRET(randomizer, sizeof(randomizer)); |
2424 | |
|
2425 | 0 | const uint8_t context_prefix[2] = {0, static_cast<uint8_t>(context_len)}; |
2426 | 0 | return BCM_mldsa65_sign_internal( |
2427 | 0 | out_encoded_signature, private_key, msg, msg_len, context_prefix, |
2428 | 0 | sizeof(context_prefix), context, context_len, randomizer); |
2429 | 0 | } |
2430 | | |
2431 | | // ML-DSA pre-hashed API: initializing a pre-hashing context. |
2432 | | void BCM_mldsa65_prehash_init(MLDSA65_prehash *out_prehash_ctx, |
2433 | | const MLDSA65_public_key *public_key, |
2434 | 0 | const uint8_t *context, size_t context_len) { |
2435 | 0 | BSSL_CHECK(context_len <= 255); |
2436 | |
|
2437 | 0 | const uint8_t context_prefix[2] = {0, static_cast<uint8_t>(context_len)}; |
2438 | 0 | mldsa_prehash_init(mldsa::prehash_context_from_external_65(out_prehash_ctx), |
2439 | 0 | mldsa::public_key_from_external_65(public_key), |
2440 | 0 | context_prefix, sizeof(context_prefix), context, |
2441 | 0 | context_len); |
2442 | 0 | } |
2443 | | |
2444 | | // ML-DSA pre-hashed API: updating a pre-hashing context with a message chunk. |
2445 | | void BCM_mldsa65_prehash_update(MLDSA65_prehash *inout_prehash_ctx, |
2446 | 0 | const uint8_t *msg, size_t msg_len) { |
2447 | 0 | mldsa_prehash_update( |
2448 | 0 | mldsa::prehash_context_from_external_65(inout_prehash_ctx), msg, msg_len); |
2449 | 0 | } |
2450 | | |
2451 | | // ML-DSA pre-hashed API: obtaining a message representative to sign. |
2452 | | void BCM_mldsa65_prehash_finalize(uint8_t out_msg_rep[MLDSA_MU_BYTES], |
2453 | 0 | MLDSA65_prehash *inout_prehash_ctx) { |
2454 | 0 | mldsa_prehash_finalize( |
2455 | 0 | out_msg_rep, mldsa::prehash_context_from_external_65(inout_prehash_ctx)); |
2456 | 0 | } |
2457 | | |
2458 | | // ML-DSA pre-hashed API: signing a message representative. |
2459 | | bcm_status BCM_mldsa65_sign_message_representative( |
2460 | | uint8_t out_encoded_signature[MLDSA65_SIGNATURE_BYTES], |
2461 | | const MLDSA65_private_key *private_key, |
2462 | 0 | const uint8_t msg_rep[MLDSA_MU_BYTES]) { |
2463 | 0 | uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]; |
2464 | 0 | BCM_rand_bytes(randomizer, sizeof(randomizer)); |
2465 | 0 | CONSTTIME_SECRET(randomizer, sizeof(randomizer)); |
2466 | |
|
2467 | 0 | return bcm_as_approved_status(mldsa_sign_mu( |
2468 | 0 | out_encoded_signature, mldsa::private_key_from_external_65(private_key), |
2469 | 0 | msg_rep, randomizer)); |
2470 | 0 | } |
2471 | | |
2472 | | // ML-DSA pre-hashed API: verifying a message representative. |
2473 | | bcm_status BCM_mldsa65_verify_message_representative( |
2474 | | const MLDSA65_public_key *public_key, |
2475 | | const uint8_t signature[MLDSA65_SIGNATURE_BYTES], |
2476 | 0 | const uint8_t msg_rep[MLDSA_MU_BYTES]) { |
2477 | 0 | return bcm_as_approved_status(mldsa::mldsa_verify_mu<6, 5>( |
2478 | 0 | mldsa::public_key_from_external_65(public_key), signature, msg_rep)); |
2479 | 0 | } |
2480 | | |
2481 | | // FIPS 204, Algorithm 3 (`ML-DSA.Verify`). |
2482 | | bcm_status BCM_mldsa65_verify(const MLDSA65_public_key *public_key, |
2483 | | const uint8_t signature[MLDSA65_SIGNATURE_BYTES], |
2484 | | const uint8_t *msg, size_t msg_len, |
2485 | 0 | const uint8_t *context, size_t context_len) { |
2486 | 0 | BSSL_CHECK(context_len <= 255); |
2487 | 0 | const uint8_t context_prefix[2] = {0, static_cast<uint8_t>(context_len)}; |
2488 | 0 | return BCM_mldsa65_verify_internal(public_key, signature, msg, msg_len, |
2489 | 0 | context_prefix, sizeof(context_prefix), |
2490 | 0 | context, context_len); |
2491 | 0 | } |
2492 | | |
2493 | | bcm_status BCM_mldsa65_verify_internal( |
2494 | | const MLDSA65_public_key *public_key, |
2495 | | const uint8_t encoded_signature[MLDSA65_SIGNATURE_BYTES], |
2496 | | const uint8_t *msg, size_t msg_len, const uint8_t *context_prefix, |
2497 | 0 | size_t context_prefix_len, const uint8_t *context, size_t context_len) { |
2498 | 0 | return bcm_as_approved_status(mldsa::mldsa_verify_internal<6, 5>( |
2499 | 0 | mldsa::public_key_from_external_65(public_key), encoded_signature, msg, |
2500 | 0 | msg_len, context_prefix, context_prefix_len, context, context_len)); |
2501 | 0 | } |
2502 | | |
2503 | | bcm_status BCM_mldsa65_marshal_public_key( |
2504 | 0 | CBB *out, const MLDSA65_public_key *public_key) { |
2505 | 0 | return bcm_as_approved_status(mldsa_marshal_public_key( |
2506 | 0 | out, mldsa::public_key_from_external_65(public_key))); |
2507 | 0 | } |
2508 | | |
2509 | | int BCM_mldsa65_public_keys_equal(const MLDSA65_public_key *a, |
2510 | 0 | const MLDSA65_public_key *b) { |
2511 | 0 | auto *a_pub = mldsa::public_key_from_external_65(a); |
2512 | 0 | auto *b_pub = mldsa::public_key_from_external_65(b); |
2513 | | // It is sufficient to compare |public_key_hash|. When importing a public key, |
2514 | | // the hash must be computed. When importing a private key in expanded form |
2515 | | // (an internal testing-only API), the hash is provided, but we recompute it |
2516 | | // and check for correctness. |
2517 | 0 | return OPENSSL_memcmp(a_pub->public_key_hash, b_pub->public_key_hash, |
2518 | 0 | sizeof(a_pub->public_key_hash)) == 0; |
2519 | 0 | } |
2520 | | |
2521 | | |
2522 | | // ML-DSA-87 specific wrappers. |
2523 | | |
2524 | | bcm_status BCM_mldsa87_parse_public_key(MLDSA87_public_key *public_key, |
2525 | 0 | CBS *in) { |
2526 | 0 | return bcm_as_approved_status(mldsa_parse_public_key( |
2527 | 0 | mldsa::public_key_from_external_87(public_key), in)); |
2528 | 0 | } |
2529 | | |
2530 | | bcm_status BCM_mldsa87_marshal_private_key( |
2531 | 0 | CBB *out, const MLDSA87_private_key *private_key) { |
2532 | 0 | return bcm_as_approved_status(mldsa_marshal_private_key( |
2533 | 0 | out, mldsa::private_key_from_external_87(private_key))); |
2534 | 0 | } |
2535 | | |
2536 | | bcm_status BCM_mldsa87_parse_private_key(MLDSA87_private_key *private_key, |
2537 | 0 | CBS *in) { |
2538 | 0 | return bcm_as_approved_status( |
2539 | 0 | mldsa_parse_private_key(mldsa::private_key_from_external_87(private_key), |
2540 | 0 | in) && |
2541 | 0 | CBS_len(in) == 0); |
2542 | 0 | } |
2543 | | |
2544 | 0 | bcm_status BCM_mldsa87_check_key_fips(MLDSA87_private_key *private_key) { |
2545 | 0 | return bcm_as_approved_status( |
2546 | 0 | mldsa::fips::check_key(mldsa::private_key_from_external_87(private_key))); |
2547 | 0 | } |
2548 | | |
2549 | | // Calls |MLDSA_generate_key_external_entropy| with random bytes from |
2550 | | // |BCM_rand_bytes|. |
2551 | | bcm_status BCM_mldsa87_generate_key( |
2552 | | uint8_t out_encoded_public_key[MLDSA87_PUBLIC_KEY_BYTES], |
2553 | 0 | uint8_t out_seed[MLDSA_SEED_BYTES], MLDSA87_private_key *out_private_key) { |
2554 | 0 | BCM_rand_bytes(out_seed, MLDSA_SEED_BYTES); |
2555 | 0 | return BCM_mldsa87_generate_key_external_entropy(out_encoded_public_key, |
2556 | 0 | out_private_key, out_seed); |
2557 | 0 | } |
2558 | | |
2559 | | bcm_status BCM_mldsa87_private_key_from_seed( |
2560 | | MLDSA87_private_key *out_private_key, |
2561 | 0 | const uint8_t seed[MLDSA_SEED_BYTES]) { |
2562 | 0 | uint8_t public_key[MLDSA87_PUBLIC_KEY_BYTES]; |
2563 | 0 | return BCM_mldsa87_generate_key_external_entropy(public_key, out_private_key, |
2564 | 0 | seed); |
2565 | 0 | } |
2566 | | |
2567 | | bcm_status BCM_mldsa87_generate_key_external_entropy( |
2568 | | uint8_t out_encoded_public_key[MLDSA87_PUBLIC_KEY_BYTES], |
2569 | | MLDSA87_private_key *out_private_key, |
2570 | 0 | const uint8_t entropy[MLDSA_SEED_BYTES]) { |
2571 | 0 | return bcm_as_not_approved_status(mldsa_generate_key_external_entropy( |
2572 | 0 | out_encoded_public_key, |
2573 | 0 | mldsa::private_key_from_external_87(out_private_key), entropy)); |
2574 | 0 | } |
2575 | | |
2576 | | bcm_status BCM_mldsa87_generate_key_fips( |
2577 | | uint8_t out_encoded_public_key[MLDSA87_PUBLIC_KEY_BYTES], |
2578 | 0 | uint8_t out_seed[MLDSA_SEED_BYTES], MLDSA87_private_key *out_private_key) { |
2579 | 0 | if (out_encoded_public_key == nullptr || out_private_key == nullptr) { |
2580 | 0 | return bcm_status::failure; |
2581 | 0 | } |
2582 | 0 | if (BCM_mldsa87_generate_key(out_encoded_public_key, out_seed, |
2583 | 0 | out_private_key) == bcm_status::failure) { |
2584 | 0 | return bcm_status::failure; |
2585 | 0 | } |
2586 | 0 | return BCM_mldsa87_check_key_fips(out_private_key); |
2587 | 0 | } |
2588 | | |
2589 | | bcm_status BCM_mldsa87_generate_key_external_entropy_fips( |
2590 | | uint8_t out_encoded_public_key[MLDSA87_PUBLIC_KEY_BYTES], |
2591 | | MLDSA87_private_key *out_private_key, |
2592 | 0 | const uint8_t entropy[MLDSA_SEED_BYTES]) { |
2593 | 0 | if (out_encoded_public_key == nullptr || out_private_key == nullptr) { |
2594 | 0 | return bcm_status::failure; |
2595 | 0 | } |
2596 | 0 | if (BCM_mldsa87_generate_key_external_entropy(out_encoded_public_key, |
2597 | 0 | out_private_key, entropy) == |
2598 | 0 | bcm_status::failure) { |
2599 | 0 | return bcm_status::failure; |
2600 | 0 | } |
2601 | 0 | return BCM_mldsa87_check_key_fips(out_private_key); |
2602 | 0 | } |
2603 | | |
2604 | | bcm_status BCM_mldsa87_private_key_from_seed_fips( |
2605 | | MLDSA87_private_key *out_private_key, |
2606 | 0 | const uint8_t seed[MLDSA_SEED_BYTES]) { |
2607 | 0 | uint8_t public_key[MLDSA87_PUBLIC_KEY_BYTES]; |
2608 | 0 | if (BCM_mldsa87_generate_key_external_entropy(public_key, out_private_key, |
2609 | 0 | seed) == bcm_status::failure) { |
2610 | 0 | return bcm_status::failure; |
2611 | 0 | } |
2612 | 0 | return BCM_mldsa87_check_key_fips(out_private_key); |
2613 | 0 | } |
2614 | | |
2615 | | bcm_status BCM_mldsa87_public_from_private( |
2616 | | MLDSA87_public_key *out_public_key, |
2617 | 0 | const MLDSA87_private_key *private_key) { |
2618 | 0 | const auto *priv = mldsa::private_key_from_external_87(private_key); |
2619 | 0 | auto *out_pub = mldsa::public_key_from_external_87(out_public_key); |
2620 | 0 | *out_pub = priv->pub; |
2621 | 0 | return bcm_status::approved; |
2622 | 0 | } |
2623 | | |
2624 | | const MLDSA87_public_key *BCM_mldsa87_public_of_private( |
2625 | 0 | const MLDSA87_private_key *private_key) { |
2626 | 0 | return reinterpret_cast<const MLDSA87_public_key *>( |
2627 | 0 | &mldsa::private_key_from_external_87(private_key)->pub); |
2628 | 0 | } |
2629 | | |
2630 | | bcm_status BCM_mldsa87_sign_internal( |
2631 | | uint8_t out_encoded_signature[MLDSA87_SIGNATURE_BYTES], |
2632 | | const MLDSA87_private_key *private_key, const uint8_t *msg, size_t msg_len, |
2633 | | const uint8_t *context_prefix, size_t context_prefix_len, |
2634 | | const uint8_t *context, size_t context_len, |
2635 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) { |
2636 | 0 | return bcm_as_approved_status(mldsa_sign_internal( |
2637 | 0 | out_encoded_signature, mldsa::private_key_from_external_87(private_key), |
2638 | 0 | msg, msg_len, context_prefix, context_prefix_len, context, context_len, |
2639 | 0 | randomizer)); |
2640 | 0 | } |
2641 | | |
2642 | | bcm_status BCM_mldsa87_sign_mu_internal( |
2643 | | uint8_t out_encoded_signature[MLDSA87_SIGNATURE_BYTES], |
2644 | | const MLDSA87_private_key *private_key, |
2645 | | const uint8_t msg_rep[MLDSA_MU_BYTES], |
2646 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) { |
2647 | 0 | return bcm_as_approved_status(mldsa_sign_mu( |
2648 | 0 | out_encoded_signature, mldsa::private_key_from_external_87(private_key), |
2649 | 0 | msg_rep, randomizer)); |
2650 | 0 | } |
2651 | | |
2652 | | // ML-DSA signature in randomized mode, filling the random bytes with |
2653 | | // |BCM_rand_bytes|. |
2654 | | bcm_status BCM_mldsa87_sign( |
2655 | | uint8_t out_encoded_signature[MLDSA87_SIGNATURE_BYTES], |
2656 | | const MLDSA87_private_key *private_key, const uint8_t *msg, size_t msg_len, |
2657 | 0 | const uint8_t *context, size_t context_len) { |
2658 | 0 | BSSL_CHECK(context_len <= 255); |
2659 | 0 | uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]; |
2660 | 0 | BCM_rand_bytes(randomizer, sizeof(randomizer)); |
2661 | |
|
2662 | 0 | const uint8_t context_prefix[2] = {0, static_cast<uint8_t>(context_len)}; |
2663 | 0 | return BCM_mldsa87_sign_internal( |
2664 | 0 | out_encoded_signature, private_key, msg, msg_len, context_prefix, |
2665 | 0 | sizeof(context_prefix), context, context_len, randomizer); |
2666 | 0 | } |
2667 | | |
2668 | | // ML-DSA pre-hashed API: initializing a pre-hashing context. |
2669 | | void BCM_mldsa87_prehash_init(MLDSA87_prehash *out_prehash_ctx, |
2670 | | const MLDSA87_public_key *public_key, |
2671 | 0 | const uint8_t *context, size_t context_len) { |
2672 | 0 | BSSL_CHECK(context_len <= 255); |
2673 | |
|
2674 | 0 | const uint8_t context_prefix[2] = {0, static_cast<uint8_t>(context_len)}; |
2675 | 0 | mldsa_prehash_init(mldsa::prehash_context_from_external_87(out_prehash_ctx), |
2676 | 0 | mldsa::public_key_from_external_87(public_key), |
2677 | 0 | context_prefix, sizeof(context_prefix), context, |
2678 | 0 | context_len); |
2679 | 0 | } |
2680 | | |
2681 | | // ML-DSA pre-hashed API: updating a pre-hashing context with a message chunk. |
2682 | | void BCM_mldsa87_prehash_update(MLDSA87_prehash *inout_prehash_ctx, |
2683 | 0 | const uint8_t *msg, size_t msg_len) { |
2684 | 0 | mldsa_prehash_update( |
2685 | 0 | mldsa::prehash_context_from_external_87(inout_prehash_ctx), msg, msg_len); |
2686 | 0 | } |
2687 | | |
2688 | | // ML-DSA pre-hashed API: obtaining a message representative to sign. |
2689 | | void BCM_mldsa87_prehash_finalize(uint8_t out_msg_rep[MLDSA_MU_BYTES], |
2690 | 0 | MLDSA87_prehash *inout_prehash_ctx) { |
2691 | 0 | mldsa_prehash_finalize( |
2692 | 0 | out_msg_rep, mldsa::prehash_context_from_external_87(inout_prehash_ctx)); |
2693 | 0 | } |
2694 | | |
2695 | | // ML-DSA pre-hashed API: signing a message representative. |
2696 | | bcm_status BCM_mldsa87_sign_message_representative( |
2697 | | uint8_t out_encoded_signature[MLDSA87_SIGNATURE_BYTES], |
2698 | | const MLDSA87_private_key *private_key, |
2699 | 0 | const uint8_t msg_rep[MLDSA_MU_BYTES]) { |
2700 | 0 | uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]; |
2701 | 0 | BCM_rand_bytes(randomizer, sizeof(randomizer)); |
2702 | 0 | CONSTTIME_SECRET(randomizer, sizeof(randomizer)); |
2703 | |
|
2704 | 0 | return bcm_as_approved_status(mldsa_sign_mu( |
2705 | 0 | out_encoded_signature, mldsa::private_key_from_external_87(private_key), |
2706 | 0 | msg_rep, randomizer)); |
2707 | 0 | } |
2708 | | |
2709 | | // ML-DSA pre-hashed API: verifying a message representative. |
2710 | | bcm_status BCM_mldsa87_verify_message_representative( |
2711 | | const MLDSA87_public_key *public_key, |
2712 | | const uint8_t signature[MLDSA87_SIGNATURE_BYTES], |
2713 | 0 | const uint8_t msg_rep[MLDSA_MU_BYTES]) { |
2714 | 0 | return bcm_as_approved_status(mldsa::mldsa_verify_mu<8, 7>( |
2715 | 0 | mldsa::public_key_from_external_87(public_key), signature, msg_rep)); |
2716 | 0 | } |
2717 | | |
2718 | | // FIPS 204, Algorithm 3 (`ML-DSA.Verify`). |
2719 | | bcm_status BCM_mldsa87_verify(const MLDSA87_public_key *public_key, |
2720 | | const uint8_t *signature, const uint8_t *msg, |
2721 | | size_t msg_len, const uint8_t *context, |
2722 | 0 | size_t context_len) { |
2723 | 0 | BSSL_CHECK(context_len <= 255); |
2724 | 0 | const uint8_t context_prefix[2] = {0, static_cast<uint8_t>(context_len)}; |
2725 | 0 | return BCM_mldsa87_verify_internal(public_key, signature, msg, msg_len, |
2726 | 0 | context_prefix, sizeof(context_prefix), |
2727 | 0 | context, context_len); |
2728 | 0 | } |
2729 | | |
2730 | | bcm_status BCM_mldsa87_verify_internal( |
2731 | | const MLDSA87_public_key *public_key, |
2732 | | const uint8_t encoded_signature[MLDSA87_SIGNATURE_BYTES], |
2733 | | const uint8_t *msg, size_t msg_len, const uint8_t *context_prefix, |
2734 | 0 | size_t context_prefix_len, const uint8_t *context, size_t context_len) { |
2735 | 0 | return bcm_as_approved_status(mldsa::mldsa_verify_internal<8, 7>( |
2736 | 0 | mldsa::public_key_from_external_87(public_key), encoded_signature, msg, |
2737 | 0 | msg_len, context_prefix, context_prefix_len, context, context_len)); |
2738 | 0 | } |
2739 | | |
2740 | | bcm_status BCM_mldsa87_marshal_public_key( |
2741 | 0 | CBB *out, const MLDSA87_public_key *public_key) { |
2742 | 0 | return bcm_as_approved_status(mldsa_marshal_public_key( |
2743 | 0 | out, mldsa::public_key_from_external_87(public_key))); |
2744 | 0 | } |
2745 | | |
2746 | | int BCM_mldsa87_public_keys_equal(const MLDSA87_public_key *a, |
2747 | 0 | const MLDSA87_public_key *b) { |
2748 | 0 | auto *a_pub = mldsa::public_key_from_external_87(a); |
2749 | 0 | auto *b_pub = mldsa::public_key_from_external_87(b); |
2750 | | // It is sufficient to compare |public_key_hash|. When importing a public key, |
2751 | | // the hash must be computed. When importing a private key in expanded form |
2752 | | // (an internal testing-only API), the hash is provided, but we recompute it |
2753 | | // and check for correctness. |
2754 | 0 | return OPENSSL_memcmp(a_pub->public_key_hash, b_pub->public_key_hash, |
2755 | 0 | sizeof(a_pub->public_key_hash)) == 0; |
2756 | 0 | } |
2757 | | |
2758 | | |
2759 | | // ML-DSA-44 specific wrappers. |
2760 | | |
2761 | | bcm_status BCM_mldsa44_parse_public_key(MLDSA44_public_key *public_key, |
2762 | 0 | CBS *in) { |
2763 | 0 | return bcm_as_approved_status(mldsa_parse_public_key( |
2764 | 0 | mldsa::public_key_from_external_44(public_key), in)); |
2765 | 0 | } |
2766 | | |
2767 | | bcm_status BCM_mldsa44_marshal_private_key( |
2768 | 0 | CBB *out, const MLDSA44_private_key *private_key) { |
2769 | 0 | return bcm_as_approved_status(mldsa_marshal_private_key( |
2770 | 0 | out, mldsa::private_key_from_external_44(private_key))); |
2771 | 0 | } |
2772 | | |
2773 | | bcm_status BCM_mldsa44_parse_private_key(MLDSA44_private_key *private_key, |
2774 | 0 | CBS *in) { |
2775 | 0 | return bcm_as_approved_status( |
2776 | 0 | mldsa_parse_private_key(mldsa::private_key_from_external_44(private_key), |
2777 | 0 | in) && |
2778 | 0 | CBS_len(in) == 0); |
2779 | 0 | } |
2780 | | |
2781 | 0 | bcm_status BCM_mldsa44_check_key_fips(MLDSA44_private_key *private_key) { |
2782 | 0 | return bcm_as_approved_status( |
2783 | 0 | mldsa::fips::check_key(mldsa::private_key_from_external_44(private_key))); |
2784 | 0 | } |
2785 | | |
2786 | | // Calls |MLDSA_generate_key_external_entropy| with random bytes from |
2787 | | // |BCM_rand_bytes|. |
2788 | | bcm_status BCM_mldsa44_generate_key( |
2789 | | uint8_t out_encoded_public_key[MLDSA44_PUBLIC_KEY_BYTES], |
2790 | 0 | uint8_t out_seed[MLDSA_SEED_BYTES], MLDSA44_private_key *out_private_key) { |
2791 | 0 | BCM_rand_bytes(out_seed, MLDSA_SEED_BYTES); |
2792 | 0 | return BCM_mldsa44_generate_key_external_entropy(out_encoded_public_key, |
2793 | 0 | out_private_key, out_seed); |
2794 | 0 | } |
2795 | | |
2796 | | bcm_status BCM_mldsa44_private_key_from_seed( |
2797 | | MLDSA44_private_key *out_private_key, |
2798 | 0 | const uint8_t seed[MLDSA_SEED_BYTES]) { |
2799 | 0 | uint8_t public_key[MLDSA44_PUBLIC_KEY_BYTES]; |
2800 | 0 | return BCM_mldsa44_generate_key_external_entropy(public_key, out_private_key, |
2801 | 0 | seed); |
2802 | 0 | } |
2803 | | |
2804 | | bcm_status BCM_mldsa44_generate_key_external_entropy( |
2805 | | uint8_t out_encoded_public_key[MLDSA44_PUBLIC_KEY_BYTES], |
2806 | | MLDSA44_private_key *out_private_key, |
2807 | 0 | const uint8_t entropy[MLDSA_SEED_BYTES]) { |
2808 | 0 | return bcm_as_not_approved_status(mldsa_generate_key_external_entropy( |
2809 | 0 | out_encoded_public_key, |
2810 | 0 | mldsa::private_key_from_external_44(out_private_key), entropy)); |
2811 | 0 | } |
2812 | | |
2813 | | bcm_status BCM_mldsa44_generate_key_fips( |
2814 | | uint8_t out_encoded_public_key[MLDSA44_PUBLIC_KEY_BYTES], |
2815 | 0 | uint8_t out_seed[MLDSA_SEED_BYTES], MLDSA44_private_key *out_private_key) { |
2816 | 0 | if (out_encoded_public_key == nullptr || out_private_key == nullptr) { |
2817 | 0 | return bcm_status::failure; |
2818 | 0 | } |
2819 | 0 | if (BCM_mldsa44_generate_key(out_encoded_public_key, out_seed, |
2820 | 0 | out_private_key) == bcm_status::failure) { |
2821 | 0 | return bcm_status::failure; |
2822 | 0 | } |
2823 | 0 | return BCM_mldsa44_check_key_fips(out_private_key); |
2824 | 0 | } |
2825 | | |
2826 | | bcm_status BCM_mldsa44_generate_key_external_entropy_fips( |
2827 | | uint8_t out_encoded_public_key[MLDSA44_PUBLIC_KEY_BYTES], |
2828 | | MLDSA44_private_key *out_private_key, |
2829 | 0 | const uint8_t entropy[MLDSA_SEED_BYTES]) { |
2830 | 0 | if (out_encoded_public_key == nullptr || out_private_key == nullptr) { |
2831 | 0 | return bcm_status::failure; |
2832 | 0 | } |
2833 | 0 | if (BCM_mldsa44_generate_key_external_entropy(out_encoded_public_key, |
2834 | 0 | out_private_key, entropy) == |
2835 | 0 | bcm_status::failure) { |
2836 | 0 | return bcm_status::failure; |
2837 | 0 | } |
2838 | 0 | return BCM_mldsa44_check_key_fips(out_private_key); |
2839 | 0 | } |
2840 | | |
2841 | | bcm_status BCM_mldsa44_private_key_from_seed_fips( |
2842 | | MLDSA44_private_key *out_private_key, |
2843 | 0 | const uint8_t seed[MLDSA_SEED_BYTES]) { |
2844 | 0 | uint8_t public_key[MLDSA44_PUBLIC_KEY_BYTES]; |
2845 | 0 | if (BCM_mldsa44_generate_key_external_entropy(public_key, out_private_key, |
2846 | 0 | seed) == bcm_status::failure) { |
2847 | 0 | return bcm_status::failure; |
2848 | 0 | } |
2849 | 0 | return BCM_mldsa44_check_key_fips(out_private_key); |
2850 | 0 | } |
2851 | | |
2852 | | bcm_status BCM_mldsa44_public_from_private( |
2853 | | MLDSA44_public_key *out_public_key, |
2854 | 0 | const MLDSA44_private_key *private_key) { |
2855 | 0 | const auto *priv = mldsa::private_key_from_external_44(private_key); |
2856 | 0 | auto *out_pub = mldsa::public_key_from_external_44(out_public_key); |
2857 | 0 | *out_pub = priv->pub; |
2858 | 0 | return bcm_status::approved; |
2859 | 0 | } |
2860 | | |
2861 | | const MLDSA44_public_key *BCM_mldsa44_public_of_private( |
2862 | 0 | const MLDSA44_private_key *private_key) { |
2863 | 0 | return reinterpret_cast<const MLDSA44_public_key *>( |
2864 | 0 | &mldsa::private_key_from_external_44(private_key)->pub); |
2865 | 0 | } |
2866 | | |
2867 | | bcm_status BCM_mldsa44_sign_internal( |
2868 | | uint8_t out_encoded_signature[MLDSA44_SIGNATURE_BYTES], |
2869 | | const MLDSA44_private_key *private_key, const uint8_t *msg, size_t msg_len, |
2870 | | const uint8_t *context_prefix, size_t context_prefix_len, |
2871 | | const uint8_t *context, size_t context_len, |
2872 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) { |
2873 | 0 | return bcm_as_approved_status(mldsa_sign_internal( |
2874 | 0 | out_encoded_signature, mldsa::private_key_from_external_44(private_key), |
2875 | 0 | msg, msg_len, context_prefix, context_prefix_len, context, context_len, |
2876 | 0 | randomizer)); |
2877 | 0 | } |
2878 | | |
2879 | | bcm_status BCM_mldsa44_sign_mu_internal( |
2880 | | uint8_t out_encoded_signature[MLDSA44_SIGNATURE_BYTES], |
2881 | | const MLDSA44_private_key *private_key, |
2882 | | const uint8_t msg_rep[MLDSA_MU_BYTES], |
2883 | 0 | const uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]) { |
2884 | 0 | return bcm_as_approved_status(mldsa_sign_mu( |
2885 | 0 | out_encoded_signature, mldsa::private_key_from_external_44(private_key), |
2886 | 0 | msg_rep, randomizer)); |
2887 | 0 | } |
2888 | | |
2889 | | // ML-DSA signature in randomized mode, filling the random bytes with |
2890 | | // |BCM_rand_bytes|. |
2891 | | bcm_status BCM_mldsa44_sign( |
2892 | | uint8_t out_encoded_signature[MLDSA44_SIGNATURE_BYTES], |
2893 | | const MLDSA44_private_key *private_key, const uint8_t *msg, size_t msg_len, |
2894 | 0 | const uint8_t *context, size_t context_len) { |
2895 | 0 | BSSL_CHECK(context_len <= 255); |
2896 | 0 | uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]; |
2897 | 0 | BCM_rand_bytes(randomizer, sizeof(randomizer)); |
2898 | |
|
2899 | 0 | const uint8_t context_prefix[2] = {0, static_cast<uint8_t>(context_len)}; |
2900 | 0 | return BCM_mldsa44_sign_internal( |
2901 | 0 | out_encoded_signature, private_key, msg, msg_len, context_prefix, |
2902 | 0 | sizeof(context_prefix), context, context_len, randomizer); |
2903 | 0 | } |
2904 | | |
2905 | | // ML-DSA pre-hashed API: initializing a pre-hashing context. |
2906 | | void BCM_mldsa44_prehash_init(MLDSA44_prehash *out_prehash_ctx, |
2907 | | const MLDSA44_public_key *public_key, |
2908 | 0 | const uint8_t *context, size_t context_len) { |
2909 | 0 | BSSL_CHECK(context_len <= 255); |
2910 | |
|
2911 | 0 | const uint8_t context_prefix[2] = {0, static_cast<uint8_t>(context_len)}; |
2912 | 0 | mldsa_prehash_init(mldsa::prehash_context_from_external_44(out_prehash_ctx), |
2913 | 0 | mldsa::public_key_from_external_44(public_key), |
2914 | 0 | context_prefix, sizeof(context_prefix), context, |
2915 | 0 | context_len); |
2916 | 0 | } |
2917 | | |
2918 | | // ML-DSA pre-hashed API: updating a pre-hashing context with a message chunk. |
2919 | | void BCM_mldsa44_prehash_update(MLDSA44_prehash *inout_prehash_ctx, |
2920 | 0 | const uint8_t *msg, size_t msg_len) { |
2921 | 0 | mldsa_prehash_update( |
2922 | 0 | mldsa::prehash_context_from_external_44(inout_prehash_ctx), msg, msg_len); |
2923 | 0 | } |
2924 | | |
2925 | | // ML-DSA pre-hashed API: obtaining a message representative to sign. |
2926 | | void BCM_mldsa44_prehash_finalize(uint8_t out_msg_rep[MLDSA_MU_BYTES], |
2927 | 0 | MLDSA44_prehash *inout_prehash_ctx) { |
2928 | 0 | mldsa_prehash_finalize( |
2929 | 0 | out_msg_rep, mldsa::prehash_context_from_external_44(inout_prehash_ctx)); |
2930 | 0 | } |
2931 | | |
2932 | | // ML-DSA pre-hashed API: signing a message representative. |
2933 | | bcm_status BCM_mldsa44_sign_message_representative( |
2934 | | uint8_t out_encoded_signature[MLDSA44_SIGNATURE_BYTES], |
2935 | | const MLDSA44_private_key *private_key, |
2936 | 0 | const uint8_t msg_rep[MLDSA_MU_BYTES]) { |
2937 | 0 | uint8_t randomizer[BCM_MLDSA_SIGNATURE_RANDOMIZER_BYTES]; |
2938 | 0 | BCM_rand_bytes(randomizer, sizeof(randomizer)); |
2939 | 0 | CONSTTIME_SECRET(randomizer, sizeof(randomizer)); |
2940 | |
|
2941 | 0 | return bcm_as_approved_status(mldsa_sign_mu( |
2942 | 0 | out_encoded_signature, mldsa::private_key_from_external_44(private_key), |
2943 | 0 | msg_rep, randomizer)); |
2944 | 0 | } |
2945 | | |
2946 | | // ML-DSA pre-hashed API: verifying a message representative. |
2947 | | bcm_status BCM_mldsa44_verify_message_representative( |
2948 | | const MLDSA44_public_key *public_key, |
2949 | | const uint8_t signature[MLDSA44_SIGNATURE_BYTES], |
2950 | 0 | const uint8_t msg_rep[MLDSA_MU_BYTES]) { |
2951 | 0 | return bcm_as_approved_status(mldsa::mldsa_verify_mu<4, 4>( |
2952 | 0 | mldsa::public_key_from_external_44(public_key), signature, msg_rep)); |
2953 | 0 | } |
2954 | | |
2955 | | // FIPS 204, Algorithm 3 (`ML-DSA.Verify`). |
2956 | | bcm_status BCM_mldsa44_verify(const MLDSA44_public_key *public_key, |
2957 | | const uint8_t *signature, const uint8_t *msg, |
2958 | | size_t msg_len, const uint8_t *context, |
2959 | 0 | size_t context_len) { |
2960 | 0 | BSSL_CHECK(context_len <= 255); |
2961 | 0 | const uint8_t context_prefix[2] = {0, static_cast<uint8_t>(context_len)}; |
2962 | 0 | return BCM_mldsa44_verify_internal(public_key, signature, msg, msg_len, |
2963 | 0 | context_prefix, sizeof(context_prefix), |
2964 | 0 | context, context_len); |
2965 | 0 | } |
2966 | | |
2967 | | bcm_status BCM_mldsa44_verify_internal( |
2968 | | const MLDSA44_public_key *public_key, |
2969 | | const uint8_t encoded_signature[MLDSA44_SIGNATURE_BYTES], |
2970 | | const uint8_t *msg, size_t msg_len, const uint8_t *context_prefix, |
2971 | 0 | size_t context_prefix_len, const uint8_t *context, size_t context_len) { |
2972 | 0 | return bcm_as_approved_status(mldsa::mldsa_verify_internal<4, 4>( |
2973 | 0 | mldsa::public_key_from_external_44(public_key), encoded_signature, msg, |
2974 | 0 | msg_len, context_prefix, context_prefix_len, context, context_len)); |
2975 | 0 | } |
2976 | | |
2977 | | bcm_status BCM_mldsa44_marshal_public_key( |
2978 | 0 | CBB *out, const MLDSA44_public_key *public_key) { |
2979 | 0 | return bcm_as_approved_status(mldsa_marshal_public_key( |
2980 | 0 | out, mldsa::public_key_from_external_44(public_key))); |
2981 | 0 | } |
2982 | | |
2983 | | int BCM_mldsa44_public_keys_equal(const MLDSA44_public_key *a, |
2984 | 0 | const MLDSA44_public_key *b) { |
2985 | 0 | auto *a_pub = mldsa::public_key_from_external_44(a); |
2986 | 0 | auto *b_pub = mldsa::public_key_from_external_44(b); |
2987 | | // It is sufficient to compare |public_key_hash|. When importing a public key, |
2988 | | // the hash must be computed. When importing a private key in expanded form |
2989 | | // (an internal testing-only API), the hash is provided, but we recompute it |
2990 | | // and check for correctness. |
2991 | 0 | return OPENSSL_memcmp(a_pub->public_key_hash, b_pub->public_key_hash, |
2992 | 0 | sizeof(a_pub->public_key_hash)) == 0; |
2993 | 0 | } |
2994 | | |
2995 | 0 | int boringssl_self_test_mldsa() { |
2996 | 0 | return mldsa::fips::keygen_self_test() && mldsa::fips::sign_self_test() && |
2997 | 0 | mldsa::fips::verify_self_test(); |
2998 | 0 | } |