/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 |