Botan 3.6.0
Crypto and TLS for C&
Botan::Kyber_Algos Namespace Reference

Classes

class  PolynomialSampler
 

Functions

template<size_t d>
requires (d > 0 && d < 12)
constexpr std::make_unsigned_t< KyberConstants::Tcompress (KyberConstants::T x)
 
void compress_ciphertext (StrongSpan< KyberCompressedCiphertext > out, const KyberPolyVec &u, const KyberPoly &v, const KyberConstants &m_mode)
 
KyberPolyVecNTT decode_polynomial_vector (std::span< const uint8_t > a, const KyberConstants &mode)
 
template<size_t d>
requires (d > 0 && d < 12)
constexpr KyberConstants::T decompress (std::make_unsigned_t< KyberConstants::T > x)
 
std::pair< KyberPolyVec, KyberPolydecompress_ciphertext (StrongSpan< const KyberCompressedCiphertext > ct, const KyberConstants &mode)
 
template<concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
T encode_polynomial_vector (const KyberPolyVecNTT &vec, const KyberConstants &mode)
 
void encode_polynomial_vector (std::span< uint8_t > out, const KyberPolyVecNTT &vec)
 
KyberInternalKeypair expand_keypair (KyberPrivateKeySeed seed, KyberConstants mode)
 
uint32_t load_le3 (std::span< const uint8_t, 3 > in)
 
KyberPoly polynomial_from_message (StrongSpan< const KyberMessage > msg)
 
KyberMessage polynomial_to_message (const KyberPoly &p)
 
template<typename T >
 PolynomialSampler (T, const KyberConstants &) -> PolynomialSampler< T >
 
KyberPolyMat sample_matrix (StrongSpan< const KyberSeedRho > seed, bool transposed, const KyberConstants &mode)
 
void sample_polynomial_from_cbd (KyberPoly &poly, KyberConstants::KyberEta eta, const KyberSamplingRandomness &randomness)
 

Function Documentation

◆ compress()

template<size_t d>
requires (d > 0 && d < 12)
std::make_unsigned_t< KyberConstants::T > Botan::Kyber_Algos::compress ( KyberConstants::T x)
constexpr

NIST FIPS 203, Formula 4.7 (Compress)

Definition at line 33 of file kyber_helpers.h.

33 {
34 BOTAN_DEBUG_ASSERT(x >= 0 && x < KyberConstants::Q);
35 const uint32_t n = (static_cast<uint32_t>(x) << d) + KyberConstants::Q / 2;
36
37 // This is a mitigation for a potential side channel called "KyberSlash".
38 //
39 // It implements the division by Q using a multiplication and a shift. Most
40 // compilers would generate similar code for such a division by a constant.
41 // Though, in some cases, compilers might use a variable-time int division,
42 // resulting in a potential side channel.
43 //
44 // The constants below work for all values that appear in Kyber with the
45 // greatest being 3328 * 2^11 + Q // 2 = 6,817,408 < 2**23 = 8,388,608.
46 //
47 // See "Hacker's Delight" (Second Edition) by Henry S. Warren, Jr.
48 // Chapter 10-9 "Unsigned Division by Divisors >= 1"
49 BOTAN_DEBUG_ASSERT(n < (1 << 23));
50 static_assert(KyberConstants::Q == 3329);
51 using unsigned_T = std::make_unsigned_t<KyberConstants::T>;
52
53 constexpr uint64_t m = 2580335;
54 constexpr size_t p = 33;
55 constexpr unsigned_T mask = (1 << d) - 1;
56 return static_cast<unsigned_T>((n * m) >> p) & mask;
57};
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:98

References BOTAN_DEBUG_ASSERT, and Botan::KyberConstants::Q.

◆ compress_ciphertext()

void Botan::Kyber_Algos::compress_ciphertext ( StrongSpan< KyberCompressedCiphertext > out,
const KyberPolyVec & u,
const KyberPoly & v,
const KyberConstants & m_mode )

Definition at line 352 of file kyber_algos.cpp.

