Botan 3.6.0
Crypto and TLS for C&
pqcrystals_helpers.h
Go to the documentation of this file.
1/*
2 * PQ CRYSTALS Common Helpers
3 *
4 * Further changes
5 * (C) 2024 Jack Lloyd
6 * (C) 2024 René Meusel, Fabian Albert, Rohde & Schwarz Cybersecurity
7 *
8 * Botan is released under the Simplified BSD License (see license.txt)
9 */
10
11#ifndef BOTAN_PQ_CRYSTALS_HELPERS_H_
12#define BOTAN_PQ_CRYSTALS_HELPERS_H_
13
14#include <concepts>
15#include <cstdint>
16#include <span>
17#include <tuple>
18
19#include <botan/exceptn.h>
20#include <botan/internal/bit_ops.h>
21
22namespace Botan {
23
24// clang-format off
25
26template <std::unsigned_integral T>
27 requires(sizeof(T) <= 4)
29 std::conditional_t<sizeof(T) == 1, uint16_t,
30 std::conditional_t<sizeof(T) == 2, uint32_t,
31 std::conditional_t<sizeof(T) == 4, uint64_t, void>>>;
32
33template <std::signed_integral T>
34 requires(sizeof(T) <= 4)
36 std::conditional_t<sizeof(T) == 1, int16_t,
37 std::conditional_t<sizeof(T) == 2, int32_t,
38 std::conditional_t<sizeof(T) == 4, int64_t, void>>>;
39
40// clang-format on
41
42template <std::integral T>
43 requires(size_t(sizeof(T)) <= 4)
44consteval T montgomery_R(T q) {
45 using T_unsigned = std::make_unsigned_t<T>;
47 return (T2(1) << (sizeof(T) * 8)) % q;
48}
49
50template <std::integral T>
51 requires(size_t(sizeof(T)) <= 4)
52consteval T montgomery_R2(T q) {
53 using T2 = next_longer_int_t<T>;
54 return (static_cast<T2>(montgomery_R(q)) * static_cast<T2>(montgomery_R(q))) % q;
55}
56
57template <std::integral T>
58struct eea_result {
62};
63
64/**
65 * Run the extended Euclidean algorithm to find the greatest common divisor of a
66 * and b and the Bézout coefficients, u and v.
67 */
68template <std::integral T>
70 if(a > b) {
71 std::swap(a, b);
72 }
73
74 T u1 = 0, v1 = 1, u2 = 1, v2 = 0;
75
76 if(a != b) {
77 while(a != 0) {
78 const T q = b / a;
79 std::tie(a, b) = std::make_tuple(static_cast<T>(b - q * a), a);
80 std::tie(u1, v1, u2, v2) = std::make_tuple(u2, v2, static_cast<T>(u1 - q * u2), static_cast<T>(v1 - q * v2));
81 }
82 }
83
84 return {.gcd = b, .u = u1, .v = v1};
85}
86
87/**
88 * Calculate the modular multiplacative inverse of q modulo m.
89 * By default, this assumes m to be 2^bitlength of T for application in a
90 * Montgomery reduction.
91 */
92template <std::integral T, std::integral T2 = next_longer_int_t<T>>
93 requires(sizeof(T) <= 4)
94consteval T modular_inverse(T q, T2 m = T2(1) << sizeof(T) * 8) {
95 return static_cast<T>(extended_euclidean_algorithm<T2>(q, m).u);
96}
97
98constexpr auto bitlen(size_t x) {
99 return ceil_log2(x + 1);
100};
101
102/**
103 * Precompute the zeta-values for the NTT. Note that the pre-computed values
104 * contain the Montgomery factor for either Kyber or Dilithium.
105 */
106template <size_t degree, std::integral T>
107consteval static auto precompute_zetas(T q, T monty, T root_of_unity) {
108 using T2 = next_longer_int_t<T>;
109
110 std::array<T, degree> result = {0};
111
112 auto bitreverse = [](size_t k) -> size_t {
113 size_t r = 0;
114 const auto l = ceil_log2(degree);
115 for(size_t i = 0; i < l; ++i) {
116 r |= ((k >> i) & 1) << (l - 1 - i);
117 }
118 return r;
119 };
120
121 auto pow = [q](T base, size_t exp) -> T2 {
122 T2 res = 1;
123 for(size_t i = 0; i < exp; ++i) {
124 res = (res * base) % q;
125 }
126 return res;
127 };
128
129 auto csubq = [q](T a) -> T { return a <= q / 2 ? a : a - q; };
130
131 for(size_t i = 0; i < result.size(); ++i) {
132 result[i] = csubq(pow(root_of_unity, bitreverse(i)) * monty % q);
133 }
134
135 return result;
136}
137
138namespace detail {
139
140/**
141 * Wraps any XOF to limit the number of bytes that can be produced to @p bound.
142 * When the bound is reached, the XOF will throw an Internal_Error.
143 */
144template <typename XofT, size_t bound>
145 requires requires(XofT xof) {
146 { xof.template output<1>() } -> std::convertible_to<std::span<const uint8_t, 1>>;
147 { xof.template output<42>() } -> std::convertible_to<std::span<const uint8_t, 42>>;
148 }
150 private:
151 template <size_t bytes, typename MapFnT>
152 using MappedValueT = std::invoke_result_t<MapFnT, std::array<uint8_t, bytes>>;
153
154 public:
155 template <size_t bytes>
156 constexpr static auto default_transformer(std::array<uint8_t, bytes> x) {
157 return x;
158 }
159
160 template <size_t bytes, typename T>
161 constexpr static bool default_predicate(T) {
162 return true;
163 }
164
165 public:
167 requires std::default_initializable<XofT>
168 : m_bytes_consumed(0) {}
169
170 explicit Bounded_XOF(XofT xof) : m_xof(xof), m_bytes_consumed(0) {}
171
172 /**
173 * @returns the next byte from the XOF that fulfills @p predicate.
174 */
175 template <typename PredicateFnT = decltype(default_predicate<1, uint8_t>)>
176 requires std::invocable<PredicateFnT, uint8_t>
177 constexpr auto next_byte(PredicateFnT&& predicate = default_predicate<1, uint8_t>) {
178 return next<1>([](const auto bytes) { return bytes[0]; }, std::forward<PredicateFnT>(predicate));
179 }
180
181 /**
182 * Pulls the next @p bytes from the XOF and applies @p transformer to the
183 * output. The result is returned if @p predicate is fulfilled.
184 * @returns the transformed output of the XOF that fulfills @p predicate.
185 */
186 template <size_t bytes,
187 typename MapFnT = decltype(default_transformer<bytes>),
188 typename PredicateFnT = decltype(default_predicate<bytes, MappedValueT<bytes, MapFnT>>)>
189 requires std::invocable<MapFnT, std::array<uint8_t, bytes>> &&
190 std::invocable<PredicateFnT, MappedValueT<bytes, MapFnT>>
191 constexpr auto next(MapFnT&& transformer = default_transformer<bytes>,
192 PredicateFnT&& predicate = default_predicate<bytes, MappedValueT<bytes, MapFnT>>) {
193 while(true) {
194 auto output = transformer(take<bytes>());
195 if(predicate(output)) {
196 return output;
197 }
198 }
199 }
200
201 private:
202 template <size_t bytes>
203 constexpr std::array<uint8_t, bytes> take() {
204 m_bytes_consumed += bytes;
205 if(m_bytes_consumed > bound) {
206 throw Internal_Error("XOF consumed more bytes than allowed");
207 }
208 return m_xof.template output<bytes>();
209 }
210
211 private:
212 XofT m_xof;
213 size_t m_bytes_consumed;
214};
215
216} // namespace detail
217
218class XOF;
219
220template <size_t bound>
222
223} // namespace Botan
224
225#endif
constexpr auto next(MapFnT &&transformer=default_transformer< bytes >, PredicateFnT &&predicate=default_predicate< bytes, MappedValueT< bytes, MapFnT > >)
static constexpr bool default_predicate(T)
static constexpr auto default_transformer(std::array< uint8_t, bytes > x)
constexpr auto next_byte(PredicateFnT &&predicate=default_predicate< 1, uint8_t >)
int(* final)(unsigned char *, CTX *)
FE_25519 T
Definition ge.cpp:34
consteval T modular_inverse(T q, T2 m=T2(1)<< sizeof(T) *8)
std::conditional_t< sizeof(T)==1, int16_t, std::conditional_t< sizeof(T)==2, int32_t, std::conditional_t< sizeof(T)==4, int64_t, void > > > next_longer_int_t
std::conditional_t< sizeof(T)==1, uint16_t, std::conditional_t< sizeof(T)==2, uint32_t, std::conditional_t< sizeof(T)==4, uint64_t, void > > > next_longer_uint_t
consteval T montgomery_R2(T q)
consteval T montgomery_R(T q)
consteval eea_result< T > extended_euclidean_algorithm(T a, T b)
const SIMD_8x32 & b
constexpr auto bitlen(size_t x)
constexpr uint8_t ceil_log2(T x)
Definition bit_ops.h:122