Botan 3.5.0
Crypto and TLS for C&
kyber.cpp
Go to the documentation of this file.
1/*
2 * Crystals Kyber key encapsulation mechanism
3 * Based on the public domain reference implementation by the
4 * designers (https://github.com/pq-crystals/kyber)
5 *
6 * Further changes
7 * (C) 2021-2022 Jack Lloyd
8 * (C) 2021-2022 Manuel Glaser and Michael Boric, Rohde & Schwarz Cybersecurity
9 * (C) 2021-2022 René Meusel and Hannes Rantzsch, neXenio GmbH
10 * (C) 2024 René Meusel, Rohde & Schwarz Cybersecurity
11 *
12 * Botan is released under the Simplified BSD License (see license.txt)
13 */
14
15#include <botan/kyber.h>
16
17#include <botan/assert.h>
18#include <botan/mem_ops.h>
19#include <botan/rng.h>
20#include <botan/secmem.h>
21
22#include <botan/internal/fmt.h>
23#include <botan/internal/kyber_constants.h>
24#include <botan/internal/kyber_keys.h>
25#include <botan/internal/kyber_symmetric_primitives.h>
26#include <botan/internal/kyber_types.h>
27#include <botan/internal/stl_util.h>
28
29#if defined(BOTAN_HAS_KYBER)
30 #include <botan/internal/kyber_modern.h>
31#endif
32
33#if defined(BOTAN_HAS_KYBER_90S)
34 #include <botan/internal/kyber_90s.h>
35#endif
36
37#if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S)
38 #include <botan/internal/kyber_encaps.h>
39#endif
40
41#include <array>
42#include <limits>
43#include <memory>
44#include <vector>
45
46namespace Botan {
47
48namespace {
49
50KyberMode::Mode kyber_mode_from_string(std::string_view str) {
51 if(str == "Kyber-512-90s-r3") {
53 }
54 if(str == "Kyber-768-90s-r3") {
56 }
57 if(str == "Kyber-1024-90s-r3") {
59 }
60 if(str == "Kyber-512-r3") {
62 }
63 if(str == "Kyber-768-r3") {
65 }
66 if(str == "Kyber-1024-r3") {
68 }
69
70 throw Invalid_Argument(fmt("'{}' is not a valid Kyber mode name", str));
71}
72
73} // namespace
74
75KyberMode::KyberMode(Mode mode) : m_mode(mode) {}
76
77KyberMode::KyberMode(const OID& oid) : m_mode(kyber_mode_from_string(oid.to_formatted_string())) {}
78
79KyberMode::KyberMode(std::string_view str) : m_mode(kyber_mode_from_string(str)) {}
80
84
85std::string KyberMode::to_string() const {
86 switch(m_mode) {
87 case Kyber512_90s:
88 return "Kyber-512-90s-r3";
89 case Kyber768_90s:
90 return "Kyber-768-90s-r3";
91 case Kyber1024_90s:
92 return "Kyber-1024-90s-r3";
93 case Kyber512_R3:
94 return "Kyber-512-r3";
95 case Kyber768_R3:
96 return "Kyber-768-r3";
97 case Kyber1024_R3:
98 return "Kyber-1024-r3";
99 }
100
102}
103
104bool KyberMode::is_90s() const {
105 return m_mode == Kyber512_90s || m_mode == Kyber768_90s || m_mode == Kyber1024_90s;
106}
107
109 return !is_90s();
110}
111
113 return m_mode == KyberMode::Kyber512_R3 || m_mode == KyberMode::Kyber768_R3 || m_mode == KyberMode::Kyber1024_R3 ||
115}
116
118#if defined(BOTAN_HAS_KYBER)
119 if(is_kyber_round3() && is_modern()) {
120 return true;
121 }
122#endif
123
124#if defined(BOTAN_HAS_KYBER_90S)
125 if(is_kyber_round3() && is_90s()) {
126 return true;
127 }
128#endif
129
130 return false;
131}
132
134 return m_public->mode().mode();
135}
136
137std::string Kyber_PublicKey::algo_name() const {
138 return "Kyber";
139}
140
144
148
150 return m_public->mode().estimated_strength();
151}
152
153std::shared_ptr<Kyber_PublicKeyInternal> Kyber_PublicKey::initialize_from_encoding(std::span<const uint8_t> pub_key,
154 KyberMode m) {
156
157 if(pub_key.size() != mode.public_key_byte_length()) {
158 throw Invalid_Argument("kyber public key does not have the correct byte count");
159 }
160
161 BufferSlicer s(pub_key);
162
163 auto poly_vec = s.take(mode.polynomial_vector_byte_length());
166
167 return std::make_shared<Kyber_PublicKeyInternal>(std::move(mode), poly_vec, std::move(seed));
168}
169
170Kyber_PublicKey::Kyber_PublicKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
171 Kyber_PublicKey(key_bits, KyberMode(alg_id.oid())) {}
172
173Kyber_PublicKey::Kyber_PublicKey(std::span<const uint8_t> pub_key, KyberMode m) :
174 m_public(initialize_from_encoding(pub_key, m)) {}
175
177 m_public(std::make_shared<Kyber_PublicKeyInternal>(*other.m_public)) {}
178
179std::vector<uint8_t> Kyber_PublicKey::raw_public_key_bits() const {
180 return m_public->public_key_bits_raw().get();
181}
182
183std::vector<uint8_t> Kyber_PublicKey::public_key_bits() const {
184 // Currently, there isn't a finalized definition of an ASN.1 structure for
185 // Kyber aka ML-KEM public keys. Therefore, we return the raw public key bits.
186 return raw_public_key_bits();
187}
188
190 // TODO: this should report 512, 768, 1024
191 return m_public->mode().public_key_byte_length();
192}
193
195 return true; // ??
196}
197
198std::unique_ptr<Private_Key> Kyber_PublicKey::generate_another(RandomNumberGenerator& rng) const {
199 return std::make_unique<Kyber_PrivateKey>(rng, mode());
200}
201
202/**
203 * NIST FIPS 203 IPD, Algorithms 12 (K-PKE.KeyGen) and 15 (ML-KEM.KeyGen)
204 */
207
208 // Algorithm 12 (K-PKE.KeyGen) ----------------
209
211 auto [rho, sigma] = mode.symmetric_primitives().G(d);
212
213 auto a = PolynomialMatrix::generate(rho, false /* not transposed */, mode);
214 auto s = PolynomialVector::getnoise_eta1(sigma, 0 /* N */, mode);
215 auto e = PolynomialVector::getnoise_eta1(sigma, mode.k() /* N */, mode);
216
217 s.ntt();
218 e.ntt();
219
220 auto t = a.pointwise_acc_montgomery(s, true);
221 t += e;
222 t.reduce();
223
224 // End Algorithm 12 ---------------------------
225
226 m_public = std::make_shared<Kyber_PublicKeyInternal>(mode, std::move(t), std::move(rho));
227 m_private = std::make_shared<Kyber_PrivateKeyInternal>(
229}
230
231Kyber_PrivateKey::Kyber_PrivateKey(const AlgorithmIdentifier& alg_id, std::span<const uint8_t> key_bits) :
232 Kyber_PrivateKey(key_bits, KyberMode(alg_id.oid())) {}
233
234Kyber_PrivateKey::Kyber_PrivateKey(std::span<const uint8_t> sk, KyberMode m) {
236
237 if(mode.private_key_byte_length() != sk.size()) {
238 throw Invalid_Argument("kyber private key does not have the correct byte count");
239 }
240
241 BufferSlicer s(sk);
242
243 auto skpv = PolynomialVector::from_bytes(s.take(mode.polynomial_vector_byte_length()), mode);
244 auto pub_key = s.take<KyberSerializedPublicKey>(mode.public_key_byte_length());
247
249
251 m_private = std::make_shared<Kyber_PrivateKeyInternal>(std::move(mode), std::move(skpv), std::move(z));
252
253 BOTAN_ASSERT(m_private && m_public, "reading private key encoding");
254 BOTAN_STATE_CHECK(m_public->H_public_key_bits_raw().size() == puk_key_hash.size() &&
255 std::equal(m_public->H_public_key_bits_raw().begin(),
256 m_public->H_public_key_bits_raw().end(),
257 puk_key_hash.begin()));
258}
259
260std::unique_ptr<Public_Key> Kyber_PrivateKey::public_key() const {
261 return std::make_unique<Kyber_PublicKey>(*this);
262}
263
267
269 return concat(m_private->s().to_bytes<secure_vector<uint8_t>>(),
270 m_public->public_key_bits_raw(),
271 m_public->H_public_key_bits_raw(),
272 m_private->z());
273}
274
275std::unique_ptr<PK_Ops::KEM_Encryption> Kyber_PublicKey::create_kem_encryption_op(std::string_view params,
276 std::string_view provider) const {
277 if(provider.empty() || provider == "base") {
278#if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S)
279 if(mode().is_kyber_round3()) {
280 return std::make_unique<Kyber_KEM_Encryptor>(m_public, params);
281 }
282#endif
283
285 }
286 throw Provider_Not_Found(algo_name(), provider);
287}
288
289std::unique_ptr<PK_Ops::KEM_Decryption> Kyber_PrivateKey::create_kem_decryption_op(RandomNumberGenerator& rng,
290 std::string_view params,
291 std::string_view provider) const {
292 BOTAN_UNUSED(rng);
293 if(provider.empty() || provider == "base") {
294#if defined(BOTAN_HAS_KYBER) || defined(BOTAN_HAS_KYBER_90S)
295 if(mode().is_kyber_round3()) {
296 return std::make_unique<Kyber_KEM_Decryptor>(m_private, m_public, params);
297 }
298#endif
299
301 }
302 throw Provider_Not_Found(algo_name(), provider);
303}
304
305} // namespace Botan
#define BOTAN_UNUSED
Definition assert.h:118
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:41
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:50
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:137
auto copy(const size_t count)
Definition stl_util.h:89
bool empty() const
Definition stl_util.h:129
std::span< const uint8_t > take(const size_t count)
Definition stl_util.h:98
static constexpr size_t kPublicKeyHashLength
static constexpr size_t kZLength
static constexpr size_t kSeedLength
static constexpr size_t kSymBytes
bool is_available() const
Definition kyber.cpp:117
bool is_kyber_round3() const
Definition kyber.cpp:112
std::string to_string() const
Definition kyber.cpp:85
bool is_modern() const
Definition kyber.cpp:108
OID object_identifier() const
Definition kyber.cpp:81
KyberMode(Mode mode)
Definition kyber.cpp:75
bool is_90s() const
Definition kyber.cpp:104
Mode mode() const
Definition kyber.h:56
std::unique_ptr< PK_Ops::KEM_Decryption > create_kem_decryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
Definition kyber.cpp:289
std::unique_ptr< Public_Key > public_key() const override
Definition kyber.cpp:260
Kyber_PrivateKey(RandomNumberGenerator &rng, KyberMode mode)
Definition kyber.cpp:205
secure_vector< uint8_t > raw_private_key_bits() const override
Definition kyber.cpp:264
secure_vector< uint8_t > private_key_bits() const override
Definition kyber.cpp:268
static std::shared_ptr< Kyber_PublicKeyInternal > initialize_from_encoding(std::span< const uint8_t > pub_key, KyberMode m)
Definition kyber.cpp:153
std::vector< uint8_t > public_key_bits() const override
Definition kyber.cpp:183
std::vector< uint8_t > raw_public_key_bits() const override
Definition kyber.cpp:179
bool check_key(RandomNumberGenerator &, bool) const override
Definition kyber.cpp:194
std::string algo_name() const override
Definition kyber.cpp:137
std::shared_ptr< Kyber_PublicKeyInternal > m_public
Definition kyber.h:126
size_t key_length() const override
Definition kyber.cpp:189
AlgorithmIdentifier algorithm_identifier() const override
Definition kyber.cpp:141
std::unique_ptr< PK_Ops::KEM_Encryption > create_kem_encryption_op(std::string_view params, std::string_view provider) const override
Definition kyber.cpp:275
KyberMode mode() const
Definition kyber.cpp:133
OID object_identifier() const override
Definition kyber.cpp:145
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
Definition kyber.cpp:198
size_t estimated_strength() const override
Definition kyber.cpp:149
static OID from_string(std::string_view str)
Definition asn1_oid.cpp:86
static PolynomialMatrix generate(StrongSpan< const KyberSeedRho > seed, const bool transposed, const KyberConstants &mode)
static PolynomialVector from_bytes(std::span< const uint8_t > a, const KyberConstants &mode)
static PolynomialVector getnoise_eta1(KyberSigmaOrEncryptionRandomness seed, uint8_t nonce, const KyberConstants &mode)
void random_vec(std::span< uint8_t > v)
Definition rng.h:179
decltype(auto) begin() noexcept(noexcept(this->get().begin()))
Definition strong_type.h:99
size_type size() const noexcept(noexcept(this->get().size()))
constexpr T rho(T x)
Definition rotate.h:51
constexpr T sigma(T x)
Definition rotate.h:43
std::string fmt(std::string_view format, const T &... args)
Definition fmt.h:53
constexpr auto concat(Rs &&... ranges)
Definition stl_util.h:262
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:61