Botan 3.8.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/kyber_symmetric_primitives.h>
15#include <botan/internal/stl_util.h>
16
17namespace Botan {
18
19namespace {
20
21KyberSerializedPublicKey validate_public_key_length(KyberSerializedPublicKey public_key, size_t expected_length) {
22 if(public_key.size() != expected_length) {
23 throw Invalid_Argument("Public key does not have the correct byte count");
24 }
25 return public_key;
26}
27
28} // namespace
29
30/**
31 * Key decoding as specified in Crystals Kyber (Version 3.01),
32 * Algorithms 4 (CPAPKE.KeyGen()), and 7 (CCAKEM.KeyGen())
33 *
34 * Public Key: pk := (encode(t) || rho)
35 * Secret Key: sk' := encode(s)
36 *
37 * Expanded Secret Key: sk := (sk' || pk || H(pk) || z)
38 */
40 auto scope = CT::scoped_poison(sk);
41 BufferSlicer s(sk);
42
44 auto pub_key = s.copy<KyberSerializedPublicKey>(mode.public_key_bytes());
47
49
50 CT::unpoison_all(pub_key, puk_key_hash, skpv, z);
51
53 std::make_shared<Kyber_PublicKeyInternal>(mode, std::move(pub_key)),
54 std::make_shared<Kyber_PrivateKeyInternal>(
55 std::move(mode),
56 std::move(skpv),
57 KyberPrivateKeySeed{std::nullopt, // Reading from an expanded and encoded
58 // private key cannot reconstruct the
59 // original seed from key generation.
60 std::move(z)}),
61 };
62
63 BOTAN_ASSERT(keypair.first && keypair.second, "reading private key encoding");
64 BOTAN_ARG_CHECK(keypair.first->H_public_key_bits_raw().size() == puk_key_hash.size() &&
65 std::equal(keypair.first->H_public_key_bits_raw().begin(),
66 keypair.first->H_public_key_bits_raw().end(),
67 puk_key_hash.begin()),
68 "public key's hash does not match the stored hash");
69
70 return keypair;
71}
72
74 BOTAN_ASSERT_NONNULL(keypair.first);
75 BOTAN_ASSERT_NONNULL(keypair.second);
76 const auto& mode = keypair.first->mode();
77 auto scope = CT::scoped_poison(*keypair.second);
78 auto result = concat(Kyber_Algos::encode_polynomial_vector(keypair.second->s().reduce(), mode),
79 keypair.first->public_key_bits_raw(),
80 keypair.first->H_public_key_bits_raw(),
81 keypair.second->z());
82 CT::unpoison(result);
83 return result;
84}
85
87 KyberConstants mode) const {
88 BufferSlicer s(private_key);
89 auto seed = KyberPrivateKeySeed{
92 };
94 return Kyber_Algos::expand_keypair(std::move(seed), std::move(mode));
95}
96
98 BOTAN_ASSERT_NONNULL(keypair.second);
99 const auto& seed = keypair.second->seed();
100 BOTAN_ARG_CHECK(seed.d.has_value(), "Cannot encode keypair without the full private seed");
101 return concat<secure_vector<uint8_t>>(seed.d.value(), seed.z);
102}
103
105 m_mode(std::move(mode)),
106 m_public_key_bits_raw(validate_public_key_length(std::move(public_key), m_mode.public_key_bytes())),
107 m_H_public_key_bits_raw(m_mode.symmetric_primitives().H(m_public_key_bits_raw)),
108 m_t(Kyber_Algos::decode_polynomial_vector(
109 std::span{m_public_key_bits_raw}.first(m_mode.polynomial_vector_bytes()), m_mode)),
110 m_rho(std::span{m_public_key_bits_raw}.last(Botan::KyberConstants::SEED_BYTES)) {}
111
113 m_mode(std::move(mode)),
114 m_public_key_bits_raw(concat(Kyber_Algos::encode_polynomial_vector<std::vector<uint8_t>>(t, m_mode), rho)),
115 m_H_public_key_bits_raw(m_mode.symmetric_primitives().H(m_public_key_bits_raw)),
116 m_t(std::move(t)),
117 m_rho(std::move(rho)) {}
118
119/**
120 * NIST FIPS 203, Algorithm 14 (K-PKE.Encrypt)
121 *
122 * In contrast to FIPS 203, the matrix @p At is not sampled for every invocation,
123 * instead it is precomputed and passed in as a parameter. Similarly, the t^T is
124 * already decoded and available as a member variable. This allows to reuse these
125 * structures for multiple encryptions.
126 *
127 * The sampling loops spelled out in FIPS 203 are hidden in the sample_* functions.
128 */
132 const KyberPolyMat& At) const {
133 // The nonce N is handled internally by the PolynomialSampler
134 Kyber_Algos::PolynomialSampler ps(r, m_mode);
135 const auto y = ntt(ps.sample_polynomial_vector_cbd_eta1());
136 const auto e1 = ps.sample_polynomial_vector_cbd_eta2();
137 const auto e2 = ps.sample_polynomial_cbd_eta2();
138
139 auto u = inverse_ntt(At * y);
140 u += e1;
141 u.reduce();
142
143 const auto mu = Kyber_Algos::polynomial_from_message(m);
144 auto v = inverse_ntt(m_t * y);
145 v += e2;
146 v += mu;
147 v.reduce();
148
149 Kyber_Algos::compress_ciphertext(out_ct, u, v, m_mode);
150}
151
152/**
153 * NIST FIPS 203, Algorithm 15 (K-PKE.Decrypt)
154 *
155 * s^T is already decoded and available as a member variable. This allows to reuse
156 * the structure for multiple decryptions.
157 */
159 auto [u, v] = Kyber_Algos::decompress_ciphertext(ct, m_mode);
160 v -= inverse_ntt(m_s * ntt(std::move(u)));
161 v.reduce();
163}
164
165} // namespace Botan
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:61
#define BOTAN_ASSERT_NONNULL(ptr)
Definition assert.h:88
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:31
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:52
auto copy(const size_t count)
Definition stl_util.h:90
bool empty() const
Definition stl_util.h:130
std::span< const uint8_t > take(const size_t count)
Definition stl_util.h:99
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:70
KyberPolyVec sample_polynomial_vector_cbd_eta2()
Definition kyber_algos.h:86
KyberMessage indcpa_decrypt(StrongSpan< const KyberCompressedCiphertext > ct) const
const KyberPolyVecNTT & t() const
Definition kyber_keys.h:61
const KyberSeedRho & rho() const
Definition kyber_keys.h:63
void indcpa_encrypt(StrongSpan< KyberCompressedCiphertext > out_ct, StrongSpan< const KyberMessage > m, StrongSpan< const KyberEncryptionRandomness > r, const KyberPolyMat &At) const
const KyberConstants & mode() const
Definition kyber_keys.h:65
KyberInternalKeypair decode_keypair(std::span< const uint8_t > buffer, KyberConstants mode) const override
secure_vector< uint8_t > encode_keypair(KyberInternalKeypair keypair) const override
constexpr void unpoison_all(Ts &&... ts)
Definition ct_utils.h:202
constexpr auto scoped_poison(const Ts &... xs)
Definition ct_utils.h:217
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:65
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 stl_util.h:264
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:64
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