kyber.c (12485B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this 3 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 #ifdef FREEBL_NO_DEPEND 6 #include "stubs.h" 7 #endif 8 9 #include <stdbool.h> 10 11 #include "blapi.h" 12 #include "secerr.h" 13 #include "secitem.h" 14 15 #include "kyber-pqcrystals-ref.h" 16 #include "kyber.h" 17 #include "verified/internal/libcrux_core.h" 18 #include "verified/libcrux_mlkem768_portable.h" 19 #include "verified/libcrux_mlkem768.h" 20 #include "verified/libcrux_mlkem1024_portable.h" 21 #include "verified/libcrux_mlkem1024.h" 22 23 /* Consistency check between kyber-pqcrystals-ref.h and kyber.h */ 24 PR_STATIC_ASSERT(KYBER768_PUBLIC_KEY_BYTES == pqcrystals_kyber768_PUBLICKEYBYTES); 25 PR_STATIC_ASSERT(KYBER768_PRIVATE_KEY_BYTES == pqcrystals_kyber768_SECRETKEYBYTES); 26 PR_STATIC_ASSERT(KYBER768_CIPHERTEXT_BYTES == pqcrystals_kyber768_CIPHERTEXTBYTES); 27 PR_STATIC_ASSERT(KYBER_SHARED_SECRET_BYTES == pqcrystals_kyber768_BYTES); 28 PR_STATIC_ASSERT(KYBER_KEYPAIR_COIN_BYTES == pqcrystals_kyber768_KEYPAIRCOINBYTES); 29 PR_STATIC_ASSERT(KYBER_ENC_COIN_BYTES == pqcrystals_kyber768_ENCCOINBYTES); 30 31 /* Consistency check between libcrux_mlkem768_portable.h and kyber.h */ 32 PR_STATIC_ASSERT(KYBER768_PUBLIC_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM768_CPA_PKE_PUBLIC_KEY_SIZE); 33 PR_STATIC_ASSERT(KYBER768_PRIVATE_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM768_SECRET_KEY_SIZE); 34 PR_STATIC_ASSERT(KYBER768_CIPHERTEXT_BYTES == LIBCRUX_ML_KEM_MLKEM768_CPA_PKE_CIPHERTEXT_SIZE); 35 PR_STATIC_ASSERT(KYBER_SHARED_SECRET_BYTES == LIBCRUX_ML_KEM_CONSTANTS_SHARED_SECRET_SIZE); 36 PR_STATIC_ASSERT(KYBER_KEYPAIR_COIN_BYTES == 64); 37 PR_STATIC_ASSERT(KYBER_ENC_COIN_BYTES == 32); 38 39 /* Consistency check between libcrux_mlkem1024_portable.h and kyber.h */ 40 PR_STATIC_ASSERT(MLKEM1024_PUBLIC_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_PUBLIC_KEY_SIZE); 41 PR_STATIC_ASSERT(MLKEM1024_PRIVATE_KEY_BYTES == LIBCRUX_ML_KEM_MLKEM1024_SECRET_KEY_SIZE); 42 PR_STATIC_ASSERT(MLKEM1024_CIPHERTEXT_BYTES == LIBCRUX_ML_KEM_MLKEM1024_CPA_PKE_CIPHERTEXT_SIZE); 43 44 static bool 45 valid_params(KyberParams params) 46 { 47 switch (params) { 48 #ifndef NSS_DISABLE_KYBER 49 case params_kyber768_round3: 50 case params_kyber768_round3_test_mode: 51 #endif 52 case params_ml_kem768: 53 case params_ml_kem768_test_mode: 54 case params_ml_kem1024: 55 case params_ml_kem1024_test_mode: 56 return true; 57 default: 58 return false; 59 } 60 } 61 62 static bool 63 valid_pubkey(KyberParams params, const SECItem *pubkey) 64 { 65 switch (params) { 66 case params_kyber768_round3: 67 case params_kyber768_round3_test_mode: 68 case params_ml_kem768: 69 case params_ml_kem768_test_mode: 70 return pubkey && pubkey->len == KYBER768_PUBLIC_KEY_BYTES; 71 case params_ml_kem1024: 72 case params_ml_kem1024_test_mode: 73 return pubkey && pubkey->len == MLKEM1024_PUBLIC_KEY_BYTES; 74 default: 75 return false; 76 } 77 } 78 79 static bool 80 valid_privkey(KyberParams params, const SECItem *privkey) 81 { 82 switch (params) { 83 case params_kyber768_round3: 84 case params_kyber768_round3_test_mode: 85 case params_ml_kem768: 86 case params_ml_kem768_test_mode: 87 return privkey && privkey->len == KYBER768_PRIVATE_KEY_BYTES; 88 case params_ml_kem1024: 89 case params_ml_kem1024_test_mode: 90 return privkey && privkey->len == MLKEM1024_PRIVATE_KEY_BYTES; 91 default: 92 return false; 93 } 94 } 95 96 static bool 97 valid_ciphertext(KyberParams params, const SECItem *ciphertext) 98 { 99 switch (params) { 100 case params_kyber768_round3: 101 case params_kyber768_round3_test_mode: 102 case params_ml_kem768: 103 case params_ml_kem768_test_mode: 104 return ciphertext && ciphertext->len == KYBER768_CIPHERTEXT_BYTES; 105 case params_ml_kem1024: 106 case params_ml_kem1024_test_mode: 107 return ciphertext && ciphertext->len == MLKEM1024_CIPHERTEXT_BYTES; 108 default: 109 return false; 110 } 111 } 112 113 static bool 114 valid_secret(KyberParams params, const SECItem *secret) 115 { 116 switch (params) { 117 case params_kyber768_round3: 118 case params_kyber768_round3_test_mode: 119 case params_ml_kem768: 120 case params_ml_kem768_test_mode: 121 case params_ml_kem1024: 122 case params_ml_kem1024_test_mode: 123 return secret && secret->len == KYBER_SHARED_SECRET_BYTES; 124 default: 125 return false; 126 } 127 } 128 129 static bool 130 valid_keypair_seed(KyberParams params, const SECItem *seed) 131 { 132 switch (params) { 133 case params_kyber768_round3: 134 case params_kyber768_round3_test_mode: 135 case params_ml_kem768: 136 case params_ml_kem768_test_mode: 137 case params_ml_kem1024: 138 case params_ml_kem1024_test_mode: 139 return !seed || seed->len == KYBER_KEYPAIR_COIN_BYTES; 140 default: 141 return false; 142 } 143 } 144 145 static bool 146 valid_enc_seed(KyberParams params, const SECItem *seed) 147 { 148 switch (params) { 149 case params_kyber768_round3: 150 case params_ml_kem768: 151 return !seed; 152 case params_kyber768_round3_test_mode: 153 case params_ml_kem768_test_mode: 154 case params_ml_kem1024: 155 case params_ml_kem1024_test_mode: 156 return !seed || seed->len == KYBER_SHARED_SECRET_BYTES; 157 default: 158 return false; 159 } 160 } 161 162 SECStatus 163 Kyber_NewKey(KyberParams params, const SECItem *keypair_seed, SECItem *privkey, SECItem *pubkey) 164 { 165 if (!valid_params(params)) { 166 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 167 return SECFailure; 168 } 169 170 if (!(valid_keypair_seed(params, keypair_seed) && valid_privkey(params, privkey) && valid_pubkey(params, pubkey))) { 171 PORT_SetError(SEC_ERROR_INVALID_ARGS); 172 return SECFailure; 173 } 174 175 uint8_t randbuf[KYBER_KEYPAIR_COIN_BYTES]; 176 uint8_t *coins; 177 if (keypair_seed) { 178 coins = keypair_seed->data; 179 } else { 180 if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) { 181 PORT_SetError(SEC_ERROR_NEED_RANDOM); 182 return SECFailure; 183 } 184 coins = randbuf; 185 } 186 NSS_CLASSIFY(coins, KYBER_KEYPAIR_COIN_BYTES); 187 if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) { 188 libcrux_ml_kem_mlkem768_MlKem768KeyPair keys = libcrux_ml_kem_mlkem768_portable_generate_key_pair(coins); 189 memcpy(pubkey->data, keys.pk.value, KYBER768_PUBLIC_KEY_BYTES); 190 memcpy(privkey->data, keys.sk.value, KYBER768_PRIVATE_KEY_BYTES); 191 } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) { 192 libcrux_ml_kem_mlkem1024_MlKem1024KeyPair keys = libcrux_ml_kem_mlkem1024_portable_generate_key_pair(coins); 193 memcpy(pubkey->data, keys.pk.value, MLKEM1024_PUBLIC_KEY_BYTES); 194 memcpy(privkey->data, keys.sk.value, MLKEM1024_PRIVATE_KEY_BYTES); 195 } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) { 196 #ifdef NSS_DISABLE_KYBER 197 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 198 return SECFailure; 199 #else 200 pqcrystals_kyber768_ref_keypair_derand(pubkey->data, privkey->data, coins); 201 #endif 202 } else { 203 /* unreachable */ 204 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 205 return SECFailure; 206 } 207 NSS_DECLASSIFY(pubkey->data, pubkey->len); 208 return SECSuccess; 209 } 210 211 SECStatus 212 Kyber_Encapsulate(KyberParams params, const SECItem *enc_seed, const SECItem *pubkey, SECItem *ciphertext, SECItem *secret) 213 { 214 if (!valid_params(params)) { 215 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 216 return SECFailure; 217 } 218 219 if (!(valid_enc_seed(params, enc_seed) && valid_pubkey(params, pubkey) && valid_ciphertext(params, ciphertext) && valid_secret(params, secret))) { 220 PORT_SetError(SEC_ERROR_INVALID_ARGS); 221 return SECFailure; 222 } 223 224 uint8_t randbuf[KYBER_ENC_COIN_BYTES]; 225 uint8_t *coins; 226 if (enc_seed) { 227 coins = enc_seed->data; 228 } else { 229 if (RNG_GenerateGlobalRandomBytes(randbuf, sizeof randbuf) != SECSuccess) { 230 PORT_SetError(SEC_ERROR_NEED_RANDOM); 231 return SECFailure; 232 } 233 coins = randbuf; 234 } 235 NSS_CLASSIFY(coins, KYBER_ENC_COIN_BYTES); 236 if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) { 237 /* shouldn't this just use the typedef im libcrux_mlkem768.h? */ 238 libcrux_ml_kem_mlkem768_MlKem768PublicKey pk_value; 239 memcpy(pk_value.value, pubkey->data, KYBER768_PUBLIC_KEY_BYTES); 240 241 bool valid_pk = libcrux_ml_kem_mlkem768_portable_validate_public_key(&pk_value); 242 if (!valid_pk) { 243 PORT_SetError(SEC_ERROR_INVALID_ARGS); 244 return SECFailure; 245 } 246 247 tuple_c2 encap = libcrux_ml_kem_mlkem768_portable_encapsulate(&pk_value, coins); 248 memcpy(ciphertext->data, encap.fst.value, KYBER768_CIPHERTEXT_BYTES); 249 memcpy(secret->data, encap.snd, KYBER_SHARED_SECRET_BYTES); 250 } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) { 251 /* shouldn't this just use the typedef im libcrux_mlkem1024.h? */ 252 libcrux_ml_kem_mlkem1024_MlKem1024PublicKey pk_value; 253 memcpy(pk_value.value, pubkey->data, MLKEM1024_PUBLIC_KEY_BYTES); 254 255 bool valid_pk = libcrux_ml_kem_mlkem1024_portable_validate_public_key(&pk_value); 256 if (!valid_pk) { 257 PORT_SetError(SEC_ERROR_INVALID_ARGS); 258 return SECFailure; 259 } 260 261 tuple_fa encap = libcrux_ml_kem_mlkem1024_portable_encapsulate(&pk_value, coins); 262 memcpy(ciphertext->data, encap.fst.value, MLKEM1024_CIPHERTEXT_BYTES); 263 memcpy(secret->data, encap.snd, KYBER_SHARED_SECRET_BYTES); 264 } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) { 265 #ifdef NSS_DISABLE_KYBER 266 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 267 return SECFailure; 268 #else 269 pqcrystals_kyber768_ref_enc_derand(ciphertext->data, secret->data, pubkey->data, coins); 270 #endif 271 } else { 272 /* unreachable */ 273 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 274 return SECFailure; 275 } 276 277 return SECSuccess; 278 } 279 280 SECStatus 281 Kyber_Decapsulate(KyberParams params, const SECItem *privkey, const SECItem *ciphertext, SECItem *secret) 282 { 283 if (!valid_params(params)) { 284 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 285 return SECFailure; 286 } 287 288 if (!(valid_privkey(params, privkey) && valid_ciphertext(params, ciphertext) && valid_secret(params, secret))) { 289 PORT_SetError(SEC_ERROR_INVALID_ARGS); 290 return SECFailure; 291 } 292 293 if (params == params_ml_kem768 || params == params_ml_kem768_test_mode) { 294 libcrux_ml_kem_mlkem768_MlKem768PrivateKey private_key; 295 memcpy(private_key.value, privkey->data, KYBER768_PRIVATE_KEY_BYTES); 296 297 libcrux_ml_kem_mlkem768_MlKem768Ciphertext cipher_text; 298 memcpy(cipher_text.value, ciphertext->data, KYBER768_CIPHERTEXT_BYTES); 299 300 bool valid = libcrux_ml_kem_mlkem768_portable_validate_private_key(&private_key, &cipher_text); 301 if (!valid) { 302 PORT_SetError(SEC_ERROR_INVALID_ARGS); 303 return SECFailure; 304 } 305 306 libcrux_ml_kem_mlkem768_portable_decapsulate(&private_key, &cipher_text, secret->data); 307 } else if (params == params_ml_kem1024 || params == params_ml_kem1024_test_mode) { 308 libcrux_ml_kem_mlkem1024_MlKem1024PrivateKey private_key; 309 memcpy(private_key.value, privkey->data, MLKEM1024_PRIVATE_KEY_BYTES); 310 311 libcrux_ml_kem_mlkem1024_MlKem1024Ciphertext cipher_text; 312 memcpy(cipher_text.value, ciphertext->data, MLKEM1024_CIPHERTEXT_BYTES); 313 314 bool valid = libcrux_ml_kem_mlkem1024_portable_validate_private_key(&private_key, &cipher_text); 315 if (!valid) { 316 PORT_SetError(SEC_ERROR_INVALID_ARGS); 317 return SECFailure; 318 } 319 320 libcrux_ml_kem_mlkem1024_portable_decapsulate(&private_key, &cipher_text, secret->data); 321 } else if (params == params_kyber768_round3 || params == params_kyber768_round3_test_mode) { 322 #ifdef NSS_DISABLE_KYBER 323 PORT_SetError(SEC_ERROR_INVALID_ALGORITHM); 324 return SECFailure; 325 #else 326 pqcrystals_kyber768_ref_dec(secret->data, ciphertext->data, privkey->data); 327 #endif 328 } else { 329 // unreachable 330 PORT_SetError(SEC_ERROR_LIBRARY_FAILURE); 331 return SECFailure; 332 } 333 334 return SECSuccess; 335 }