kyber_unittest.cc (19083B)
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 file, 3 // You can obtain one at http://mozilla.org/MPL/2.0/. 4 5 #include "gtest/gtest.h" 6 7 #include "blapi.h" 8 #include "nss_scoped_ptrs.h" 9 #include "kat/kyber768_kat.h" 10 #include "testvectors_base/test-structs.h" 11 #include "testvectors/ml-kem-keygen-vectors.h" 12 #include "testvectors/ml-kem-encap-vectors.h" 13 #include "testvectors/ml-kem-decap-vectors.h" 14 15 namespace nss_test { 16 17 size_t get_ciphertext_length(KyberParams param) { 18 size_t len = 0; 19 switch (param) { 20 case params_kyber768_round3: 21 case params_kyber768_round3_test_mode: 22 case params_ml_kem768: 23 case params_ml_kem768_test_mode: 24 len = KYBER768_CIPHERTEXT_BYTES; 25 break; 26 case params_ml_kem1024: 27 case params_ml_kem1024_test_mode: 28 len = MLKEM1024_CIPHERTEXT_BYTES; 29 break; 30 case params_kyber_invalid: 31 break; 32 } 33 return len; 34 } 35 36 size_t get_private_key_length(KyberParams param) { 37 size_t len = 0; 38 switch (param) { 39 case params_kyber768_round3: 40 case params_kyber768_round3_test_mode: 41 case params_ml_kem768: 42 case params_ml_kem768_test_mode: 43 len = KYBER768_PRIVATE_KEY_BYTES; 44 break; 45 case params_ml_kem1024: 46 case params_ml_kem1024_test_mode: 47 len = MLKEM1024_PRIVATE_KEY_BYTES; 48 break; 49 case params_kyber_invalid: 50 break; 51 } 52 return len; 53 } 54 55 size_t get_public_key_length(KyberParams param) { 56 size_t len = 0; 57 switch (param) { 58 case params_kyber768_round3: 59 case params_kyber768_round3_test_mode: 60 case params_ml_kem768: 61 case params_ml_kem768_test_mode: 62 len = KYBER768_PUBLIC_KEY_BYTES; 63 break; 64 case params_ml_kem1024: 65 case params_ml_kem1024_test_mode: 66 len = MLKEM1024_PUBLIC_KEY_BYTES; 67 break; 68 case params_kyber_invalid: 69 break; 70 } 71 return len; 72 } 73 74 class KyberTest : public ::testing::Test {}; 75 76 class KyberSelfTest : public KyberTest, 77 public ::testing::WithParamInterface<KyberParams> {}; 78 79 TEST_P(KyberSelfTest, ConsistencyTest) { 80 const KyberParams& param(GetParam()); 81 82 ScopedSECItem privateKey( 83 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PRIVATE_KEY_LENGTH)); 84 ScopedSECItem publicKey( 85 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PUBLIC_KEY_LENGTH)); 86 ScopedSECItem ciphertext( 87 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_CIPHER_LENGTH)); 88 ScopedSECItem secret( 89 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 90 ScopedSECItem secret2( 91 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 92 93 privateKey->len = get_private_key_length(param); 94 publicKey->len = get_public_key_length(param); 95 96 SECStatus rv = 97 Kyber_NewKey(param, nullptr, privateKey.get(), publicKey.get()); 98 EXPECT_EQ(SECSuccess, rv); 99 100 ciphertext->len = get_ciphertext_length(param); 101 102 rv = Kyber_Encapsulate(param, nullptr, publicKey.get(), ciphertext.get(), 103 secret.get()); 104 EXPECT_EQ(SECSuccess, rv); 105 106 rv = Kyber_Decapsulate(param, privateKey.get(), ciphertext.get(), 107 secret2.get()); 108 EXPECT_EQ(SECSuccess, rv); 109 110 EXPECT_EQ(secret->len, KYBER_SHARED_SECRET_BYTES); 111 EXPECT_EQ(secret2->len, KYBER_SHARED_SECRET_BYTES); 112 EXPECT_EQ(0, memcmp(secret->data, secret2->data, KYBER_SHARED_SECRET_BYTES)); 113 } 114 115 TEST_P(KyberSelfTest, InvalidParameterTest) { 116 const KyberParams& param(GetParam()); 117 118 ScopedSECItem privateKey( 119 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PRIVATE_KEY_LENGTH)); 120 ScopedSECItem publicKey( 121 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PUBLIC_KEY_LENGTH)); 122 ScopedSECItem ciphertext( 123 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_CIPHER_LENGTH)); 124 ScopedSECItem secret( 125 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 126 127 privateKey->len = get_private_key_length(param); 128 publicKey->len = get_public_key_length(param); 129 130 SECStatus rv = Kyber_NewKey(params_kyber_invalid, nullptr, privateKey.get(), 131 publicKey.get()); 132 EXPECT_EQ(SECFailure, rv); 133 134 rv = Kyber_NewKey(param, nullptr, privateKey.get(), publicKey.get()); 135 EXPECT_EQ(SECSuccess, rv); 136 137 ciphertext->len = get_ciphertext_length(param); 138 139 rv = Kyber_Encapsulate(params_kyber_invalid, nullptr, publicKey.get(), 140 ciphertext.get(), secret.get()); 141 EXPECT_EQ(SECFailure, rv); 142 143 rv = Kyber_Encapsulate(param, nullptr, publicKey.get(), ciphertext.get(), 144 secret.get()); 145 EXPECT_EQ(SECSuccess, rv); 146 147 rv = Kyber_Decapsulate(params_kyber_invalid, privateKey.get(), 148 ciphertext.get(), secret.get()); 149 EXPECT_EQ(SECFailure, rv); 150 151 rv = Kyber_Decapsulate(param, privateKey.get(), ciphertext.get(), 152 secret.get()); 153 EXPECT_EQ(SECSuccess, rv); 154 } 155 156 TEST_P(KyberSelfTest, InvalidPublicKeyTest) { 157 const KyberParams& param(GetParam()); 158 159 ScopedSECItem shortBuffer(SECITEM_AllocItem(nullptr, nullptr, 7)); 160 ScopedSECItem privateKey( 161 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PRIVATE_KEY_LENGTH)); 162 163 privateKey->len = get_private_key_length(param); 164 165 SECStatus rv = 166 Kyber_NewKey(param, nullptr, privateKey.get(), shortBuffer.get()); 167 EXPECT_EQ(SECFailure, rv); // short publicKey buffer 168 } 169 170 TEST_P(KyberSelfTest, InvalidCiphertextTest) { 171 const KyberParams& param(GetParam()); 172 173 ScopedSECItem shortBuffer(SECITEM_AllocItem(nullptr, nullptr, 7)); 174 ScopedSECItem privateKey( 175 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PRIVATE_KEY_LENGTH)); 176 ScopedSECItem publicKey( 177 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PUBLIC_KEY_LENGTH)); 178 ScopedSECItem ciphertext( 179 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_CIPHER_LENGTH)); 180 ScopedSECItem secret( 181 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 182 ScopedSECItem secret2( 183 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 184 185 privateKey->len = get_private_key_length(param); 186 publicKey->len = get_public_key_length(param); 187 188 SECStatus rv = 189 Kyber_NewKey(param, nullptr, privateKey.get(), publicKey.get()); 190 EXPECT_EQ(SECSuccess, rv); 191 192 ciphertext->len = get_ciphertext_length(param); 193 194 rv = Kyber_Encapsulate(param, nullptr, publicKey.get(), shortBuffer.get(), 195 secret.get()); 196 EXPECT_EQ(SECFailure, rv); // short ciphertext input 197 198 rv = Kyber_Encapsulate(param, nullptr, publicKey.get(), ciphertext.get(), 199 secret.get()); 200 EXPECT_EQ(SECSuccess, rv); 201 202 // Modify a random byte in the ciphertext 203 size_t pos; 204 rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&pos, sizeof(pos)); 205 EXPECT_EQ(SECSuccess, rv); 206 207 uint8_t byte; 208 rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&byte, sizeof(byte)); 209 EXPECT_EQ(SECSuccess, rv); 210 211 size_t ct_len = get_ciphertext_length(param); 212 EXPECT_EQ(ciphertext->len, ct_len); 213 ciphertext->data[pos % ct_len] ^= (byte | 1); 214 215 rv = Kyber_Decapsulate(param, privateKey.get(), ciphertext.get(), 216 secret2.get()); 217 EXPECT_EQ(SECSuccess, rv); 218 219 EXPECT_EQ(secret->len, KYBER_SHARED_SECRET_BYTES); 220 EXPECT_EQ(secret2->len, KYBER_SHARED_SECRET_BYTES); 221 EXPECT_NE(0, memcmp(secret->data, secret2->data, KYBER_SHARED_SECRET_BYTES)); 222 } 223 224 TEST_P(KyberSelfTest, InvalidPrivateKeyTest) { 225 const KyberParams& param(GetParam()); 226 227 ScopedSECItem shortBuffer(SECITEM_AllocItem(nullptr, nullptr, 7)); 228 ScopedSECItem privateKey( 229 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PRIVATE_KEY_LENGTH)); 230 ScopedSECItem publicKey( 231 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PUBLIC_KEY_LENGTH)); 232 ScopedSECItem ciphertext( 233 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_CIPHER_LENGTH)); 234 ScopedSECItem secret( 235 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 236 ScopedSECItem secret2( 237 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 238 239 privateKey->len = get_private_key_length(param); 240 publicKey->len = get_public_key_length(param); 241 242 SECStatus rv = 243 Kyber_NewKey(param, nullptr, shortBuffer.get(), publicKey.get()); 244 EXPECT_EQ(SECFailure, rv); // short privateKey buffer 245 246 rv = Kyber_NewKey(param, nullptr, privateKey.get(), publicKey.get()); 247 EXPECT_EQ(SECSuccess, rv); 248 249 ciphertext->len = get_ciphertext_length(param); 250 251 rv = Kyber_Encapsulate(param, nullptr, publicKey.get(), ciphertext.get(), 252 secret.get()); 253 EXPECT_EQ(SECSuccess, rv); 254 255 // Modify a random byte in the private key 256 size_t pos; 257 rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&pos, sizeof(pos)); 258 EXPECT_EQ(SECSuccess, rv); 259 260 uint8_t byte; 261 rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&byte, sizeof(byte)); 262 EXPECT_EQ(SECSuccess, rv); 263 264 // Modifying the implicit rejection key will not cause decapsulation failure. 265 size_t pvk_len = get_private_key_length(param); 266 size_t puk_len = get_public_key_length(param); 267 EXPECT_EQ(privateKey->len, pvk_len); 268 size_t ir_pos = pvk_len - (pos % KYBER_SHARED_SECRET_BYTES) - 1; 269 uint8_t ir_pos_old = privateKey->data[ir_pos]; 270 privateKey->data[ir_pos] ^= (byte | 1); 271 272 rv = Kyber_Decapsulate(param, privateKey.get(), ciphertext.get(), 273 secret2.get()); 274 EXPECT_EQ(SECSuccess, rv); 275 276 EXPECT_EQ(secret->len, KYBER_SHARED_SECRET_BYTES); 277 EXPECT_EQ(secret2->len, KYBER_SHARED_SECRET_BYTES); 278 EXPECT_EQ(0, memcmp(secret->data, secret2->data, KYBER_SHARED_SECRET_BYTES)); 279 280 // Fix the private key 281 privateKey->data[ir_pos] = ir_pos_old; 282 283 // For ML-KEM when modifying the public key, the key must be rejected. 284 // Kyber will decapsulate without an error in these cases 285 size_t pk_pos = pvk_len - 2 * KYBER_SHARED_SECRET_BYTES - (pos % puk_len) - 1; 286 uint8_t pk_pos_old = privateKey->data[pk_pos]; 287 privateKey->data[pk_pos] ^= (byte | 1); 288 289 rv = Kyber_Decapsulate(param, privateKey.get(), ciphertext.get(), 290 secret2.get()); 291 if (param == params_kyber768_round3) { 292 EXPECT_EQ(SECSuccess, rv); 293 } else { 294 EXPECT_EQ(SECFailure, rv); 295 } 296 297 // Fix the key again. 298 privateKey->data[pk_pos] = pk_pos_old; 299 300 // For ML-KEM when modifying the public key hash, the key must be rejected. 301 // Kyber will decapsulate without an error in these cases 302 size_t pk_hash_pos = pvk_len - KYBER_SHARED_SECRET_BYTES - 303 (pos % KYBER_SHARED_SECRET_BYTES) - 1; 304 privateKey->data[pk_hash_pos] ^= (byte | 1); 305 306 rv = Kyber_Decapsulate(param, privateKey.get(), ciphertext.get(), 307 secret2.get()); 308 if (param == params_kyber768_round3) { 309 EXPECT_EQ(SECSuccess, rv); 310 } else { 311 EXPECT_EQ(SECFailure, rv); 312 } 313 } 314 315 TEST_P(KyberSelfTest, DecapsulationWithModifiedRejectionKeyTest) { 316 const KyberParams& param(GetParam()); 317 318 ScopedSECItem privateKey( 319 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PRIVATE_KEY_LENGTH)); 320 ScopedSECItem publicKey( 321 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PUBLIC_KEY_LENGTH)); 322 ScopedSECItem ciphertext( 323 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_CIPHER_LENGTH)); 324 ScopedSECItem secret( 325 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 326 ScopedSECItem secret2( 327 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 328 ScopedSECItem secret3( 329 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 330 331 privateKey->len = get_private_key_length(param); 332 publicKey->len = get_public_key_length(param); 333 334 SECStatus rv = 335 Kyber_NewKey(param, nullptr, privateKey.get(), publicKey.get()); 336 EXPECT_EQ(SECSuccess, rv); 337 338 ciphertext->len = get_ciphertext_length(param); 339 340 rv = Kyber_Encapsulate(param, nullptr, publicKey.get(), ciphertext.get(), 341 secret.get()); 342 EXPECT_EQ(SECSuccess, rv); 343 344 // Modify a random byte in the ciphertext and decapsulate it 345 size_t pos; 346 rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&pos, sizeof(pos)); 347 EXPECT_EQ(SECSuccess, rv); 348 349 uint8_t byte; 350 rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&byte, sizeof(byte)); 351 EXPECT_EQ(SECSuccess, rv); 352 353 size_t ct_len = get_ciphertext_length(param); 354 EXPECT_EQ(ciphertext->len, ct_len); 355 ciphertext->data[pos % ct_len] ^= (byte | 1); 356 357 rv = Kyber_Decapsulate(param, privateKey.get(), ciphertext.get(), 358 secret2.get()); 359 EXPECT_EQ(SECSuccess, rv); 360 361 // Now, modify a random byte in the implicit rejection key and try 362 // the decapsulation again. The result should be different. 363 rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&pos, sizeof(pos)); 364 EXPECT_EQ(SECSuccess, rv); 365 366 rv = RNG_GenerateGlobalRandomBytes((uint8_t*)&byte, sizeof(byte)); 367 EXPECT_EQ(SECSuccess, rv); 368 369 size_t pvk_len = get_private_key_length(param); 370 pos = 371 (pvk_len - KYBER_SHARED_SECRET_BYTES) + (pos % KYBER_SHARED_SECRET_BYTES); 372 EXPECT_EQ(privateKey->len, pvk_len); 373 privateKey->data[pos] ^= (byte | 1); 374 375 rv = Kyber_Decapsulate(param, privateKey.get(), ciphertext.get(), 376 secret3.get()); 377 EXPECT_EQ(SECSuccess, rv); 378 379 EXPECT_EQ(secret2->len, KYBER_SHARED_SECRET_BYTES); 380 EXPECT_EQ(secret3->len, KYBER_SHARED_SECRET_BYTES); 381 EXPECT_NE(0, memcmp(secret2->data, secret3->data, KYBER_SHARED_SECRET_BYTES)); 382 } 383 384 #ifdef NSS_DISABLE_KYBER 385 INSTANTIATE_TEST_SUITE_P(SelfTests, KyberSelfTest, 386 ::testing::Values(params_ml_kem768, 387 params_ml_kem1024)); 388 #else 389 INSTANTIATE_TEST_SUITE_P(SelfTests, KyberSelfTest, 390 ::testing::Values(params_ml_kem768, params_ml_kem1024, 391 params_kyber768_round3)); 392 #endif 393 394 TEST(Kyber768Test, KnownAnswersTest) { 395 ScopedSECItem privateKey( 396 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PRIVATE_KEY_LENGTH)); 397 ScopedSECItem publicKey( 398 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PUBLIC_KEY_LENGTH)); 399 ScopedSECItem ciphertext( 400 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_CIPHER_LENGTH)); 401 ScopedSECItem secret( 402 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 403 ScopedSECItem secret2( 404 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 405 406 SECStatus rv; 407 uint8_t digest[SHA256_LENGTH]; 408 409 for (const auto& kat : KyberKATs) { 410 SECItem keypair_seed = {siBuffer, (unsigned char*)kat.newKeySeed, 411 sizeof kat.newKeySeed}; 412 SECItem enc_seed = {siBuffer, (unsigned char*)kat.encapsSeed, 413 sizeof kat.encapsSeed}; 414 415 privateKey->len = get_private_key_length(kat.params); 416 publicKey->len = get_public_key_length(kat.params); 417 ciphertext->len = get_ciphertext_length(kat.params); 418 419 rv = Kyber_NewKey(kat.params, &keypair_seed, privateKey.get(), 420 publicKey.get()); 421 EXPECT_EQ(SECSuccess, rv); 422 423 SHA256_HashBuf(digest, privateKey->data, privateKey->len); 424 EXPECT_EQ(0, memcmp(kat.privateKeyDigest, digest, sizeof digest)); 425 426 SHA256_HashBuf(digest, publicKey->data, publicKey->len); 427 EXPECT_EQ(0, memcmp(kat.publicKeyDigest, digest, sizeof digest)); 428 429 rv = Kyber_Encapsulate(kat.params, &enc_seed, publicKey.get(), 430 ciphertext.get(), secret.get()); 431 EXPECT_EQ(SECSuccess, rv); 432 433 SHA256_HashBuf(digest, ciphertext->data, ciphertext->len); 434 EXPECT_EQ(0, memcmp(kat.ciphertextDigest, digest, sizeof digest)); 435 436 EXPECT_EQ(secret->len, KYBER_SHARED_SECRET_BYTES); 437 EXPECT_EQ(0, memcmp(kat.secret, secret->data, secret->len)); 438 439 rv = Kyber_Decapsulate(kat.params, privateKey.get(), ciphertext.get(), 440 secret2.get()); 441 EXPECT_EQ(SECSuccess, rv); 442 EXPECT_EQ(secret2->len, KYBER_SHARED_SECRET_BYTES); 443 EXPECT_EQ(0, memcmp(secret->data, secret2->data, secret2->len)); 444 } 445 } 446 447 TEST(MlKemKeyGen, KnownAnswersTest) { 448 ScopedSECItem privateKey( 449 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PRIVATE_KEY_LENGTH)); 450 ScopedSECItem publicKey( 451 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_PUBLIC_KEY_LENGTH)); 452 453 uint8_t digest[SHA3_256_LENGTH]; 454 455 for (const auto& kat : MlKemKeyGenTests) { 456 SECItem keypair_seed = {siBuffer, (unsigned char*)kat.seed.data(), 457 (unsigned int)kat.seed.size()}; 458 459 privateKey->len = get_private_key_length(kat.params); 460 publicKey->len = get_public_key_length(kat.params); 461 462 SECStatus rv = Kyber_NewKey(kat.params, &keypair_seed, privateKey.get(), 463 publicKey.get()); 464 EXPECT_EQ(SECSuccess, rv); 465 466 rv = SHA3_256_HashBuf(digest, privateKey->data, privateKey->len); 467 EXPECT_EQ(SECSuccess, rv); 468 EXPECT_EQ(kat.privateKeyDigest.size(), sizeof(digest)); 469 EXPECT_EQ(0, memcmp(kat.privateKeyDigest.data(), digest, sizeof(digest))); 470 471 rv = SHA3_256_HashBuf(digest, publicKey->data, publicKey->len); 472 EXPECT_EQ(SECSuccess, rv); 473 EXPECT_EQ(kat.publicKeyDigest.size(), sizeof(digest)); 474 EXPECT_EQ(0, memcmp(kat.publicKeyDigest.data(), digest, sizeof(digest))); 475 } 476 } 477 478 TEST(MlKemEncap, KnownAnswersTest) { 479 ScopedSECItem ciphertext( 480 SECITEM_AllocItem(nullptr, nullptr, MAX_ML_KEM_CIPHER_LENGTH)); 481 ScopedSECItem secret( 482 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 483 484 uint8_t digest[SHA3_256_LENGTH]; 485 486 for (const auto& kat : MlKemEncapTests) { 487 SECItem seed = {siBuffer, (unsigned char*)kat.entropy.data(), 488 (unsigned int)kat.entropy.size()}; 489 SECItem publicKey = {siBuffer, (unsigned char*)kat.publicKey.data(), 490 (unsigned int)kat.publicKey.size()}; 491 492 ciphertext->len = get_ciphertext_length(kat.params); 493 494 // Only valid tests for now 495 EXPECT_TRUE(kat.expectedResult); 496 497 SECStatus rv = Kyber_Encapsulate(kat.params, &seed, &publicKey, 498 ciphertext.get(), secret.get()); 499 EXPECT_EQ(SECSuccess, rv); 500 501 rv = SHA3_256_HashBuf(digest, ciphertext->data, ciphertext->len); 502 EXPECT_EQ(SECSuccess, rv); 503 EXPECT_EQ(kat.cipherTextDigest.size(), sizeof(digest)); 504 EXPECT_EQ(0, memcmp(kat.cipherTextDigest.data(), digest, sizeof(digest))); 505 506 EXPECT_EQ(kat.secret.size(), secret->len); 507 EXPECT_EQ(0, memcmp(kat.secret.data(), secret->data, secret->len)); 508 } 509 } 510 511 TEST(MlKemDecap, KnownAnswersTest) { 512 ScopedSECItem secret( 513 SECITEM_AllocItem(nullptr, nullptr, KYBER_SHARED_SECRET_BYTES)); 514 515 for (const auto& kat : MlKemDecapTests) { 516 SECItem ciphertext = {siBuffer, (unsigned char*)kat.cipherText.data(), 517 (unsigned int)kat.cipherText.size()}; 518 SECItem privateKey = {siBuffer, (unsigned char*)kat.privateKey.data(), 519 (unsigned int)kat.privateKey.size()}; 520 521 // Only valid tests for now 522 EXPECT_TRUE(kat.expectedResult); 523 524 SECStatus rv = 525 Kyber_Decapsulate(kat.params, &privateKey, &ciphertext, secret.get()); 526 EXPECT_EQ(SECSuccess, rv); 527 EXPECT_EQ(secret->len, KYBER_SHARED_SECRET_BYTES); 528 EXPECT_EQ( 529 0, memcmp(secret->data, kat.secret.data(), KYBER_SHARED_SECRET_BYTES)); 530 } 531 } 532 533 } // namespace nss_test