15#ifndef BOTAN_KYBER_STRUCTURES_H_
16#define BOTAN_KYBER_STRUCTURES_H_
18#include <botan/exceptn.h>
21#include <botan/internal/ct_utils.h>
22#include <botan/internal/kyber_constants.h>
23#include <botan/internal/kyber_symmetric_primitives.h>
24#include <botan/internal/kyber_types.h>
25#include <botan/internal/loadstor.h>
26#include <botan/internal/stl_util.h>
52 const uint64_t m = 161271;
54 return static_cast<uint16_t
>((a * m) >> p);
67 for(
auto& coeff : m_coeffs) {
77 for(
auto& c : m_coeffs) {
78 c = barrett_reduce(c);
86 for(
size_t i = 0; i <
size() / 2; ++i) {
87 const uint16_t t0 = m_coeffs[2 * i];
88 const uint16_t t1 = m_coeffs[2 * i + 1];
89 auto buf = bs.
next<3>();
90 buf[0] =
static_cast<uint8_t
>(t0 >> 0);
91 buf[1] =
static_cast<uint8_t
>((t0 >> 8) | (t1 << 4));
92 buf[2] =
static_cast<uint8_t
>(t1 >> 4);
107 for(
size_t i = 0; i < r.
size() / 8; ++i) {
109 uint32_t d = t & 0x55555555;
110 d += (t >> 1) & 0x55555555;
112 for(
size_t j = 0; j < 8; ++j) {
113 int16_t a = (d >> (4 * j + 0)) & 0x3;
114 int16_t b = (d >> (4 * j + 2)) & 0x3;
115 r.m_coeffs[8 * i + j] = a - b;
135 const auto load_le = [](std::span<const uint8_t, 3> in) {
return make_uint32(0, in[2], in[1], in[0]); };
138 for(
size_t i = 0; i < r.
size() / 4; ++i) {
140 uint32_t d = t & 0x00249249;
141 d += (t >> 1) & 0x00249249;
142 d += (t >> 2) & 0x00249249;
144 for(
size_t j = 0; j < 4; ++j) {
145 int16_t a = (d >> (6 * j + 0)) & 0x7;
146 int16_t b = (d >> (6 * j + 3)) & 0x7;
147 r.m_coeffs[4 * i + j] = a - b;
162 const auto eta2 = mode.
eta2();
176 const auto eta1 = mode.
eta1();
177 BOTAN_ASSERT(eta1 == 2 || eta1 == 3,
"Invalid eta1 value");
186 for(
size_t i = 0; i < r.
size() / 2; ++i) {
187 r.m_coeffs[2 * i] = ((a[3 * i + 0] >> 0) | (
static_cast<uint16_t
>(a[3 * i + 1]) << 8)) & 0xFFF;
188 r.m_coeffs[2 * i + 1] = ((a[3 * i + 1] >> 4) | (
static_cast<uint16_t
>(a[3 * i + 2]) << 4)) & 0xFFF;
197 for(
size_t i = 0; i < r.
size() / 8; ++i) {
198 for(
size_t j = 0; j < 8; ++j) {
211 for(
size_t i = 0; i <
size() / 8; ++i) {
213 for(
size_t j = 0; j < 8; ++j) {
216 result[i] |= (t & 1) << j;
228 for(
size_t i = 0; i < this->
size(); ++i) {
230 std::numeric_limits<int16_t>::max());
231 this->m_coeffs[i] = this->m_coeffs[i] + other.m_coeffs[i];
241 for(
size_t i = 0; i < this->
size(); ++i) {
243 std::numeric_limits<int16_t>::min());
244 this->m_coeffs[i] = other.m_coeffs[i] - this->m_coeffs[i];
257 auto basemul = [](int16_t r[2],
const int16_t s[2],
const int16_t t[2],
const int16_t zeta) {
258 r[0] = fqmul(s[1], t[1]);
259 r[0] = fqmul(r[0], zeta);
260 r[0] += fqmul(s[0], t[0]);
262 r[1] = fqmul(s[0], t[1]);
263 r[1] += fqmul(s[1], t[0]);
268 for(
size_t i = 0; i < r.size() / 4; ++i) {
271 &r.m_coeffs[4 * i + 2], &a.m_coeffs[4 * i + 2], &b.m_coeffs[4 * i + 2], -
KyberConstants::zetas[64 + i]);
285 while(count < p.
size()) {
286 std::array<uint8_t, 3> buf;
289 const uint16_t val0 = ((buf[0] >> 0) | (
static_cast<uint16_t
>(buf[1]) << 8)) & 0xFFF;
290 const uint16_t val1 = ((buf[1] >> 4) | (
static_cast<uint16_t
>(buf[2]) << 4)) & 0xFFF;
293 p.m_coeffs[count++] = val0;
296 p.m_coeffs[count++] = val1;
309 for(
auto& c : m_coeffs) {
310 c = montgomery_reduce(
static_cast<int32_t
>(c) * f);
319 for(
size_t len =
size() / 2, k = 0; len >= 2; len /= 2) {
320 for(
size_t start = 0, j = 0; start <
size(); start = j + len) {
322 for(j = start; j < start + len; ++j) {
323 const auto t = fqmul(zeta, m_coeffs[j + len]);
324 m_coeffs[j + len] = m_coeffs[j] - t;
325 m_coeffs[j] = m_coeffs[j] + t;
338 for(
size_t len = 2, k = 0; len <=
size() / 2; len *= 2) {
339 for(
size_t start = 0, j = 0; start <
size(); start = j + len) {
341 for(j = start; j < start + len; ++j) {
342 const auto t = m_coeffs[j];
343 m_coeffs[j] = barrett_reduce(t + m_coeffs[j + len]);
344 m_coeffs[j + len] = fqmul(zeta, t - m_coeffs[j + len]);
349 for(
auto& c : m_coeffs) {
354 size_t size()
const {
return m_coeffs.size(); }
356 int16_t
operator[](
size_t idx)
const {
return m_coeffs[idx]; }
365 static int16_t barrett_reduce(int16_t a) {
374 static int16_t fqmul(int16_t a, int16_t b) {
return montgomery_reduce(
static_cast<int32_t
>(a) * b); }
380 static int16_t montgomery_reduce(int32_t a) {
385 return static_cast<int16_t
>(t);
388 std::array<int16_t, KyberConstants::N> m_coeffs;
404 for(
size_t i = 0; i < mode.
k(); ++i) {
417 "pointwise_acc_montgomery works on equally sized "
418 "PolynomialVectors only");
421 for(
size_t i = 0; i < a.m_vec.size(); ++i) {
432 for(
auto& p : r.m_vec) {
442 for(
auto& p : r.m_vec) {
448 template <concepts::resizable_
byte_buffer T = secure_vector<u
int8_t>>
453 for(
auto& v : m_vec) {
466 for(
auto& p : m_vec) {
472 BOTAN_ASSERT(m_vec.size() == other.m_vec.size(),
"cannot add polynomial vectors of differing lengths");
474 for(
size_t i = 0; i < m_vec.size(); ++i) {
475 m_vec[i] += other.m_vec[i];
486 for(
auto& v : m_vec) {
495 for(
auto& v : m_vec) {
504 for(
auto& v : m_vec) {
510 std::vector<Polynomial> m_vec;
518 const bool transposed,
524 for(uint8_t i = 0; i < mode.
k(); ++i) {
525 for(uint8_t j = 0; j < mode.
k(); ++j) {
526 const auto pos = (transposed) ? std::tuple(i, j) : std::tuple(j, i);
537 for(
size_t i = 0; i < m_mat.size(); ++i) {
551 std::vector<PolynomialVector> m_mat;
559 m_mode(std::move(mode)), m_b(std::move(
b)), m_v(
v) {}
565 if(buffer.
size() != pvb + pcb) {
570 auto pv = bs.
take(pvb);
571 auto p = bs.
take(pcb);
574 return Ciphertext(decompress_polynomial_vector(pv, mode), decompress_polynomial(p, mode), mode);
599 if(mode.
k() == 2 || mode.
k() == 3) {
601 for(
size_t i = 0; i < mode.
k(); ++i) {
603 for(
size_t k = 0; k < 4; ++k) {
604 t[k] = (((
static_cast<uint32_t
>(pv[i][4 * j + k]) << 10) +
KyberConstants::Q / 2) /
609 auto r = bs.next<5>();
610 r[0] =
static_cast<uint8_t
>(t[0] >> 0);
611 r[1] =
static_cast<uint8_t
>((t[0] >> 8) | (t[1] << 2));
612 r[2] =
static_cast<uint8_t
>((t[1] >> 6) | (t[2] << 4));
613 r[3] =
static_cast<uint8_t
>((t[2] >> 4) | (t[3] << 6));
614 r[4] =
static_cast<uint8_t
>(t[3] >> 2);
619 for(
size_t i = 0; i < mode.
k(); ++i) {
621 for(
size_t k = 0; k < 8; ++k) {
622 t[k] = (((
static_cast<uint32_t
>(pv[i][8 * j + k]) << 11) +
KyberConstants::Q / 2) /
627 auto r = bs.next<11>();
628 r[0] =
static_cast<uint8_t
>(t[0] >> 0);
629 r[1] =
static_cast<uint8_t
>((t[0] >> 8) | (t[1] << 3));
630 r[2] =
static_cast<uint8_t
>((t[1] >> 5) | (t[2] << 6));
631 r[3] =
static_cast<uint8_t
>(t[2] >> 2);
632 r[4] =
static_cast<uint8_t
>((t[2] >> 10) | (t[3] << 1));
633 r[5] =
static_cast<uint8_t
>((t[3] >> 7) | (t[4] << 4));
634 r[6] =
static_cast<uint8_t
>((t[4] >> 4) | (t[5] << 7));
635 r[7] =
static_cast<uint8_t
>(t[5] >> 1);
636 r[8] =
static_cast<uint8_t
>((t[5] >> 9) | (t[6] << 2));
637 r[9] =
static_cast<uint8_t
>((t[6] >> 6) | (t[7] << 5));
638 r[10] =
static_cast<uint8_t
>(t[7] >> 3);
646 static void compress(std::span<uint8_t> out, Polynomial& p,
const KyberConstants& mode) {
649 BufferStuffer bs(out);
651 if(mode.k() == 2 || mode.k() == 3) {
652 for(
size_t i = 0; i < p.size() / 8; ++i) {
653 for(
size_t j = 0; j < 8; ++j) {
659 auto r = bs.next<4>();
660 r[0] = t[0] | (t[1] << 4);
661 r[1] = t[2] | (t[3] << 4);
662 r[2] = t[4] | (t[5] << 4);
663 r[3] = t[6] | (t[7] << 4);
665 }
else if(mode.k() == 4) {
666 for(
size_t i = 0; i < p.size() / 8; ++i) {
667 for(
size_t j = 0; j < 8; ++j) {
673 auto r = bs.next<5>();
674 r[0] = (t[0] >> 0) | (t[1] << 5);
675 r[1] = (t[1] >> 3) | (t[2] << 2) | (t[3] << 7);
676 r[2] = (t[3] >> 1) | (t[4] << 4);
677 r[3] = (t[4] >> 4) | (t[5] << 1) | (t[6] << 6);
678 r[4] = (t[6] >> 2) | (t[7] << 3);
685 static PolynomialVector decompress_polynomial_vector(std::span<const uint8_t> buffer,
686 const KyberConstants& mode) {
687 BOTAN_ASSERT(buffer.size() == mode.polynomial_vector_compressed_bytes(),
688 "unexpected length of compressed polynomial vector");
690 PolynomialVector r(mode.k());
691 BufferSlicer bs(buffer);
694 for(
size_t i = 0; i < mode.k(); ++i) {
696 const auto a = bs.take<11>();
697 t[0] = (a[0] >> 0) | (
static_cast<uint16_t
>(a[1]) << 8);
698 t[1] = (a[1] >> 3) | (
static_cast<uint16_t
>(a[2]) << 5);
699 t[2] = (a[2] >> 6) | (
static_cast<uint16_t
>(a[3]) << 2) | (
static_cast<uint16_t
>(a[4]) << 10);
700 t[3] = (a[4] >> 1) | (
static_cast<uint16_t
>(a[5]) << 7);
701 t[4] = (a[5] >> 4) | (
static_cast<uint16_t
>(a[6]) << 4);
702 t[5] = (a[6] >> 7) | (
static_cast<uint16_t
>(a[7]) << 1) | (
static_cast<uint16_t
>(a[8]) << 9);
703 t[6] = (a[8] >> 2) | (
static_cast<uint16_t
>(a[9]) << 6);
704 t[7] = (a[9] >> 5) | (
static_cast<uint16_t
>(a[10]) << 3);
706 for(
size_t k = 0; k < 8; ++k) {
707 r[i][8 * j + k] = (
static_cast<uint32_t
>(t[k] & 0x7FF) *
KyberConstants::Q + 1024) >> 11;
713 for(
size_t i = 0; i < mode.k(); ++i) {
715 const auto a = bs.take<5>();
716 t[0] = (a[0] >> 0) | (
static_cast<uint16_t
>(a[1]) << 8);
717 t[1] = (a[1] >> 2) | (
static_cast<uint16_t
>(a[2]) << 6);
718 t[2] = (a[2] >> 4) | (
static_cast<uint16_t
>(a[3]) << 4);
719 t[3] = (a[3] >> 6) | (
static_cast<uint16_t
>(a[4]) << 2);
721 for(
size_t k = 0; k < 4; ++k) {
722 r[i][4 * j + k] = (
static_cast<uint32_t
>(t[k] & 0x3FF) *
KyberConstants::Q + 512) >> 10;
732 static Polynomial decompress_polynomial(std::span<const uint8_t> buffer,
const KyberConstants& mode) {
733 BOTAN_ASSERT(buffer.size() == mode.polynomial_compressed_bytes(),
734 "unexpected length of compressed polynomial");
737 BufferSlicer bs(buffer);
741 const auto a = bs.take<5>();
743 t[1] = (a[0] >> 5) | (a[1] << 3);
745 t[3] = (a[1] >> 7) | (a[2] << 1);
746 t[4] = (a[2] >> 4) | (a[3] << 4);
748 t[6] = (a[3] >> 6) | (a[4] << 2);
751 for(
size_t j = 0; j < 8; ++j) {
757 const auto a = bs.take_byte();
768 KyberConstants m_mode;
769 PolynomialVector m_b;
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_DEBUG_ASSERT(expr)
#define BOTAN_ASSERT(expr, assertion_made)
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
static constexpr Mask< T > is_zero(T x)
void to_bytes(StrongSpan< KyberCompressedCiphertext > out)
KyberCompressedCiphertext to_bytes()
static Ciphertext from_bytes(StrongSpan< const KyberCompressedCiphertext > buffer, const KyberConstants &mode)
Ciphertext(PolynomialVector b, const Polynomial &v, KyberConstants mode)
size_t polynomial_vector_compressed_bytes() const
size_t polynomial_compressed_bytes() const
static constexpr int16_t zetas_inv[128]
static constexpr size_t Q_Inv
static constexpr size_t kSerializedPolynomialByteLength
static constexpr int16_t zetas[128]
size_t encapsulated_key_length() const
static constexpr size_t N
size_t polynomial_vector_byte_length() const
static constexpr size_t kSymBytes
Kyber_Symmetric_Primitives & symmetric_primitives() const
static constexpr size_t Q
std::unique_ptr< Botan::XOF > XOF(StrongSpan< const KyberSeedRho > seed, std::tuple< uint8_t, uint8_t > matrix_position) const
KyberSamplingRandomness PRF(KyberSigmaOrEncryptionRandomness seed, const uint8_t nonce, const size_t outlen) const
PolynomialMatrix()=delete
PolynomialVector pointwise_acc_montgomery(const PolynomialVector &vec, const bool with_mont=false) const
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)
PolynomialVector(const size_t k)
Polynomial & operator[](size_t idx)
static PolynomialVector getnoise_eta1(KyberSigmaOrEncryptionRandomness seed, uint8_t nonce, const KyberConstants &mode)
PolynomialVector & operator+=(const PolynomialVector &other)
PolynomialVector()=delete
static Polynomial pointwise_acc_montgomery(const PolynomialVector &a, const PolynomialVector &b)
static PolynomialVector getnoise_eta2(StrongSpan< const KyberEncryptionRandomness > seed, uint8_t nonce, const KyberConstants &mode)
static Polynomial from_bytes(std::span< const uint8_t > a)
Polynomial & operator+=(const Polynomial &other)
int16_t & operator[](size_t idx)
static Polynomial cbd2(StrongSpan< const KyberSamplingRandomness > buf)
static Polynomial getnoise_eta2(StrongSpan< const KyberEncryptionRandomness > seed, uint8_t nonce, const KyberConstants &mode)
Polynomial & operator-=(const Polynomial &other)
static Polynomial basemul_montgomery(const Polynomial &a, const Polynomial &b)
int16_t operator[](size_t idx) const
static Polynomial cbd3(StrongSpan< const KyberSamplingRandomness > buf)
static Polynomial getnoise_eta1(KyberSigmaOrEncryptionRandomness seed, uint8_t nonce, const KyberConstants &mode)
static Polynomial sample_rej_uniform(std::unique_ptr< XOF > xof)
static Polynomial from_message(StrongSpan< const KyberMessage > msg)
void to_bytes(std::span< uint8_t > out)
KyberMessage to_message()
decltype(auto) size() const noexcept(noexcept(this->m_span.size()))
constexpr uint16_t ct_int_div_kyber_q(uint32_t a)
constexpr uint32_t make_uint32(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3)
std::variant< StrongSpan< const KyberSeedSigma >, StrongSpan< const KyberEncryptionRandomness > > KyberSigmaOrEncryptionRandomness
constexpr auto load_le(ParamTs &&... params)