// Copyright 2026 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "crypto/hpke.h"

#include <array>
#include <vector>

#include "base/containers/span.h"
#include "crypto/keypair.h"
#include "testing/gmock/include/gmock/gmock.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace crypto::hpke {
namespace {

const HpkeParams kParams = {.kem = KemType::kX25519HkdfSha256,
                            .kdf = KdfType::kHkdfSha256,
                            .aead = AeadType::kChaCha20Poly1305};

TEST(HpkeTest, AuthSealOpenRoundTrip) {
  auto sender_key = crypto::keypair::PrivateKey::GenerateX25519();
  auto recipient_key = crypto::keypair::PrivateKey::GenerateX25519();

  auto recipient_pub_bytes = recipient_key.ToX25519PublicKey();
  auto recipient_pub =
      crypto::keypair::PublicKey::FromX25519PublicKey(recipient_pub_bytes);

  auto sender_pub_bytes = sender_key.ToX25519PublicKey();
  auto sender_pub =
      crypto::keypair::PublicKey::FromX25519PublicKey(sender_pub_bytes);

  const auto plaintext = std::to_array<uint8_t>({1, 2, 3, 4, 5});
  const auto info = std::to_array<uint8_t>({6, 7, 8});

  auto encrypted =
      AuthSeal(kParams, sender_key, recipient_pub, plaintext, info, {});
  ASSERT_TRUE(encrypted.has_value());
  EXPECT_GT(encrypted->size(), 32u);  // Encapsulated key (32) + ciphertext

  auto decrypted =
      AuthOpen(kParams, recipient_key, sender_pub, *encrypted, info, {});
  ASSERT_TRUE(decrypted.has_value());
  EXPECT_THAT(*decrypted, testing::ElementsAreArray(plaintext));
}

TEST(HpkeTest, AuthOpenCorruptedCiphertext) {
  auto sender_key = crypto::keypair::PrivateKey::GenerateX25519();
  auto recipient_key = crypto::keypair::PrivateKey::GenerateX25519();

  auto recipient_pub_bytes = recipient_key.ToX25519PublicKey();
  auto recipient_pub =
      crypto::keypair::PublicKey::FromX25519PublicKey(recipient_pub_bytes);

  auto sender_pub_bytes = sender_key.ToX25519PublicKey();
  auto sender_pub =
      crypto::keypair::PublicKey::FromX25519PublicKey(sender_pub_bytes);

  const auto plaintext = std::to_array<uint8_t>({1, 2, 3, 4, 5});
  const auto info = std::to_array<uint8_t>({6, 7, 8});

  auto encrypted =
      AuthSeal(kParams, sender_key, recipient_pub, plaintext, info, {});
  ASSERT_TRUE(encrypted.has_value());

  // Corrupt the ciphertext (last byte)
  encrypted->back() ^= 0xFF;

  auto decrypted =
      AuthOpen(kParams, recipient_key, sender_pub, *encrypted, info, {});
  EXPECT_FALSE(decrypted.has_value());
}

TEST(HpkeTest, AuthOpenWrongInfo) {
  auto sender_key = crypto::keypair::PrivateKey::GenerateX25519();
  auto recipient_key = crypto::keypair::PrivateKey::GenerateX25519();

  auto recipient_pub_bytes = recipient_key.ToX25519PublicKey();
  auto recipient_pub =
      crypto::keypair::PublicKey::FromX25519PublicKey(recipient_pub_bytes);

  auto sender_pub_bytes = sender_key.ToX25519PublicKey();
  auto sender_pub =
      crypto::keypair::PublicKey::FromX25519PublicKey(sender_pub_bytes);

  const auto plaintext = std::to_array<uint8_t>({1, 2, 3, 4, 5});
  const auto info = std::to_array<uint8_t>({6, 7, 8});
  const auto wrong_info = std::to_array<uint8_t>({6, 7, 9});

  auto encrypted =
      AuthSeal(kParams, sender_key, recipient_pub, plaintext, info, {});
  ASSERT_TRUE(encrypted.has_value());

  auto decrypted =
      AuthOpen(kParams, recipient_key, sender_pub, *encrypted, wrong_info, {});
  EXPECT_FALSE(decrypted.has_value());
}

TEST(HpkeTest, AuthOpenTooShortEncryptedData) {
  auto recipient_key = crypto::keypair::PrivateKey::GenerateX25519();
  auto sender_key = crypto::keypair::PrivateKey::GenerateX25519();

  auto sender_pub_bytes = sender_key.ToX25519PublicKey();
  auto sender_pub =
      crypto::keypair::PublicKey::FromX25519PublicKey(sender_pub_bytes);

  const auto too_short_data =
      std::to_array<uint8_t>({1, 2, 3});  // Less than 32 bytes
  const std::array<uint8_t, 0> info = {};

  auto decrypted =
      AuthOpen(kParams, recipient_key, sender_pub, too_short_data, info, {});
  EXPECT_FALSE(decrypted.has_value());
}

TEST(HpkeTest, AuthOpenKnownAnswer) {
  // RFC 9180, Appendix A.2.3. Auth Setup Information
  // mode: 2 kem_id: 32 kdf_id: 1 aead_id: 3

  const auto skRm = std::to_array<uint8_t>(
      {0x3c, 0xa2, 0x2a, 0x6d, 0x1c, 0xda, 0x1b, 0xb9, 0x48, 0x09, 0x49,
       0xec, 0x53, 0x29, 0xd3, 0xbf, 0x0b, 0x08, 0x0c, 0xa4, 0xc4, 0x58,
       0x79, 0xc9, 0x5e, 0xdd, 0xb5, 0x5c, 0x70, 0xb8, 0x0b, 0x82});

  const auto pkSm = std::to_array<uint8_t>(
      {0xf0, 0xf4, 0xf9, 0xe9, 0x6c, 0x54, 0xae, 0xed, 0x3f, 0x32, 0x3d,
       0xe8, 0x53, 0x4f, 0xff, 0xd7, 0xe0, 0x57, 0x7e, 0x4c, 0xe2, 0x69,
       0x89, 0x67, 0x16, 0xbc, 0xb9, 0x56, 0x43, 0xc8, 0x71, 0x2b});

  const auto info = std::to_array<uint8_t>(
      {0x4f, 0x64, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x47,
       0x72, 0x65, 0x63, 0x69, 0x61, 0x6e, 0x20, 0x55, 0x72, 0x6e});

  // enc (32 bytes) + ct (49 bytes)
  const auto encrypted_data = std::to_array<uint8_t>(
      {// enc
       0xf7, 0x67, 0x4c, 0xc8, 0xcd, 0x7b, 0xaa, 0x58, 0x72, 0xd1, 0xf3, 0x3d,
       0xba, 0xff, 0xe3, 0x31, 0x42, 0x39, 0xf6, 0x19, 0x7d, 0xdf, 0x5d, 0xed,
       0x17, 0x46, 0x76, 0x0b, 0xfc, 0x84, 0x7e, 0x0e,
       // ct
       0xab, 0x1a, 0x13, 0xc9, 0xd4, 0xf0, 0x1a, 0x87, 0xec, 0x34, 0x40, 0xdb,
       0xd7, 0x56, 0xe2, 0x67, 0x7b, 0xd2, 0xec, 0xf9, 0xdf, 0x0c, 0xe7, 0xed,
       0x73, 0x86, 0x9b, 0x98, 0xe0, 0x0c, 0x09, 0xbe, 0x11, 0x1c, 0xb9, 0xfd,
       0xf0, 0x77, 0x34, 0x7a, 0xeb, 0x88, 0xe6, 0x1b, 0xdf});

  const auto expected_plaintext = std::to_array<uint8_t>(
      {0x42, 0x65, 0x61, 0x75, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20,
       0x74, 0x72, 0x75, 0x74, 0x68, 0x2c, 0x20, 0x74, 0x72, 0x75,
       0x74, 0x68, 0x20, 0x62, 0x65, 0x61, 0x75, 0x74, 0x79});

  auto recipient_priv = crypto::keypair::PrivateKey::FromX25519PrivateKey(skRm);
  auto sender_pub = crypto::keypair::PublicKey::FromX25519PublicKey(pkSm);

  const auto ad = std::to_array<uint8_t>(
      {0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x30});  // Count-0

  auto decrypted =
      AuthOpen(kParams, recipient_priv, sender_pub, encrypted_data, info, ad);
  ASSERT_TRUE(decrypted.has_value());
  EXPECT_THAT(*decrypted, testing::ElementsAreArray(expected_plaintext));
}

TEST(HpkeTest, OpenKnownAnswerAesGcm) {
  // RFC 9180, Appendix A. Test Vectors
  // mode: 0 kem_id: 32 kdf_id: 1 aead_id: 1

  const auto skRm = std::to_array<uint8_t>(
      {0x46, 0x12, 0xc5, 0x50, 0x26, 0x3f, 0xc8, 0xad, 0x58, 0x37, 0x5d,
       0xf3, 0xf5, 0x57, 0xaa, 0xc5, 0x31, 0xd2, 0x68, 0x50, 0x90, 0x3e,
       0x55, 0xa9, 0xf2, 0x3f, 0x21, 0xd8, 0x53, 0x4e, 0x8a, 0xc8});

  const auto info = std::to_array<uint8_t>(
      {0x4f, 0x64, 0x65, 0x20, 0x6f, 0x6e, 0x20, 0x61, 0x20, 0x47,
       0x72, 0x65, 0x63, 0x69, 0x61, 0x6e, 0x20, 0x55, 0x72, 0x6e});

  const auto ad =
      std::to_array<uint8_t>({0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x30});

  // enc (32 bytes) + ct (47 bytes)
  const auto encrypted_data = std::to_array<uint8_t>(
      {// enc
       0x37, 0xfd, 0xa3, 0x56, 0x7b, 0xdb, 0xd6, 0x28, 0xe8, 0x86, 0x68, 0xc3,
       0xc8, 0xd7, 0xe9, 0x7d, 0x1d, 0x12, 0x53, 0xb6, 0xd4, 0xea, 0x6d, 0x44,
       0xc1, 0x50, 0xf7, 0x41, 0xf1, 0xbf, 0x44, 0x31,
       // ct
       0xf9, 0x38, 0x55, 0x8b, 0x5d, 0x72, 0xf1, 0xa2, 0x38, 0x10, 0xb4, 0xbe,
       0x2a, 0xb4, 0xf8, 0x43, 0x31, 0xac, 0xc0, 0x2f, 0xc9, 0x7b, 0xab, 0xc5,
       0x3a, 0x52, 0xae, 0x82, 0x18, 0xa3, 0x55, 0xa9, 0x6d, 0x87, 0x70, 0xac,
       0x83, 0xd0, 0x7b, 0xea, 0x87, 0xe1, 0x3c, 0x51, 0x2a});

  const auto expected_plaintext = std::to_array<uint8_t>(
      {0x42, 0x65, 0x61, 0x75, 0x74, 0x79, 0x20, 0x69, 0x73, 0x20,
       0x74, 0x72, 0x75, 0x74, 0x68, 0x2c, 0x20, 0x74, 0x72, 0x75,
       0x74, 0x68, 0x20, 0x62, 0x65, 0x61, 0x75, 0x74, 0x79});

  auto recipient_priv = crypto::keypair::PrivateKey::FromX25519PrivateKey(skRm);

  const HpkeParams params = {.kem = KemType::kX25519HkdfSha256,
                             .kdf = KdfType::kHkdfSha256,
                             .aead = AeadType::kAes128Gcm};

  auto decrypted = Open(params, recipient_priv, encrypted_data, info, ad);
  ASSERT_TRUE(decrypted.has_value());
  EXPECT_THAT(*decrypted, testing::ElementsAreArray(expected_plaintext));
}

TEST(HpkeTest, SealOpenRoundTripMlkem768) {
  const HpkeParams params = {.kem = KemType::kMlkem768,
                             .kdf = KdfType::kHkdfSha256,
                             .aead = AeadType::kChaCha20Poly1305};
  auto recipient_key = crypto::keypair::PrivateKey::GenerateMlkem768();
  auto recipient_pub_bytes = recipient_key.ToMlkem768PublicKey();
  auto recipient_pub =
      crypto::keypair::PublicKey::FromMlkem768PublicKey(recipient_pub_bytes);
  ASSERT_TRUE(recipient_pub.has_value());

  const auto plaintext = std::to_array<uint8_t>({1, 2, 3, 4, 5});
  const auto info = std::to_array<uint8_t>({6, 7, 8});

  auto encrypted = Seal(params, *recipient_pub, plaintext, info, {});
  ASSERT_TRUE(encrypted.has_value());
  EXPECT_GT(encrypted->size(), 1088u);  // Encapsulated key (1088) + ciphertext

  auto decrypted = Open(params, recipient_key, *encrypted, info, {});
  ASSERT_TRUE(decrypted.has_value());
  EXPECT_THAT(*decrypted, testing::ElementsAreArray(plaintext));
}

TEST(HpkeTest, OpenCorruptedCiphertextMlkem768) {
  const HpkeParams params = {.kem = KemType::kMlkem768,
                             .kdf = KdfType::kHkdfSha256,
                             .aead = AeadType::kChaCha20Poly1305};
  auto recipient_key = crypto::keypair::PrivateKey::GenerateMlkem768();
  auto recipient_pub_bytes = recipient_key.ToMlkem768PublicKey();
  auto recipient_pub =
      crypto::keypair::PublicKey::FromMlkem768PublicKey(recipient_pub_bytes);
  ASSERT_TRUE(recipient_pub.has_value());

  const auto plaintext = std::to_array<uint8_t>({1, 2, 3, 4, 5});
  const auto info = std::to_array<uint8_t>({6, 7, 8});

  auto encrypted = Seal(params, *recipient_pub, plaintext, info, {});
  ASSERT_TRUE(encrypted.has_value());

  // Corrupt the ciphertext (last byte)
  encrypted->back() ^= 0xFF;

  auto decrypted = Open(params, recipient_key, *encrypted, info, {});
  EXPECT_FALSE(decrypted.has_value());
}

TEST(HpkeTest, OpenKnownAnswerMlkem768) {
  // Test vector from draft-ietf-hpke-pq
  // mode: 0 kem_id: 65 (ML-KEM-768) kdf_id: 1 (HKDF-SHA256) aead_id: 1 (AES-128-GCM)
  const auto skRm = std::to_array<uint8_t>({
      0xe3, 0x40, 0x8a, 0xae, 0x32, 0x2a, 0x36, 0x28, 0xa4, 0xd6, 0x41, 0xc2,
      0x69, 0x0d, 0x4e, 0xb2, 0x12, 0xfd, 0x66, 0xf3, 0x69, 0x78, 0x2f, 0x2d,
      0xd2, 0x2f, 0xa2, 0x93, 0x47, 0x6c, 0x69, 0x95, 0x77, 0x16, 0xbe, 0x20,
      0xe8, 0x39, 0x20, 0xcd, 0x26, 0xa7, 0x71, 0x01, 0x10, 0xa3, 0x4a, 0xc3,
      0xd5, 0xda, 0x7d, 0x90, 0xef, 0xdc, 0x97, 0x59, 0x81, 0x2f, 0x5c, 0xf1,
      0xa4, 0x7e, 0x85, 0xbf
  });

  const auto info = std::to_array<uint8_t>({
      0x34, 0x66, 0x36, 0x34, 0x36, 0x35, 0x32, 0x30, 0x36, 0x66, 0x36, 0x65,
      0x32, 0x30, 0x36, 0x31, 0x32, 0x30, 0x34, 0x37, 0x37, 0x32, 0x36, 0x35,
      0x36, 0x33, 0x36, 0x39, 0x36, 0x31, 0x36, 0x65, 0x32, 0x30, 0x35, 0x35,
      0x37, 0x32, 0x36, 0x65
  });

  const auto ad = std::to_array<uint8_t>({
      0x43, 0x6f, 0x75, 0x6e, 0x74, 0x2d, 0x30
  });

  const auto encrypted_data = std::to_array<uint8_t>({
      0xf4, 0xc7, 0x58, 0xbd, 0x51, 0x70, 0x40, 0xc9, 0x7d, 0x32, 0x7a, 0x0d,
      0x30, 0xde, 0x97, 0x70, 0x05, 0x55, 0x83, 0xac, 0x2f, 0xb9, 0x0a, 0x91,
      0xa6, 0xec, 0x7c, 0xca, 0x4b, 0x46, 0x4a, 0xbb, 0xd7, 0x87, 0x22, 0xdb,
      0x29, 0xb9, 0x85, 0x60, 0x7a, 0xea, 0x1b, 0xb4, 0xa7, 0x9f, 0xc7, 0x6f,
      0xb7, 0x84, 0xc4, 0xd1, 0x08, 0x28, 0xe9, 0xbf, 0xd2, 0x14, 0x95, 0xc3,
      0xe9, 0x45, 0x96, 0xc4, 0xb6, 0x26, 0x05, 0x1f, 0x30, 0xc7, 0x02, 0x8a,
      0x29, 0xc7, 0x16, 0xa2, 0x56, 0x89, 0x97, 0x39, 0x2b, 0x30, 0x17, 0x9c,
      0xfb, 0xe1, 0x36, 0xfb, 0x06, 0xb7, 0x41, 0x50, 0x4d, 0xd8, 0x90, 0x1a,
      0x72, 0x91, 0x44, 0x6a, 0x69, 0x2c, 0x80, 0x48, 0x59, 0x17, 0x12, 0x45,
      0xd1, 0x2a, 0xa5, 0x3e, 0x0f, 0x58, 0xb6, 0x64, 0x3a, 0x3b, 0xa8, 0x49,
      0x01, 0x80, 0x16, 0x13, 0x40, 0xf2, 0x4d, 0xfb, 0xeb, 0x0a, 0xb8, 0x65,
      0x44, 0x5c, 0xea, 0xa2, 0x35, 0x23, 0x6e, 0xe0, 0xdb, 0x44, 0xc1, 0x19,
      0xbf, 0xe9, 0x42, 0xc7, 0xf8, 0x3d, 0x38, 0x1d, 0x7d, 0x65, 0x17, 0x20,
      0x08, 0xde, 0x0d, 0x68, 0x4d, 0xe2, 0xe8, 0x7f, 0x21, 0x39, 0x4a, 0x66,
      0xbf, 0xcf, 0x88, 0x91, 0x88, 0x32, 0xf2, 0x99, 0x46, 0x9f, 0x32, 0xfc,
      0xa0, 0xe7, 0xd5, 0xef, 0xac, 0x51, 0xd3, 0x4b, 0x6a, 0x78, 0x8c, 0x54,
      0x92, 0x2b, 0x3b, 0x4b, 0x7e, 0x83, 0x25, 0xf6, 0x30, 0x6c, 0xf5, 0x45,
      0x38, 0x01, 0x69, 0x77, 0x3e, 0xbd, 0xc0, 0x3f, 0xa0, 0x6c, 0xe2, 0x5a,
      0xa1, 0xc7, 0x1d, 0x30, 0x7c, 0x08, 0xbe, 0xf2, 0x01, 0x6a, 0xff, 0xdd,
      0x6c, 0x29, 0x3f, 0x3c, 0xbb, 0x0c, 0xdb, 0x92, 0x02, 0x16, 0x92, 0xa8,
      0xeb, 0xae, 0xf6, 0xb7, 0x4c, 0xd6, 0xa2, 0xbb, 0x46, 0x8d, 0xa7, 0x9c,
      0xc9, 0xd0, 0x8a, 0x04, 0x94, 0xbb, 0x88, 0xbb, 0x2b, 0xa0, 0xc8, 0x8d,
      0x4a, 0x3e, 0xe2, 0xaf, 0x38, 0x76, 0x2c, 0xd6, 0xc2, 0x97, 0xc6, 0xb3,
      0x6e, 0xe1, 0x88, 0x16, 0x54, 0x6b, 0x37, 0x57, 0x18, 0x87, 0x6e, 0xfa,
      0x55, 0x7e, 0xc6, 0x00, 0xe7, 0xc4, 0xc6, 0xe4, 0x4a, 0xaa, 0x3a, 0x13,
      0x72, 0xc6, 0x77, 0xdc, 0x63, 0x8d, 0xc9, 0x74, 0x2d, 0x90, 0x31, 0x9f,
      0xfc, 0x27, 0xee, 0x99, 0x14, 0x9c, 0x5c, 0x8a, 0x81, 0x85, 0xec, 0xf6,
      0x00, 0xfd, 0xd8, 0xbe, 0x89, 0x7e, 0xfe, 0xa5, 0x2b, 0xfb, 0xdc, 0x4e,
      0xf5, 0x3f, 0xff, 0x73, 0x01, 0xee, 0x49, 0xa7, 0xa3, 0x52, 0xb4, 0x89,
      0x0e, 0x31, 0xc2, 0xf4, 0x4b, 0x45, 0x9b, 0x9f, 0x7d, 0xf4, 0x62, 0x3b,
      0x0b, 0xe8, 0x7f, 0x1c, 0xb9, 0x21, 0x2d, 0xe1, 0xbe, 0xb1, 0x96, 0x87,
      0xf3, 0xfc, 0xa6, 0xd1, 0x3c, 0xa7, 0xf9, 0x24, 0xc0, 0x47, 0x1c, 0xf3,
      0xd9, 0xb2, 0x84, 0xe1, 0x3d, 0xb8, 0xe2, 0x5e, 0x2f, 0xd8, 0x80, 0x95,
      0xae, 0x02, 0x01, 0x00, 0xcd, 0x9a, 0xd5, 0xaa, 0x53, 0x55, 0xb8, 0xaa,
      0x90, 0xd3, 0x16, 0x57, 0x35, 0x5f, 0x80, 0x16, 0x0b, 0x3e, 0x1e, 0x12,
      0x82, 0x09, 0x08, 0xb3, 0xa8, 0x5d, 0x32, 0x1b, 0xe6, 0xd6, 0x8b, 0xeb,
      0xfc, 0x73, 0x35, 0x73, 0x8b, 0x71, 0x22, 0xde, 0x60, 0xf4, 0xac, 0xbb,
      0x92, 0x4d, 0x3a, 0x61, 0x07, 0x49, 0x57, 0x7e, 0x8c, 0x09, 0x57, 0x4a,
      0xc0, 0x16, 0x0a, 0x3a, 0x2f, 0x37, 0xf9, 0xf8, 0xaf, 0x00, 0x82, 0x08,
      0x26, 0x73, 0x34, 0x7d, 0xb7, 0xf2, 0xec, 0x20, 0xf9, 0xd0, 0x5e, 0x96,
      0xe4, 0x83, 0x41, 0x1b, 0x4c, 0x2b, 0x18, 0xcc, 0x49, 0xa0, 0x1e, 0xc6,
      0x5a, 0xe3, 0xa0, 0x77, 0xba, 0x18, 0xa7, 0x07, 0x4e, 0x5b, 0xd1, 0x4c,
      0xe9, 0x7b, 0x77, 0x36, 0x87, 0xa2, 0xcc, 0x89, 0xb1, 0x8d, 0x9f, 0x44,
      0x2d, 0x30, 0xee, 0xbd, 0x49, 0x25, 0xd1, 0x59, 0x1a, 0xeb, 0xa4, 0xa0,
      0x4c, 0x1a, 0x69, 0xa7, 0xcc, 0x6c, 0xf3, 0x4e, 0x25, 0x81, 0x30, 0x0a,
      0x27, 0xb2, 0xbb, 0xe9, 0xc2, 0xfe, 0xc6, 0x1e, 0xd1, 0xb6, 0x3e, 0x50,
      0xf8, 0x70, 0x4c, 0x27, 0x37, 0xde, 0x13, 0xf4, 0xa9, 0xe5, 0x3e, 0x02,
      0x1c, 0x5a, 0x31, 0x4d, 0x13, 0x95, 0x12, 0x93, 0xc0, 0xa7, 0x4c, 0xc4,
      0xf0, 0x98, 0xa4, 0x58, 0x88, 0x5f, 0xee, 0x8d, 0xcf, 0x87, 0x9e, 0xe8,
      0xfe, 0x91, 0xeb, 0xd2, 0xa2, 0xca, 0x1f, 0xfa, 0xa9, 0xef, 0xd8, 0x4a,
      0x04, 0x2b, 0x32, 0xe1, 0x95, 0x16, 0x5a, 0xe1, 0x87, 0xd6, 0x6b, 0x27,
      0xe3, 0xcd, 0xe4, 0x33, 0x4b, 0xff, 0x1e, 0xce, 0xd5, 0x09, 0x10, 0xc3,
      0xea, 0x02, 0x6a, 0xe0, 0x49, 0xdf, 0x54, 0xab, 0x30, 0x79, 0x1f, 0x12,
      0x9c, 0xaa, 0x89, 0x18, 0x0c, 0x1b, 0x69, 0x39, 0xf8, 0x01, 0x7e, 0xf9,
      0x80, 0xde, 0x39, 0x00, 0xbb, 0xb3, 0x2e, 0x9b, 0xc2, 0xe1, 0xbc, 0x53,
      0x59, 0x5c, 0x43, 0x81, 0x37, 0xc6, 0x2a, 0xfa, 0x34, 0x99, 0x61, 0x77,
      0x2d, 0x12, 0x69, 0x4f, 0xea, 0x97, 0x9f, 0x0f, 0x4e, 0x70, 0xc8, 0x17,
      0x6b, 0x75, 0x0e, 0xb9, 0x00, 0x24, 0x83, 0x81, 0x59, 0x84, 0xb6, 0x74,
      0x7d, 0x8d, 0x4f, 0x30, 0x1e, 0xb0, 0xb7, 0x69, 0x87, 0xd4, 0x07, 0xb2,
      0x26, 0x1a, 0xde, 0xcf, 0x58, 0x01, 0x60, 0xd3, 0x18, 0x5f, 0x49, 0xae,
      0xca, 0xce, 0x7e, 0x82, 0x70, 0x1a, 0x2e, 0xb7, 0x0d, 0x20, 0xc4, 0x3d,
      0xe1, 0xbe, 0x39, 0xc1, 0xa2, 0x6e, 0x4b, 0x54, 0x33, 0xe2, 0x13, 0xab,
      0xb7, 0x48, 0xed, 0x5e, 0x6f, 0xa0, 0x88, 0xc5, 0x84, 0x3c, 0x72, 0x53,
      0x36, 0xc6, 0x50, 0xfb, 0xd7, 0x3f, 0x2e, 0xe3, 0xf8, 0x80, 0x0e, 0x9c,
      0x07, 0x94, 0x8b, 0xed, 0xec, 0x99, 0xf7, 0x56, 0x73, 0x54, 0x54, 0x25,
      0xab, 0x82, 0x6d, 0xfe, 0x8a, 0x06, 0x36, 0xf4, 0x22, 0x03, 0x5b, 0xb5,
      0x6e, 0xf9, 0x0b, 0x5d, 0xfa, 0xb3, 0x59, 0x22, 0x32, 0xa0, 0xb9, 0xa8,
      0x4b, 0x1b, 0xdd, 0x78, 0xb6, 0x10, 0xa9, 0xc3, 0xa8, 0x9a, 0xb3, 0xdd,
      0xde, 0xac, 0xea, 0xe9, 0xbc, 0x5b, 0x5d, 0x89, 0xc9, 0x30, 0xca, 0x20,
      0x03, 0x9b, 0x65, 0xac, 0xce, 0xb1, 0xdb, 0xa5, 0x27, 0xb5, 0x8f, 0xd6,
      0x51, 0x7a, 0x21, 0xba, 0x90, 0xcf, 0xb3, 0x8a, 0x2c, 0xec, 0x95, 0x0c,
      0x3f, 0x3b, 0x49, 0x0f, 0xa4, 0x45, 0x8f, 0xe5, 0xcc, 0xdf, 0x79, 0xfb,
      0xd8, 0x8a, 0xe0, 0xa8, 0x4b, 0x02, 0xcf, 0x98, 0x0a, 0xac, 0xd4, 0x10,
      0x7c, 0x29, 0xbf, 0xf7, 0xac, 0x8c, 0x2f, 0xb9, 0xe8, 0xc1, 0x31, 0x14,
      0x4d, 0x96, 0x8a, 0x8b, 0x9f, 0x4c, 0x5b, 0xc7, 0x54, 0x20, 0xf6, 0xcb,
      0xa5, 0x90, 0x68, 0x21, 0x70, 0xf2, 0x93, 0x1c, 0x99, 0xb4, 0x18, 0x95,
      0xd6, 0x8e, 0xa4, 0x74, 0xf7, 0x48, 0x29, 0xfd, 0xa2, 0x55, 0xf8, 0x0c,
      0x7d, 0x4a, 0xe7, 0xb2, 0xb0, 0xdb, 0xd0, 0x02, 0x68, 0x4f, 0x01, 0xaa,
      0x5a, 0x2b, 0xb1, 0x70, 0x03, 0x81, 0x7d, 0x29, 0xf2, 0x76, 0x97, 0x77,
      0x84, 0x04, 0xbb, 0x9d, 0x07, 0xfc, 0x46, 0xee, 0xde, 0xa4, 0x87, 0xf5,
      0x04, 0x90, 0xe9, 0xbe, 0xaa, 0xa2, 0xbe, 0x10, 0x1b, 0x0d, 0x03, 0xae,
      0x96, 0x12, 0xe7, 0x57, 0x40, 0x22, 0xc4, 0x91, 0x66, 0xe1, 0xe0, 0xce,
      0x14, 0x18, 0x7d, 0xf4, 0xc7, 0x5a, 0x13, 0x4f, 0x12, 0xf6, 0x0f, 0x74,
      0xd4, 0x16, 0x45, 0x58, 0x40, 0x17, 0x40, 0x4b, 0x3d, 0xa7, 0xc7, 0xe2,
      0xde, 0xc2, 0xec, 0xa5, 0x54, 0xfb, 0x90, 0xeb, 0x5c, 0x95, 0x8d, 0xb7,
      0xe6, 0xf5, 0xf1, 0x9c, 0xac, 0xd2, 0x7d, 0xe4, 0x65, 0x1c, 0x52, 0x35,
      0x8b, 0xb7, 0xbe, 0x40, 0x72, 0x61, 0xae, 0x4f, 0x16, 0x55, 0x9c, 0x96,
      0x17, 0xcb, 0xcd, 0xea, 0x92, 0x13, 0x31, 0x14, 0xb3, 0x5c, 0x37, 0x6e,
      0x17, 0x41, 0x65, 0xd5, 0x60, 0x82, 0xb0, 0xe6, 0xe2, 0xea, 0x34, 0x7f,
      0x4e, 0x26, 0xb9, 0x04, 0x37, 0x5d, 0xa1, 0x24, 0x8a, 0x86, 0x37, 0x66,
      0xd9, 0x5b, 0x2c, 0x5a, 0x2d, 0xe3, 0x6b, 0x47, 0x47, 0x93, 0xc6, 0xf4,
      0xdc, 0x58, 0x24, 0xa0, 0x03, 0x9d, 0x8f, 0xaf, 0x2d, 0x84, 0xd3, 0x59,
      0xfd, 0x6c, 0xf4, 0x23, 0xea, 0xee, 0xe5, 0x78, 0xbb, 0xb7, 0x83, 0x00,
      0x68, 0xba, 0x34, 0xb5, 0x76, 0xa6, 0xe3, 0xf4, 0xba, 0x03, 0xc5, 0xc2,
      0xc6, 0x2f, 0x2b, 0x86, 0x92, 0x24, 0xa1, 0xc5, 0xac, 0xf9, 0x60, 0x83,
      0xcd, 0x13, 0xbd, 0xc3, 0x62, 0x3a, 0x47, 0xbd, 0xe5, 0x44, 0x17, 0x1a,
      0x72, 0xaa, 0x68, 0x4b, 0x12, 0xa5, 0x62, 0x19, 0x67, 0x85
  });

  const auto expected_plaintext = std::to_array<uint8_t>({
      0x34, 0x32, 0x36, 0x35, 0x36, 0x31, 0x37, 0x35, 0x37, 0x34, 0x37, 0x39,
      0x32, 0x30, 0x36, 0x39, 0x37, 0x33, 0x32, 0x30, 0x37, 0x34, 0x37, 0x32,
      0x37, 0x35, 0x37, 0x34, 0x36, 0x38, 0x32, 0x63, 0x32, 0x30, 0x37, 0x34,
      0x37, 0x32, 0x37, 0x35, 0x37, 0x34, 0x36, 0x38, 0x32, 0x30, 0x36, 0x32,
      0x36, 0x35, 0x36, 0x31, 0x37, 0x35, 0x37, 0x34, 0x37, 0x39
  });

  auto recipient_priv =
      crypto::keypair::PrivateKey::FromMlkem768PrivateKey(skRm);

  const HpkeParams params = {.kem = KemType::kMlkem768,
                             .kdf = KdfType::kHkdfSha256,
                             .aead = AeadType::kAes128Gcm};

  auto decrypted = Open(params, recipient_priv, encrypted_data, info, ad);
  ASSERT_TRUE(decrypted.has_value());
  EXPECT_THAT(*decrypted, testing::ElementsAreArray(expected_plaintext));
}

}  // namespace
}  // namespace crypto::hpke