355 {
356 BufferStuffer bs(out);
357 compress_polyvec(bs.next(m_mode.polynomial_vector_compressed_bytes()), u, m_mode);
358 compress_poly(bs.next(m_mode.polynomial_compressed_bytes()), v, m_mode);
359 BOTAN_ASSERT_NOMSG(bs.full());
360}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:59
Helper class to ease in-place marshalling of concatenated fixed-length values.
Definition stl_util.h:142
size_t polynomial_vector_compressed_bytes() const
byte length of an encoded compressed polynomial vector
size_t polynomial_compressed_bytes() const
byte length of an encoded compressed polynomial

References BOTAN_ASSERT_NOMSG, Botan::BufferStuffer::full(), Botan::BufferStuffer::next(), Botan::KyberConstants::polynomial_compressed_bytes(), and Botan::KyberConstants::polynomial_vector_compressed_bytes().

Referenced by Botan::Kyber_PublicKeyInternal::indcpa_encrypt().

◆ decode_polynomial_vector()

KyberPolyVecNTT Botan::Kyber_Algos::decode_polynomial_vector ( std::span< const uint8_t > a,
const KyberConstants & mode )

Definition at line 192 of file kyber_algos.cpp.

192 {
193 KyberPolyVecNTT vec(mode.k());
194
195 BufferSlicer bs(a);
196 for(auto& p : vec) {
197 byte_decode(p, bs);
198 }
199 BOTAN_ASSERT_NOMSG(bs.empty());
200
201 return vec;
202}

References BOTAN_ASSERT_NOMSG, Botan::BufferSlicer::empty(), and Botan::KyberConstants::k().

Referenced by Botan::Kyber_Expanded_Keypair_Codec::decode_keypair().

◆ decompress()

template<size_t d>
requires (d > 0 && d < 12)
KyberConstants::T Botan::Kyber_Algos::decompress ( std::make_unsigned_t< KyberConstants::T > x)
constexpr

NIST FIPS 203, Formula 4.8 (Decompress)

Definition at line 64 of file kyber_helpers.h.

64 {
65 BOTAN_DEBUG_ASSERT(x >= 0 && x < (1 << d));
66
67 constexpr uint32_t offset = 1 << (d - 1);
68 constexpr uint32_t mask = (1 << d) - 1;
69 return static_cast<KyberConstants::T>(((static_cast<uint32_t>(x) & mask) * KyberConstants::Q + offset) >> d);
70}
int16_t T
base data type for most calculations

References BOTAN_DEBUG_ASSERT, and Botan::KyberConstants::Q.

◆ decompress_ciphertext()

std::pair< KyberPolyVec, KyberPoly > Botan::Kyber_Algos::decompress_ciphertext ( StrongSpan< const KyberCompressedCiphertext > ct,
const KyberConstants & mode )

Definition at line 362 of file kyber_algos.cpp.

363 {
364 const size_t pvb = mode.polynomial_vector_compressed_bytes();
365 const size_t pcb = mode.polynomial_compressed_bytes();
366
367 // FIPS 203, Section 7.3 check 1 "Ciphertext type check"
368 if(ct.size() != pvb + pcb) {
369 throw Decoding_Error("Kyber: unexpected ciphertext length");
370 }
371
372 BufferSlicer bs(ct);
373 auto pv = bs.take(pvb);
374 auto p = bs.take(pcb);
375 BOTAN_ASSERT_NOMSG(bs.empty());
376
377 return {decompress_polynomial_vector(pv, mode), decompress_polynomial(p, mode)};
378}
decltype(auto) size() const noexcept(noexcept(this->m_span.size()))

References BOTAN_ASSERT_NOMSG, Botan::BufferSlicer::empty(), Botan::KyberConstants::polynomial_compressed_bytes(), Botan::KyberConstants::polynomial_vector_compressed_bytes(), Botan::StrongSpan< T >::size(), and Botan::BufferSlicer::take().

Referenced by Botan::Kyber_PrivateKeyInternal::indcpa_decrypt().

◆ encode_polynomial_vector() [1/2]

template<concepts::resizable_byte_buffer T = secure_vector<uint8_t>>
T Botan::Kyber_Algos::encode_polynomial_vector ( const KyberPolyVecNTT & vec,
const KyberConstants & mode )

