Coverage Report

Created: 2025-04-11 06:34

/src/botan/src/lib/math/pcurves/pcurves_secp384r1/pcurves_secp384r1.cpp
Line
Count
Source (jump to first uncovered line)
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
12
namespace Botan::PCurve {
13
14
namespace {
15
16
template <typename Params>
17
class 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
5.10M
      constexpr static std::array<W, N> redc(const std::array<W, 2 * N>& z) {
24
5.10M
         const int64_t X00 = get_uint32(z.data(), 0);
25
5.10M
         const int64_t X01 = get_uint32(z.data(), 1);
26
5.10M
         const int64_t X02 = get_uint32(z.data(), 2);
27
5.10M
         const int64_t X03 = get_uint32(z.data(), 3);
28
5.10M
         const int64_t X04 = get_uint32(z.data(), 4);
29
5.10M
         const int64_t X05 = get_uint32(z.data(), 5);
30
5.10M
         const int64_t X06 = get_uint32(z.data(), 6);
31
5.10M
         const int64_t X07 = get_uint32(z.data(), 7);
32
5.10M
         const int64_t X08 = get_uint32(z.data(), 8);
33
5.10M
         const int64_t X09 = get_uint32(z.data(), 9);
34
5.10M
         const int64_t X10 = get_uint32(z.data(), 10);
35
5.10M
         const int64_t X11 = get_uint32(z.data(), 11);
36
5.10M
         const int64_t X12 = get_uint32(z.data(), 12);
37
5.10M
         const int64_t X13 = get_uint32(z.data(), 13);
38
5.10M
         const int64_t X14 = get_uint32(z.data(), 14);
39
5.10M
         const int64_t X15 = get_uint32(z.data(), 15);
40
5.10M
         const int64_t X16 = get_uint32(z.data(), 16);
41
5.10M
         const int64_t X17 = get_uint32(z.data(), 17);
42
5.10M
         const int64_t X18 = get_uint32(z.data(), 18);
43
5.10M
         const int64_t X19 = get_uint32(z.data(), 19);
44
5.10M
         const int64_t X20 = get_uint32(z.data(), 20);
45
5.10M
         const int64_t X21 = get_uint32(z.data(), 21);
46
5.10M
         const int64_t X22 = get_uint32(z.data(), 22);
47
5.10M
         const int64_t X23 = get_uint32(z.data(), 23);
48
49
         // One copy of P-384 is added to prevent underflow
50
5.10M
         const int64_t S0 = 0xFFFFFFFF + X00 + X12 + X20 + X21 - X23;
51
5.10M
         const int64_t S1 = 0x00000000 + X01 + X13 + X22 + X23 - X12 - X20;
52
5.10M
         const int64_t S2 = 0x00000000 + X02 + X14 + X23 - X13 - X21;
53
5.10M
         const int64_t S3 = 0xFFFFFFFF + X03 + X12 + X15 + X20 + X21 - X14 - X22 - X23;
54
5.10M
         const int64_t S4 = 0xFFFFFFFE + X04 + X12 + X13 + X16 + X20 + X21 * 2 + X22 - X15 - X23 * 2;
55
5.10M
         const int64_t S5 = 0xFFFFFFFF + X05 + X13 + X14 + X17 + X21 + X22 * 2 + X23 - X16;
56
5.10M
         const int64_t S6 = 0xFFFFFFFF + X06 + X14 + X15 + X18 + X22 + X23 * 2 - X17;
57
5.10M
         const int64_t S7 = 0xFFFFFFFF + X07 + X15 + X16 + X19 + X23 - X18;
58
5.10M
         const int64_t S8 = 0xFFFFFFFF + X08 + X16 + X17 + X20 - X19;
59
5.10M
         const int64_t S9 = 0xFFFFFFFF + X09 + X17 + X18 + X21 - X20;
60
5.10M
         const int64_t SA = 0xFFFFFFFF + X10 + X18 + X19 + X22 - X21;
61
5.10M
         const int64_t SB = 0xFFFFFFFF + X11 + X19 + X20 + X23 - X22;
62
63
5.10M
         std::array<W, N> r = {};
64
65
5.10M
         SolinasAccum sum(r);
66
67
5.10M
         sum.accum(S0);
68
5.10M
         sum.accum(S1);
69
5.10M
         sum.accum(S2);
70
5.10M
         sum.accum(S3);
71
5.10M
         sum.accum(S4);
72
5.10M
         sum.accum(S5);
73
5.10M
         sum.accum(S6);
74
5.10M
         sum.accum(S7);
75
5.10M
         sum.accum(S8);
76
5.10M
         sum.accum(S9);
77
5.10M
         sum.accum(SA);
78
5.10M
         sum.accum(SB);
79
5.10M
         const auto S = sum.final_carry(0);
80
81
5.10M
         BOTAN_DEBUG_ASSERT(S <= 4);
82
83
5.10M
         bigint_correct_redc<N>(r, P, p384_mul_mod_384(S));
84
85
5.10M
         return r;
86
5.10M
      }
87
88
223k
      constexpr static std::array<W, N> one() { return std::array<W, N>{1}; }
89
90
8.63k
      constexpr static std::array<W, N> to_rep(const std::array<W, N>& x) { return x; }
91
92
0
      constexpr static std::array<W, N> wide_to_rep(const std::array<W, 2 * N>& x) { return redc(x); }
93
94
5.17k
      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
5.10M
      constexpr static std::array<W, N> p384_mul_mod_384(W i) {
101
5.10M
         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
5.10M
         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
5.10M
         } else {
113
5.10M
            const uint64_t i32 = static_cast<uint64_t>(i) << 32;
114
5.10M
            r[2] -= i;
115
5.10M
            r[1] -= i32;
116
5.10M
            r[0] += i32;
117
5.10M
            r[0] -= i;
118
5.10M
         }
119
5.10M
         return r;
120
5.10M
      }
121
};
122
123
// clang-format off
124
namespace secp384r1 {
125
126
class Params final : public EllipticCurveParameters<
127
   "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFF",
128
   "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFFFF0000000000000000FFFFFFFC",
129
   "B3312FA7E23EE7E4988E056BE3F82D19181D9C6EFE8141120314088F5013875AC656398D8A2ED19D2A85C8EDD3EC2AEF",
130
   "FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC7634D81F4372DDF581A0DB248B0A77AECEC196ACCC52973",
131
   "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7",
132
   "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F",
133
   -12> {
134
};
135
136
// clang-format on
137
138
class Curve final : public EllipticCurve<Params, Secp384r1Rep> {
139
   public:
140
      // Return the square of the inverse of x
141
2.43k
      static constexpr FieldElement fe_invert2(const FieldElement& x) {
142
         // From https://briansmith.org/ecc-inversion-addition-chains-01
143
144
2.43k
         FieldElement r = x.square();
145
2.43k
         r *= x;
146
2.43k
         const auto x2 = r;
147
2.43k
         r = r.square();
148
2.43k
         r *= x;
149
2.43k
         const auto x3 = r;
150
2.43k
         r.square_n(3);
151
2.43k
         r *= x3;
152
2.43k
         auto rl = r;
153
2.43k
         r.square_n(6);
154
2.43k
         r *= rl;
155
2.43k
         r.square_n(3);
156
2.43k
         r *= x3;
157
2.43k
         const auto x15 = r;
158
2.43k
         r.square_n(15);
159
2.43k
         r *= x15;
160
2.43k
         const auto x30 = r;
161
2.43k
         r.square_n(30);
162
2.43k
         r *= x30;
163
2.43k
         rl = r;
164
2.43k
         r.square_n(60);
165
2.43k
         r *= rl;
166
2.43k
         rl = r;
167
2.43k
         r.square_n(120);
168
2.43k
         r *= rl;
169
2.43k
         r.square_n(15);
170
2.43k
         r *= x15;
171
2.43k
         r.square_n(31);
172
2.43k
         r *= x30;
173
2.43k
         r.square_n(2);
174
2.43k
         r *= x2;
175
2.43k
         r.square_n(94);
176
2.43k
         r *= x30;
177
2.43k
         r.square_n(2);
178
179
2.43k
         return r;
180
2.43k
      }
181
182
0
      static constexpr Scalar scalar_invert(const Scalar& x) {
183
         // Generated using https://github.com/mmcloughlin/addchain
184
185
0
         auto t3 = x.square();
186
0
         auto t1 = x * t3;
187
0
         auto t0 = t3 * t1;
188
0
         auto t2 = t3 * t0;
189
0
         auto t4 = t3 * t2;
190
0
         auto z = t3 * t4;
191
0
         auto t5 = t3 * z;
192
0
         t3 *= t5;
193
0
         auto t6 = t3.square();
194
0
         t6 *= x;
195
0
         auto t8 = t6;
196
0
         t8.square_n(2);
197
0
         auto t9 = t8.square();
198
0
         auto t7 = t9.square();
199
0
         auto t10 = t7;
200
0
         t10.square_n(5);
201
0
         t7 *= t10;
202
0
         t10 = t7;
203
0
         t10.square_n(10);
204
0
         t7 *= t10;
205
0
         t10 = t7;
206
0
         t10.square_n(4);
207
0
         t9 *= t10;
208
0
         t9.square_n(21);
209
0
         t7 *= t9;
210
0
         t9 = t7;
211
0
         t9.square_n(3);
212
0
         t8 *= t9;
213
0
         t8.square_n(47);
214
0
         t7 *= t8;
215
0
         t8 = t7;
216
0
         t8.square_n(95);
217
0
         t7 *= t8;
218
0
         t7 *= t3;
219
0
         t7.square_n(6);
220
0
         t7 *= t2;
221
0
         t7.square_n(3);
222
0
         t7 *= t1;
223
0
         t7.square_n(7);
224
0
         t7 *= t5;
225
0
         t7.square_n(6);
226
0
         t7 *= t5;
227
0
         t7 = t7.square();
228
0
         t7 *= x;
229
0
         t7.square_n(11);
230
0
         t7 *= t6;
231
0
         t7.square_n(2);
232
0
         t7 *= x;
233
0
         t7.square_n(8);
234
0
         t7 *= t5;
235
0
         t7.square_n(2);
236
0
         t7 *= t1;
237
0
         t7.square_n(6);
238
0
         t7 *= z;
239
0
         t7.square_n(4);
240
0
         t7 *= t2;
241
0
         t7.square_n(6);
242
0
         t6 *= t7;
243
0
         t6.square_n(5);
244
0
         t6 *= z;
245
0
         t6.square_n(10);
246
0
         t6 *= t5;
247
0
         t6.square_n(9);
248
0
         t5 *= t6;
249
0
         t5.square_n(4);
250
0
         t5 *= z;
251
0
         t5.square_n(6);
252
0
         t4 *= t5;
253
0
         t4.square_n(3);
254
0
         t4 *= x;
255
0
         t4.square_n(7);
256
0
         t4 *= z;
257
0
         t4.square_n(7);
258
0
         t4 *= t0;
259
0
         t4.square_n(5);
260
0
         t4 *= t2;
261
0
         t4.square_n(5);
262
0
         t3 *= t4;
263
0
         t3.square_n(5);
264
0
         t3 *= z;
265
0
         t3.square_n(4);
266
0
         t3 *= z;
267
0
         t3.square_n(5);
268
0
         t2 *= t3;
269
0
         t2.square_n(3);
270
0
         t2 *= t1;
271
0
         t2.square_n(7);
272
0
         t2 *= t1;
273
0
         t2.square_n(6);
274
0
         t2 *= z;
275
0
         t2.square_n(4);
276
0
         t2 *= t0;
277
0
         t2.square_n(3);
278
0
         t2 *= t1;
279
0
         t2.square_n(4);
280
0
         t2 *= t1;
281
0
         t2.square_n(4);
282
0
         t1 *= t2;
283
0
         t1.square_n(6);
284
0
         t1 *= t0;
285
0
         t1.square_n(5);
286
0
         t0 *= t1;
287
0
         t0.square_n(6);
288
0
         z *= t0;
289
0
         z = z.square();
290
0
         z *= x;
291
0
         z.square_n(4);
292
0
         z *= x;
293
294
0
         return z;
295
0
      }
296
};
297
298
}  // namespace secp384r1
299
300
}  // namespace
301
302
81
std::shared_ptr<const PrimeOrderCurve> PCurveInstance::secp384r1() {
303
81
   return PrimeOrderCurveImpl<secp384r1::Curve>::instance();
304
81
}
305
306
}  // namespace Botan::PCurve