Botan 3.11.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>>
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 {
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:129
static constexpr T Q
modulus

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 354 of file kyber_algos.cpp.

357 {
358 BufferStuffer bs(out);
359 compress_polyvec(bs.next(m_mode.polynomial_vector_compressed_bytes()), u, m_mode);
360 compress_poly(bs.next(m_mode.polynomial_compressed_bytes()), v, m_mode);
361 BOTAN_ASSERT_NOMSG(bs.full());
362}
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
Helper class to ease in-place marshalling of concatenated fixed-length values.
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 194 of file kyber_algos.cpp.

194 {
195 KyberPolyVecNTT vec(mode.k());
196
197 BufferSlicer bs(a);
198 for(auto& p : vec) {
199 byte_decode(p, bs);
200 }
201 BOTAN_ASSERT_NOMSG(bs.empty());
202
203 return vec;
204}
Botan::CRYSTALS::PolynomialVector< KyberPolyTraits, Botan::CRYSTALS::Domain::NTT > KyberPolyVecNTT
Definition kyber_types.h:26

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

Referenced by Botan::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 364 of file kyber_algos.cpp.

365 {
366 const size_t pvb = mode.polynomial_vector_compressed_bytes();
367 const size_t pcb = mode.polynomial_compressed_bytes();
368
369 // FIPS 203, Section 7.3 check 1 "Ciphertext type check"
370 if(ct.size() != pvb + pcb) {
371 throw Decoding_Error("Kyber: unexpected ciphertext length");
372 }
373
374 BufferSlicer bs(ct);
375 auto pv = bs.take(pvb);
376 auto p = bs.take(pcb);
377 BOTAN_ASSERT_NOMSG(bs.empty());
378
379 return {decompress_polynomial_vector(pv, mode), decompress_polynomial(p, mode)};
380}
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 48 of file kyber_algos.h.

48 {
49 T r(mode.polynomial_vector_bytes());
51 return r;
52}
size_t polynomial_vector_bytes() const
byte length of an encoded polynomial vector
void encode_polynomial_vector(std::span< uint8_t > out, const KyberPolyVecNTT &vec)

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

◆ encode_polynomial_vector() [2/2]

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

Definition at line 186 of file kyber_algos.cpp.

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

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

Referenced by Botan::Kyber_PublicKey::check_key(), Botan::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 323 of file kyber_algos.cpp.

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

References Botan::load_le().

◆ polynomial_from_message()

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

Definition at line 206 of file kyber_algos.cpp.

206 {
207 BOTAN_ASSERT(msg.size() == KyberConstants::N / 8, "message length must be N/8 bytes");
208 KyberPoly r;
209 BufferSlicer bs(msg);
210 poly_decode_and_decompress<1>(r, bs);
211 return r;
212}
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
static constexpr T N
number of coefficients in a polynomial
Botan::CRYSTALS::Polynomial< KyberPolyTraits, Botan::CRYSTALS::Domain::Normal > KyberPoly
Definition kyber_types.h:29

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 214 of file kyber_algos.cpp.

214 {
215 KyberMessage result(p.size() / 8);
216 BufferStuffer bs(result);
217 poly_compress_and_encode<1>(bs, p);
218 return result;
219}
constexpr size_t size() const
Definition pqcrystals.h:276
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

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 382 of file kyber_algos.cpp.

382 {
383 BOTAN_ASSERT(seed.size() == KyberConstants::SEED_BYTES, "unexpected seed size");
384
385 KyberPolyMat mat(mode.k(), mode.k());
386
387 const auto& sym = mode.symmetric_primitives();
388 std::unique_ptr<Botan::XOF> xof;
389
390 for(uint8_t i = 0; i < mode.k(); ++i) {
391 for(uint8_t j = 0; j < mode.k(); ++j) {
392 const auto pos = (transposed) ? std::tuple(i, j) : std::tuple(j, i);
393 sym.setup_XOF(xof, seed, pos);
394 sample_ntt_uniform(mat[i][j], *xof);
395 }
396 }
397
398 return mat;
399}
static constexpr size_t SEED_BYTES
Botan::CRYSTALS::PolynomialMatrix< KyberPolyTraits > KyberPolyMat
Definition kyber_types.h:27

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

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 407 of file kyber_algos.cpp.

409 {
410 switch(eta) {
412 return sample_poly_cbd<KyberConstants::KyberEta::_2>(poly, randomness);
414 return sample_poly_cbd<KyberConstants::KyberEta::_3>(poly, randomness);
415 }
416
418}
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:163

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