Definition at line 51 of file kyber_algos.h.

51 {
52 T r(mode.polynomial_vector_bytes());
54 return r;
55}
size_t polynomial_vector_bytes() const
byte length of an encoded polynomial vector
FE_25519 T
Definition ge.cpp:34
void encode_polynomial_vector(std::span< uint8_t > out, const KyberPolyVecNTT &vec)

References encode_polynomial_vector(), Botan::KyberConstants::polynomial_vector_bytes(), and T.

◆ encode_polynomial_vector() [2/2]

void Botan::Kyber_Algos::encode_polynomial_vector ( std::span< uint8_t > out,
const KyberPolyVecNTT & vec )

Definition at line 184 of file kyber_algos.cpp.

184 {
185 BufferStuffer bs(out);
186 for(auto& v : vec) {
187 byte_encode(bs, v);
188 }
189 BOTAN_ASSERT_NOMSG(bs.full());
190}

References BOTAN_ASSERT_NOMSG, and Botan::BufferStuffer::full().

Referenced by Botan::Kyber_PublicKey::check_key(), Botan::Kyber_Expanded_Keypair_Codec::encode_keypair(), and encode_polynomial_vector().

◆ expand_keypair()

KyberInternalKeypair Botan::Kyber_Algos::expand_keypair ( KyberPrivateKeySeed seed,
KyberConstants mode )

NIST FIPS 203, Algorithms 16 (ML-KEM.KeyGen_internal), and 13 (K-PKE.KeyGen)

In contrast to the specification, the expansion of rho and sigma is inlined with the actual PKE key generation. The sampling loops spelled out in FIPS 203 are hidden in the sample_* functions. The keys are kept in memory without serialization, which is deferred until requested.

Definition at line 321 of file kyber_algos.cpp.

321 {
322 BOTAN_ARG_CHECK(seed.d.has_value(), "Cannot expand keypair without the full private seed");
323 const auto& d = seed.d.value();
324
325 CT::poison(d);
326 auto [rho, sigma] = mode.symmetric_primitives().G(d, mode);
327 CT::unpoison(rho); // rho is public (seed for the public matrix A)
328
329 // Algorithm 13 (K-PKE.KeyGen) ----------------
330
331 auto A = Kyber_Algos::sample_matrix(rho, false /* not transposed */, mode);
332
333 // The nonce N is handled internally by the PolynomialSampler
334 Kyber_Algos::PolynomialSampler ps(sigma, mode);
335 auto s = ntt(ps.sample_polynomial_vector_cbd_eta1());
336 const auto e = ntt(ps.sample_polynomial_vector_cbd_eta1());
337
338 auto t = montgomery(A * s);
339 t += e;
340 t.reduce();
341
342 // End Algorithm 13 ---------------------------
343
344 CT::unpoison_all(d, t, s);
345
346 return {
347 std::make_shared<Kyber_PublicKeyInternal>(mode, std::move(t), std::move(rho)),
348 std::make_shared<Kyber_PrivateKeyInternal>(std::move(mode), std::move(s), std::move(seed)),
349 };
350}
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:29
Kyber_Symmetric_Primitives & symmetric_primitives() const
std::pair< KyberSeedRho, KyberSeedSigma > G(StrongSpan< const KyberSeedRandomness > seed, const KyberConstants &mode) const
constexpr T rho(T x)
Definition rotate.h:51
constexpr T sigma(T x)
Definition rotate.h:43
std::optional< KyberSeedRandomness > d
Definition kyber_types.h:80

References BOTAN_ARG_CHECK, Botan::KyberPrivateKeySeed::d, Botan::Kyber_Symmetric_Primitives::G(), Botan::CT::poison(), Botan::rho(), sample_matrix(), Botan::Kyber_Algos::PolynomialSampler< SeedT >::sample_polynomial_vector_cbd_eta1(), Botan::sigma(), Botan::KyberConstants::symmetric_primitives(), Botan::CT::unpoison(), and Botan::CT::unpoison_all().

Referenced by Botan::ML_KEM_Expanding_Keypair_Codec::decode_keypair(), and Botan::Kyber_PrivateKey::Kyber_PrivateKey().

