15#include <botan/internal/kyber_algos.h>
17#include <botan/internal/kyber_helpers.h>
18#include <botan/internal/kyber_keys.h>
19#include <botan/internal/loadstor.h>
20#include <botan/internal/pqcrystals_encoding.h>
21#include <botan/internal/pqcrystals_helpers.h>
63 throw Decoding_Error(
"Decoded polynomial coefficients out of range");
78 auto sample = [stashed_coeff = std::optional<uint16_t>{},
81 auto lowerthan_q = [](uint32_t d) -> std::optional<uint16_t> {
83 return static_cast<uint16_t
>(d);
89 if(
auto stashed = std::exchange(stashed_coeff, std::nullopt)) {
94 const auto [d1, d2] = bounded_xof.next<3>([&](
const auto bytes) {
96 return std::pair{lowerthan_q(x & 0x0FFF), lowerthan_q(x >> 12)};
102 }
else if(d2.has_value()) {
109 for(
auto& coeff : p) {
120template <KyberConstants::KyberEta eta>
127void sample_poly_cbd<KyberConstants::KyberEta::_2>(
KyberPoly& poly,
131 for(
size_t i = 0; i < poly.
size() / 8; ++i) {
135 constexpr uint32_t operand_bitmask = 0b01010101010101010101010101010101;
138 const uint32_t d = ((t >> 0) & operand_bitmask) +
139 ((t >> 1) & operand_bitmask);
142 for(
size_t j = 0; j < 8; ++j) {
143 const int16_t a = (d >> (4 * j + 0)) & 0x3;
144 const int16_t
b = (d >> (4 * j + 2)) & 0x3;
145 poly[8 * i + j] = a -
b;
156void sample_poly_cbd<KyberConstants::KyberEta::_3>(
KyberPoly& poly,
160 for(
size_t i = 0; i < poly.
size() / 4; ++i) {
164 constexpr uint32_t operand_bitmask = 0b00000000001001001001001001001001;
167 const uint32_t d = ((t >> 0) & operand_bitmask) +
168 ((t >> 1) & operand_bitmask) +
169 ((t >> 2) & operand_bitmask);
172 for(
size_t j = 0; j < 4; ++j) {
173 const int16_t a = (d >> (6 * j + 0)) & 0x7;
174 const int16_t
b = (d >> (6 * j + 3)) & 0x7;
175 poly[4 * i + j] = a -
b;
208 poly_decode_and_decompress<1>(r, bs);
215 poly_compress_and_encode<1>(bs, p);
223 for(
const auto& p : polyvec) {
224 poly_compress_and_encode<d>(sink, p);
228void compress_polyvec(std::span<uint8_t> out,
const KyberPolyVec& pv,
const KyberConstants& mode) {
229 BufferStuffer bs(out);
233 polyvec_compress_and_encode<10>(bs, pv);
237 polyvec_compress_and_encode<11>(bs, pv);
245void compress_poly(std::span<uint8_t> out,
const KyberPoly& p,
const KyberConstants& mode) {
246 BufferStuffer bs(out);
250 poly_compress_and_encode<4>(bs, p);
254 poly_compress_and_encode<5>(bs, p);
263void polyvec_decode_and_decompress(
KyberPolyVec& polyvec, BufferSlicer& source) {
264 for(
auto& p : polyvec) {
265 poly_decode_and_decompress<d>(p, source);
269KyberPolyVec decompress_polynomial_vector(std::span<const uint8_t> buffer,
const KyberConstants& mode) {
270 BOTAN_ASSERT(buffer.size() == mode.polynomial_vector_compressed_bytes(),
271 "unexpected length of compressed polynomial vector");
274 BufferSlicer bs(buffer);
278 polyvec_decode_and_decompress<10>(r, bs);
282 polyvec_decode_and_decompress<11>(r, bs);
290KyberPoly decompress_polynomial(std::span<const uint8_t> buffer,
const KyberConstants& mode) {
291 BOTAN_ASSERT(buffer.size() == mode.polynomial_compressed_bytes(),
"unexpected length of compressed polynomial");
294 BufferSlicer bs(buffer);
298 poly_decode_and_decompress<4>(r, bs);
302 poly_decode_and_decompress<5>(r, bs);
322 BOTAN_ARG_CHECK(seed.
d.has_value(),
"Cannot expand keypair without the full private seed");
323 const auto& d = seed.
d.value();
338 auto t = montgomery(A * s);
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)),
368 if(ct.
size() != pvb + pcb) {
373 auto pv = bs.
take(pvb);
374 auto p = bs.
take(pcb);
377 return {decompress_polynomial_vector(pv, mode), decompress_polynomial(p, mode)};
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);
406 return sample_poly_cbd<KyberConstants::KyberEta::_2>(poly, randomness);
408 return sample_poly_cbd<KyberConstants::KyberEta::_3>(poly, randomness);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
#define BOTAN_ASSERT_UNREACHABLE()
std::span< const uint8_t > take(const size_t count)
Helper class to ease in-place marshalling of concatenated fixed-length values.
constexpr std::span< uint8_t > next(size_t bytes)
constexpr bool full() const
constexpr size_t size() const
size_t polynomial_vector_compressed_bytes() const
byte length of an encoded compressed polynomial vector
static constexpr T N
number of coefficients in a polynomial
size_t polynomial_compressed_bytes() const
byte length of an encoded compressed polynomial
static constexpr T Q
modulus
static constexpr size_t SEED_BYTES
Kyber_Symmetric_Primitives & symmetric_primitives() const
KyberPolyVec sample_polynomial_vector_cbd_eta1()
Botan::XOF & XOF(StrongSpan< const KyberSeedRho > seed, std::tuple< uint8_t, uint8_t > matrix_position) const
std::pair< KyberSeedRho, KyberSeedSigma > G(StrongSpan< const KyberSeedRandomness > seed, const KyberConstants &mode) const
decltype(auto) size() const noexcept(noexcept(this->m_span.size()))
constexpr void unpack(Polynomial< PolyTrait, D > &p, ByteSourceT &byte_source, UnmapFnT unmap)
constexpr void pack(const Polynomial< PolyTrait, D > &p, BufferStuffer &stuffer, MapFnT map)
constexpr void unpoison_all(Ts &&... ts)
constexpr void unpoison(const T *p, size_t n)
constexpr void poison(const T *p, size_t n)
constexpr std::make_unsigned_t< KyberConstants::T > compress(KyberConstants::T x)
void encode_polynomial_vector(std::span< uint8_t > out, const KyberPolyVecNTT &vec)
KyberMessage polynomial_to_message(const KyberPoly &p)
KyberPolyMat sample_matrix(StrongSpan< const KyberSeedRho > seed, bool transposed, const KyberConstants &mode)
uint32_t load_le3(std::span< const uint8_t, 3 > in)
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)
void sample_polynomial_from_cbd(KyberPoly &poly, KyberConstants::KyberEta eta, const KyberSamplingRandomness &randomness)
std::pair< KyberPolyVec, KyberPoly > decompress_ciphertext(StrongSpan< const KyberCompressedCiphertext > ct, const KyberConstants &mode)
constexpr KyberConstants::T decompress(std::make_unsigned_t< KyberConstants::T > x)
KyberPolyVecNTT decode_polynomial_vector(std::span< const uint8_t > a, const KyberConstants &mode)
Botan::CRYSTALS::Polynomial< KyberPolyTraits, Botan::CRYSTALS::Domain::Normal > KyberPoly
detail::Bounded_XOF< XOF &, bound > Bounded_XOF
constexpr auto load_le(ParamTs &&... params)
std::pair< std::shared_ptr< Kyber_PublicKeyInternal >, std::shared_ptr< Kyber_PrivateKeyInternal > > KyberInternalKeypair
Botan::CRYSTALS::PolynomialVector< KyberPolyTraits, Botan::CRYSTALS::Domain::Normal > KyberPolyVec
std::optional< KyberSeedRandomness > d