Botan 3.5.0
Crypto and TLS for C&
pcurves_util.h
Go to the documentation of this file.
1/*
2* (C) 2024 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#ifndef BOTAN_PCURVES_UTIL_H_
8#define BOTAN_PCURVES_UTIL_H_
9
10#include <botan/internal/mp_core.h>
11#include <array>
12
13namespace Botan {
14
15namespace {
16
17template <WordType W, size_t N, size_t XN>
18inline consteval std::array<W, N> reduce_mod(const std::array<W, XN>& x, const std::array<W, N>& p) {
19 std::array<W, N + 1> r = {0};
20 std::array<W, N + 1> t = {0};
21
22 const size_t x_bits = XN * WordInfo<W>::bits;
23
24 for(size_t i = 0; i != x_bits; ++i) {
25 const size_t b = x_bits - 1 - i;
26
27 const size_t b_word = b / WordInfo<W>::bits;
28 const size_t b_bit = b % WordInfo<W>::bits;
29 const bool x_b = (x[b_word] >> b_bit) & 1;
30
32 if(x_b) {
33 r[0] += 1;
34 }
35
36 const W carry = bigint_sub3(t.data(), r.data(), N + 1, p.data(), N);
37
38 if(carry == 0) {
39 std::swap(r, t);
40 }
41 }
42
43 std::array<W, N> rs;
44 copy_mem(rs, std::span{r}.template first<N>());
45 return rs;
46}
47
48template <WordType W, size_t N>
49inline consteval std::array<W, N> montygomery_r(const std::array<W, N>& p) {
50 std::array<W, N + 1> x = {0};
51 x[N] = 1;
52 return reduce_mod(x, p);
53}
54
55template <WordType W, size_t N>
56inline consteval std::array<W, N> mul_mod(const std::array<W, N>& x,
57 const std::array<W, N>& y,
58 const std::array<W, N>& p) {
59 std::array<W, 2 * N> z;
60 comba_mul<N>(z.data(), x.data(), y.data());
61 return reduce_mod(z, p);
62}
63
64template <WordType W, size_t N>
65inline constexpr auto monty_redc_pdash1(const std::array<W, 2 * N>& z, const std::array<W, N>& p) -> std::array<W, N> {
66 static_assert(N >= 1);
67
68 std::array<W, N> ws;
69
70 word3<W> accum;
71
72 accum.add(z[0]);
73
74 ws[0] = accum.monty_step_pdash1();
75
76 for(size_t i = 1; i != N; ++i) {
77 for(size_t j = 0; j < i; ++j) {
78 accum.mul(ws[j], p[i - j]);
79 }
80
81 accum.add(z[i]);
82
83 ws[i] = accum.monty_step_pdash1();
84 }
85
86 for(size_t i = 0; i != N - 1; ++i) {
87 for(size_t j = i + 1; j != N; ++j) {
88 accum.mul(ws[j], p[N + i - j]);
89 }
90
91 accum.add(z[N + i]);
92
93 ws[i] = accum.extract();
94 }
95
96 accum.add(z[2 * N - 1]);
97
98 ws[N - 1] = accum.extract();
99 // w1 is the final part, which is not stored in the workspace
100 const W w1 = accum.extract();
101
102 std::array<W, N> r;
103 bigint_monty_maybe_sub<N>(r.data(), w1, ws.data(), p.data());
104
105 return r;
106}
107
108template <WordType W, size_t N>
109inline constexpr auto monty_redc(const std::array<W, 2 * N>& z, const std::array<W, N>& p, W p_dash)
110 -> std::array<W, N> {
111 static_assert(N >= 1);
112
113 std::array<W, N> ws;
114
115 word3<W> accum;
116
117 accum.add(z[0]);
118
119 ws[0] = accum.monty_step(p[0], p_dash);
120
121 for(size_t i = 1; i != N; ++i) {
122 for(size_t j = 0; j < i; ++j) {
123 accum.mul(ws[j], p[i - j]);
124 }
125
126 accum.add(z[i]);
127
128 ws[i] = accum.monty_step(p[0], p_dash);
129 }
130
131 for(size_t i = 0; i != N - 1; ++i) {
132 for(size_t j = i + 1; j != N; ++j) {
133 accum.mul(ws[j], p[N + i - j]);
134 }
135
136 accum.add(z[N + i]);
137
138 ws[i] = accum.extract();
139 }
140
141 accum.add(z[2 * N - 1]);
142
143 ws[N - 1] = accum.extract();
144 // w1 is the final part, which is not stored in the workspace
145 const W w1 = accum.extract();
146
147 std::array<W, N> r;
148 bigint_monty_maybe_sub<N>(r.data(), w1, ws.data(), p.data());
149
150 return r;
151}
152
153template <uint8_t X, WordType W, size_t N>
154inline consteval std::array<W, N> p_minus(const std::array<W, N>& p) {
155 // TODO combine into p_plus_x_over_y<-1, 1>
156 static_assert(X > 0);
157 std::array<W, N> r;
158 W x = X;
159 bigint_sub3(r.data(), p.data(), N, &x, 1);
160 std::reverse(r.begin(), r.end());
161 return r;
162}
163
164template <WordType W, size_t N>
165inline consteval std::array<W, N> p_plus_1_over_4(const std::array<W, N>& p) {
166 const W one = 1;
167 std::array<W, N> r;
168 bigint_add3_nc(r.data(), p.data(), N, &one, 1);
170 std::reverse(r.begin(), r.end());
171 return r;
172}
173
174template <WordType W, size_t N>
175inline consteval std::array<W, N> p_minus_1_over_2(const std::array<W, N>& p) {
176 const W one = 1;
177 std::array<W, N> r;
178 bigint_sub3(r.data(), p.data(), N, &one, 1);
180 std::reverse(r.begin(), r.end());
181 return r;
182}
183
184template <WordType W, size_t N>
185inline consteval size_t count_bits(const std::array<W, N>& p) {
186 auto get_bit = [&](size_t i) {
187 const size_t w = i / WordInfo<W>::bits;
188 const size_t b = i % WordInfo<W>::bits;
189 return static_cast<uint8_t>((p[w] >> b) & 0x01);
190 };
191
192 size_t b = WordInfo<W>::bits * N;
193
194 while(get_bit(b - 1) == 0) {
195 b -= 1;
196 }
197
198 return b;
199}
200
201template <WordType W, size_t N, size_t L>
202inline constexpr auto bytes_to_words(std::span<const uint8_t, L> bytes) {
203 static_assert(L <= WordInfo<W>::bytes * N);
204
205 // TODO: This could be optimized quite a bit which is relevant
206 // since it executes at runtime
207 std::array<W, N> r = {};
208 for(size_t i = 0; i != L; ++i) {
209 shift_left<8>(r);
210 r[0] += bytes[i];
211 }
212 return r;
213}
214
215// Extract a WindowBits sized window out of s, depending on offset.
216template <size_t WindowBits, typename W, size_t N>
217constexpr size_t read_window_bits(std::span<const W, N> words, size_t offset) {
218 static_assert(WindowBits >= 1 && WindowBits <= 7);
219
220 const uint8_t WindowMask = static_cast<uint8_t>(1 << WindowBits) - 1;
221
222 const size_t W_bits = sizeof(W) * 8;
223 const auto bit_shift = offset % W_bits;
224 const auto word_offset = words.size() - 1 - (offset / W_bits);
225
226 const bool single_byte_window = bit_shift <= (W_bits - WindowBits) || word_offset == 0;
227
228 const auto w0 = words[word_offset];
229
230 if(single_byte_window) {
231 return (w0 >> bit_shift) & WindowMask;
232 } else {
233 // Otherwise we must join two words and extract the result
234 const auto w1 = words[word_offset - 1];
235 const auto combined = ((w0 >> bit_shift) | (w1 << (W_bits - bit_shift)));
236 return combined & WindowMask;
237 }
238}
239
240} // namespace
241
242} // namespace Botan
243
244#endif
FE_25519 X
Definition ge.cpp:25
constexpr W shift_left(std::array< W, N > &x)
Definition mp_core.h:861
constexpr void comba_mul(W z[2 *N], const W x[N], const W y[N])
Definition mp_core.h:948
constexpr auto bigint_sub3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:341
constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[])
Definition mp_core.h:374
void carry(int64_t &h0, int64_t &h1)
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:146
constexpr W shift_right(std::array< W, N > &x)
Definition mp_core.h:875
constexpr auto bigint_add3_nc(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:232