14#include <botan/kyber.h>
16#include <botan/assert.h>
17#include <botan/ber_dec.h>
18#include <botan/hash.h>
19#include <botan/mem_ops.h>
20#include <botan/pubkey.h>
22#include <botan/secmem.h>
24#include <botan/internal/ct_utils.h>
25#include <botan/internal/fmt.h>
26#include <botan/internal/kyber_symmetric_primitives.h>
27#include <botan/internal/loadstor.h>
28#include <botan/internal/pk_ops_impl.h>
29#include <botan/internal/stl_util.h>
31#if defined(BOTAN_HAS_KYBER)
32 #include <botan/internal/kyber_modern.h>
35#if defined(BOTAN_HAS_KYBER_90S)
36 #include <botan/internal/kyber_90s.h>
52 if(str ==
"Kyber-512-90s-r3") {
55 if(str ==
"Kyber-768-90s-r3") {
58 if(str ==
"Kyber-1024-90s-r3") {
61 if(str ==
"Kyber-512-r3") {
64 if(str ==
"Kyber-768-r3") {
67 if(str ==
"Kyber-1024-r3") {
71 throw Invalid_Argument(
fmt(
"'{}' is not a valid Kyber mode name", str));
85uint16_t ct_int_div_kyber_q(uint32_t a) {
92 const uint64_t m = 161271;
94 return static_cast<uint16_t
>((a * m) >> p);
112 return "Kyber-512-90s-r3";
114 return "Kyber-768-90s-r3";
116 return "Kyber-1024-90s-r3";
118 return "Kyber-512-r3";
120 return "Kyber-768-r3";
122 return "Kyber-1024-r3";
137#if defined(BOTAN_HAS_KYBER)
143#if defined(BOTAN_HAS_KYBER_90S)
154class KyberConstants {
156 static constexpr size_t N = 256;
157 static constexpr size_t Q = 3329;
158 static constexpr size_t Q_Inv = 62209;
160 static constexpr int16_t zetas[128] = {
161 2285, 2571, 2970, 1812, 1493, 1422, 287, 202, 3158, 622, 1577, 182, 962, 2127, 1855, 1468,
162 573, 2004, 264, 383, 2500, 1458, 1727, 3199, 2648, 1017, 732, 608, 1787, 411, 3124, 1758,
163 1223, 652, 2777, 1015, 2036, 1491, 3047, 1785, 516, 3321, 3009, 2663, 1711, 2167, 126, 1469,
164 2476, 3239, 3058, 830, 107, 1908, 3082, 2378, 2931, 961, 1821, 2604, 448, 2264, 677, 2054,
165 2226, 430, 555, 843, 2078, 871, 1550, 105, 422, 587, 177, 3094, 3038, 2869, 1574, 1653,
166 3083, 778, 1159, 3182, 2552, 1483, 2727, 1119, 1739, 644, 2457, 349, 418, 329, 3173, 3254,
167 817, 1097, 603, 610, 1322, 2044, 1864, 384, 2114, 3193, 1218, 1994, 2455, 220, 2142, 1670,
168 2144, 1799, 2051, 794, 1819, 2475, 2459, 478, 3221, 3021, 996, 991, 958, 1869, 1522, 1628};
170 static constexpr int16_t zetas_inv[128] = {
171 1701, 1807, 1460, 2371, 2338, 2333, 308, 108, 2851, 870, 854, 1510, 2535, 1278, 1530, 1185,
172 1659, 1187, 3109, 874, 1335, 2111, 136, 1215, 2945, 1465, 1285, 2007, 2719, 2726, 2232, 2512,
173 75, 156, 3000, 2911, 2980, 872, 2685, 1590, 2210, 602, 1846, 777, 147, 2170, 2551, 246,
174 1676, 1755, 460, 291, 235, 3152, 2742, 2907, 3224, 1779, 2458, 1251, 2486, 2774, 2899, 1103,
175 1275, 2652, 1065, 2881, 725, 1508, 2368, 398, 951, 247, 1421, 3222, 2499, 271, 90, 853,
176 1860, 3203, 1162, 1618, 666, 320, 8, 2813, 1544, 282, 1838, 1293, 2314, 552, 2677, 2106,
177 1571, 205, 2918, 1542, 2721, 2597, 2312, 681, 130, 1602, 1871, 829, 2946, 3065, 1325, 2756,
178 1861, 1474, 1202, 2367, 3147, 1752, 2707, 171, 3127, 3042, 1907, 1836, 1517, 359, 758, 1441};
180 static constexpr size_t kSymBytes = 32;
181 static constexpr size_t kSeedLength = kSymBytes;
182 static constexpr size_t kSerializedPolynomialByteLength = N / 2 * 3;
183 static constexpr size_t kPublicKeyHashLength = 32;
184 static constexpr size_t kZLength = kSymBytes;
187 KyberConstants(
const KyberMode mode) : m_mode(mode) {
188 switch(mode.mode()) {
191 m_nist_strength = 128;
198 m_nist_strength = 192;
205 m_nist_strength = 256;
214#ifdef BOTAN_HAS_KYBER_90S
216 m_symmetric_primitives = std::make_unique<Kyber_90s_Symmetric_Primitives>();
219#ifdef BOTAN_HAS_KYBER
221 m_symmetric_primitives = std::make_unique<Kyber_Modern_Symmetric_Primitives>();
225 if(!m_symmetric_primitives) {
226 throw Not_Implemented(
"requested Kyber mode is not enabled in this build");
230 ~KyberConstants() =
default;
232 KyberConstants(
const KyberConstants& other) : KyberConstants(other.m_mode) {}
234 KyberConstants(KyberConstants&& other) =
default;
235 KyberConstants& operator=(
const KyberConstants& other) =
delete;
236 KyberConstants& operator=(KyberConstants&& other) =
default;
238 KyberMode mode()
const {
return m_mode; }
240 size_t estimated_strength()
const {
return m_nist_strength; }
242 uint8_t k()
const {
return m_k; }
244 uint8_t eta1()
const {
return m_eta1; }
246 uint8_t eta2()
const {
return 2; }
248 size_t polynomial_vector_byte_length()
const {
return kSerializedPolynomialByteLength * k(); }
250 size_t public_key_byte_length()
const {
return polynomial_vector_byte_length() + kSeedLength; }
252 size_t private_key_byte_length()
const {
253 return polynomial_vector_byte_length() + public_key_byte_length() + kPublicKeyHashLength + kZLength;
256 std::unique_ptr<HashFunction> G()
const {
return m_symmetric_primitives->G(); }
258 std::unique_ptr<HashFunction> H()
const {
return m_symmetric_primitives->H(); }
260 std::unique_ptr<HashFunction> KDF()
const {
return m_symmetric_primitives->KDF(); }
262 Botan::XOF& XOF(std::span<const uint8_t> seed, std::tuple<uint8_t, uint8_t> matrix_position)
const {
263 return m_symmetric_primitives->XOF(seed, matrix_position);
266 secure_vector<uint8_t> PRF(std::span<const uint8_t> seed,
const uint8_t nonce,
const size_t outlen)
const {
267 return m_symmetric_primitives->PRF(seed, nonce, outlen);
272 std::unique_ptr<Kyber_Symmetric_Primitives> m_symmetric_primitives;
273 size_t m_nist_strength;
284 for(
auto& coeff : m_coeffs) {
285 coeff -= KyberConstants::Q;
286 coeff += (coeff >> 15) & KyberConstants::Q;
294 for(
auto& c : m_coeffs) {
295 c = barrett_reduce(c);
299 template <
typename T = std::vector<u
int8_t>>
303 T r(KyberConstants::kSerializedPolynomialByteLength);
305 for(
size_t i = 0; i < size() / 2; ++i) {
306 const uint16_t t0 = m_coeffs[2 * i];
307 const uint16_t t1 = m_coeffs[2 * i + 1];
308 r[3 * i + 0] =
static_cast<uint8_t
>(t0 >> 0);
309 r[3 * i + 1] =
static_cast<uint8_t
>((t0 >> 8) | (t1 << 4));
310 r[3 * i + 2] =
static_cast<uint8_t
>(t1 >> 4);
320 static Polynomial cbd2(std::span<const uint8_t> buf) {
323 BOTAN_ASSERT(buf.size() == (2 * r.size() / 4),
"wrong input buffer size for cbd2");
325 for(
size_t i = 0; i < r.size() / 8; ++i) {
326 uint32_t t = load_le<uint32_t>(buf.data(), i);
327 uint32_t d = t & 0x55555555;
328 d += (t >> 1) & 0x55555555;
330 for(
size_t j = 0; j < 8; ++j) {
331 int16_t a = (d >> (4 * j + 0)) & 0x3;
332 int16_t b = (d >> (4 * j + 2)) & 0x3;
333 r.m_coeffs[8 * i + j] = a - b;
346 static Polynomial cbd3(std::span<const uint8_t> buf) {
349 BOTAN_ASSERT(buf.size() == (3 * r.size() / 4),
"wrong input buffer size for cbd3");
352 const auto load_le24 = [](
const uint8_t in[],
const size_t off) {
353 const auto off3 = off * 3;
354 return make_uint32(0, in[off3 + 2], in[off3 + 1], in[off3]);
357 for(
size_t i = 0; i < r.size() / 4; ++i) {
358 uint32_t t = load_le24(buf.data(), i);
359 uint32_t d = t & 0x00249249;
360 d += (t >> 1) & 0x00249249;
361 d += (t >> 2) & 0x00249249;
363 for(
size_t j = 0; j < 4; ++j) {
364 int16_t a = (d >> (6 * j + 0)) & 0x7;
365 int16_t b = (d >> (6 * j + 3)) & 0x7;
366 r.m_coeffs[4 * i + j] = a - b;
376 static Polynomial getnoise_eta2(std::span<const uint8_t> seed, uint8_t nonce,
const KyberConstants& mode) {
377 const auto eta2 = mode.eta2();
380 const auto outlen = eta2 * KyberConstants::N / 4;
381 return Polynomial::cbd2(mode.PRF(seed, nonce, outlen));
388 static Polynomial getnoise_eta1(std::span<const uint8_t> seed, uint8_t nonce,
const KyberConstants& mode) {
389 const auto eta1 = mode.eta1();
390 BOTAN_ASSERT(eta1 == 2 || eta1 == 3,
"Invalid eta1 value");
392 const auto outlen = eta1 * KyberConstants::N / 4;
393 return (eta1 == 2) ? Polynomial::cbd2(mode.PRF(seed, nonce, outlen))
394 : Polynomial::cbd3(mode.PRF(seed, nonce, outlen));
397 static Polynomial from_bytes(std::span<const uint8_t> a) {
399 for(
size_t i = 0; i < r.size() / 2; ++i) {
400 r.m_coeffs[2 * i] = ((a[3 * i + 0] >> 0) | (
static_cast<uint16_t
>(a[3 * i + 1]) << 8)) & 0xFFF;
401 r.m_coeffs[2 * i + 1] = ((a[3 * i + 1] >> 4) | (
static_cast<uint16_t
>(a[3 * i + 2]) << 4)) & 0xFFF;
406 static Polynomial from_message(std::span<const uint8_t> msg) {
407 BOTAN_ASSERT(msg.size() == KyberConstants::N / 8,
"message length must be Kyber_N/8 bytes");
410 for(
size_t i = 0; i < r.size() / 8; ++i) {
411 for(
size_t j = 0; j < 8; ++j) {
412 const auto mask = -
static_cast<int16_t
>((msg[i] >> j) & 1);
413 r.m_coeffs[8 * i + j] = mask & ((KyberConstants::Q + 1) / 2);
419 template <
typename T = secure_vector<u
int8_t>>
421 T result(size() / 8);
425 for(
size_t i = 0; i < size() / 8; ++i) {
427 for(
size_t j = 0; j < 8; ++j) {
429 ct_int_div_kyber_q((
static_cast<uint16_t
>(this->m_coeffs[8 * i + j]) << 1) + KyberConstants::Q / 2);
430 result[i] |= (t & 1) << j;
441 Polynomial&
operator+=(
const Polynomial& other) {
442 for(
size_t i = 0; i < this->size(); ++i) {
444 std::numeric_limits<int16_t>::max());
445 this->m_coeffs[i] = this->m_coeffs[i] + other.m_coeffs[i];
454 Polynomial&
operator-=(
const Polynomial& other) {
455 for(
size_t i = 0; i < this->size(); ++i) {
457 std::numeric_limits<int16_t>::min());
458 this->m_coeffs[i] = other.m_coeffs[i] - this->m_coeffs[i];
466 static Polynomial basemul_montgomery(
const Polynomial& a,
const Polynomial& b) {
471 auto basemul = [](int16_t r[2],
const int16_t s[2],
const int16_t t[2],
const int16_t zeta) {
472 r[0] = fqmul(s[1], t[1]);
473 r[0] = fqmul(r[0], zeta);
474 r[0] += fqmul(s[0], t[0]);
476 r[1] = fqmul(s[0], t[1]);
477 r[1] += fqmul(s[1], t[0]);
482 for(
size_t i = 0; i < r.size() / 4; ++i) {
483 basemul(&r.m_coeffs[4 * i], &a.m_coeffs[4 * i], &b.m_coeffs[4 * i], KyberConstants::zetas[64 + i]);
485 &r.m_coeffs[4 * i + 2], &a.m_coeffs[4 * i + 2], &b.m_coeffs[4 * i + 2], -KyberConstants::zetas[64 + i]);
495 static Polynomial sample_rej_uniform(XOF& xof) {
499 while(count < p.size()) {
500 std::array<uint8_t, 3> buf;
503 const uint16_t val0 = ((buf[0] >> 0) | (
static_cast<uint16_t
>(buf[1]) << 8)) & 0xFFF;
504 const uint16_t val1 = ((buf[1] >> 4) | (
static_cast<uint16_t
>(buf[2]) << 4)) & 0xFFF;
506 if(val0 < KyberConstants::Q) {
507 p.m_coeffs[count++] = val0;
509 if(count < p.size() && val1 < KyberConstants::Q) {
510 p.m_coeffs[count++] = val1;
522 constexpr int16_t f = (1ULL << 32) % KyberConstants::Q;
523 for(
auto& c : m_coeffs) {
524 c = montgomery_reduce(
static_cast<int32_t
>(c) * f);
533 for(
size_t len = size() / 2, k = 0; len >= 2; len /= 2) {
534 for(
size_t start = 0, j = 0; start < size(); start = j + len) {
535 const auto zeta = KyberConstants::zetas[++k];
536 for(j = start; j < start + len; ++j) {
537 const auto t = fqmul(zeta, m_coeffs[j + len]);
538 m_coeffs[j + len] = m_coeffs[j] - t;
539 m_coeffs[j] = m_coeffs[j] + t;
551 void invntt_tomont() {
552 for(
size_t len = 2, k = 0; len <= size() / 2; len *= 2) {
553 for(
size_t start = 0, j = 0; start < size(); start = j + len) {
554 const auto zeta = KyberConstants::zetas_inv[k++];
555 for(j = start; j < start + len; ++j) {
556 const auto t = m_coeffs[j];
557 m_coeffs[j] = barrett_reduce(t + m_coeffs[j + len]);
558 m_coeffs[j + len] = fqmul(zeta, t - m_coeffs[j + len]);
563 for(
auto& c : m_coeffs) {
564 c = fqmul(c, KyberConstants::zetas_inv[127]);
568 size_t size()
const {
return m_coeffs.size(); }
570 int16_t operator[](
size_t idx)
const {
return m_coeffs[idx]; }
572 int16_t& operator[](
size_t idx) {
return m_coeffs[idx]; }
579 static int16_t barrett_reduce(int16_t a) {
581 constexpr int16_t v = ((1U << 26) + KyberConstants::Q / 2) / KyberConstants::Q;
583 t =
static_cast<int32_t
>(v) * a >> 26;
584 t *= KyberConstants::Q;
591 static int16_t fqmul(int16_t a, int16_t b) {
return montgomery_reduce(
static_cast<int32_t
>(a) * b); }
597 static int16_t montgomery_reduce(int32_t a) {
598 const int16_t u =
static_cast<int16_t
>(a * KyberConstants::Q_Inv);
599 int32_t t =
static_cast<int32_t
>(u) * KyberConstants::Q;
602 return static_cast<int16_t
>(t);
605 std::array<int16_t, KyberConstants::N> m_coeffs;
608class PolynomialVector {
610 PolynomialVector() =
delete;
612 explicit PolynomialVector(
const size_t k) : m_vec(k) {}
614 static PolynomialVector from_bytes(std::span<const uint8_t> a,
const KyberConstants& mode) {
615 BOTAN_ASSERT(a.size() == mode.polynomial_vector_byte_length(),
"wrong byte length for frombytes");
617 PolynomialVector r(mode.k());
618 for(
size_t i = 0; i < mode.k(); ++i) {
619 r.m_vec[i] = Polynomial::from_bytes(a.subspan(0, KyberConstants::kSerializedPolynomialByteLength));
620 a = a.subspan(KyberConstants::kSerializedPolynomialByteLength);
628 static Polynomial pointwise_acc_montgomery(
const PolynomialVector& a,
const PolynomialVector& b) {
630 "pointwise_acc_montgomery works on equally sized "
631 "PolynomialVectors only");
633 auto r = Polynomial::basemul_montgomery(a.m_vec[0], b.m_vec[0]);
634 for(
size_t i = 1; i < a.m_vec.size(); ++i) {
635 r += Polynomial::basemul_montgomery(a.m_vec[i], b.m_vec[i]);
642 static PolynomialVector getnoise_eta2(std::span<const uint8_t> seed, uint8_t nonce,
const KyberConstants& mode) {
643 PolynomialVector r(mode.k());
645 for(
auto& p : r.m_vec) {
646 p = Polynomial::getnoise_eta2(seed, nonce++, mode);
652 static PolynomialVector getnoise_eta1(std::span<const uint8_t> seed, uint8_t nonce,
const KyberConstants& mode) {
653 PolynomialVector r(mode.k());
655 for(
auto& p : r.m_vec) {
656 p = Polynomial::getnoise_eta1(seed, nonce++, mode);
662 template <
typename T = std::vector<u
int8_t>>
666 r.reserve(m_vec.size() * KyberConstants::kSerializedPolynomialByteLength);
667 for(
auto& v : m_vec) {
668 const auto poly = v.to_bytes<
T>();
669 r.insert(r.end(), poly.begin(), poly.end());
680 for(
auto& p : m_vec) {
685 PolynomialVector&
operator+=(
const PolynomialVector& other) {
686 BOTAN_ASSERT(m_vec.size() == other.m_vec.size(),
"cannot add polynomial vectors of differing lengths");
688 for(
size_t i = 0; i < m_vec.size(); ++i) {
689 m_vec[i] += other.m_vec[i];
694 Polynomial& operator[](
size_t idx) {
return m_vec[idx]; }
700 for(
auto& v : m_vec) {
708 void invntt_tomont() {
709 for(
auto& v : m_vec) {
718 for(
auto& v : m_vec) {
724 std::vector<Polynomial> m_vec;
727class PolynomialMatrix {
729 PolynomialMatrix() =
delete;
731 static PolynomialMatrix generate(std::span<const uint8_t> seed,
732 const bool transposed,
733 const KyberConstants& mode) {
734 BOTAN_ASSERT(seed.size() == KyberConstants::kSymBytes,
"unexpected seed size");
736 PolynomialMatrix matrix(mode);
738 for(uint8_t i = 0; i < mode.k(); ++i) {
739 for(uint8_t j = 0; j < mode.k(); ++j) {
740 const auto pos = (transposed) ? std::tuple(i, j) : std::tuple(j, i);
741 matrix.m_mat[i][j] = Polynomial::sample_rej_uniform(mode.XOF(seed, pos));
748 PolynomialVector pointwise_acc_montgomery(
const PolynomialVector& vec,
const bool with_mont =
false)
const {
749 PolynomialVector result(m_mat.size());
751 for(
size_t i = 0; i < m_mat.size(); ++i) {
752 result[i] = PolynomialVector::pointwise_acc_montgomery(m_mat[i], vec);
762 explicit PolynomialMatrix(
const KyberConstants& mode) : m_mat(mode.k(), PolynomialVector(mode.k())) {}
765 std::vector<PolynomialVector> m_mat;
770 Ciphertext() =
delete;
772 Ciphertext(PolynomialVector b,
const Polynomial& v, KyberConstants mode) :
773 m_mode(std::move(mode)), m_b(std::move(b)), m_v(v) {}
775 static Ciphertext from_bytes(std::span<const uint8_t> buffer,
const KyberConstants& mode) {
776 const size_t pvb = polynomial_vector_compressed_bytes(mode);
777 const size_t pcb = polynomial_compressed_bytes(mode);
779 if(buffer.size() != pvb + pcb) {
780 throw Decoding_Error(
"Kyber: unexpected ciphertext length");
783 auto pv = buffer.subspan(0, pvb);
784 auto p = buffer.subspan(pvb);
786 return Ciphertext(decompress_polynomial_vector(pv, mode), decompress_polynomial(p, mode), mode);
789 secure_vector<uint8_t> to_bytes() {
790 auto ct = compress(m_b, m_mode);
791 const auto p = compress(m_v, m_mode);
792 ct.insert(ct.end(), p.begin(), p.end());
797 secure_vector<uint8_t> indcpa_decrypt(
const PolynomialVector& polynomials) {
799 auto mp = PolynomialVector::pointwise_acc_montgomery(polynomials, m_b);
804 return mp.to_message();
808 static size_t polynomial_vector_compressed_bytes(
const KyberConstants& mode) {
809 const auto k = mode.k();
810 return (k == 2 || k == 3) ? k * 320 : k * 352;
813 static size_t polynomial_compressed_bytes(
const KyberConstants& mode) {
814 const auto k = mode.k();
815 return (k == 2 || k == 3) ? 128 : 160;
818 static secure_vector<uint8_t> compress(PolynomialVector& pv,
const KyberConstants& mode) {
819 secure_vector<uint8_t> r(polynomial_vector_compressed_bytes(mode));
823 if(mode.k() == 2 || mode.k() == 3) {
826 for(
size_t i = 0; i < mode.k(); ++i) {
827 for(
size_t j = 0; j < KyberConstants::N / 4; ++j) {
828 for(
size_t k = 0; k < 4; ++k) {
829 t[k] = (((
static_cast<uint32_t
>(pv[i][4 * j + k]) << 10) + KyberConstants::Q / 2) /
834 r[0 + offset] =
static_cast<uint8_t
>(t[0] >> 0);
835 r[1 + offset] =
static_cast<uint8_t
>((t[0] >> 8) | (t[1] << 2));
836 r[2 + offset] =
static_cast<uint8_t
>((t[1] >> 6) | (t[2] << 4));
837 r[3 + offset] =
static_cast<uint8_t
>((t[2] >> 4) | (t[3] << 6));
838 r[4 + offset] =
static_cast<uint8_t
>(t[3] >> 2);
845 for(
size_t i = 0; i < mode.k(); ++i) {
846 for(
size_t j = 0; j < KyberConstants::N / 8; ++j) {
847 for(
size_t k = 0; k < 8; ++k) {
848 t[k] = (((
static_cast<uint32_t
>(pv[i][8 * j + k]) << 11) + KyberConstants::Q / 2) /
853 r[0 + offset] =
static_cast<uint8_t
>(t[0] >> 0);
854 r[1 + offset] =
static_cast<uint8_t
>((t[0] >> 8) | (t[1] << 3));
855 r[2 + offset] =
static_cast<uint8_t
>((t[1] >> 5) | (t[2] << 6));
856 r[3 + offset] =
static_cast<uint8_t
>(t[2] >> 2);
857 r[4 + offset] =
static_cast<uint8_t
>((t[2] >> 10) | (t[3] << 1));
858 r[5 + offset] =
static_cast<uint8_t
>((t[3] >> 7) | (t[4] << 4));
859 r[6 + offset] =
static_cast<uint8_t
>((t[4] >> 4) | (t[5] << 7));
860 r[7 + offset] =
static_cast<uint8_t
>(t[5] >> 1);
861 r[8 + offset] =
static_cast<uint8_t
>((t[5] >> 9) | (t[6] << 2));
862 r[9 + offset] =
static_cast<uint8_t
>((t[6] >> 6) | (t[7] << 5));
863 r[10 + offset] =
static_cast<uint8_t
>(t[7] >> 3);
872 static secure_vector<uint8_t> compress(Polynomial& p,
const KyberConstants& mode) {
873 secure_vector<uint8_t> r(polynomial_compressed_bytes(mode));
878 if(mode.k() == 2 || mode.k() == 3) {
880 for(
size_t i = 0; i < p.size() / 8; ++i) {
881 for(
size_t j = 0; j < 8; ++j) {
882 t[j] = ct_int_div_kyber_q((
static_cast<uint16_t
>(p[8 * i + j]) << 4) + KyberConstants::Q / 2) & 15;
885 r[0 + offset] = t[0] | (t[1] << 4);
886 r[1 + offset] = t[2] | (t[3] << 4);
887 r[2 + offset] = t[4] | (t[5] << 4);
888 r[3 + offset] = t[6] | (t[7] << 4);
891 }
else if(mode.k() == 4) {
893 for(
size_t i = 0; i < p.size() / 8; ++i) {
894 for(
size_t j = 0; j < 8; ++j) {
895 t[j] = ct_int_div_kyber_q((
static_cast<uint32_t
>(p[8 * i + j]) << 5) + KyberConstants::Q / 2) & 31;
898 r[0 + offset] = (t[0] >> 0) | (t[1] << 5);
899 r[1 + offset] = (t[1] >> 3) | (t[2] << 2) | (t[3] << 7);
900 r[2 + offset] = (t[3] >> 1) | (t[4] << 4);
901 r[3 + offset] = (t[4] >> 4) | (t[5] << 1) | (t[6] << 6);
902 r[4 + offset] = (t[6] >> 2) | (t[7] << 3);
910 static PolynomialVector decompress_polynomial_vector(std::span<const uint8_t> buffer,
911 const KyberConstants& mode) {
912 BOTAN_ASSERT(buffer.size() == polynomial_vector_compressed_bytes(mode),
913 "unexpected length of compressed polynomial vector");
915 PolynomialVector r(mode.k());
916 const uint8_t* a = buffer.data();
920 for(
size_t i = 0; i < mode.k(); ++i) {
921 for(
size_t j = 0; j < KyberConstants::N / 8; ++j) {
922 t[0] = (a[0] >> 0) | (
static_cast<uint16_t
>(a[1]) << 8);
923 t[1] = (a[1] >> 3) | (
static_cast<uint16_t
>(a[2]) << 5);
924 t[2] = (a[2] >> 6) | (
static_cast<uint16_t
>(a[3]) << 2) | (
static_cast<uint16_t
>(a[4]) << 10);
925 t[3] = (a[4] >> 1) | (
static_cast<uint16_t
>(a[5]) << 7);
926 t[4] = (a[5] >> 4) | (
static_cast<uint16_t
>(a[6]) << 4);
927 t[5] = (a[6] >> 7) | (
static_cast<uint16_t
>(a[7]) << 1) | (
static_cast<uint16_t
>(a[8]) << 9);
928 t[6] = (a[8] >> 2) | (
static_cast<uint16_t
>(a[9]) << 6);
929 t[7] = (a[9] >> 5) | (
static_cast<uint16_t
>(a[10]) << 3);
932 for(
size_t k = 0; k < 8; ++k) {
933 r[i][8 * j + k] = (
static_cast<uint32_t
>(t[k] & 0x7FF) * KyberConstants::Q + 1024) >> 11;
939 for(
size_t i = 0; i < mode.k(); ++i) {
940 for(
size_t j = 0; j < KyberConstants::N / 4; ++j) {
941 t[0] = (a[0] >> 0) | (
static_cast<uint16_t
>(a[1]) << 8);
942 t[1] = (a[1] >> 2) | (
static_cast<uint16_t
>(a[2]) << 6);
943 t[2] = (a[2] >> 4) | (
static_cast<uint16_t
>(a[3]) << 4);
944 t[3] = (a[3] >> 6) | (
static_cast<uint16_t
>(a[4]) << 2);
947 for(
size_t k = 0; k < 4; ++k) {
948 r[i][4 * j + k] = (
static_cast<uint32_t
>(t[k] & 0x3FF) * KyberConstants::Q + 512) >> 10;
957 static Polynomial decompress_polynomial(std::span<const uint8_t> buffer,
const KyberConstants& mode) {
958 BOTAN_ASSERT(buffer.size() == polynomial_compressed_bytes(mode),
"unexpected length of compressed polynomial");
961 const uint8_t* a = buffer.data();
965 for(
size_t i = 0; i < KyberConstants::N / 8; ++i) {
967 t[1] = (a[0] >> 5) | (a[1] << 3);
969 t[3] = (a[1] >> 7) | (a[2] << 1);
970 t[4] = (a[2] >> 4) | (a[3] << 4);
972 t[6] = (a[3] >> 6) | (a[4] << 2);
976 for(
size_t j = 0; j < 8; ++j) {
977 r[8 * i + j] = (
static_cast<uint32_t
>(t[j] & 31) * KyberConstants::Q + 16) >> 5;
981 for(
size_t i = 0; i < KyberConstants::N / 2; ++i) {
982 r[2 * i + 0] = ((
static_cast<uint16_t
>(a[0] & 15) * KyberConstants::Q) + 8) >> 4;
983 r[2 * i + 1] = ((
static_cast<uint16_t
>(a[0] >> 4) * KyberConstants::Q) + 8) >> 4;
992 KyberConstants m_mode;
993 PolynomialVector m_b;
999class Kyber_PublicKeyInternal {
1001 Kyber_PublicKeyInternal(KyberConstants mode, std::span<const uint8_t> polynomials, std::vector<uint8_t> seed) :
1002 m_mode(std::move(mode)),
1003 m_polynomials(PolynomialVector::from_bytes(polynomials, m_mode)),
1004 m_seed(std::move(seed)),
1005 m_public_key_bits_raw(
concat(m_polynomials.to_bytes<std::vector<uint8_t>>(), m_seed)),
1006 m_H_public_key_bits_raw(m_mode.H()->process<std::vector<uint8_t>>(m_public_key_bits_raw)) {}
1008 Kyber_PublicKeyInternal(KyberConstants mode, PolynomialVector polynomials, std::vector<uint8_t> seed) :
1009 m_mode(std::move(mode)),
1010 m_polynomials(std::move(polynomials)),
1011 m_seed(std::move(seed)),
1012 m_public_key_bits_raw(
concat(m_polynomials.to_bytes<std::vector<uint8_t>>(), m_seed)),
1013 m_H_public_key_bits_raw(m_mode.H()->process<std::vector<uint8_t>>(m_public_key_bits_raw)) {}
1015 const PolynomialVector& polynomials()
const {
return m_polynomials; }
1017 const std::vector<uint8_t>& seed()
const {
return m_seed; }
1019 const KyberConstants& mode()
const {
return m_mode; }
1021 const std::vector<uint8_t>& public_key_bits_raw()
const {
return m_public_key_bits_raw; }
1023 const std::vector<uint8_t>& H_public_key_bits_raw()
const {
return m_H_public_key_bits_raw; }
1025 Kyber_PublicKeyInternal() =
delete;
1028 const KyberConstants m_mode;
1029 PolynomialVector m_polynomials;
1030 const std::vector<uint8_t> m_seed;
1031 const std::vector<uint8_t> m_public_key_bits_raw;
1032 const std::vector<uint8_t> m_H_public_key_bits_raw;
1035class Kyber_PrivateKeyInternal {
1037 Kyber_PrivateKeyInternal(KyberConstants mode, PolynomialVector polynomials, secure_vector<uint8_t> z) :
1038 m_mode(std::move(mode)), m_polynomials(std::move(polynomials)), m_z(std::move(z)) {}
1040 PolynomialVector& polynomials() {
return m_polynomials; }
1042 const secure_vector<uint8_t>& z()
const {
return m_z; }
1044 const KyberConstants& mode()
const {
return m_mode; }
1046 Kyber_PrivateKeyInternal() =
delete;
1049 KyberConstants m_mode;
1050 PolynomialVector m_polynomials;
1051 secure_vector<uint8_t> m_z;
1054class Kyber_KEM_Cryptor {
1056 Kyber_KEM_Cryptor(std::shared_ptr<const Kyber_PublicKeyInternal> public_key) :
1057 m_public_key(std::move(public_key)),
1058 m_mode(m_public_key->mode()),
1059 m_at(PolynomialMatrix::generate(m_public_key->seed(), true, m_mode)) {}
1061 secure_vector<uint8_t> indcpa_enc(std::span<const uint8_t> m, std::span<const uint8_t> coins) {
1062 auto sp = PolynomialVector::getnoise_eta1(coins, 0, m_mode);
1063 auto ep = PolynomialVector::getnoise_eta2(coins, m_mode.k(), m_mode);
1064 auto epp = Polynomial::getnoise_eta2(coins, 2 * m_mode.k(), m_mode);
1066 auto k = Polynomial::from_message(m);
1071 auto bp = m_at.pointwise_acc_montgomery(sp);
1072 auto v = PolynomialVector::pointwise_acc_montgomery(m_public_key->polynomials(), sp);
1083 return Ciphertext(std::move(bp), v, m_mode).to_bytes();
1086 const KyberConstants& mode()
const {
return m_mode; }
1089 std::shared_ptr<const Kyber_PublicKeyInternal> m_public_key;
1090 const KyberConstants& m_mode;
1091 const PolynomialMatrix m_at;
1096size_t kyber_key_length_to_encap_key_length(
size_t kl) {
1111class Kyber_KEM_Encryptor
final :
public PK_Ops::KEM_Encryption_with_KDF,
1112 protected Kyber_KEM_Cryptor {
1114 Kyber_KEM_Encryptor(
const Kyber_PublicKey& key, std::string_view kdf) :
1117 size_t raw_kem_shared_key_length()
const override {
return 32; }
1119 size_t encapsulated_key_length()
const override {
1120 return kyber_key_length_to_encap_key_length(m_key.
key_length());
1123 void raw_kem_encrypt(std::span<uint8_t> out_encapsulated_key,
1124 std::span<uint8_t> out_shared_key,
1125 RandomNumberGenerator& rng)
override {
1127 auto H = mode().H();
1128 auto G = mode().G();
1129 auto KDF = mode().KDF();
1131 H->update(rng.random_vec(KyberConstants::kSymBytes));
1132 const auto shared_secret = H->final();
1135 G->update(shared_secret);
1137 const auto g_out = G->final();
1141 const auto lower_g_out = std::span(g_out).subspan(0, 32);
1142 const auto upper_g_out = std::span(g_out).subspan(32, 32);
1144 const auto encapsulation = indcpa_enc(shared_secret, upper_g_out);
1148 std::copy(encapsulation.begin(), encapsulation.end(), out_encapsulated_key.begin());
1150 KDF->update(lower_g_out.data(), lower_g_out.size());
1151 KDF->update(H->process(out_encapsulated_key));
1152 KDF->final(out_shared_key);
1156 const Kyber_PublicKey& m_key;
1159class Kyber_KEM_Decryptor
final :
public PK_Ops::KEM_Decryption_with_KDF,
1160 protected Kyber_KEM_Cryptor {
1162 Kyber_KEM_Decryptor(
const Kyber_PrivateKey& key, std::string_view kdf) :
1165 size_t raw_kem_shared_key_length()
const override {
return 32; }
1167 size_t encapsulated_key_length()
const override {
1168 return kyber_key_length_to_encap_key_length(m_key.
key_length());
1171 void raw_kem_decrypt(std::span<uint8_t> out_shared_key, std::span<const uint8_t> encapsulated_key)
override {
1173 auto H = mode().H();
1174 auto G = mode().G();
1175 auto KDF = mode().KDF();
1177 const auto shared_secret = indcpa_dec(encapsulated_key);
1180 G->update(shared_secret);
1183 const auto g_out = G->final();
1187 const auto lower_g_out = std::span(g_out).subspan(0, 32);
1188 const auto upper_g_out = std::span(g_out).subspan(32, 32);
1190 H->update(encapsulated_key);
1192 const auto cmp = indcpa_enc(shared_secret, upper_g_out);
1193 BOTAN_ASSERT(encapsulated_key.size() == cmp.size(),
"output of indcpa_enc has unexpected length");
1196 secure_vector<uint8_t> lower_g_out_final(lower_g_out.size());
1199 const auto reencrypt_success =
CT::is_equal(encapsulated_key.data(), cmp.data(), encapsulated_key.size());
1201 lower_g_out_final.data(),
1203 m_key.m_private->z().data(),
1204 lower_g_out_final.size());
1206 KDF->update(lower_g_out_final);
1207 KDF->update(H->final());
1208 KDF->final(out_shared_key);
1212 secure_vector<uint8_t> indcpa_dec(std::span<const uint8_t> c) {
1213 auto ct = Ciphertext::from_bytes(c, mode());
1214 return ct.indcpa_decrypt(m_key.m_private->polynomials());
1218 const Kyber_PrivateKey& m_key;
1234 return m_public->mode().estimated_strength();
1239 KyberConstants
mode(m);
1241 if(pub_key.size() !=
mode.public_key_byte_length()) {
1242 throw Invalid_Argument(
"kyber public key does not have the correct byte count");
1247 auto poly_vec = s.
take(
mode.polynomial_vector_byte_length());
1251 return std::make_shared<Kyber_PublicKeyInternal>(std::move(
mode), poly_vec, std::move(seed));
1258 m_public(initialize_from_encoding(pub_key, m)) {}
1261 m_public(std::make_shared<Kyber_PublicKeyInternal>(*other.m_public)) {}
1268 return m_public->public_key_bits_raw();
1272 return m_public->H_public_key_bits_raw();
1276 return m_public->mode().public_key_byte_length();
1284 return std::make_unique<Kyber_PrivateKey>(rng,
mode());
1288 KyberConstants
mode(m);
1291 auto seed = G->process(rng.
random_vec(KyberConstants::kSymBytes));
1293 const auto middle = G->output_length() / 2;
1297 auto seed2 = s.
take(middle);
1300 auto a = PolynomialMatrix::generate(seed1,
false,
mode);
1301 auto skpv = PolynomialVector::getnoise_eta1(seed2, 0,
mode);
1302 auto e = PolynomialVector::getnoise_eta1(seed2,
mode.k(),
mode);
1308 auto pkpv = a.pointwise_acc_montgomery(skpv,
true);
1312 m_public = std::make_shared<Kyber_PublicKeyInternal>(
mode, std::move(pkpv), std::move(seed1));
1313 m_private = std::make_shared<Kyber_PrivateKeyInternal>(
1314 std::move(
mode), std::move(skpv), rng.
random_vec(KyberConstants::kZLength));
1321 KyberConstants
mode(m);
1323 if(
mode.private_key_byte_length() != sk.size()) {
1324 throw Invalid_Argument(
"kyber private key does not have the correct byte count");
1329 auto skpv = PolynomialVector::from_bytes(s.
take(
mode.polynomial_vector_byte_length()),
mode);
1330 auto pub_key = s.
take(
mode.public_key_byte_length());
1331 s.
skip(KyberConstants::kPublicKeyHashLength);
1337 m_private = std::make_shared<Kyber_PrivateKeyInternal>(std::move(
mode), std::move(skpv), std::move(z));
1343 return std::make_unique<Kyber_PublicKey>(*
this);
1358 std::string_view provider)
const {
1359 if(provider.empty() || provider ==
"base") {
1360 return std::make_unique<Kyber_KEM_Encryptor>(*
this, params);
1366 std::string_view params,
1367 std::string_view provider)
const {
1369 if(provider.empty() || provider ==
"base") {
1370 return std::make_unique<Kyber_KEM_Decryptor>(*
this, params);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_DEBUG_ASSERT(expr)
#define BOTAN_ASSERT_EQUAL(expr1, expr2, assertion_made)
#define BOTAN_ASSERT(expr, assertion_made)
#define BOTAN_ASSERT_UNREACHABLE()
void skip(const size_t count)
auto copy_as_secure_vector(const size_t count)
std::span< const uint8_t > take(const size_t count)
auto copy_as_vector(const size_t count)
bool is_available() const
std::string to_string() const
OID object_identifier() const
std::unique_ptr< PK_Ops::KEM_Decryption > create_kem_decryption_op(RandomNumberGenerator &rng, std::string_view params, std::string_view provider) const override
std::unique_ptr< Public_Key > public_key() const override
Kyber_PrivateKey(RandomNumberGenerator &rng, KyberMode mode)
secure_vector< uint8_t > raw_private_key_bits() const override
secure_vector< uint8_t > private_key_bits() const override
static std::shared_ptr< Kyber_PublicKeyInternal > initialize_from_encoding(std::span< const uint8_t > pub_key, KyberMode m)
std::vector< uint8_t > public_key_bits() const override
bool check_key(RandomNumberGenerator &, bool) const override
std::string algo_name() const override
std::shared_ptr< Kyber_PublicKeyInternal > m_public
size_t key_length() const override
AlgorithmIdentifier algorithm_identifier() const override
Kyber_PublicKey()=default
const std::vector< uint8_t > & H_public_key_bits_raw() const
std::unique_ptr< PK_Ops::KEM_Encryption > create_kem_encryption_op(std::string_view params, std::string_view provider) const override
const std::vector< uint8_t > & public_key_bits_raw() const
OID object_identifier() const override
std::unique_ptr< Private_Key > generate_another(RandomNumberGenerator &rng) const final
size_t estimated_strength() const override
static OID from_string(std::string_view str)
KEM_Decryption_with_KDF(std::string_view kdf)
KEM_Encryption_with_KDF(std::string_view kdf)
void random_vec(std::span< uint8_t > v)
int(* final)(unsigned char *, CTX *)
constexpr Mask< T > conditional_copy_mem(Mask< T > mask, T *to, const T *from0, const T *from1, size_t elems)
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
std::string fmt(std::string_view format, const T &... args)
RetT reduce(const std::vector< KeyT > &keys, RetT acc, ReducerT reducer)
constexpr uint32_t make_uint32(uint8_t i0, uint8_t i1, uint8_t i2, uint8_t i3)
std::vector< T, Alloc > & operator+=(std::vector< T, Alloc > &out, const std::vector< T, Alloc2 > &in)
constexpr auto operator-=(Strong< T1, Tags... > &a, T2 b)
std::vector< T, secure_allocator< T > > secure_vector
decltype(auto) concat(Ts &&... buffers)