tor-browser

The Tor Browser
git clone https://git.dasho.dev/tor-browser.git
Log | Files | Refs | README | LICENSE

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