◆ load_le3()

uint32_t Botan::Kyber_Algos::load_le3 ( std::span< const uint8_t, 3 > in)
inline

Special load_le<> that takes 3 bytes and returns a 32-bit integer.

Definition at line 24 of file kyber_helpers.h.

24 {
25 return Botan::load_le(std::array<uint8_t, 4>{in[0], in[1], in[2], 0});
26}
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:521

References Botan::load_le().

◆ polynomial_from_message()

KyberPoly Botan::Kyber_Algos::polynomial_from_message ( StrongSpan< const KyberMessage > msg)

Definition at line 204 of file kyber_algos.cpp.

204 {
205 BOTAN_ASSERT(msg.size() == KyberConstants::N / 8, "message length must be N/8 bytes");
206 KyberPoly r;
207 BufferSlicer bs(msg);
208 poly_decode_and_decompress<1>(r, bs);
209 return r;
210}
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:50

References BOTAN_ASSERT, Botan::KyberConstants::N, and Botan::StrongSpan< T >::size().

Referenced by Botan::Kyber_PublicKeyInternal::indcpa_encrypt().

◆ polynomial_to_message()

KyberMessage Botan::Kyber_Algos::polynomial_to_message ( const KyberPoly & p)

Definition at line 212 of file kyber_algos.cpp.

212 {
213 KyberMessage result(p.size() / 8);
214 BufferStuffer bs(result);
215 poly_compress_and_encode<1>(bs, p);
216 return result;
217}
constexpr size_t size() const
Definition pqcrystals.h:274

References Botan::CRYSTALS::Polynomial< Trait, D >::size().

Referenced by Botan::Kyber_PrivateKeyInternal::indcpa_decrypt().

◆ PolynomialSampler()

template<typename T >
Botan::Kyber_Algos::PolynomialSampler ( T ,
const KyberConstants &  ) -> PolynomialSampler< T >

◆ sample_matrix()

KyberPolyMat Botan::Kyber_Algos::sample_matrix ( StrongSpan< const KyberSeedRho > seed,
bool transposed,
const KyberConstants & mode )

Definition at line 380 of file kyber_algos.cpp.

380 {
381 BOTAN_ASSERT(seed.size() == KyberConstants::SEED_BYTES, "unexpected seed size");
382
383 KyberPolyMat mat(mode.k(), mode.k());
384
385 for(uint8_t i = 0; i < mode.k(); ++i) {
386 for(uint8_t j = 0; j < mode.k(); ++j) {
387 const auto pos = (transposed) ? std::tuple(i, j) : std::tuple(j, i);
388 sample_ntt_uniform(mat[i][j], mode.symmetric_primitives().XOF(seed, pos));
389 }
390 }
391
392 return mat;
393}
Botan::XOF & XOF(StrongSpan< const KyberSeedRho > seed, std::tuple< uint8_t, uint8_t > matrix_position) const

References BOTAN_ASSERT, Botan::KyberConstants::k(), Botan::KyberConstants::SEED_BYTES, Botan::StrongSpan< T >::size(), Botan::KyberConstants::symmetric_primitives(), and Botan::Kyber_Symmetric_Primitives::XOF().

Referenced by expand_keypair().

◆ sample_polynomial_from_cbd()

void Botan::Kyber_Algos::sample_polynomial_from_cbd ( KyberPoly & poly,
KyberConstants::KyberEta eta,
const KyberSamplingRandomness & randomness )

NIST FIPS 203, Algorithm 8 (SamplePolyCBD)

The actual implementation is above. This just dispatches to the correct specialization based on the eta of the chosen mode.

Definition at line 401 of file kyber_algos.cpp.

403 {
404 switch(eta) {
405 case KyberConstants::KyberEta::_2:
406 return sample_poly_cbd<KyberConstants::KyberEta::_2>(poly, randomness);
407 case KyberConstants::KyberEta::_3:
408 return sample_poly_cbd<KyberConstants::KyberEta::_3>(poly, randomness);
409 }
410
412}
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:137

References Botan::KyberConstants::_2, Botan::KyberConstants::_3, and BOTAN_ASSERT_UNREACHABLE.