Botan 3.11.0
Crypto and TLS for C&
pcurves_secp384r1.cpp
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#include <botan/internal/pcurves_instance.h>
8
9#include <botan/internal/pcurves_solinas.h>
10#include <botan/internal/pcurves_wrap.h>
11
12namespace Botan::PCurve {
13
14namespace {
15
16template <typename Params>
17class Secp384r1Rep final {
18 public:
19 static constexpr auto P = Params::P;
20 static constexpr size_t N = Params::N;
21 typedef typename Params::W W;
22
23 constexpr static std::array<W, N> redc(const std::array<W, 2 * N>& z) {
24 const int64_t X00 = get_uint32(z.data(), 0);
25 const int64_t X01 = get_uint32(z.data(), 1);
26 const int64_t X02 = get_uint32(z.data(), 2);
27 const int64_t X03 = get_uint32(z.data(), 3);
28 const int64_t X04 = get_uint32(z.data(), 4);
29 const int64_t X05 = get_uint32(z.data(), 5);
30 const int64_t X06 = get_uint32(z.data(), 6);
31 const int64_t X07 = get_uint32(z.data(), 7);
32 const int64_t X08 = get_uint32(z.data(), 8);
33 const int64_t X09 = get_uint32(z.data(), 9);
34 const int64_t X10 = get_uint32(z.data(), 10);
35 const int64_t X11 = get_uint32(z.data(), 11);
36 const int64_t X12 = get_uint32(z.data(), 12);
37 const int64_t X13 = get_uint32(z.data(), 13);
38 const int64_t X14 = get_uint32(z.data(), 14);
39 const int64_t X15 = get_uint32(z.data(), 15);
40 const int64_t X16 = get_uint32(z.data(), 16);
41 const int64_t X17 = get_uint32(z.data(), 17);
42 const int64_t X18 = get_uint32(z.data(), 18);
43 const int64_t X19 = get_uint32(z.data(), 19);
44 const int64_t X20 = get_uint32(z.data(), 20);
45 const int64_t X21 = get_uint32(z.data(), 21);
46 const int64_t X22 = get_uint32(z.data(), 22);
47 const int64_t X23 = get_uint32(z.data(), 23);
48
49 // One copy of P-384 is added to prevent underflow
50 const int64_t S0 = 0xFFFFFFFF + X00 + X12 + X20 + X21 - X23;
51 const int64_t S1 = 0x00000000 + X01 + X13 + X22 + X23 - X12 - X20;
52 const int64_t S2 = 0x00000000 + X02 + X14 + X23 - X13 - X21;
53 const int64_t S3 = 0xFFFFFFFF + X03 + X12 + X15 + X20 + X21 - X14 - X22 - X23;
54 const int64_t S4 = 0xFFFFFFFE + X04 + X12 + X13 + X16 + X20 + X21 * 2 + X22 - X15 - X23 * 2;
55 const int64_t S5 = 0xFFFFFFFF + X05 + X13 + X14 + X17 + X21 + X22 * 2 + X23 - X16;
56 const int64_t S6 = 0xFFFFFFFF + X06 + X14 + X15 + X18 + X22 + X23 * 2 - X17;
57 const int64_t S7 = 0xFFFFFFFF + X07 + X15 + X16 + X19 + X23 - X18;
58 const int64_t S8 = 0xFFFFFFFF + X08 + X16 + X17 + X20 - X19;
59 const int64_t S9 = 0xFFFFFFFF + X09 + X17 + X18 + X21 - X20;
60 const int64_t SA = 0xFFFFFFFF + X10 + X18 + X19 + X22 - X21;
61 const int64_t SB = 0xFFFFFFFF + X11 + X19 + X20 + X23 - X22;
62
63 std::array<W, N> r = {};
64
65 SolinasAccum sum(r);
66
67 sum.accum(S0);
68 sum.accum(S1);
69 sum.accum(S2);
70 sum.accum(S3);
71 sum.accum(S4);
72 sum.accum(S5);
73 sum.accum(S6);
74 sum.accum(S7);
75 sum.accum(S8);
76 sum.accum(S9);
77 sum.accum(SA);
78 sum.accum(SB);
79 const auto S = sum.final_carry(0);
80
81 BOTAN_DEBUG_ASSERT(S <= 4);
82
83 solinas_correct_redc<N>(r, P, p384_mul_mod_384(S));
84
85 return r;
86 }
87
88 constexpr static std::array<W, N> one() { return std::array<W, N>{1}; }
89
90 constexpr static std::array<W, N> to_rep(const std::array<W, N>& x) { return x; }
91
92 constexpr static std::array<W, N> wide_to_rep(const std::array<W, 2 * N>& x) { return redc(x); }
93
94 constexpr static std::array<W, N> from_rep(const std::array<W, N>& z) { return z; }
95
96 private:
97 // Return (i*P-384) % 2**384
98 //
99 // Assumes i is small
100 constexpr static std::array<W, N> p384_mul_mod_384(W i) {
101 static_assert(WordInfo<W>::bits == 32 || WordInfo<W>::bits == 64);
102
103 // For small i, multiples of P-384 have a simple structure so it's faster to
104 // compute the value directly vs a (constant time) table lookup
105
106 auto r = P;
107 if constexpr(WordInfo<W>::bits == 32) {
108 r[4] -= i;
109 r[3] -= i;
110 r[1] += i;
111 r[0] -= i;
112 } else {
113 const uint64_t i32 = static_cast<uint64_t>(i) << 32;
114 r[2] -= i;
115 r[1] -= i32;
116 r[0] += i32;
117 r[0] -= i;
118 }
119 return r;
120 }
121};
122
123namespace secp384r1 {
124
125// clang-format off
126
127class Params final : public EllipticCurveParameters<
128 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
129 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
130 "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
131 "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
132 "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
133 "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
134 -12> {
135};
136
137// clang-format on
138
139class Curve final : public EllipticCurve<Params, Secp384r1Rep> {
140 public:
141 // Return the square of the inverse of x
142 static constexpr FieldElement fe_invert2(const FieldElement& x) {
143 // From https://briansmith.org/ecc-inversion-addition-chains-01
144
145 FieldElement r = x.square();
146 r *= x;
147 const auto x2 = r;
148 r = r.square();
149 r *= x;
150 const auto x3 = r;
151 r.square_n(3);
152 r *= x3;
153 auto rl = r;
154 r.square_n(6);
155 r *= rl;
156 r.square_n(3);
157 r *= x3;
158 const auto x15 = r;
159 r.square_n(15);
160 r *= x15;
161 const auto x30 = r;
162 r.square_n(30);
163 r *= x30;
164 rl = r;
165 r.square_n(60);
166 r *= rl;
167 rl = r;
168 r.square_n(120);
169 r *= rl;
170 r.square_n(15);
171 r *= x15;
172 r.square_n(31);
173 r *= x30;
174 r.square_n(2);
175 r *= x2;
176 r.square_n(94);
177 r *= x30;
178 r.square_n(2);
179
180 return r;
181 }
182
183 static constexpr FieldElement fe_sqrt(const FieldElement& x) {
184 // Generated using https://github.com/mmcloughlin/addchain
185
186 auto z = x.square();
187 z *= x;
188 z = z.square();
189 auto t0 = x * z;
190 z = t0;
191 z.square_n(3);
192 auto t1 = t0 * z;
193 auto t2 = t1.square();
194 z = t2 * x;
195 t2.square_n(5);
196 t1 *= t2;
197 t2 = t1;
198 t2.square_n(12);
199 t1 *= t2;
200 t1.square_n(7);
201 t1 *= z;
202 z = t1.square();
203 z *= x;
204 t2 = z;
205 t2.square_n(31);
206 t1 *= t2;
207 t2 = t1;
208 t2.square_n(63);
209 t1 *= t2;
210 t2 = t1;
211 t2.square_n(126);
212 t1 *= t2;
213 t1.square_n(3);
214 t0 *= t1;
215 t0.square_n(33);
216 z *= t0;
217 z.square_n(64);
218 z *= x;
219 z.square_n(30);
220 return z;
221 }
222
223 static constexpr Scalar scalar_invert(const Scalar& x) {
224 // Generated using https://github.com/mmcloughlin/addchain
225
226 auto t3 = x.square();
227 auto t1 = x * t3;
228 auto t0 = t3 * t1;
229 auto t2 = t3 * t0;
230 auto t4 = t3 * t2;
231 auto z = t3 * t4;
232 auto t5 = t3 * z;
233 t3 *= t5;
234 auto t6 = t3.square();
235 t6 *= x;
236 auto t8 = t6;
237 t8.square_n(2);
238 auto t9 = t8.square();
239 auto t7 = t9.square();
240 auto t10 = t7;
241 t10.square_n(5);
242 t7 *= t10;
243 t10 = t7;
244 t10.square_n(10);
245 t7 *= t10;
246 t10 = t7;
247 t10.square_n(4);
248 t9 *= t10;
249 t9.square_n(21);
250 t7 *= t9;
251 t9 = t7;
252 t9.square_n(3);
253 t8 *= t9;
254 t8.square_n(47);
255 t7 *= t8;
256 t8 = t7;
257 t8.square_n(95);
258 t7 *= t8;
259 t7 *= t3;
260 t7.square_n(6);
261 t7 *= t2;
262 t7.square_n(3);
263 t7 *= t1;
264 t7.square_n(7);
265 t7 *= t5;
266 t7.square_n(6);
267 t7 *= t5;
268 t7 = t7.square();
269 t7 *= x;
270 t7.square_n(11);
271 t7 *= t6;
272 t7.square_n(2);
273 t7 *= x;
274 t7.square_n(8);
275 t7 *= t5;
276 t7.square_n(2);
277 t7 *= t1;
278 t7.square_n(6);
279 t7 *= z;
280 t7.square_n(4);
281 t7 *= t2;
282 t7.square_n(6);
283 t6 *= t7;
284 t6.square_n(5);
285 t6 *= z;
286 t6.square_n(10);
287 t6 *= t5;
288 t6.square_n(9);
289 t5 *= t6;
290 t5.square_n(4);
291 t5 *= z;
292 t5.square_n(6);
293 t4 *= t5;
294 t4.square_n(3);
295 t4 *= x;
296 t4.square_n(7);
297 t4 *= z;
298 t4.square_n(7);
299 t4 *= t0;
300 t4.square_n(5);
301 t4 *= t2;
302 t4.square_n(5);
303 t3 *= t4;
304 t3.square_n(5);
305 t3 *= z;
306 t3.square_n(4);
307 t3 *= z;
308 t3.square_n(5);
309 t2 *= t3;
310 t2.square_n(3);
311 t2 *= t1;
312 t2.square_n(7);
313 t2 *= t1;
314 t2.square_n(6);
315 t2 *= z;
316 t2.square_n(4);
317 t2 *= t0;
318 t2.square_n(3);
319 t2 *= t1;
320 t2.square_n(4);
321 t2 *= t1;
322 t2.square_n(4);
323 t1 *= t2;
324 t1.square_n(6);
325 t1 *= t0;
326 t1.square_n(5);
327 t0 *= t1;
328 t0.square_n(6);
329 z *= t0;
330 z = z.square();
331 z *= x;
332 z.square_n(4);
333 z *= x;
334
335 return z;
336 }
337};
338
339} // namespace secp384r1
340
341} // namespace
342
343std::shared_ptr<const PrimeOrderCurve> PCurveInstance::secp384r1() {
345}
346
347} // namespace Botan::PCurve
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:129
static std::shared_ptr< const PrimeOrderCurve > instance()
constexpr uint32_t get_uint32(const W xw[], size_t i)
constexpr void solinas_correct_redc(std::array< W, N > &r, const std::array< W, N > &P, const std::array< W, N > &C)