Botan 3.11.0
Crypto and TLS for C&
kyber_keys.cpp
Go to the documentation of this file.
1/*
2 * Crystals Kyber Internal Key Types
3 *
4 * (C) 2021-2024 Jack Lloyd
5 * (C) 2021-2022 Manuel Glaser and Michael Boric, Rohde & Schwarz Cybersecurity
6 * (C) 2021-2022 René Meusel and Hannes Rantzsch, neXenio GmbH
7 * (C) 2024 René Meusel, Fabian Albert, Rohde & Schwarz Cybersecurity
8 *
9 * Botan is released under the Simplified BSD License (see license.txt)
10 */
11
12#include <botan/internal/kyber_keys.h>
13
14#include <botan/internal/buffer_slicer.h>
15#include <botan/internal/concat_util.h>
16#include <botan/internal/kyber_symmetric_primitives.h>
17
18namespace Botan {
19
20namespace {
21
22KyberSerializedPublicKey validate_public_key_length(KyberSerializedPublicKey public_key, size_t expected_length) {
23 if(public_key.size() != expected_length) {
24 throw Invalid_Argument("Public key does not have the correct byte count");
25 }
26 return public_key;
27}
28
29} // namespace
30
31/**
32 * Key decoding as specified in Crystals Kyber (Version 3.01),
33 * Algorithms 4 (CPAPKE.KeyGen()), and 7 (CCAKEM.KeyGen())
34 *
35 * Public Key: pk := (encode(t) || rho)
36 * Secret Key: sk' := encode(s)
37 *
38 * Expanded Secret Key: sk := (sk' || pk || H(pk) || z)
39 */
41 auto scope = CT::scoped_poison(sk);
42 BufferSlicer s(sk);
43
45 auto pub_key = s.copy<KyberSerializedPublicKey>(mode.public_key_bytes());
48
50
51 CT::unpoison_all(pub_key, puk_key_hash, skpv, z);
52
54 std::make_shared<Kyber_PublicKeyInternal>(mode, std::move(pub_key)),
55 std::make_shared<Kyber_PrivateKeyInternal>(
56 std::move(mode),
57 std::move(skpv),
58 KyberPrivateKeySeed{std::nullopt, // Reading from an expanded and encoded
59 // private key cannot reconstruct the
60 // original seed from key generation.
61 std::move(z)}),
62 };
63
64 BOTAN_ASSERT(keypair.first && keypair.second, "reading private key encoding");
65 BOTAN_ARG_CHECK(keypair.first->H_public_key_bits_raw().size() == puk_key_hash.size() &&
66 std::equal(keypair.first->H_public_key_bits_raw().begin(),
67 keypair.first->H_public_key_bits_raw().end(),
68 puk_key_hash.begin()),
69 "public key's hash does not match the stored hash");
70
71 return keypair;
72}
73
75 BOTAN_ASSERT_NONNULL(keypair.first);
76 BOTAN_ASSERT_NONNULL(keypair.second);
77 const auto& mode = keypair.first->mode();
78 auto scope = CT::scoped_poison(*keypair.second);
79 auto result = concat(Kyber_Algos::encode_polynomial_vector(keypair.second->s().reduce(), mode),
80 keypair.first->public_key_bits_raw(),
81 keypair.first->H_public_key_bits_raw(),
82 keypair.second->z());
83 CT::unpoison(result);
84 return result;
85}
86
88 KyberConstants mode) const {
89 BufferSlicer s(private_key);
90 auto seed = KyberPrivateKeySeed{
93 };
95 return Kyber_Algos::expand_keypair(std::move(seed), std::move(mode));
96}
97
99 BOTAN_ASSERT_NONNULL(keypair.second);
100 const auto& seed = keypair.second->seed();
101 BOTAN_ARG_CHECK(seed.d.has_value(), "Cannot encode keypair without the full private seed");
102 return concat<secure_vector<uint8_t>>(seed.d.value(), seed.z);
103}
104
106 m_mode(std::move(mode)),
107 m_public_key_bits_raw(validate_public_key_length(std::move(public_key), m_mode.public_key_bytes())),
108 m_H_public_key_bits_raw(m_mode.symmetric_primitives().H(m_public_key_bits_raw)),
109 m_t(Kyber_Algos::decode_polynomial_vector(
110 std::span{m_public_key_bits_raw}.first(m_mode.polynomial_vector_bytes()), m_mode)),
111 m_rho(std::span{m_public_key_bits_raw}.last(Botan::KyberConstants::SEED_BYTES)) {}
112
114 m_mode(std::move(mode)),
115 m_public_key_bits_raw(concat(Kyber_Algos::encode_polynomial_vector<std::vector<uint8_t>>(t, m_mode), rho)),
116 m_H_public_key_bits_raw(m_mode.symmetric_primitives().H(m_public_key_bits_raw)),
117 m_t(std::move(t)),
118 m_rho(std::move(rho)) {}
119
120/**
121 * NIST FIPS 203, Algorithm 14 (K-PKE.Encrypt)
122 *
123 * In contrast to FIPS 203, the matrix @p At is not sampled for every invocation,
124 * instead it is precomputed and passed in as a parameter. Similarly, the t^T is
125 * already decoded and available as a member variable. This allows to reuse these
126 * structures for multiple encryptions.
127 *
128 * The sampling loops spelled out in FIPS 203 are hidden in the sample_* functions.
129 */
133 const KyberPolyMat& At,
134 const KyberConstants& mode) const {
135 // The nonce N is handled internally by the PolynomialSampler
137 const auto y = ntt(ps.sample_polynomial_vector_cbd_eta1());
138 const auto e1 = ps.sample_polynomial_vector_cbd_eta2();
139 const auto e2 = ps.sample_polynomial_cbd_eta2();
140
141 auto u = inverse_ntt(At * y);
142 u += e1;
143 u.reduce();
144
145 const auto mu = Kyber_Algos::polynomial_from_message(m);
146 auto v = inverse_ntt(m_t * y);
147 v += e2;
148 v += mu;
149 v.reduce();
150
151 Kyber_Algos::compress_ciphertext(out_ct, u, v, m_mode);
152}
153
154/**
155 * NIST FIPS 203, Algorithm 15 (K-PKE.Decrypt)
156 *
157 * s^T is already decoded and available as a member variable. This allows to reuse
158 * the structure for multiple decryptions.
159 */
161 auto [u, v] = Kyber_Algos::decompress_ciphertext(ct, m_mode);
162 v -= inverse_ntt(m_s * ntt(std::move(u)));
163 v.reduce();
165}
166
167} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:114
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
auto copy(const size_t count)
std::span< const uint8_t > take(const size_t count)
secure_vector< uint8_t > encode_keypair(KyberInternalKeypair private_key) const override
KyberInternalKeypair decode_keypair(std::span< const uint8_t > buffer, KyberConstants mode) const override
static constexpr size_t SEED_BYTES
size_t public_key_bytes() const
byte length of an encoded public key
size_t polynomial_vector_bytes() const
byte length of an encoded polynomial vector
static constexpr size_t PUBLIC_KEY_HASH_BYTES
KyberPolyVec sample_polynomial_vector_cbd_eta1()
Definition kyber_algos.h:67
KyberPolyVec sample_polynomial_vector_cbd_eta2()
Definition kyber_algos.h:83
KyberMessage indcpa_decrypt(StrongSpan< const KyberCompressedCiphertext > ct) const
const KyberPolyVecNTT & t() const
Definition kyber_keys.h:63
const KyberSeedRho & rho() const
Definition kyber_keys.h:65
void indcpa_encrypt(StrongSpan< KyberCompressedCiphertext > out_ct, StrongSpan< const KyberMessage > m, StrongSpan< const KyberEncryptionRandomness > r, const KyberPolyMat &At, const KyberConstants &mode) const
const KyberConstants & mode() const
Definition kyber_keys.h:67
KyberInternalKeypair decode_keypair(std::span< const uint8_t > buffer, KyberConstants mode) const override
secure_vector< uint8_t > encode_keypair(KyberInternalKeypair keypair) const override
constexpr auto scoped_poison(const Ts &... xs)
Definition ct_utils.h:222
constexpr void unpoison_all(const Ts &... ts)
Definition ct_utils.h:207
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:67
void encode_polynomial_vector(std::span< uint8_t > out, const KyberPolyVecNTT &vec)
KyberMessage polynomial_to_message(const KyberPoly &p)
void compress_ciphertext(StrongSpan< KyberCompressedCiphertext > out, const KyberPolyVec &u, const KyberPoly &v, const KyberConstants &m_mode)
KyberInternalKeypair expand_keypair(KyberPrivateKeySeed seed, KyberConstants mode)
KyberPoly polynomial_from_message(StrongSpan< const KyberMessage > msg)
std::pair< KyberPolyVec, KyberPoly > decompress_ciphertext(StrongSpan< const KyberCompressedCiphertext > ct, const KyberConstants &mode)
KyberPolyVecNTT decode_polynomial_vector(std::span< const uint8_t > a, const KyberConstants &mode)
Strong< secure_vector< uint8_t >, struct KyberImplicitRejectionValue_ > KyberImplicitRejectionValue
Secret random value (called Z in the spec), used for implicit rejection in the decapsulation.
Definition kyber_types.h:42
Strong< secure_vector< uint8_t >, struct KyberMessage_ > KyberMessage
Random message value to be encrypted by the CPA-secure Kyber encryption scheme.
Definition kyber_types.h:45
Botan::CRYSTALS::PolynomialVector< KyberPolyTraits, Botan::CRYSTALS::Domain::NTT > KyberPolyVecNTT
Definition kyber_types.h:26
Strong< secure_vector< uint8_t >, struct KyberSeedRandomness_ > KyberSeedRandomness
Principal seed used to generate Kyber key pairs.
Definition kyber_types.h:33
Strong< std::vector< uint8_t >, struct KyberSeedRho_ > KyberSeedRho
Public seed value to generate the Kyber matrix A.
Definition kyber_types.h:36
constexpr auto concat(Rs &&... ranges)
Definition concat_util.h:90
std::pair< std::shared_ptr< Kyber_PublicKeyInternal >, std::shared_ptr< Kyber_PrivateKeyInternal > > KyberInternalKeypair
Definition kyber_types.h:73
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
Botan::CRYSTALS::PolynomialMatrix< KyberPolyTraits > KyberPolyMat
Definition kyber_types.h:27
Strong< std::vector< uint8_t >, struct KyberHashedPublicKey_ > KyberHashedPublicKey
Hash value of the serialized public key.
Definition kyber_types.h:60
Strong< std::vector< uint8_t >, struct KyberSerializedPublicKey_ > KyberSerializedPublicKey
Public key in serialized form (t || rho).
Definition kyber_types.h:57