/src/wolfssl-normal-math/wolfcrypt/src/wc_mlkem.c
Line | Count | Source |
1 | | /* wc_mlkem.c |
2 | | * |
3 | | * Copyright (C) 2006-2026 wolfSSL Inc. |
4 | | * |
5 | | * This file is part of wolfSSL. |
6 | | * |
7 | | * wolfSSL is free software; you can redistribute it and/or modify |
8 | | * it under the terms of the GNU General Public License as published by |
9 | | * the Free Software Foundation; either version 3 of the License, or |
10 | | * (at your option) any later version. |
11 | | * |
12 | | * wolfSSL is distributed in the hope that it will be useful, |
13 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
14 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
15 | | * GNU General Public License for more details. |
16 | | * |
17 | | * You should have received a copy of the GNU General Public License |
18 | | * along with this program; if not, write to the Free Software |
19 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1335, USA |
20 | | */ |
21 | | |
22 | | /* Implementation based on FIPS 203: |
23 | | * https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.203.pdf |
24 | | * |
25 | | * Original implementation based on NIST 3rd Round submission package. |
26 | | * See link at: |
27 | | * https://csrc.nist.gov/Projects/post-quantum-cryptography/ |
28 | | * post-quantum-cryptography-standardization/round-3-submissions |
29 | | */ |
30 | | |
31 | | /* Possible Kyber options: |
32 | | * |
33 | | * WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM Default: OFF |
34 | | * Uses less dynamic memory to perform key generation. |
35 | | * Has a small performance trade-off. |
36 | | * Only usable with C implementation. |
37 | | * |
38 | | * WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM Default: OFF |
39 | | * Uses less dynamic memory to perform encapsulation. |
40 | | * Affects decapsulation too as encapsulation called. |
41 | | * Has a small performance trade-off. |
42 | | * Only usable with C implementation. |
43 | | * |
44 | | * WOLFSSL_MLKEM_NO_MAKE_KEY Default: OFF |
45 | | * Disable the make key or key generation API. |
46 | | * Reduces the code size. |
47 | | * Turn on when only doing encapsulation. |
48 | | * |
49 | | * WOLFSSL_MLKEM_NO_ENCAPSULATE Default: OFF |
50 | | * Disable the encapsulation API. |
51 | | * Reduces the code size. |
52 | | * Turn on when doing make key/decapsulation. |
53 | | * |
54 | | * WOLFSSL_MLKEM_NO_DECAPSULATE Default: OFF |
55 | | * Disable the decapsulation API. |
56 | | * Reduces the code size. |
57 | | * Turn on when only doing encapsulation. |
58 | | * |
59 | | * WOLFSSL_MLKEM_CACHE_A Default: OFF |
60 | | * Stores the matrix A during key generation for use in encapsulation when |
61 | | * performing decapsulation. |
62 | | * KyberKey is 8KB larger but decapsulation is significantly faster. |
63 | | * Turn on when performing make key and decapsulation with same object. |
64 | | */ |
65 | | |
66 | | #include <wolfssl/wolfcrypt/libwolfssl_sources.h> |
67 | | |
68 | | #ifdef WC_MLKEM_NO_ASM |
69 | | #undef USE_INTEL_SPEEDUP |
70 | | #undef WOLFSSL_ARMASM |
71 | | #undef WOLFSSL_RISCV_ASM |
72 | | #endif |
73 | | |
74 | | #include <wolfssl/wolfcrypt/mlkem.h> |
75 | | #include <wolfssl/wolfcrypt/wc_mlkem.h> |
76 | | #include <wolfssl/wolfcrypt/hash.h> |
77 | | #include <wolfssl/wolfcrypt/memory.h> |
78 | | |
79 | | #ifdef NO_INLINE |
80 | | #include <wolfssl/wolfcrypt/misc.h> |
81 | | #else |
82 | | #define WOLFSSL_MISC_INCLUDED |
83 | | #include <wolfcrypt/src/misc.c> |
84 | | #endif |
85 | | |
86 | | #if defined(USE_INTEL_SPEEDUP) || \ |
87 | | (defined(__aarch64__) && defined(WOLFSSL_ARMASM)) |
88 | | #if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \ |
89 | | defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM) |
90 | | #error "Can't use small memory with assembly optimized code" |
91 | | #endif |
92 | | #endif |
93 | | #if defined(WOLFSSL_MLKEM_CACHE_A) |
94 | | #if defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) || \ |
95 | | defined(WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM) |
96 | | #error "Can't cache A with small memory code" |
97 | | #endif |
98 | | #endif |
99 | | |
100 | | #if defined(WOLFSSL_MLKEM_NO_MAKE_KEY) && \ |
101 | | defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) && \ |
102 | | defined(WOLFSSL_MLKEM_NO_DECAPSULATE) |
103 | | #error "No ML-KEM operations to be built." |
104 | | #endif |
105 | | |
106 | | #ifdef WOLFSSL_WC_MLKEM |
107 | | |
108 | | #ifdef DEBUG_MLKEM |
109 | | void print_polys(const char* name, const sword16* a, int d1, int d2); |
110 | | void print_polys(const char* name, const sword16* a, int d1, int d2) |
111 | | { |
112 | | int i; |
113 | | int j; |
114 | | int k; |
115 | | |
116 | | fprintf(stderr, "%s: %d %d\n", name, d1, d2); |
117 | | for (i = 0; i < d1; i++) { |
118 | | for (j = 0; j < d2; j++) { |
119 | | for (k = 0; k < 256; k++) { |
120 | | fprintf(stderr, "%9d,", a[(i*d2*256) + (j*256) + k]); |
121 | | if ((k % 8) == 7) fprintf(stderr, "\n"); |
122 | | } |
123 | | fprintf(stderr, "\n"); |
124 | | } |
125 | | } |
126 | | } |
127 | | #endif |
128 | | |
129 | | #ifdef DEBUG_MLKEM |
130 | | void print_data(const char* name, const byte* d, int len); |
131 | | void print_data(const char* name, const byte* d, int len) |
132 | | { |
133 | | int i; |
134 | | |
135 | | fprintf(stderr, "%s\n", name); |
136 | | for (i = 0; i < len; i++) { |
137 | | fprintf(stderr, "0x%02x,", d[i]); |
138 | | if ((i % 16) == 15) fprintf(stderr, "\n"); |
139 | | } |
140 | | fprintf(stderr, "\n"); |
141 | | } |
142 | | #endif |
143 | | |
144 | | /******************************************************************************/ |
145 | | |
146 | | /* Use SHA3-256 to generate 32-bytes of hash. */ |
147 | 3.25k | #define MLKEM_HASH_H mlkem_hash256 |
148 | | /* Use SHA3-512 to generate 64-bytes of hash. */ |
149 | 3.25k | #define MLKEM_HASH_G mlkem_hash512 |
150 | | /* Use SHAKE-256 as a key derivation function (KDF). */ |
151 | | #if defined(USE_INTEL_SPEEDUP) || \ |
152 | | (defined(WOLFSSL_ARMASM) && defined(__aarch64__)) |
153 | | #define MLKEM_KDF mlkem_kdf |
154 | | #else |
155 | | #define MLKEM_KDF wc_Shake256Hash |
156 | | #endif |
157 | | |
158 | | /******************************************************************************/ |
159 | | |
160 | | /* Helper function with volatile variable, to force compiler not to optimize |
161 | | * code in mlkem_from_msg(). |
162 | | */ |
163 | | sword16 wc_mlkem_opt_blocker(void); |
164 | 0 | sword16 wc_mlkem_opt_blocker(void) { |
165 | 0 | static volatile sword16 static_mlkem_opt_blocker = 0; |
166 | 0 | return static_mlkem_opt_blocker; |
167 | 0 | } |
168 | | |
169 | | /******************************************************************************/ |
170 | | |
171 | | #ifndef WC_NO_CONSTRUCTORS |
172 | | /** |
173 | | * Create a new ML-KEM key object. |
174 | | * |
175 | | * Allocates and initializes a ML-KEM key object. |
176 | | * |
177 | | * @param [in] type Type of key: |
178 | | * WC_ML_KEM_512, WC_ML_KEM_768, WC_ML_KEM_1024, |
179 | | * KYBER512, KYBER768, KYBER1024. |
180 | | * @param [in] heap Dynamic memory hint. |
181 | | * @param [in] devId Device Id. |
182 | | * @return Pointer to new MlKemKey object, or NULL on failure. |
183 | | */ |
184 | | |
185 | | MlKemKey* wc_MlKemKey_New(int type, void* heap, int devId) |
186 | 0 | { |
187 | 0 | int ret; |
188 | 0 | MlKemKey* key = (MlKemKey*)XMALLOC(sizeof(MlKemKey), heap, |
189 | 0 | DYNAMIC_TYPE_TMP_BUFFER); |
190 | 0 | if (key != NULL) { |
191 | 0 | ret = wc_MlKemKey_Init(key, type, heap, devId); |
192 | 0 | if (ret != 0) { |
193 | 0 | XFREE(key, heap, DYNAMIC_TYPE_TMP_BUFFER); |
194 | 0 | key = NULL; |
195 | 0 | } |
196 | 0 | } |
197 | |
|
198 | 0 | return key; |
199 | 0 | } |
200 | | |
201 | | /** |
202 | | * Delete and free a ML-KEM key object. |
203 | | * |
204 | | * Frees resources associated with a ML-KEM key object and sets pointer to NULL. |
205 | | * |
206 | | * @param [in] key ML-KEM key object to delete. |
207 | | * @param [in, out] key_p Pointer to key pointer to set to NULL. |
208 | | * @return 0 on success. |
209 | | * @return BAD_FUNC_ARG when key is NULL. |
210 | | */ |
211 | | |
212 | | int wc_MlKemKey_Delete(MlKemKey* key, MlKemKey** key_p) |
213 | 0 | { |
214 | 0 | if (key == NULL) |
215 | 0 | return BAD_FUNC_ARG; |
216 | 0 | wc_MlKemKey_Free(key); |
217 | 0 | XFREE(key, key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
218 | 0 | if (key_p != NULL) |
219 | 0 | *key_p = NULL; |
220 | |
|
221 | 0 | return 0; |
222 | 0 | } |
223 | | #endif /* !WC_NO_CONSTRUCTORS */ |
224 | | |
225 | | /** |
226 | | * Initialize the Kyber key. |
227 | | * |
228 | | * @param [out] key Kyber key object to initialize. |
229 | | * @param [in] type Type of key: |
230 | | * WC_ML_KEM_512, WC_ML_KEM_768, WC_ML_KEM_1024, |
231 | | * KYBER512, KYBER768, KYBER1024. |
232 | | * @param [in] heap Dynamic memory hint. |
233 | | * @param [in] devId Device Id. |
234 | | * @return 0 on success. |
235 | | * @return BAD_FUNC_ARG when key is NULL or type is unrecognized. |
236 | | * @return NOT_COMPILED_IN when key type is not supported. |
237 | | */ |
238 | | int wc_MlKemKey_Init(MlKemKey* key, int type, void* heap, int devId) |
239 | 3.26k | { |
240 | 3.26k | int ret = 0; |
241 | | |
242 | | /* Validate key. */ |
243 | 3.26k | if (key == NULL) { |
244 | 0 | ret = BAD_FUNC_ARG; |
245 | 0 | } |
246 | 3.26k | if (ret == 0) { |
247 | | /* Validate type. */ |
248 | 3.26k | switch (type) { |
249 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
250 | 0 | case WC_ML_KEM_512: |
251 | | #ifndef WOLFSSL_WC_ML_KEM_512 |
252 | | /* Code not compiled in for Kyber-512. */ |
253 | | ret = NOT_COMPILED_IN; |
254 | | #endif |
255 | 0 | break; |
256 | 3.22k | case WC_ML_KEM_768: |
257 | | #ifndef WOLFSSL_WC_ML_KEM_768 |
258 | | /* Code not compiled in for Kyber-768. */ |
259 | | ret = NOT_COMPILED_IN; |
260 | | #endif |
261 | 3.22k | break; |
262 | 34 | case WC_ML_KEM_1024: |
263 | | #ifndef WOLFSSL_WC_ML_KEM_1024 |
264 | | /* Code not compiled in for Kyber-1024. */ |
265 | | ret = NOT_COMPILED_IN; |
266 | | #endif |
267 | 34 | break; |
268 | 0 | #endif |
269 | | #ifdef WOLFSSL_MLKEM_KYBER |
270 | | case KYBER512: |
271 | | #ifndef WOLFSSL_KYBER512 |
272 | | /* Code not compiled in for Kyber-512. */ |
273 | | ret = NOT_COMPILED_IN; |
274 | | #endif |
275 | | break; |
276 | | case KYBER768: |
277 | | #ifndef WOLFSSL_KYBER768 |
278 | | /* Code not compiled in for Kyber-768. */ |
279 | | ret = NOT_COMPILED_IN; |
280 | | #endif |
281 | | break; |
282 | | case KYBER1024: |
283 | | #ifndef WOLFSSL_KYBER1024 |
284 | | /* Code not compiled in for Kyber-1024. */ |
285 | | ret = NOT_COMPILED_IN; |
286 | | #endif |
287 | | break; |
288 | | #endif |
289 | 0 | default: |
290 | | /* No other values supported. */ |
291 | 0 | ret = BAD_FUNC_ARG; |
292 | 0 | break; |
293 | 3.26k | } |
294 | 3.26k | } |
295 | 3.26k | if (ret == 0) { |
296 | | /* Keep type for parameters. */ |
297 | 3.26k | key->type = type; |
298 | | /* Cache heap pointer. */ |
299 | 3.26k | key->heap = heap; |
300 | 3.26k | #ifdef WOLF_CRYPTO_CB |
301 | | /* Cache device id - not used in this algorithm yet. */ |
302 | 3.26k | key->devId = devId; |
303 | 3.26k | #endif |
304 | 3.26k | key->flags = 0; |
305 | | |
306 | | /* Zero out all data. */ |
307 | 3.26k | XMEMSET(&key->prf, 0, sizeof(key->prf)); |
308 | | |
309 | | /* Initialize the hash algorithm object. */ |
310 | 3.26k | ret = mlkem_hash_new(&key->hash, heap, devId); |
311 | 3.26k | } |
312 | 3.26k | if (ret == 0) { |
313 | | /* Initialize the PRF algorithm object. */ |
314 | 3.26k | ret = mlkem_prf_new(&key->prf, heap, devId); |
315 | 3.26k | } |
316 | 3.26k | if (ret == 0) { |
317 | 3.26k | mlkem_init(); |
318 | 3.26k | } |
319 | | |
320 | 3.26k | (void)devId; |
321 | | |
322 | 3.26k | return ret; |
323 | 3.26k | } |
324 | | |
325 | | /** |
326 | | * Free the Kyber key object. |
327 | | * |
328 | | * @param [in, out] key Kyber key object to dispose of. |
329 | | * @return 0 on success. |
330 | | */ |
331 | | int wc_MlKemKey_Free(MlKemKey* key) |
332 | 6.49k | { |
333 | 6.49k | if (key != NULL) { |
334 | | /* Dispose of PRF object. */ |
335 | 3.26k | mlkem_prf_free(&key->prf); |
336 | | /* Dispose of hash object. */ |
337 | 3.26k | mlkem_hash_free(&key->hash); |
338 | | /* Ensure all private data is zeroed. */ |
339 | 3.26k | ForceZero(&key->hash, sizeof(key->hash)); |
340 | 3.26k | ForceZero(&key->prf, sizeof(key->prf)); |
341 | 3.26k | ForceZero(key->priv, sizeof(key->priv)); |
342 | 3.26k | ForceZero(key->z, sizeof(key->z)); |
343 | 3.26k | } |
344 | | |
345 | 6.49k | return 0; |
346 | 6.49k | } |
347 | | |
348 | | /******************************************************************************/ |
349 | | |
350 | | #ifndef WOLFSSL_MLKEM_NO_MAKE_KEY |
351 | | /** |
352 | | * Make a Kyber key object using a random number generator. |
353 | | * |
354 | | * FIPS 203 - Algorithm 19: ML-KEM.KeyGen() |
355 | | * Generates an encapsulation key and a corresponding decapsulation key. |
356 | | * 1: d <- B_32 > d is 32 random bytes |
357 | | * 2: z <- B_32 > z is 32 random bytes |
358 | | * 3: if d == NULL or z == NULL then |
359 | | * 4: return falsum |
360 | | * > return an error indication if random bit generation failed |
361 | | * 5: end if |
362 | | * 6: (ek,dk) <- ML-KEM.KeyGen_Internal(d, z) |
363 | | * > run internal key generation algorithm |
364 | | * 7: return (ek,dk) |
365 | | * |
366 | | * @param [in, out] key Kyber key object. |
367 | | * @param [in] rng Random number generator. |
368 | | * @return 0 on success. |
369 | | * @return BAD_FUNC_ARG when key or rng is NULL. |
370 | | * @return MEMORY_E when dynamic memory allocation failed. |
371 | | * @return RNG_FAILURE_E when generating random numbers failed. |
372 | | * @return DRBG_CONT_FAILURE when random number generator health check fails. |
373 | | */ |
374 | | int wc_MlKemKey_MakeKey(MlKemKey* key, WC_RNG* rng) |
375 | 3.25k | { |
376 | 3.25k | #ifndef WC_NO_RNG |
377 | 3.25k | int ret = 0; |
378 | 3.25k | unsigned char rand[WC_ML_KEM_MAKEKEY_RAND_SZ]; |
379 | | |
380 | | /* Validate parameters. */ |
381 | 3.25k | if ((key == NULL) || (rng == NULL)) { |
382 | 0 | ret = BAD_FUNC_ARG; |
383 | 0 | } |
384 | | |
385 | 3.25k | if (ret == 0) { |
386 | | /* Generate random to use with PRFs. |
387 | | * Step 1: d is 32 random bytes |
388 | | * Step 2: z is 32 random bytes |
389 | | */ |
390 | 3.25k | ret = wc_RNG_GenerateBlock(rng, rand, WC_ML_KEM_SYM_SZ * 2); |
391 | | /* Step 3: ret is not zero when d == NULL or z == NULL. */ |
392 | 3.25k | } |
393 | 3.25k | if (ret == 0) { |
394 | | /* Make a key pair from the random. |
395 | | * Step 6. run internal key generation algorithm |
396 | | * Step 7. public and private key are stored in key |
397 | | */ |
398 | 3.25k | ret = wc_KyberKey_MakeKeyWithRandom(key, rand, sizeof(rand)); |
399 | 3.25k | } |
400 | | |
401 | | /* Ensure seeds are zeroized. */ |
402 | 3.25k | ForceZero((void*)rand, (word32)sizeof(rand)); |
403 | | |
404 | | /* Step 4: return ret != 0 on falsum or internal key generation failure. */ |
405 | 3.25k | return ret; |
406 | | #else |
407 | | (void)key; |
408 | | (void)rng; |
409 | | return NOT_COMPILED_IN; |
410 | | #endif /* WC_NO_RNG */ |
411 | 3.25k | } |
412 | | |
413 | | /** |
414 | | * Make a Kyber key object using random data. |
415 | | * |
416 | | * FIPS 203 - Algorithm 16: ML-KEM.KeyGen_internal(d,z) |
417 | | * Uses randomness to generate an encapsulation key and a corresponding |
418 | | * decapsulation key. |
419 | | * 1: (ek_PKE,dk_PKE) <- K-PKE.KeyGen(d) > run key generation for K-PKE |
420 | | * ... |
421 | | * |
422 | | * FIPS 203 - Algorithm 13: K-PKE.KeyGen(d) |
423 | | * Uses randomness to generate an encryption key and a corresponding decryption |
424 | | * key. |
425 | | * 1: (rho,sigma) <- G(d||k) |
426 | | * > expand 32+1 bytes to two pseudorandom 32-byte seeds |
427 | | * 2: N <- 0 |
428 | | * 3-7: generate matrix A_hat |
429 | | * 8-11: generate s |
430 | | * 12-15: generate e |
431 | | * 16-18: calculate t_hat from A_hat, s and e |
432 | | * ... |
433 | | * |
434 | | * @param [in, out] key Kyber key object. |
435 | | * @param [in] rand Random data. |
436 | | * @param [in] len Length of random data in bytes. |
437 | | * @return 0 on success. |
438 | | * @return BAD_FUNC_ARG when key or rand is NULL. |
439 | | * @return BUFFER_E when length is not WC_ML_KEM_MAKEKEY_RAND_SZ. |
440 | | * @return NOT_COMPILED_IN when key type is not supported. |
441 | | * @return MEMORY_E when dynamic memory allocation failed. |
442 | | */ |
443 | | int wc_MlKemKey_MakeKeyWithRandom(MlKemKey* key, const unsigned char* rand, |
444 | | int len) |
445 | 3.25k | { |
446 | 3.25k | byte buf[2 * WC_ML_KEM_SYM_SZ + 1]; |
447 | 3.25k | byte* rho = buf; |
448 | 3.25k | #ifndef WC_MLKEM_FAULT_HARDEN |
449 | 3.25k | byte* sigma = buf + WC_ML_KEM_SYM_SZ; |
450 | | #else |
451 | | byte sigma[WC_ML_KEM_SYM_SZ + 1]; |
452 | | #endif |
453 | 3.25k | #ifndef WOLFSSL_NO_MALLOC |
454 | 3.25k | sword16* e = NULL; |
455 | | #else |
456 | | #ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM |
457 | | #ifndef WOLFSSL_MLKEM_CACHE_A |
458 | | sword16 e[(WC_ML_KEM_MAX_K + 1) * WC_ML_KEM_MAX_K * MLKEM_N]; |
459 | | #else |
460 | | sword16 e[WC_ML_KEM_MAX_K * MLKEM_N]; |
461 | | #endif |
462 | | #else |
463 | | sword16 e[WC_ML_KEM_MAX_K * MLKEM_N]; |
464 | | #endif |
465 | | #endif |
466 | 3.25k | #ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM |
467 | 3.25k | sword16* a = NULL; |
468 | 3.25k | #endif |
469 | 3.25k | sword16* s = NULL; |
470 | 3.25k | sword16* t = NULL; |
471 | 3.25k | int ret = 0; |
472 | 3.25k | int k = 0; |
473 | | |
474 | | /* Validate parameters. */ |
475 | 3.25k | if ((key == NULL) || (rand == NULL)) { |
476 | 0 | ret = BAD_FUNC_ARG; |
477 | 0 | } |
478 | 3.25k | if ((ret == 0) && (len != WC_ML_KEM_MAKEKEY_RAND_SZ)) { |
479 | 0 | ret = BUFFER_E; |
480 | 0 | } |
481 | | |
482 | 3.25k | if (ret == 0) { |
483 | 3.25k | key->flags = 0; |
484 | | |
485 | | /* Establish parameters based on key type. */ |
486 | 3.25k | switch (key->type) { |
487 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
488 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
489 | 0 | case WC_ML_KEM_512: |
490 | 0 | k = WC_ML_KEM_512_K; |
491 | 0 | break; |
492 | 0 | #endif |
493 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
494 | 3.22k | case WC_ML_KEM_768: |
495 | 3.22k | k = WC_ML_KEM_768_K; |
496 | 3.22k | break; |
497 | 0 | #endif |
498 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
499 | 34 | case WC_ML_KEM_1024: |
500 | 34 | k = WC_ML_KEM_1024_K; |
501 | 34 | break; |
502 | 0 | #endif |
503 | 0 | #endif |
504 | | #ifdef WOLFSSL_MLKEM_KYBER |
505 | | #ifdef WOLFSSL_KYBER512 |
506 | | case KYBER512: |
507 | | k = KYBER512_K; |
508 | | break; |
509 | | #endif |
510 | | #ifdef WOLFSSL_KYBER768 |
511 | | case KYBER768: |
512 | | k = KYBER768_K; |
513 | | break; |
514 | | #endif |
515 | | #ifdef WOLFSSL_KYBER1024 |
516 | | case KYBER1024: |
517 | | k = KYBER1024_K; |
518 | | break; |
519 | | #endif |
520 | | #endif |
521 | 0 | default: |
522 | | /* No other values supported. */ |
523 | 0 | ret = NOT_COMPILED_IN; |
524 | 0 | break; |
525 | 3.25k | } |
526 | 3.25k | } |
527 | | |
528 | 3.25k | #ifndef WOLFSSL_NO_MALLOC |
529 | 3.25k | if (ret == 0) { |
530 | | /* Allocate dynamic memory for matrix and error vector. */ |
531 | 3.25k | #ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM |
532 | 3.25k | #ifndef WOLFSSL_MLKEM_CACHE_A |
533 | | /* e (v) | a (m) */ |
534 | 3.25k | e = (sword16*)XMALLOC((size_t)((k + 1) * k * MLKEM_N) * sizeof(sword16), |
535 | 3.25k | key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
536 | | #else |
537 | | /* e (v) */ |
538 | | e = (sword16*)XMALLOC((size_t)(k * MLKEM_N) * sizeof(sword16), |
539 | | key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
540 | | #endif |
541 | | #else |
542 | | /* e (v) */ |
543 | | e = (sword16*)XMALLOC((size_t)(k * MLKEM_N) * sizeof(sword16), |
544 | | key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
545 | | #endif |
546 | 3.25k | if (e == NULL) { |
547 | 4 | ret = MEMORY_E; |
548 | 4 | } |
549 | 3.25k | } |
550 | 3.25k | #endif |
551 | 3.25k | if (ret == 0) { |
552 | 3.25k | const byte* d = rand; |
553 | | |
554 | | #ifdef WOLFSSL_MLKEM_CACHE_A |
555 | | a = key->a; |
556 | | #elif !defined(WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM) |
557 | | /* Matrix A allocated at end of error vector. */ |
558 | 3.25k | a = e + (k * MLKEM_N); |
559 | 3.25k | #endif |
560 | | |
561 | | #if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM) |
562 | | if (key->type & MLKEM_KYBER) |
563 | | #endif |
564 | | #ifdef WOLFSSL_MLKEM_KYBER |
565 | | { |
566 | | /* Expand 32 bytes of random to 64. */ |
567 | | ret = MLKEM_HASH_G(&key->hash, d, WC_ML_KEM_SYM_SZ, NULL, 0, buf); |
568 | | } |
569 | | #endif |
570 | | #if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM) |
571 | | else |
572 | | #endif |
573 | 3.25k | #ifndef WOLFSSL_NO_ML_KEM |
574 | 3.25k | { |
575 | 3.25k | buf[0] = (byte)k; |
576 | | /* Expand 33 bytes of random to 64. |
577 | | * Alg 13: Step 1: (rho,sigma) <- G(d||k) |
578 | | */ |
579 | 3.25k | ret = MLKEM_HASH_G(&key->hash, d, WC_ML_KEM_SYM_SZ, buf, 1, buf); |
580 | 3.25k | } |
581 | 3.25k | #endif |
582 | 3.25k | } |
583 | | #ifdef WC_MLKEM_FAULT_HARDEN |
584 | | if (ret == 0) { |
585 | | XMEMCPY(sigma, buf + WC_ML_KEM_SYM_SZ, WC_ML_KEM_SYM_SZ); |
586 | | /* Check that correct data was copied and pointer not changed. */ |
587 | | if (XMEMCMP(sigma, rho, WC_ML_KEM_SYM_SZ) == 0) { |
588 | | ret = BAD_COND_E; |
589 | | } |
590 | | /* Check that rho is sigma - rho may have been modified. */ |
591 | | if (XMEMCMP(sigma, rho + WC_ML_KEM_SYM_SZ, WC_ML_KEM_SYM_SZ) != 0) { |
592 | | ret = BAD_COND_E; |
593 | | } |
594 | | } |
595 | | #endif |
596 | 3.25k | if (ret == 0) { |
597 | 3.25k | const byte* z = rand + WC_ML_KEM_SYM_SZ; |
598 | 3.25k | s = key->priv; |
599 | 3.25k | t = key->pub; |
600 | | |
601 | | /* Cache the public seed for use in encapsulation and encoding public |
602 | | * key. */ |
603 | 3.25k | XMEMCPY(key->pubSeed, rho, WC_ML_KEM_SYM_SZ); |
604 | | /* Cache the z value for decapsulation and encoding private key. */ |
605 | 3.25k | XMEMCPY(key->z, z, sizeof(key->z)); |
606 | | |
607 | | /* Initialize PRF for use in noise generation. */ |
608 | 3.25k | mlkem_prf_init(&key->prf); |
609 | 3.25k | #ifndef WOLFSSL_MLKEM_MAKEKEY_SMALL_MEM |
610 | | /* Generate noise using PRF. |
611 | | * Alg 13: Steps 8-15: generate s and e |
612 | | */ |
613 | 3.25k | ret = mlkem_get_noise(&key->prf, k, s, e, NULL, sigma); |
614 | 3.25k | } |
615 | 3.25k | if (ret == 0) { |
616 | | /* Generate the matrix A. |
617 | | * Alg 13: Steps 3-7 |
618 | | */ |
619 | 3.25k | ret = mlkem_gen_matrix(&key->prf, a, k, rho, 0); |
620 | 3.25k | } |
621 | 3.25k | if (ret == 0) { |
622 | | /* Generate key pair from random data. |
623 | | * Alg 13: Steps 16-18. |
624 | | */ |
625 | 3.25k | mlkem_keygen(s, t, e, a, k); |
626 | | #else |
627 | | /* Generate noise using PRF. |
628 | | * Alg 13: Steps 8-11: generate s |
629 | | */ |
630 | | ret = mlkem_get_noise(&key->prf, k, s, NULL, NULL, sigma); |
631 | | } |
632 | | if (ret == 0) { |
633 | | /* Generate key pair from private vector and seeds. |
634 | | * Alg 13: Steps 3-7: generate matrix A_hat |
635 | | * Alg 13: Steps 12-15: generate e |
636 | | * Alg 13: Steps 16-18: calculate t_hat from A_hat, s and e |
637 | | */ |
638 | | ret = mlkem_keygen_seeds(s, t, &key->prf, e, k, rho, sigma); |
639 | | } |
640 | | if (ret == 0) { |
641 | | #endif |
642 | | /* Private and public key are set/available. */ |
643 | 3.25k | key->flags |= MLKEM_FLAG_PRIV_SET | MLKEM_FLAG_PUB_SET; |
644 | | #ifdef WOLFSSL_MLKEM_CACHE_A |
645 | | key->flags |= MLKEM_FLAG_A_SET; |
646 | | #endif |
647 | 3.25k | } |
648 | | |
649 | 3.25k | #ifndef WOLFSSL_NO_MALLOC |
650 | | /* Free dynamic memory allocated in function. */ |
651 | 3.25k | if (key != NULL) { |
652 | 3.25k | XFREE(e, key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
653 | 3.25k | } |
654 | 3.25k | #endif |
655 | | |
656 | 3.25k | return ret; |
657 | 3.25k | } |
658 | | #endif /* !WOLFSSL_MLKEM_NO_MAKE_KEY */ |
659 | | |
660 | | /******************************************************************************/ |
661 | | |
662 | | /** |
663 | | * Get the size in bytes of cipher text for key. |
664 | | * |
665 | | * @param [in] key Kyber key object. |
666 | | * @param [out] len Length of cipher text in bytes. |
667 | | * @return 0 on success. |
668 | | * @return BAD_FUNC_ARG when key or len is NULL. |
669 | | * @return NOT_COMPILED_IN when key type is not supported. |
670 | | */ |
671 | | int wc_MlKemKey_CipherTextSize(MlKemKey* key, word32* len) |
672 | 0 | { |
673 | 0 | int ret = 0; |
674 | | |
675 | | /* Validate parameters. */ |
676 | 0 | if ((key == NULL) || (len == NULL)) { |
677 | 0 | ret = BAD_FUNC_ARG; |
678 | 0 | } |
679 | |
|
680 | 0 | if (ret == 0) { |
681 | | /* Return in 'len' size of the cipher text for the type of this key. */ |
682 | 0 | switch (key->type) { |
683 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
684 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
685 | 0 | case WC_ML_KEM_512: |
686 | 0 | *len = WC_ML_KEM_512_CIPHER_TEXT_SIZE; |
687 | 0 | break; |
688 | 0 | #endif |
689 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
690 | 0 | case WC_ML_KEM_768: |
691 | 0 | *len = WC_ML_KEM_768_CIPHER_TEXT_SIZE; |
692 | 0 | break; |
693 | 0 | #endif |
694 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
695 | 0 | case WC_ML_KEM_1024: |
696 | 0 | *len = WC_ML_KEM_1024_CIPHER_TEXT_SIZE; |
697 | 0 | break; |
698 | 0 | #endif |
699 | 0 | #endif |
700 | | #ifdef WOLFSSL_MLKEM_KYBER |
701 | | #ifdef WOLFSSL_KYBER512 |
702 | | case KYBER512: |
703 | | *len = KYBER512_CIPHER_TEXT_SIZE; |
704 | | break; |
705 | | #endif |
706 | | #ifdef WOLFSSL_KYBER768 |
707 | | case KYBER768: |
708 | | *len = KYBER768_CIPHER_TEXT_SIZE; |
709 | | break; |
710 | | #endif |
711 | | #ifdef WOLFSSL_KYBER1024 |
712 | | case KYBER1024: |
713 | | *len = KYBER1024_CIPHER_TEXT_SIZE; |
714 | | break; |
715 | | #endif |
716 | | #endif |
717 | 0 | default: |
718 | | /* No other values supported. */ |
719 | 0 | ret = NOT_COMPILED_IN; |
720 | 0 | break; |
721 | 0 | } |
722 | 0 | } |
723 | | |
724 | 0 | return ret; |
725 | 0 | } |
726 | | |
727 | | /** |
728 | | * Size of a shared secret in bytes. Always KYBER_SS_SZ. |
729 | | * |
730 | | * @param [in] key Kyber key object. Not used. |
731 | | * @param [out] len Size of the shared secret created with a Kyber key. |
732 | | * @return 0 on success. |
733 | | * @return BAD_FUNC_ARG when len is NULL. |
734 | | */ |
735 | | int wc_MlKemKey_SharedSecretSize(MlKemKey* key, word32* len) |
736 | 0 | { |
737 | 0 | int ret = 0; |
738 | |
|
739 | 0 | if (len == NULL) { |
740 | 0 | ret = BAD_FUNC_ARG; |
741 | 0 | } |
742 | 0 | else { |
743 | 0 | *len = WC_ML_KEM_SS_SZ; |
744 | 0 | } |
745 | |
|
746 | 0 | (void)key; |
747 | 0 | return ret; |
748 | 0 | } |
749 | | |
750 | | #if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \ |
751 | | !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) |
752 | | /* Encapsulate data and derive secret. |
753 | | * |
754 | | * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE, m, r) |
755 | | * Uses the encryption key to encrypt a plaintext message using the randomness |
756 | | * r. |
757 | | * 1: N <- 0 |
758 | | * 2: t_hat <- ByteDecode_12(ek_PKE[0:384k]) |
759 | | * > run ByteDecode_12 k times to decode t_hat |
760 | | * 3: rho <- ek_PKE[384k : 384k + 32] |
761 | | * > extract 32-byte seed from ek_PKE |
762 | | * 4-8: generate matrix A_hat |
763 | | * 9-12: generate y |
764 | | * 13-16: generate e_1 |
765 | | * 17: generate e_2 |
766 | | * 18-19: calculate u |
767 | | * 20: mu <- Decompress_1(ByteDecode_1(m)) |
768 | | * 21: calculate v |
769 | | * 22: c_1 <- ByteEncode_d_u(Compress_d_u(u)) |
770 | | * > run ByteEncode_d_u and Compress_d_u k times |
771 | | * 23: c_2 <- ByteEncode_d_v(Compress_d_v(v)) |
772 | | * 24: return c <- (c_1||c_2) |
773 | | * |
774 | | * @param [in] key Kyber key object. |
775 | | * @param [in] m Random bytes. |
776 | | * @param [in] r Seed to feed to PRF when generating y, e1 and e2. |
777 | | * @param [out] c Calculated cipher text. |
778 | | * @return 0 on success. |
779 | | * @return NOT_COMPILED_IN when key type is not supported. |
780 | | */ |
781 | | static int mlkemkey_encapsulate(MlKemKey* key, const byte* m, byte* r, byte* c) |
782 | 0 | { |
783 | 0 | int ret = 0; |
784 | 0 | sword16* a = NULL; |
785 | 0 | #ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM |
786 | 0 | sword16* mu = NULL; |
787 | 0 | sword16* e1 = NULL; |
788 | 0 | sword16* e2 = NULL; |
789 | 0 | #endif |
790 | 0 | unsigned int k = 0; |
791 | 0 | unsigned int compVecSz = 0; |
792 | 0 | #ifndef WOLFSSL_NO_MALLOC |
793 | 0 | sword16* y = NULL; |
794 | | #else |
795 | | #ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM |
796 | | sword16 y[((WC_ML_KEM_MAX_K + 3) * WC_ML_KEM_MAX_K + 3) * MLKEM_N]; |
797 | | #else |
798 | | sword16 y[3 * WC_ML_KEM_MAX_K * MLKEM_N]; |
799 | | #endif |
800 | | #endif |
801 | 0 | sword16* u = 0; |
802 | 0 | sword16* v = 0; |
803 | | |
804 | | /* Establish parameters based on key type. */ |
805 | 0 | switch (key->type) { |
806 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
807 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
808 | 0 | case WC_ML_KEM_512: |
809 | 0 | k = WC_ML_KEM_512_K; |
810 | 0 | compVecSz = WC_ML_KEM_512_POLY_VEC_COMPRESSED_SZ; |
811 | 0 | break; |
812 | 0 | #endif |
813 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
814 | 0 | case WC_ML_KEM_768: |
815 | 0 | k = WC_ML_KEM_768_K; |
816 | 0 | compVecSz = WC_ML_KEM_768_POLY_VEC_COMPRESSED_SZ; |
817 | 0 | break; |
818 | 0 | #endif |
819 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
820 | 0 | case WC_ML_KEM_1024: |
821 | 0 | k = WC_ML_KEM_1024_K; |
822 | 0 | compVecSz = WC_ML_KEM_1024_POLY_VEC_COMPRESSED_SZ; |
823 | 0 | break; |
824 | 0 | #endif |
825 | 0 | #endif |
826 | | #ifdef WOLFSSL_MLKEM_KYBER |
827 | | #ifdef WOLFSSL_KYBER512 |
828 | | case KYBER512: |
829 | | k = KYBER512_K; |
830 | | compVecSz = KYBER512_POLY_VEC_COMPRESSED_SZ; |
831 | | break; |
832 | | #endif |
833 | | #ifdef WOLFSSL_KYBER768 |
834 | | case KYBER768: |
835 | | k = KYBER768_K; |
836 | | compVecSz = KYBER768_POLY_VEC_COMPRESSED_SZ; |
837 | | break; |
838 | | #endif |
839 | | #ifdef WOLFSSL_KYBER1024 |
840 | | case KYBER1024: |
841 | | k = KYBER1024_K; |
842 | | compVecSz = KYBER1024_POLY_VEC_COMPRESSED_SZ; |
843 | | break; |
844 | | #endif |
845 | | #endif |
846 | 0 | default: |
847 | | /* No other values supported. */ |
848 | 0 | ret = NOT_COMPILED_IN; |
849 | 0 | break; |
850 | 0 | } |
851 | | |
852 | 0 | #ifndef WOLFSSL_NO_MALLOC |
853 | 0 | if (ret == 0) { |
854 | | /* Allocate dynamic memory for all matrices, vectors and polynomials. */ |
855 | 0 | #ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM |
856 | 0 | y = (sword16*)XMALLOC(((k + 3) * k + 3) * MLKEM_N * sizeof(sword16), |
857 | 0 | key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
858 | | #else |
859 | | y = (sword16*)XMALLOC(3 * k * MLKEM_N * sizeof(sword16), key->heap, |
860 | | DYNAMIC_TYPE_TMP_BUFFER); |
861 | | #endif |
862 | 0 | if (y == NULL) { |
863 | 0 | ret = MEMORY_E; |
864 | 0 | } |
865 | 0 | } |
866 | 0 | #endif |
867 | |
|
868 | 0 | #ifndef WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM |
869 | 0 | if (ret == 0) { |
870 | | /* Assign allocated dynamic memory to pointers. |
871 | | * y (b) | a (m) | mu (p) | e1 (p) | e2 (v) | u (v) | v (p) */ |
872 | 0 | a = y + MLKEM_N * k; |
873 | 0 | mu = a + MLKEM_N * k * k; |
874 | 0 | e1 = mu + MLKEM_N; |
875 | 0 | e2 = e1 + MLKEM_N * k; |
876 | | |
877 | | /* Convert msg to a polynomial. |
878 | | * Step 20: mu <- Decompress_1(ByteDecode_1(m)) */ |
879 | 0 | mlkem_from_msg(mu, m); |
880 | | |
881 | | /* Initialize the PRF for use in the noise generation. */ |
882 | 0 | mlkem_prf_init(&key->prf); |
883 | | /* Generate noise using PRF. |
884 | | * Steps 9-17: generate y, e_1, e_2 |
885 | | */ |
886 | 0 | ret = mlkem_get_noise(&key->prf, (int)k, y, e1, e2, r); |
887 | 0 | } |
888 | | #ifdef WOLFSSL_MLKEM_CACHE_A |
889 | | if ((ret == 0) && ((key->flags & MLKEM_FLAG_A_SET) != 0)) { |
890 | | unsigned int i; |
891 | | /* Transpose matrix. |
892 | | * Steps 4-8: generate matrix A_hat (from original) */ |
893 | | for (i = 0; i < k; i++) { |
894 | | unsigned int j; |
895 | | for (j = 0; j < k; j++) { |
896 | | XMEMCPY(&a[(i * k + j) * MLKEM_N], |
897 | | &key->a[(j * k + i) * MLKEM_N], |
898 | | MLKEM_N * 2); |
899 | | } |
900 | | } |
901 | | } |
902 | | else |
903 | | #endif /* WOLFSSL_MLKEM_CACHE_A */ |
904 | 0 | if (ret == 0) { |
905 | | /* Generate the transposed matrix. |
906 | | * Step 4-8: generate matrix A_hat */ |
907 | 0 | ret = mlkem_gen_matrix(&key->prf, a, (int)k, key->pubSeed, 1); |
908 | 0 | } |
909 | 0 | if (ret == 0) { |
910 | | /* Assign remaining allocated dynamic memory to pointers. |
911 | | * y (b) | a (m) | mu (p) | e1 (p) | e2 (v) | u (v) | v (p) */ |
912 | 0 | u = e2 + MLKEM_N; |
913 | 0 | v = u + MLKEM_N * k; |
914 | | |
915 | | /* Perform encapsulation maths. |
916 | | * Steps 18-19, 21: calculate u and v */ |
917 | 0 | mlkem_encapsulate(key->pub, u, v, a, y, e1, e2, mu, (int)k); |
918 | 0 | } |
919 | | #else /* WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM */ |
920 | | if (ret == 0) { |
921 | | /* Assign allocated dynamic memory to pointers. |
922 | | * y (v) | a (v) | u (v) */ |
923 | | a = y + MLKEM_N * k; |
924 | | |
925 | | /* Initialize the PRF for use in the noise generation. */ |
926 | | mlkem_prf_init(&key->prf); |
927 | | /* Generate noise using PRF. |
928 | | * Steps 9-12: generate y */ |
929 | | ret = mlkem_get_noise(&key->prf, (int)k, y, NULL, NULL, r); |
930 | | } |
931 | | if (ret == 0) { |
932 | | /* Assign remaining allocated dynamic memory to pointers. |
933 | | * y (v) | at (v) | u (v) */ |
934 | | u = a + MLKEM_N * k; |
935 | | v = a; |
936 | | |
937 | | /* Perform encapsulation maths. |
938 | | * Steps 13-17: generate e_1 and e_2 |
939 | | * Steps 18-19, 21: calculate u and v */ |
940 | | ret = mlkem_encapsulate_seeds(key->pub, &key->prf, u, a, y, (int)k, m, |
941 | | key->pubSeed, r); |
942 | | } |
943 | | #endif /* WOLFSSL_MLKEM_ENCAPSULATE_SMALL_MEM */ |
944 | |
|
945 | 0 | if (ret == 0) { |
946 | 0 | byte* c1 = c; |
947 | 0 | byte* c2 = c + compVecSz; |
948 | |
|
949 | 0 | #if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512) |
950 | 0 | if (k == WC_ML_KEM_512_K) { |
951 | | /* Step 22: c_1 <- ByteEncode_d_u(Compress_d_u(u)) */ |
952 | 0 | mlkem_vec_compress_10(c1, u, k); |
953 | | /* Step 23: c_2 <- ByteEncode_d_v(Compress_d_v(v)) */ |
954 | 0 | mlkem_compress_4(c2, v); |
955 | | /* Step 24: return c <- (c_1||c_2) */ |
956 | 0 | } |
957 | 0 | #endif |
958 | 0 | #if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768) |
959 | 0 | if (k == WC_ML_KEM_768_K) { |
960 | | /* Step 22: c_1 <- ByteEncode_d_u(Compress_d_u(u)) */ |
961 | 0 | mlkem_vec_compress_10(c1, u, k); |
962 | | /* Step 23: c_2 <- ByteEncode_d_v(Compress_d_v(v)) */ |
963 | 0 | mlkem_compress_4(c2, v); |
964 | | /* Step 24: return c <- (c_1||c_2) */ |
965 | 0 | } |
966 | 0 | #endif |
967 | 0 | #if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024) |
968 | 0 | if (k == WC_ML_KEM_1024_K) { |
969 | | /* Step 22: c_1 <- ByteEncode_d_u(Compress_d_u(u)) */ |
970 | 0 | mlkem_vec_compress_11(c1, u); |
971 | | /* Step 23: c_2 <- ByteEncode_d_v(Compress_d_v(v)) */ |
972 | 0 | mlkem_compress_5(c2, v); |
973 | | /* Step 24: return c <- (c_1||c_2) */ |
974 | 0 | } |
975 | 0 | #endif |
976 | 0 | } |
977 | |
|
978 | 0 | #ifndef WOLFSSL_NO_MALLOC |
979 | | /* Dispose of dynamic memory allocated in function. */ |
980 | 0 | XFREE(y, key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
981 | 0 | #endif |
982 | |
|
983 | 0 | return ret; |
984 | 0 | } |
985 | | #endif |
986 | | |
987 | | #if !defined(WOLFSSL_MLKEM_NO_ENCAPSULATE) || \ |
988 | | !defined(WOLFSSL_MLKEM_NO_DECAPSULATE) |
989 | | static int wc_mlkemkey_check_h(MlKemKey* key) |
990 | 0 | { |
991 | 0 | int ret = 0; |
992 | | |
993 | | /* If public hash (h) is not stored against key, calculate it |
994 | | * (fields set explicitly instead of using decode). |
995 | | * Step 1: ... H(ek)... |
996 | | */ |
997 | 0 | if ((key->flags & MLKEM_FLAG_H_SET) == 0) { |
998 | 0 | #ifndef WOLFSSL_NO_MALLOC |
999 | 0 | byte* pubKey = NULL; |
1000 | 0 | word32 pubKeyLen; |
1001 | | #else |
1002 | | byte pubKey[WC_ML_KEM_MAX_PUBLIC_KEY_SIZE]; |
1003 | | word32 pubKeyLen; |
1004 | | #endif |
1005 | | |
1006 | | /* Determine how big an encoded public key will be. */ |
1007 | 0 | ret = wc_KyberKey_PublicKeySize(key, &pubKeyLen); |
1008 | 0 | if (ret == 0) { |
1009 | 0 | #ifndef WOLFSSL_NO_MALLOC |
1010 | | /* Allocate dynamic memory for encoded public key. */ |
1011 | 0 | pubKey = (byte*)XMALLOC(pubKeyLen, key->heap, |
1012 | 0 | DYNAMIC_TYPE_TMP_BUFFER); |
1013 | 0 | if (pubKey == NULL) { |
1014 | 0 | ret = MEMORY_E; |
1015 | 0 | } |
1016 | 0 | } |
1017 | 0 | if (ret == 0) { |
1018 | 0 | #endif |
1019 | | /* Encode public key - h is hash of encoded public key. */ |
1020 | 0 | ret = wc_KyberKey_EncodePublicKey(key, pubKey, pubKeyLen); |
1021 | 0 | } |
1022 | 0 | #ifndef WOLFSSL_NO_MALLOC |
1023 | | /* Dispose of encoded public key. */ |
1024 | 0 | XFREE(pubKey, key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1025 | 0 | #endif |
1026 | 0 | } |
1027 | 0 | if ((ret == 0) && ((key->flags & MLKEM_FLAG_H_SET) == 0)) { |
1028 | | /* Implementation issue if h not cached and flag set. */ |
1029 | 0 | ret = BAD_STATE_E; |
1030 | 0 | } |
1031 | |
|
1032 | 0 | return ret; |
1033 | 0 | } |
1034 | | #endif |
1035 | | |
1036 | | #ifndef WOLFSSL_MLKEM_NO_ENCAPSULATE |
1037 | | /** |
1038 | | * Encapsulate with random number generator and derive secret. |
1039 | | * |
1040 | | * FIPS 203, Algorithm 20: ML-KEM.Encaps(ek) |
1041 | | * Uses the encapsulation key to generate a shared secret key and an associated |
1042 | | * ciphertext. |
1043 | | * 1: m <- B_32 > m is 32 random bytes |
1044 | | * 2: if m == NULL then |
1045 | | * 3: return falsum |
1046 | | * 4: end if |
1047 | | * 5: (K,c) <- ML-KEM.Encaps_internal(ek,m) |
1048 | | * > run internal encapsulation algorithm |
1049 | | * 6: return (K,c) |
1050 | | * |
1051 | | * @param [in] key Kyber key object. |
1052 | | * @param [out] c Cipher text. |
1053 | | * @param [out] k Shared secret generated. |
1054 | | * @param [in] rng Random number generator. |
1055 | | * @return 0 on success. |
1056 | | * @return BAD_FUNC_ARG when key, c, k or rng is NULL. |
1057 | | * @return NOT_COMPILED_IN when key type is not supported. |
1058 | | * @return MEMORY_E when dynamic memory allocation failed. |
1059 | | */ |
1060 | | int wc_MlKemKey_Encapsulate(MlKemKey* key, unsigned char* c, unsigned char* k, |
1061 | | WC_RNG* rng) |
1062 | 0 | { |
1063 | 0 | #ifndef WC_NO_RNG |
1064 | 0 | int ret = 0; |
1065 | 0 | unsigned char m[WC_ML_KEM_ENC_RAND_SZ]; |
1066 | | |
1067 | | /* Validate parameters. */ |
1068 | 0 | if ((key == NULL) || (c == NULL) || (k == NULL) || (rng == NULL)) { |
1069 | 0 | ret = BAD_FUNC_ARG; |
1070 | 0 | } |
1071 | |
|
1072 | 0 | if (ret == 0) { |
1073 | | /* Generate seed for use with PRFs. |
1074 | | * Step 1: m is 32 random bytes |
1075 | | */ |
1076 | 0 | ret = wc_RNG_GenerateBlock(rng, m, sizeof(m)); |
1077 | | /* Step 2: ret is not zero when m == NULL. */ |
1078 | 0 | } |
1079 | 0 | if (ret == 0) { |
1080 | | /* Encapsulate with the random. |
1081 | | * Step 5: run internal encapsulation algorithm |
1082 | | */ |
1083 | 0 | ret = wc_KyberKey_EncapsulateWithRandom(key, c, k, m, sizeof(m)); |
1084 | 0 | } |
1085 | | |
1086 | | /* Step 3: return ret != 0 on falsum or internal key generation failure. */ |
1087 | 0 | return ret; |
1088 | | #else |
1089 | | (void)key; |
1090 | | (void)c; |
1091 | | (void)k; |
1092 | | (void)rng; |
1093 | | return NOT_COMPILED_IN; |
1094 | | #endif /* WC_NO_RNG */ |
1095 | 0 | } |
1096 | | |
1097 | | /** |
1098 | | * Encapsulate with random data and derive secret. |
1099 | | * |
1100 | | * FIPS 203, Algorithm 17: ML-KEM.Encaps_internal(ek, m) |
1101 | | * Uses the encapsulation key and randomness to generate a key and an associated |
1102 | | * ciphertext. |
1103 | | * Step 1: (K,r) <- G(m||H(ek)) |
1104 | | * > derive shared secret key K and randomness r |
1105 | | * Step 2: c <- K-PKE.Encrypt(ek, m, r) |
1106 | | * > encrypt m using K-PKE with randomness r |
1107 | | * Step 3: return (K,c) |
1108 | | * |
1109 | | * @param [out] c Cipher text. |
1110 | | * @param [out] k Shared secret generated. |
1111 | | * @param [in] m Random bytes. |
1112 | | * @param [in] len Length of random bytes. |
1113 | | * @return 0 on success. |
1114 | | * @return BAD_FUNC_ARG when key, c, k or m is NULL. |
1115 | | * @return BUFFER_E when len is not WC_ML_KEM_ENC_RAND_SZ. |
1116 | | * @return NOT_COMPILED_IN when key type is not supported. |
1117 | | * @return MEMORY_E when dynamic memory allocation failed. |
1118 | | */ |
1119 | | int wc_MlKemKey_EncapsulateWithRandom(MlKemKey* key, unsigned char* c, |
1120 | | unsigned char* k, const unsigned char* m, int len) |
1121 | 0 | { |
1122 | | #ifdef WOLFSSL_MLKEM_KYBER |
1123 | | byte msg[KYBER_SYM_SZ]; |
1124 | | #endif |
1125 | 0 | byte kr[2 * KYBER_SYM_SZ + 1]; |
1126 | 0 | int ret = 0; |
1127 | | #ifdef WOLFSSL_MLKEM_KYBER |
1128 | | unsigned int cSz = 0; |
1129 | | #endif |
1130 | | |
1131 | | /* Validate parameters. */ |
1132 | 0 | if ((key == NULL) || (c == NULL) || (k == NULL) || (m == NULL)) { |
1133 | 0 | ret = BAD_FUNC_ARG; |
1134 | 0 | } |
1135 | 0 | if ((ret == 0) && (len != WC_ML_KEM_ENC_RAND_SZ)) { |
1136 | 0 | ret = BUFFER_E; |
1137 | 0 | } |
1138 | |
|
1139 | | #ifdef WOLFSSL_MLKEM_KYBER |
1140 | | if (ret == 0) { |
1141 | | /* Establish parameters based on key type. */ |
1142 | | switch (key->type) { |
1143 | | #ifndef WOLFSSL_NO_ML_KEM |
1144 | | #ifdef WOLFSSL_WC_ML_KEM_512 |
1145 | | case WC_ML_KEM_512: |
1146 | | #endif |
1147 | | #ifdef WOLFSSL_WC_ML_KEM_768 |
1148 | | case WC_ML_KEM_768: |
1149 | | #endif |
1150 | | #ifdef WOLFSSL_WC_ML_KEM_1024 |
1151 | | case WC_ML_KEM_1024: |
1152 | | #endif |
1153 | | break; |
1154 | | #endif |
1155 | | #ifdef WOLFSSL_KYBER512 |
1156 | | case KYBER512: |
1157 | | cSz = KYBER512_CIPHER_TEXT_SIZE; |
1158 | | break; |
1159 | | #endif |
1160 | | #ifdef WOLFSSL_KYBER768 |
1161 | | case KYBER768: |
1162 | | cSz = KYBER768_CIPHER_TEXT_SIZE; |
1163 | | break; |
1164 | | #endif |
1165 | | #ifdef WOLFSSL_KYBER1024 |
1166 | | case KYBER1024: |
1167 | | cSz = KYBER1024_CIPHER_TEXT_SIZE; |
1168 | | break; |
1169 | | #endif |
1170 | | default: |
1171 | | /* No other values supported. */ |
1172 | | ret = NOT_COMPILED_IN; |
1173 | | break; |
1174 | | } |
1175 | | } |
1176 | | #endif |
1177 | |
|
1178 | 0 | if (ret == 0) { |
1179 | 0 | ret = wc_mlkemkey_check_h(key); |
1180 | 0 | } |
1181 | |
|
1182 | | #ifdef WOLFSSL_MLKEM_KYBER |
1183 | | if (ret == 0) { |
1184 | | #ifndef WOLFSSL_NO_ML_KEM |
1185 | | if (key->type & MLKEM_KYBER) |
1186 | | #endif |
1187 | | { |
1188 | | /* Hash random to anonymize as seed data. */ |
1189 | | ret = MLKEM_HASH_H(&key->hash, m, WC_ML_KEM_SYM_SZ, msg); |
1190 | | } |
1191 | | } |
1192 | | #endif |
1193 | 0 | if (ret == 0) { |
1194 | | /* Hash message into seed buffer. */ |
1195 | | #if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM) |
1196 | | if (key->type & MLKEM_KYBER) |
1197 | | #endif |
1198 | | #ifdef WOLFSSL_MLKEM_KYBER |
1199 | | { |
1200 | | ret = MLKEM_HASH_G(&key->hash, msg, WC_ML_KEM_SYM_SZ, key->h, |
1201 | | WC_ML_KEM_SYM_SZ, kr); |
1202 | | } |
1203 | | #endif |
1204 | | #if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM) |
1205 | | else |
1206 | | #endif |
1207 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
1208 | 0 | { |
1209 | | /* Step 1: (K,r) <- G(m||H(ek)) */ |
1210 | 0 | ret = MLKEM_HASH_G(&key->hash, m, WC_ML_KEM_SYM_SZ, key->h, |
1211 | 0 | WC_ML_KEM_SYM_SZ, kr); |
1212 | 0 | } |
1213 | 0 | #endif |
1214 | 0 | } |
1215 | |
|
1216 | 0 | if (ret == 0) { |
1217 | | /* Encapsulate the message using the key and the seed. */ |
1218 | | #if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM) |
1219 | | if (key->type & MLKEM_KYBER) |
1220 | | #endif |
1221 | | #ifdef WOLFSSL_MLKEM_KYBER |
1222 | | { |
1223 | | ret = mlkemkey_encapsulate(key, msg, kr + WC_ML_KEM_SYM_SZ, c); |
1224 | | } |
1225 | | #endif |
1226 | | #if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM) |
1227 | | else |
1228 | | #endif |
1229 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
1230 | 0 | { |
1231 | | /* Step 2: c <- K-PKE.Encrypt(ek,m,r) */ |
1232 | 0 | ret = mlkemkey_encapsulate(key, m, kr + WC_ML_KEM_SYM_SZ, c); |
1233 | 0 | } |
1234 | 0 | #endif |
1235 | 0 | } |
1236 | |
|
1237 | | #if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM) |
1238 | | if (key->type & MLKEM_KYBER) |
1239 | | #endif |
1240 | | #ifdef WOLFSSL_MLKEM_KYBER |
1241 | | { |
1242 | | if (ret == 0) { |
1243 | | /* Hash the cipher text after the seed. */ |
1244 | | ret = MLKEM_HASH_H(&key->hash, c, cSz, kr + WC_ML_KEM_SYM_SZ); |
1245 | | } |
1246 | | if (ret == 0) { |
1247 | | /* Derive the secret from the seed and hash of cipher text. */ |
1248 | | ret = MLKEM_KDF(kr, 2 * WC_ML_KEM_SYM_SZ, k, WC_ML_KEM_SS_SZ); |
1249 | | } |
1250 | | } |
1251 | | #endif |
1252 | | #if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM) |
1253 | | else |
1254 | | #endif |
1255 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
1256 | 0 | { |
1257 | 0 | if (ret == 0) { |
1258 | | /* return (K,c) */ |
1259 | 0 | XMEMCPY(k, kr, WC_ML_KEM_SS_SZ); |
1260 | 0 | } |
1261 | 0 | } |
1262 | 0 | #endif |
1263 | |
|
1264 | 0 | ForceZero(kr, sizeof(kr)); |
1265 | |
|
1266 | 0 | return ret; |
1267 | 0 | } |
1268 | | #endif /* !WOLFSSL_MLKEM_NO_ENCAPSULATE */ |
1269 | | |
1270 | | /******************************************************************************/ |
1271 | | |
1272 | | #ifndef WOLFSSL_MLKEM_NO_DECAPSULATE |
1273 | | /* Decapsulate cipher text to the message using key. |
1274 | | * |
1275 | | * FIPS 203, Algorithm 15: K-PKE.Decrypt(dk_PKE,c) |
1276 | | * Uses the decryption key to decrypt a ciphertext. |
1277 | | * 1: c1 <- c[0 : 32.d_u.k] |
1278 | | * 2: c2 <- c[32.d_u.k : 32(d_u.k + d_v)] |
1279 | | * 3: u' <- Decompress_d_u(ByteDecode_d_u(c1)) |
1280 | | * 4: v' <- Decompress_d_v(ByteDecode_d_v(c2)) |
1281 | | * ... |
1282 | | * 6: w <- v' - InvNTT(s_hat_trans o NTT(u')) |
1283 | | * 7: m <- ByteEncode_1(Compress_1(w)) |
1284 | | * 8: return m |
1285 | | * |
1286 | | * @param [in] key Kyber key object. |
1287 | | * @param [out] m Message that was encapsulated. |
1288 | | * @param [in] c Cipher text. |
1289 | | * @return 0 on success. |
1290 | | * @return NOT_COMPILED_IN when key type is not supported. |
1291 | | * @return MEMORY_E when dynamic memory allocation failed. |
1292 | | */ |
1293 | | static MLKEM_NOINLINE int mlkemkey_decapsulate(MlKemKey* key, byte* m, |
1294 | | const byte* c) |
1295 | 0 | { |
1296 | 0 | int ret = 0; |
1297 | 0 | sword16* v; |
1298 | 0 | sword16* w; |
1299 | 0 | unsigned int k = 0; |
1300 | 0 | unsigned int compVecSz; |
1301 | 0 | #if defined(WOLFSSL_SMALL_STACK) || \ |
1302 | 0 | (!defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)) |
1303 | 0 | sword16* u = NULL; |
1304 | | #else |
1305 | | sword16 u[(WC_ML_KEM_MAX_K + 1) * MLKEM_N]; |
1306 | | #endif |
1307 | | |
1308 | | /* Establish parameters based on key type. */ |
1309 | 0 | switch (key->type) { |
1310 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
1311 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
1312 | 0 | case WC_ML_KEM_512: |
1313 | 0 | k = WC_ML_KEM_512_K; |
1314 | 0 | compVecSz = WC_ML_KEM_512_POLY_VEC_COMPRESSED_SZ; |
1315 | 0 | break; |
1316 | 0 | #endif |
1317 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
1318 | 0 | case WC_ML_KEM_768: |
1319 | 0 | k = WC_ML_KEM_768_K; |
1320 | 0 | compVecSz = WC_ML_KEM_768_POLY_VEC_COMPRESSED_SZ; |
1321 | 0 | break; |
1322 | 0 | #endif |
1323 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
1324 | 0 | case WC_ML_KEM_1024: |
1325 | 0 | k = WC_ML_KEM_1024_K; |
1326 | 0 | compVecSz = WC_ML_KEM_1024_POLY_VEC_COMPRESSED_SZ; |
1327 | 0 | break; |
1328 | 0 | #endif |
1329 | 0 | #endif |
1330 | | #ifdef WOLFSSL_MLKEM_KYBER |
1331 | | #ifdef WOLFSSL_KYBER512 |
1332 | | case KYBER512: |
1333 | | k = KYBER512_K; |
1334 | | compVecSz = KYBER512_POLY_VEC_COMPRESSED_SZ; |
1335 | | break; |
1336 | | #endif |
1337 | | #ifdef WOLFSSL_KYBER768 |
1338 | | case KYBER768: |
1339 | | k = KYBER768_K; |
1340 | | compVecSz = KYBER768_POLY_VEC_COMPRESSED_SZ; |
1341 | | break; |
1342 | | #endif |
1343 | | #ifdef WOLFSSL_KYBER1024 |
1344 | | case KYBER1024: |
1345 | | k = KYBER1024_K; |
1346 | | compVecSz = KYBER1024_POLY_VEC_COMPRESSED_SZ; |
1347 | | break; |
1348 | | #endif |
1349 | | #endif |
1350 | 0 | default: |
1351 | | /* No other values supported. */ |
1352 | 0 | ret = NOT_COMPILED_IN; |
1353 | 0 | break; |
1354 | 0 | } |
1355 | | |
1356 | 0 | #if defined(WOLFSSL_SMALL_STACK) || \ |
1357 | 0 | (!defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)) |
1358 | 0 | if (ret == 0) { |
1359 | | /* Allocate dynamic memory for a vector and a polynomial. */ |
1360 | 0 | u = (sword16*)XMALLOC((k + 1) * MLKEM_N * sizeof(sword16), key->heap, |
1361 | 0 | DYNAMIC_TYPE_TMP_BUFFER); |
1362 | 0 | if (u == NULL) { |
1363 | 0 | ret = MEMORY_E; |
1364 | 0 | } |
1365 | 0 | } |
1366 | 0 | #endif |
1367 | 0 | if (ret == 0) { |
1368 | | /* Step 1: c1 <- c[0 : 32.d_u.k] */ |
1369 | 0 | const byte* c1 = c; |
1370 | | /* Step 2: c2 <- c[32.d_u.k : 32(d_u.k + d_v)] */ |
1371 | 0 | const byte* c2 = c + compVecSz; |
1372 | | |
1373 | | /* Assign allocated dynamic memory to pointers. |
1374 | | * u (v) | v (p) */ |
1375 | 0 | v = u + k * MLKEM_N; |
1376 | 0 | w = u; |
1377 | |
|
1378 | 0 | #if defined(WOLFSSL_KYBER512) || defined(WOLFSSL_WC_ML_KEM_512) |
1379 | 0 | if (k == WC_ML_KEM_512_K) { |
1380 | | /* Step 3: u' <- Decompress_d_u(ByteDecode_d_u(c1)) */ |
1381 | 0 | mlkem_vec_decompress_10(u, c1, k); |
1382 | | /* Step 4: v' <- Decompress_d_v(ByteDecode_d_v(c2)) */ |
1383 | 0 | mlkem_decompress_4(v, c2); |
1384 | 0 | } |
1385 | 0 | #endif |
1386 | 0 | #if defined(WOLFSSL_KYBER768) || defined(WOLFSSL_WC_ML_KEM_768) |
1387 | 0 | if (k == WC_ML_KEM_768_K) { |
1388 | | /* Step 3: u' <- Decompress_d_u(ByteDecode_d_u(c1)) */ |
1389 | 0 | mlkem_vec_decompress_10(u, c1, k); |
1390 | | /* Step 4: v' <- Decompress_d_v(ByteDecode_d_v(c2)) */ |
1391 | 0 | mlkem_decompress_4(v, c2); |
1392 | 0 | } |
1393 | 0 | #endif |
1394 | 0 | #if defined(WOLFSSL_KYBER1024) || defined(WOLFSSL_WC_ML_KEM_1024) |
1395 | 0 | if (k == WC_ML_KEM_1024_K) { |
1396 | | /* Step 3: u' <- Decompress_d_u(ByteDecode_d_u(c1)) */ |
1397 | 0 | mlkem_vec_decompress_11(u, c1); |
1398 | | /* Step 4: v' <- Decompress_d_v(ByteDecode_d_v(c2)) */ |
1399 | 0 | mlkem_decompress_5(v, c2); |
1400 | 0 | } |
1401 | 0 | #endif |
1402 | | |
1403 | | /* Decapsulate the cipher text into polynomial. |
1404 | | * Step 6: w <- v' - InvNTT(s_hat_trans o NTT(u')) */ |
1405 | 0 | mlkem_decapsulate(key->priv, w, u, v, (int)k); |
1406 | | |
1407 | | /* Convert the polynomial into a array of bytes (message). |
1408 | | * Step 7: m <- ByteEncode_1(Compress_1(w)) */ |
1409 | 0 | mlkem_to_msg(m, w); |
1410 | | /* Step 8: return m */ |
1411 | 0 | } |
1412 | |
|
1413 | 0 | #if defined(WOLFSSL_SMALL_STACK) || \ |
1414 | 0 | (!defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC)) |
1415 | | /* Dispose of dynamically memory allocated in function. */ |
1416 | 0 | XFREE(u, key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1417 | 0 | #endif |
1418 | |
|
1419 | 0 | return ret; |
1420 | 0 | } |
1421 | | |
1422 | | /** |
1423 | | * Decapsulate the cipher text to calculate the shared secret. |
1424 | | * |
1425 | | * Validates the cipher text by encapsulating and comparing with data passed in. |
1426 | | * |
1427 | | * FIPS 203, Algorithm 21: ML-KEM.Decaps(dk, c) |
1428 | | * Uses the decapsulation key to produce a shared secret key from a ciphertext. |
1429 | | * 1: K' <- ML-KEM.Decaps_internal(dk,c) |
1430 | | * > run internal decapsulation algorithm |
1431 | | * 2: return K' |
1432 | | * |
1433 | | * FIPS 203, Algorithm 18: ML-KEM.Decaps_internal(dk, c) |
1434 | | * Uses the decapsulation key to produce a shared secret key from a ciphertext. |
1435 | | * ... |
1436 | | * 1: dk_PKE <- dk[0 : 384k] |
1437 | | * > extract (from KEM decaps key) the PKE decryption key |
1438 | | * 2: ek_PKE <- dk[384k : 768k + 32] |
1439 | | * > extract PKE encryption key |
1440 | | * 3: h <- dk[768k + 32 : 768k + 64] |
1441 | | * > extract hash of PKE encryption key |
1442 | | * 4: z <- dk[768k + 64 : 768k + 96] |
1443 | | * > extract implicit rejection value |
1444 | | * 5: m' <- K-PKE.Decrypt(dk_PKE, c) > decrypt ciphertext |
1445 | | * 6: (K', r') <- G(m'||h) |
1446 | | * 7: K_bar <- J(z||c) |
1447 | | * 8: c' <- K-PKE.Encrypt(ek_PKE, m', r') |
1448 | | * > re-encrypt using the derived randomness r' |
1449 | | * 9: if c != c' then |
1450 | | * 10: K' <- K_bar |
1451 | | * > if ciphertexts do not match, "implicitly reject" |
1452 | | * 11: end if |
1453 | | * 12: return K' |
1454 | | * |
1455 | | * @param [in] key Kyber key object. |
1456 | | * @param [out] ss Shared secret. |
1457 | | * @param [in] ct Cipher text. |
1458 | | * @param [in] len Length of cipher text. |
1459 | | * @return 0 on success. |
1460 | | * @return BAD_FUNC_ARG when key, ss or ct are NULL. |
1461 | | * @return NOT_COMPILED_IN when key type is not supported. |
1462 | | * @return BUFFER_E when len is not the length of cipher text for the key type. |
1463 | | * @return MEMORY_E when dynamic memory allocation failed. |
1464 | | */ |
1465 | | int wc_MlKemKey_Decapsulate(MlKemKey* key, unsigned char* ss, |
1466 | | const unsigned char* ct, word32 len) |
1467 | 0 | { |
1468 | 0 | byte msg[WC_ML_KEM_SYM_SZ]; |
1469 | 0 | byte kr[2 * WC_ML_KEM_SYM_SZ + 1]; |
1470 | 0 | int ret = 0; |
1471 | 0 | unsigned int ctSz = 0; |
1472 | 0 | unsigned int i = 0; |
1473 | 0 | int fail = 0; |
1474 | 0 | #if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC) |
1475 | 0 | byte* cmp = NULL; |
1476 | | #else |
1477 | | byte cmp[WC_ML_KEM_MAX_CIPHER_TEXT_SIZE]; |
1478 | | #endif |
1479 | | |
1480 | | /* Validate parameters. */ |
1481 | 0 | if ((key == NULL) || (ss == NULL) || (ct == NULL)) { |
1482 | 0 | ret = BAD_FUNC_ARG; |
1483 | 0 | } |
1484 | |
|
1485 | 0 | if (ret == 0) { |
1486 | | /* Establish cipher text size based on key type. */ |
1487 | 0 | switch (key->type) { |
1488 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
1489 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
1490 | 0 | case WC_ML_KEM_512: |
1491 | 0 | ctSz = WC_ML_KEM_512_CIPHER_TEXT_SIZE; |
1492 | 0 | break; |
1493 | 0 | #endif |
1494 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
1495 | 0 | case WC_ML_KEM_768: |
1496 | 0 | ctSz = WC_ML_KEM_768_CIPHER_TEXT_SIZE; |
1497 | 0 | break; |
1498 | 0 | #endif |
1499 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
1500 | 0 | case WC_ML_KEM_1024: |
1501 | 0 | ctSz = WC_ML_KEM_1024_CIPHER_TEXT_SIZE; |
1502 | 0 | break; |
1503 | 0 | #endif |
1504 | 0 | #endif |
1505 | | #ifdef WOLFSSL_MLKEM_KYBER |
1506 | | #ifdef WOLFSSL_KYBER512 |
1507 | | case KYBER512: |
1508 | | ctSz = KYBER512_CIPHER_TEXT_SIZE; |
1509 | | break; |
1510 | | #endif |
1511 | | #ifdef WOLFSSL_KYBER768 |
1512 | | case KYBER768: |
1513 | | ctSz = KYBER768_CIPHER_TEXT_SIZE; |
1514 | | break; |
1515 | | #endif |
1516 | | #ifdef WOLFSSL_KYBER1024 |
1517 | | case KYBER1024: |
1518 | | ctSz = KYBER1024_CIPHER_TEXT_SIZE; |
1519 | | break; |
1520 | | #endif |
1521 | | #endif |
1522 | 0 | default: |
1523 | | /* No other values supported. */ |
1524 | 0 | ret = NOT_COMPILED_IN; |
1525 | 0 | break; |
1526 | 0 | } |
1527 | 0 | } |
1528 | | |
1529 | | /* Ensure the cipher text passed in is the correct size. */ |
1530 | 0 | if ((ret == 0) && (len != ctSz)) { |
1531 | 0 | ret = BUFFER_E; |
1532 | 0 | } |
1533 | |
|
1534 | 0 | #if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC) |
1535 | 0 | if (ret == 0) { |
1536 | | /* Allocate memory for cipher text that is generated. */ |
1537 | 0 | cmp = (byte*)XMALLOC(ctSz, key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1538 | 0 | if (cmp == NULL) { |
1539 | 0 | ret = MEMORY_E; |
1540 | 0 | } |
1541 | 0 | } |
1542 | 0 | #endif |
1543 | |
|
1544 | 0 | if (ret == 0) { |
1545 | | /* Decapsulate the cipher text. */ |
1546 | 0 | ret = mlkemkey_decapsulate(key, msg, ct); |
1547 | 0 | } |
1548 | 0 | if (ret == 0) { |
1549 | | /* Check we have H, hash of public, set. */ |
1550 | 0 | ret = wc_mlkemkey_check_h(key); |
1551 | 0 | } |
1552 | 0 | if (ret == 0) { |
1553 | | /* Hash message into seed buffer. */ |
1554 | 0 | ret = MLKEM_HASH_G(&key->hash, msg, WC_ML_KEM_SYM_SZ, key->h, |
1555 | 0 | WC_ML_KEM_SYM_SZ, kr); |
1556 | 0 | } |
1557 | 0 | if (ret == 0) { |
1558 | | /* Encapsulate the message. */ |
1559 | 0 | ret = mlkemkey_encapsulate(key, msg, kr + WC_ML_KEM_SYM_SZ, cmp); |
1560 | 0 | } |
1561 | 0 | if (ret == 0) { |
1562 | | /* Compare generated cipher text with that passed in. */ |
1563 | 0 | fail = mlkem_cmp(ct, cmp, (int)ctSz); |
1564 | |
|
1565 | | #if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM) |
1566 | | if (key->type & MLKEM_KYBER) |
1567 | | #endif |
1568 | | #ifdef WOLFSSL_MLKEM_KYBER |
1569 | | { |
1570 | | /* Hash the cipher text after the seed. */ |
1571 | | ret = MLKEM_HASH_H(&key->hash, ct, ctSz, kr + WC_ML_KEM_SYM_SZ); |
1572 | | if (ret == 0) { |
1573 | | /* Change seed to z on comparison failure. */ |
1574 | | for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) { |
1575 | | kr[i] ^= (kr[i] ^ key->z[i]) & fail; |
1576 | | } |
1577 | | |
1578 | | /* Derive the secret from the seed and hash of cipher text. */ |
1579 | | ret = MLKEM_KDF(kr, 2 * WC_ML_KEM_SYM_SZ, ss, WC_ML_KEM_SS_SZ); |
1580 | | } |
1581 | | } |
1582 | | #endif |
1583 | | #if defined(WOLFSSL_MLKEM_KYBER) && !defined(WOLFSSL_NO_ML_KEM) |
1584 | | else |
1585 | | #endif |
1586 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
1587 | 0 | { |
1588 | 0 | ret = mlkem_derive_secret(&key->prf, key->z, ct, ctSz, msg); |
1589 | 0 | if (ret == 0) { |
1590 | | /* Set secret to kr or fake secret on comparison failure. */ |
1591 | 0 | for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) { |
1592 | 0 | ss[i] = (byte)(kr[i] ^ ((kr[i] ^ msg[i]) & fail)); |
1593 | 0 | } |
1594 | 0 | } |
1595 | 0 | } |
1596 | 0 | #endif |
1597 | 0 | } |
1598 | |
|
1599 | 0 | #if !defined(USE_INTEL_SPEEDUP) && !defined(WOLFSSL_NO_MALLOC) |
1600 | | /* Dispose of dynamic memory allocated in function. */ |
1601 | 0 | if (key != NULL) { |
1602 | 0 | XFREE(cmp, key->heap, DYNAMIC_TYPE_TMP_BUFFER); |
1603 | 0 | } |
1604 | 0 | #endif |
1605 | |
|
1606 | 0 | ForceZero(msg, sizeof(msg)); |
1607 | 0 | ForceZero(kr, sizeof(kr)); |
1608 | |
|
1609 | 0 | return ret; |
1610 | 0 | } |
1611 | | #endif /* WOLFSSL_MLKEM_NO_DECAPSULATE */ |
1612 | | |
1613 | | /******************************************************************************/ |
1614 | | |
1615 | | /** |
1616 | | * Get the public key and public seed from bytes. |
1617 | | * |
1618 | | * FIPS 203, Algorithm 14: K-PKE.Encrypt(ek_PKE, m, r) |
1619 | | * ... |
1620 | | * 2: t <- ByteDecode_12(ek_PKE[0 : 384k]) |
1621 | | * 3: rho <- ek_PKE[384k : 384k + 32] |
1622 | | * ... |
1623 | | * |
1624 | | * @param [out] pub Public key - vector. |
1625 | | * @param [out] pubSeed Public seed. |
1626 | | * @param [in] p Public key data. |
1627 | | * @param [in] k Number of polynomials in vector. |
1628 | | */ |
1629 | | static void mlkemkey_decode_public(sword16* pub, byte* pubSeed, const byte* p, |
1630 | | unsigned int k) |
1631 | 0 | { |
1632 | 0 | unsigned int i; |
1633 | | |
1634 | | /* Decode public key that is vector of polynomials. |
1635 | | * Step 2: t <- ByteDecode_12(ek_PKE[0 : 384k]) */ |
1636 | 0 | mlkem_from_bytes(pub, p, (int)k); |
1637 | 0 | p += k * WC_ML_KEM_POLY_SIZE; |
1638 | | |
1639 | | /* Read public key seed. |
1640 | | * Step 3: rho <- ek_PKE[384k : 384k + 32] */ |
1641 | 0 | for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) { |
1642 | 0 | pubSeed[i] = p[i]; |
1643 | 0 | } |
1644 | 0 | } |
1645 | | |
1646 | | /** |
1647 | | * Decode the private key. |
1648 | | * |
1649 | | * Private Vector | Public Key | Public Hash | Randomizer |
1650 | | * |
1651 | | * FIPS 203, Algorithm 18: ML-KEM.Decaps_internal(dk, c) |
1652 | | * 1: dk_PKE <- dk[0 : 384k] |
1653 | | * > extract (from KEM decaps key) the PKE decryption key |
1654 | | * 2: ek_PKE <- dk[384k : 768k + 32] |
1655 | | * > extract PKE encryption key |
1656 | | * 3: h <- dk[768k + 32 : 768k + 64] |
1657 | | * > extract hash of PKE encryption key |
1658 | | * 4: z <- dk[768k + 64 : 768k + 96] |
1659 | | * > extract implicit rejection value |
1660 | | * |
1661 | | * FIPS 203, Algorithm 15: K-PKE.Decrypt(dk_PKE, c) |
1662 | | * ... |
1663 | | * 5: s_hat <- ByteDecode_12(dk_PKE) |
1664 | | * ... |
1665 | | * |
1666 | | * @param [in, out] key Kyber key object. |
1667 | | * @param [in] in Buffer holding encoded key. |
1668 | | * @param [in] len Length of data in buffer. |
1669 | | * @return 0 on success. |
1670 | | * @return BAD_FUNC_ARG when key or in is NULL. |
1671 | | * @return NOT_COMPILED_IN when key type is not supported. |
1672 | | * @return BUFFER_E when len is not the correct size. |
1673 | | */ |
1674 | | int wc_MlKemKey_DecodePrivateKey(MlKemKey* key, const unsigned char* in, |
1675 | | word32 len) |
1676 | 0 | { |
1677 | 0 | int ret = 0; |
1678 | 0 | word32 privLen = 0; |
1679 | 0 | word32 pubLen = 0; |
1680 | 0 | unsigned int k = 0; |
1681 | 0 | const unsigned char* p = in; |
1682 | | |
1683 | | /* Validate parameters. */ |
1684 | 0 | if ((key == NULL) || (in == NULL)) { |
1685 | 0 | ret = BAD_FUNC_ARG; |
1686 | 0 | } |
1687 | |
|
1688 | 0 | if (ret == 0) { |
1689 | | /* Establish parameters based on key type. */ |
1690 | 0 | switch (key->type) { |
1691 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
1692 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
1693 | 0 | case WC_ML_KEM_512: |
1694 | 0 | k = WC_ML_KEM_512_K; |
1695 | 0 | privLen = WC_ML_KEM_512_PRIVATE_KEY_SIZE; |
1696 | 0 | pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE; |
1697 | 0 | break; |
1698 | 0 | #endif |
1699 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
1700 | 0 | case WC_ML_KEM_768: |
1701 | 0 | k = WC_ML_KEM_768_K; |
1702 | 0 | privLen = WC_ML_KEM_768_PRIVATE_KEY_SIZE; |
1703 | 0 | pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE; |
1704 | 0 | break; |
1705 | 0 | #endif |
1706 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
1707 | 0 | case WC_ML_KEM_1024: |
1708 | 0 | k = WC_ML_KEM_1024_K; |
1709 | 0 | privLen = WC_ML_KEM_1024_PRIVATE_KEY_SIZE; |
1710 | 0 | pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE; |
1711 | 0 | break; |
1712 | 0 | #endif |
1713 | 0 | #endif |
1714 | | #ifdef WOLFSSL_MLKEM_KYBER |
1715 | | #ifdef WOLFSSL_KYBER512 |
1716 | | case KYBER512: |
1717 | | k = KYBER512_K; |
1718 | | privLen = KYBER512_PRIVATE_KEY_SIZE; |
1719 | | pubLen = KYBER512_PUBLIC_KEY_SIZE; |
1720 | | break; |
1721 | | #endif |
1722 | | #ifdef WOLFSSL_KYBER768 |
1723 | | case KYBER768: |
1724 | | k = KYBER768_K; |
1725 | | privLen = KYBER768_PRIVATE_KEY_SIZE; |
1726 | | pubLen = KYBER768_PUBLIC_KEY_SIZE; |
1727 | | break; |
1728 | | #endif |
1729 | | #ifdef WOLFSSL_KYBER1024 |
1730 | | case KYBER1024: |
1731 | | k = KYBER1024_K; |
1732 | | privLen = KYBER1024_PRIVATE_KEY_SIZE; |
1733 | | pubLen = KYBER1024_PUBLIC_KEY_SIZE; |
1734 | | break; |
1735 | | #endif |
1736 | | #endif |
1737 | 0 | default: |
1738 | | /* No other values supported. */ |
1739 | 0 | ret = NOT_COMPILED_IN; |
1740 | 0 | break; |
1741 | 0 | } |
1742 | 0 | } |
1743 | | /* Ensure the data is the correct length for the key type. */ |
1744 | 0 | if ((ret == 0) && (len != privLen)) { |
1745 | 0 | ret = BUFFER_E; |
1746 | 0 | } |
1747 | |
|
1748 | 0 | if (ret == 0) { |
1749 | | /* Decode private key that is vector of polynomials. |
1750 | | * Alg 18 Step 1: dk_PKE <- dk[0 : 384k] |
1751 | | * Alg 15 Step 5: s_hat <- ByteDecode_12(dk_PKE) */ |
1752 | 0 | mlkem_from_bytes(key->priv, p, (int)k); |
1753 | 0 | p += k * WC_ML_KEM_POLY_SIZE; |
1754 | | |
1755 | | /* Decode the public key that is after the private key. */ |
1756 | 0 | mlkemkey_decode_public(key->pub, key->pubSeed, p, k); |
1757 | | /* Compute the hash of the public key. */ |
1758 | 0 | ret = MLKEM_HASH_H(&key->hash, p, pubLen, key->h); |
1759 | 0 | if (ret != 0) { |
1760 | 0 | ForceZero(key->priv, k * MLKEM_N); |
1761 | 0 | } |
1762 | 0 | } |
1763 | |
|
1764 | 0 | if (ret == 0) { |
1765 | 0 | p += pubLen; |
1766 | | /* Compare computed public key hash with stored hash */ |
1767 | 0 | if (XMEMCMP(key->h, p, WC_ML_KEM_SYM_SZ) != 0) { |
1768 | 0 | ForceZero(key->priv, k * MLKEM_N); |
1769 | 0 | ret = MLKEM_PUB_HASH_E; |
1770 | 0 | } |
1771 | 0 | } |
1772 | |
|
1773 | 0 | if (ret == 0) { |
1774 | | /* Copy the hash of the encoded public key that is after public key. */ |
1775 | 0 | XMEMCPY(key->h, p, sizeof(key->h)); |
1776 | 0 | p += WC_ML_KEM_SYM_SZ; |
1777 | | /* Copy the z (randomizer) that is after hash. */ |
1778 | 0 | XMEMCPY(key->z, p, sizeof(key->z)); |
1779 | | |
1780 | | /* Set flags */ |
1781 | 0 | key->flags |= MLKEM_FLAG_H_SET | MLKEM_FLAG_BOTH_SET; |
1782 | 0 | } |
1783 | |
|
1784 | 0 | return ret; |
1785 | 0 | } |
1786 | | |
1787 | | /** |
1788 | | * Decode public key. |
1789 | | * |
1790 | | * Public vector | Public Seed |
1791 | | * |
1792 | | * @param [in, out] key Kyber key object. |
1793 | | * @param [in] in Buffer holding encoded key. |
1794 | | * @param [in] len Length of data in buffer. |
1795 | | * @return 0 on success. |
1796 | | * @return BAD_FUNC_ARG when key or in is NULL. |
1797 | | * @return NOT_COMPILED_IN when key type is not supported. |
1798 | | * @return BUFFER_E when len is not the correct size. |
1799 | | */ |
1800 | | int wc_MlKemKey_DecodePublicKey(MlKemKey* key, const unsigned char* in, |
1801 | | word32 len) |
1802 | 0 | { |
1803 | 0 | int ret = 0; |
1804 | 0 | word32 pubLen = 0; |
1805 | 0 | unsigned int k = 0; |
1806 | 0 | const unsigned char* p = in; |
1807 | |
|
1808 | 0 | if ((key == NULL) || (in == NULL)) { |
1809 | 0 | ret = BAD_FUNC_ARG; |
1810 | 0 | } |
1811 | |
|
1812 | 0 | if (ret == 0) { |
1813 | | /* Establish parameters based on key type. */ |
1814 | 0 | switch (key->type) { |
1815 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
1816 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
1817 | 0 | case WC_ML_KEM_512: |
1818 | 0 | k = WC_ML_KEM_512_K; |
1819 | 0 | pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE; |
1820 | 0 | break; |
1821 | 0 | #endif |
1822 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
1823 | 0 | case WC_ML_KEM_768: |
1824 | 0 | k = WC_ML_KEM_768_K; |
1825 | 0 | pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE; |
1826 | 0 | break; |
1827 | 0 | #endif |
1828 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
1829 | 0 | case WC_ML_KEM_1024: |
1830 | 0 | k = WC_ML_KEM_1024_K; |
1831 | 0 | pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE; |
1832 | 0 | break; |
1833 | 0 | #endif |
1834 | 0 | #endif |
1835 | | #ifdef WOLFSSL_MLKEM_KYBER |
1836 | | #ifdef WOLFSSL_KYBER512 |
1837 | | case KYBER512: |
1838 | | k = KYBER512_K; |
1839 | | pubLen = KYBER512_PUBLIC_KEY_SIZE; |
1840 | | break; |
1841 | | #endif |
1842 | | #ifdef WOLFSSL_KYBER768 |
1843 | | case KYBER768: |
1844 | | k = KYBER768_K; |
1845 | | pubLen = KYBER768_PUBLIC_KEY_SIZE; |
1846 | | break; |
1847 | | #endif |
1848 | | #ifdef WOLFSSL_KYBER1024 |
1849 | | case KYBER1024: |
1850 | | k = KYBER1024_K; |
1851 | | pubLen = KYBER1024_PUBLIC_KEY_SIZE; |
1852 | | break; |
1853 | | #endif |
1854 | | #endif |
1855 | 0 | default: |
1856 | | /* No other values supported. */ |
1857 | 0 | ret = NOT_COMPILED_IN; |
1858 | 0 | break; |
1859 | 0 | } |
1860 | 0 | } |
1861 | | /* Ensure the data is the correct length for the key type. */ |
1862 | 0 | if ((ret == 0) && (len != pubLen)) { |
1863 | 0 | ret = BUFFER_E; |
1864 | 0 | } |
1865 | |
|
1866 | 0 | if (ret == 0) { |
1867 | 0 | mlkemkey_decode_public(key->pub, key->pubSeed, p, k); |
1868 | 0 | ret = mlkem_check_public(key->pub, (int)k); |
1869 | 0 | } |
1870 | 0 | if (ret == 0) { |
1871 | | /* Calculate public hash. */ |
1872 | 0 | ret = MLKEM_HASH_H(&key->hash, in, len, key->h); |
1873 | 0 | } |
1874 | 0 | if (ret == 0) { |
1875 | | /* Record public key and public hash set. */ |
1876 | 0 | key->flags |= MLKEM_FLAG_PUB_SET | MLKEM_FLAG_H_SET; |
1877 | 0 | } |
1878 | |
|
1879 | 0 | return ret; |
1880 | 0 | } |
1881 | | |
1882 | | /** |
1883 | | * Get the size in bytes of encoded private key for the key. |
1884 | | * |
1885 | | * @param [in] key Kyber key object. |
1886 | | * @param [out] len Length of encoded private key in bytes. |
1887 | | * @return 0 on success. |
1888 | | * @return BAD_FUNC_ARG when key or len is NULL. |
1889 | | * @return NOT_COMPILED_IN when key type is not supported. |
1890 | | */ |
1891 | | int wc_MlKemKey_PrivateKeySize(MlKemKey* key, word32* len) |
1892 | 3.26k | { |
1893 | 3.26k | int ret = 0; |
1894 | | |
1895 | | /* Validate parameters. */ |
1896 | 3.26k | if ((key == NULL) || (len == NULL)) { |
1897 | 0 | ret = BAD_FUNC_ARG; |
1898 | 0 | } |
1899 | | |
1900 | 3.26k | if (ret == 0) { |
1901 | | /* Return in 'len' size of the encoded private key for the type of this |
1902 | | * key. */ |
1903 | 3.26k | switch (key->type) { |
1904 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
1905 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
1906 | 0 | case WC_ML_KEM_512: |
1907 | 0 | *len = WC_ML_KEM_512_PRIVATE_KEY_SIZE; |
1908 | 0 | break; |
1909 | 0 | #endif |
1910 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
1911 | 3.22k | case WC_ML_KEM_768: |
1912 | 3.22k | *len = WC_ML_KEM_768_PRIVATE_KEY_SIZE; |
1913 | 3.22k | break; |
1914 | 0 | #endif |
1915 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
1916 | 33 | case WC_ML_KEM_1024: |
1917 | 33 | *len = WC_ML_KEM_1024_PRIVATE_KEY_SIZE; |
1918 | 33 | break; |
1919 | 0 | #endif |
1920 | 0 | #endif |
1921 | | #ifdef WOLFSSL_MLKEM_KYBER |
1922 | | #ifdef WOLFSSL_KYBER512 |
1923 | | case KYBER512: |
1924 | | *len = KYBER512_PRIVATE_KEY_SIZE; |
1925 | | break; |
1926 | | #endif |
1927 | | #ifdef WOLFSSL_KYBER768 |
1928 | | case KYBER768: |
1929 | | *len = KYBER768_PRIVATE_KEY_SIZE; |
1930 | | break; |
1931 | | #endif |
1932 | | #ifdef WOLFSSL_KYBER1024 |
1933 | | case KYBER1024: |
1934 | | *len = KYBER1024_PRIVATE_KEY_SIZE; |
1935 | | break; |
1936 | | #endif |
1937 | | #endif |
1938 | 0 | default: |
1939 | | /* No other values supported. */ |
1940 | 0 | ret = NOT_COMPILED_IN; |
1941 | 0 | break; |
1942 | 3.26k | } |
1943 | 3.26k | } |
1944 | | |
1945 | 3.26k | return ret; |
1946 | 3.26k | } |
1947 | | |
1948 | | /** |
1949 | | * Get the size in bytes of encoded public key for the key. |
1950 | | * |
1951 | | * @param [in] key Kyber key object. |
1952 | | * @param [out] len Length of encoded public key in bytes. |
1953 | | * @return 0 on success. |
1954 | | * @return BAD_FUNC_ARG when key or len is NULL. |
1955 | | * @return NOT_COMPILED_IN when key type is not supported. |
1956 | | */ |
1957 | | int wc_MlKemKey_PublicKeySize(MlKemKey* key, word32* len) |
1958 | 3.26k | { |
1959 | 3.26k | int ret = 0; |
1960 | | |
1961 | | /* Validate parameters. */ |
1962 | 3.26k | if ((key == NULL) || (len == NULL)) { |
1963 | 0 | ret = BAD_FUNC_ARG; |
1964 | 0 | } |
1965 | | |
1966 | 3.26k | if (ret == 0) { |
1967 | | /* Return in 'len' size of the encoded public key for the type of this |
1968 | | * key. */ |
1969 | 3.26k | switch (key->type) { |
1970 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
1971 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
1972 | 0 | case WC_ML_KEM_512: |
1973 | 0 | *len = WC_ML_KEM_512_PUBLIC_KEY_SIZE; |
1974 | 0 | break; |
1975 | 0 | #endif |
1976 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
1977 | 3.22k | case WC_ML_KEM_768: |
1978 | 3.22k | *len = WC_ML_KEM_768_PUBLIC_KEY_SIZE; |
1979 | 3.22k | break; |
1980 | 0 | #endif |
1981 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
1982 | 33 | case WC_ML_KEM_1024: |
1983 | 33 | *len = WC_ML_KEM_1024_PUBLIC_KEY_SIZE; |
1984 | 33 | break; |
1985 | 0 | #endif |
1986 | 0 | #endif |
1987 | | #ifdef WOLFSSL_MLKEM_KYBER |
1988 | | #ifdef WOLFSSL_KYBER512 |
1989 | | case KYBER512: |
1990 | | *len = KYBER512_PUBLIC_KEY_SIZE; |
1991 | | break; |
1992 | | #endif |
1993 | | #ifdef WOLFSSL_KYBER768 |
1994 | | case KYBER768: |
1995 | | *len = KYBER768_PUBLIC_KEY_SIZE; |
1996 | | break; |
1997 | | #endif |
1998 | | #ifdef WOLFSSL_KYBER1024 |
1999 | | case KYBER1024: |
2000 | | *len = KYBER1024_PUBLIC_KEY_SIZE; |
2001 | | break; |
2002 | | #endif |
2003 | | #endif |
2004 | 0 | default: |
2005 | | /* No other values supported. */ |
2006 | 0 | ret = NOT_COMPILED_IN; |
2007 | 0 | break; |
2008 | 3.26k | } |
2009 | 3.26k | } |
2010 | | |
2011 | 3.26k | return ret; |
2012 | 3.26k | } |
2013 | | |
2014 | | /** |
2015 | | * Encode the private key. |
2016 | | * |
2017 | | * Private Vector | Public Key | Public Hash | Randomizer |
2018 | | * |
2019 | | * FIPS 203, Algorithm 16: ML-KEM.KeyGen_internal(d,z) |
2020 | | * ... |
2021 | | * 3: dk <- (dk_PKE||ek||H(ek)||z) |
2022 | | * ... |
2023 | | * FIPS 203, Algorithm 13: K-PKE.KeyGen(d) |
2024 | | * ... |
2025 | | * 20: dk_PKE <- ByteEncode_12(s_hat) |
2026 | | * ... |
2027 | | * |
2028 | | * @param [in] key Kyber key object. |
2029 | | * @param [out] out Buffer to hold data. |
2030 | | * @param [in] len Size of buffer in bytes. |
2031 | | * @return 0 on success. |
2032 | | * @return BAD_FUNC_ARG when key or out is NULL or private/public key not |
2033 | | * available. |
2034 | | * @return NOT_COMPILED_IN when key type is not supported. |
2035 | | */ |
2036 | | int wc_MlKemKey_EncodePrivateKey(MlKemKey* key, unsigned char* out, word32 len) |
2037 | 3.25k | { |
2038 | 3.25k | int ret = 0; |
2039 | 3.25k | unsigned int k = 0; |
2040 | 3.25k | unsigned int pubLen = 0; |
2041 | 3.25k | unsigned int privLen = 0; |
2042 | 3.25k | unsigned char* p = out; |
2043 | | |
2044 | 3.25k | if ((key == NULL) || (out == NULL)) { |
2045 | 0 | ret = BAD_FUNC_ARG; |
2046 | 0 | } |
2047 | 3.25k | if ((ret == 0) && |
2048 | 3.25k | ((key->flags & MLKEM_FLAG_BOTH_SET) != MLKEM_FLAG_BOTH_SET)) { |
2049 | 0 | ret = BAD_FUNC_ARG; |
2050 | 0 | } |
2051 | | |
2052 | 3.25k | if (ret == 0) { |
2053 | 3.25k | switch (key->type) { |
2054 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
2055 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
2056 | 0 | case WC_ML_KEM_512: |
2057 | 0 | k = WC_ML_KEM_512_K; |
2058 | 0 | pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE; |
2059 | 0 | privLen = WC_ML_KEM_512_PRIVATE_KEY_SIZE; |
2060 | 0 | break; |
2061 | 0 | #endif |
2062 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
2063 | 3.21k | case WC_ML_KEM_768: |
2064 | 3.21k | k = WC_ML_KEM_768_K; |
2065 | 3.21k | pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE; |
2066 | 3.21k | privLen = WC_ML_KEM_768_PRIVATE_KEY_SIZE; |
2067 | 3.21k | break; |
2068 | 0 | #endif |
2069 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
2070 | 33 | case WC_ML_KEM_1024: |
2071 | 33 | k = WC_ML_KEM_1024_K; |
2072 | 33 | pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE; |
2073 | 33 | privLen = WC_ML_KEM_1024_PRIVATE_KEY_SIZE; |
2074 | 33 | break; |
2075 | 0 | #endif |
2076 | 0 | #endif |
2077 | | #ifdef WOLFSSL_MLKEM_KYBER |
2078 | | #ifdef WOLFSSL_KYBER512 |
2079 | | case KYBER512: |
2080 | | k = KYBER512_K; |
2081 | | pubLen = KYBER512_PUBLIC_KEY_SIZE; |
2082 | | privLen = KYBER512_PRIVATE_KEY_SIZE; |
2083 | | break; |
2084 | | #endif |
2085 | | #ifdef WOLFSSL_KYBER768 |
2086 | | case KYBER768: |
2087 | | k = KYBER768_K; |
2088 | | pubLen = KYBER768_PUBLIC_KEY_SIZE; |
2089 | | privLen = KYBER768_PRIVATE_KEY_SIZE; |
2090 | | break; |
2091 | | #endif |
2092 | | #ifdef WOLFSSL_KYBER1024 |
2093 | | case KYBER1024: |
2094 | | k = KYBER1024_K; |
2095 | | pubLen = KYBER1024_PUBLIC_KEY_SIZE; |
2096 | | privLen = KYBER1024_PRIVATE_KEY_SIZE; |
2097 | | break; |
2098 | | #endif |
2099 | | #endif |
2100 | 0 | default: |
2101 | | /* No other values supported. */ |
2102 | 0 | ret = NOT_COMPILED_IN; |
2103 | 0 | break; |
2104 | 3.25k | } |
2105 | 3.25k | } |
2106 | | /* Check buffer is big enough for encoding. */ |
2107 | 3.25k | if ((ret == 0) && (len != privLen)) { |
2108 | 0 | ret = BUFFER_E; |
2109 | 0 | } |
2110 | | |
2111 | 3.25k | if (ret == 0) { |
2112 | | /* Encode private key that is vector of polynomials. */ |
2113 | 3.25k | mlkem_to_bytes(p, key->priv, (int)k); |
2114 | 3.25k | p += WC_ML_KEM_POLY_SIZE * k; |
2115 | | |
2116 | | /* Encode public key. */ |
2117 | 3.25k | ret = wc_KyberKey_EncodePublicKey(key, p, pubLen); |
2118 | 3.25k | p += pubLen; |
2119 | 3.25k | } |
2120 | | /* Ensure hash of public key is available. */ |
2121 | 3.25k | if ((ret == 0) && ((key->flags & MLKEM_FLAG_H_SET) == 0)) { |
2122 | 0 | ret = MLKEM_HASH_H(&key->hash, p - pubLen, pubLen, key->h); |
2123 | 0 | } |
2124 | 3.25k | if (ret == 0) { |
2125 | | /* Public hash is available. */ |
2126 | 3.25k | key->flags |= MLKEM_FLAG_H_SET; |
2127 | | /* Append public hash. */ |
2128 | 3.25k | XMEMCPY(p, key->h, sizeof(key->h)); |
2129 | 3.25k | p += WC_ML_KEM_SYM_SZ; |
2130 | | /* Append z (randomizer). */ |
2131 | 3.25k | XMEMCPY(p, key->z, sizeof(key->z)); |
2132 | 3.25k | } |
2133 | | |
2134 | 3.25k | return ret; |
2135 | 3.25k | } |
2136 | | |
2137 | | /** |
2138 | | * Encode the public key. |
2139 | | * |
2140 | | * Public vector | Public Seed |
2141 | | * |
2142 | | * FIPS 203, Algorithm 16: ML-KEM.KeyGen_internal(d,z) |
2143 | | * ... |
2144 | | * 2: ek <- ek_PKE |
2145 | | * ... |
2146 | | * FIPS 203, Algorithm 13: K-PKE.KeyGen(d) |
2147 | | * ... |
2148 | | * 19: ek_PKE <- ByteEncode_12(t_hat)||rho |
2149 | | * ... |
2150 | | * |
2151 | | * @param [in] key Kyber key object. |
2152 | | * @param [out] out Buffer to hold data. |
2153 | | * @param [in] len Size of buffer in bytes. |
2154 | | * @return 0 on success. |
2155 | | * @return BAD_FUNC_ARG when key or out is NULL or public key not available. |
2156 | | * @return NOT_COMPILED_IN when key type is not supported. |
2157 | | */ |
2158 | | int wc_MlKemKey_EncodePublicKey(MlKemKey* key, unsigned char* out, word32 len) |
2159 | 6.50k | { |
2160 | 6.50k | int ret = 0; |
2161 | 6.50k | unsigned int k = 0; |
2162 | 6.50k | unsigned int pubLen = 0; |
2163 | 6.50k | unsigned char* p = out; |
2164 | | |
2165 | 6.50k | if ((key == NULL) || (out == NULL)) { |
2166 | 0 | ret = BAD_FUNC_ARG; |
2167 | 0 | } |
2168 | 6.50k | if ((ret == 0) && |
2169 | 6.50k | ((key->flags & MLKEM_FLAG_PUB_SET) != MLKEM_FLAG_PUB_SET)) { |
2170 | 0 | ret = BAD_FUNC_ARG; |
2171 | 0 | } |
2172 | | |
2173 | 6.50k | if (ret == 0) { |
2174 | 6.50k | switch (key->type) { |
2175 | 0 | #ifndef WOLFSSL_NO_ML_KEM |
2176 | 0 | #ifdef WOLFSSL_WC_ML_KEM_512 |
2177 | 0 | case WC_ML_KEM_512: |
2178 | 0 | k = WC_ML_KEM_512_K; |
2179 | 0 | pubLen = WC_ML_KEM_512_PUBLIC_KEY_SIZE; |
2180 | 0 | break; |
2181 | 0 | #endif |
2182 | 0 | #ifdef WOLFSSL_WC_ML_KEM_768 |
2183 | 6.43k | case WC_ML_KEM_768: |
2184 | 6.43k | k = WC_ML_KEM_768_K; |
2185 | 6.43k | pubLen = WC_ML_KEM_768_PUBLIC_KEY_SIZE; |
2186 | 6.43k | break; |
2187 | 0 | #endif |
2188 | 0 | #ifdef WOLFSSL_WC_ML_KEM_1024 |
2189 | 66 | case WC_ML_KEM_1024: |
2190 | 66 | k = WC_ML_KEM_1024_K; |
2191 | 66 | pubLen = WC_ML_KEM_1024_PUBLIC_KEY_SIZE; |
2192 | 66 | break; |
2193 | 0 | #endif |
2194 | 0 | #endif |
2195 | | #ifdef WOLFSSL_MLKEM_KYBER |
2196 | | #ifdef WOLFSSL_KYBER512 |
2197 | | case KYBER512: |
2198 | | k = KYBER512_K; |
2199 | | pubLen = KYBER512_PUBLIC_KEY_SIZE; |
2200 | | break; |
2201 | | #endif |
2202 | | #ifdef WOLFSSL_KYBER768 |
2203 | | case KYBER768: |
2204 | | k = KYBER768_K; |
2205 | | pubLen = KYBER768_PUBLIC_KEY_SIZE; |
2206 | | break; |
2207 | | #endif |
2208 | | #ifdef WOLFSSL_KYBER1024 |
2209 | | case KYBER1024: |
2210 | | k = KYBER1024_K; |
2211 | | pubLen = KYBER1024_PUBLIC_KEY_SIZE; |
2212 | | break; |
2213 | | #endif |
2214 | | #endif |
2215 | 0 | default: |
2216 | | /* No other values supported. */ |
2217 | 0 | ret = NOT_COMPILED_IN; |
2218 | 0 | break; |
2219 | 6.50k | } |
2220 | 6.50k | } |
2221 | | /* Check buffer is big enough for encoding. */ |
2222 | 6.50k | if ((ret == 0) && (len != pubLen)) { |
2223 | 0 | ret = BUFFER_E; |
2224 | 0 | } |
2225 | | |
2226 | 6.50k | if (ret == 0) { |
2227 | 6.50k | int i; |
2228 | | |
2229 | | /* Encode public key polynomial by polynomial. */ |
2230 | 6.50k | mlkem_to_bytes(p, key->pub, (int)k); |
2231 | 6.50k | p += k * WC_ML_KEM_POLY_SIZE; |
2232 | | |
2233 | | /* Append public seed. */ |
2234 | 214k | for (i = 0; i < WC_ML_KEM_SYM_SZ; i++) { |
2235 | 208k | p[i] = key->pubSeed[i]; |
2236 | 208k | } |
2237 | | |
2238 | | /* Make sure public hash is set. */ |
2239 | 6.50k | if ((key->flags & MLKEM_FLAG_H_SET) == 0) { |
2240 | 3.25k | ret = MLKEM_HASH_H(&key->hash, out, len, key->h); |
2241 | 3.25k | } |
2242 | 6.50k | } |
2243 | 6.50k | if (ret == 0) { |
2244 | | /* Public hash is set. */ |
2245 | 6.50k | key->flags |= MLKEM_FLAG_H_SET; |
2246 | 6.50k | } |
2247 | | |
2248 | 6.50k | return ret; |
2249 | 6.50k | } |
2250 | | |
2251 | | #endif /* WOLFSSL_WC_MLKEM */ |