Botan 3.13.0
Crypto and TLS for C&
pcurves_secp521r1.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_wrap.h>
10
11namespace Botan::PCurve {
12
13namespace {
14
15namespace secp521r1 {
16
17template <typename Params>
18class P521Rep final {
19 public:
20 static constexpr auto P = Params::P;
21 static constexpr size_t N = Params::N;
22 typedef typename Params::W W;
23
24 constexpr static std::array<W, N> one() { return std::array<W, N>{1}; }
25
26 constexpr static std::array<W, N> redc(const std::array<W, 2 * N>& z) {
27 // Regardless of word size (32 or 64) the top word is 9 bits long
28 constexpr W TOP_BITS = static_cast<W>(0x1FF);
29 // The 23 or 55 bits that should be cleared in the top word
30 constexpr W CLEARED_TOP_BITS = WordInfo<W>::max ^ TOP_BITS;
31
32 /*
33 * Extract the high part of z (z >> 521)
34 */
35 std::array<W, N> t; // NOLINT(*-member-init)
36
37 for(size_t i = 0; i != N; ++i) {
38 t[i] = z[(N - 1) + i] >> 9;
39 }
40
41 for(size_t i = 0; i != N - 1; ++i) {
42 t[i] |= z[(N - 1) + i + 1] << (WordInfo<W>::bits - 9);
43 }
44
45 // Now t += z & (2**521-1)
46 W carry = 0;
47 for(size_t i = 0; i != N - 1; ++i) {
48 t[i] = word_add(t[i], z[i], &carry);
49 }
50
51 // Now add the (partial) top words; this can't carry out
52 // since both inputs are at most 2**9-1
53 t[N - 1] += (z[N - 1] & TOP_BITS) + carry;
54
55 /*
56 Since the modulus P is exactly 2**521 - 1 the only way the computed
57 result can be larger than P is if the top word is larger than TOP_BITS
58
59 Since TOP_BITS has the low 9 bits set, we can check if t[N - 1] > TOP_BITS
60 by checking if t[N - 1] >> 9 has any bits set. Doing it this way is
61 faster than a standard comparison since CT::Mask::is_gt requires
62 several bit operations.
63 */
64
65 const W is_over_p521 = ~CT::Mask<W>::is_zero(t[N - 1] >> 9).value();
66
67 /*
68 * Also must detect/handle x == P
69 */
70 const W is_eq_p521 = [&]() {
71 W sum = WordInfo<W>::max;
72 for(size_t i = 0; i != N - 1; ++i) {
73 sum &= t[i];
74 }
75 sum &= (CLEARED_TOP_BITS | t[N - 1]);
76
77 return CT::Mask<W>::is_zero(sum ^ WordInfo<W>::max).value();
78 }();
79
80 const W need_sub = is_over_p521 | is_eq_p521;
81
82 W borrow = 0;
83 for(size_t i = 0; i != N - 1; ++i) {
84 t[i] = word_sub(t[i], need_sub & WordInfo<W>::max, &borrow);
85 }
86 t[N - 1] = word_sub(t[N - 1], need_sub & TOP_BITS, &borrow);
87
88 return t;
89 }
90
91 constexpr static std::array<W, N> to_rep(const std::array<W, N>& x) { return x; }
92
93 constexpr static std::array<W, N> wide_to_rep(const std::array<W, 2 * N>& x) { return redc(x); }
94
95 constexpr static std::array<W, N> from_rep(const std::array<W, N>& z) { return z; }
96};
97
98// clang-format off
99
100class Params final : public EllipticCurveParameters<
101 "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
102 "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
103 "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
104 "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
105 "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
106 "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
107 -4> {
108};
109
110// clang-format on
111
112class Curve final : public EllipticCurve<Params, P521Rep> {
113 public:
114 // Return the square of the inverse of x
115 static constexpr FieldElement fe_invert2(const FieldElement& x) {
116 // Addition chain from https://eprint.iacr.org/2014/852.pdf page 6
117
118 FieldElement r = x.square();
119 r *= x;
120 r = r.square();
121 r *= x;
122 FieldElement rl = r;
123 r.square_n(3);
124 r *= rl;
125 r.square_n(1);
126 r *= x;
127 const auto a7 = r;
128 r.square_n(1);
129 r *= x;
130 rl = r;
131 r.square_n(8);
132 r *= rl;
133 rl = r;
134 r.square_n(16);
135 r *= rl;
136 rl = r;
137 r.square_n(32);
138 r *= rl;
139 rl = r;
140 r.square_n(64);
141 r *= rl;
142 rl = r;
143 r.square_n(128);
144 r *= rl;
145 rl = r;
146 r.square_n(256);
147 r *= rl;
148 r.square_n(7);
149 r *= a7;
150 r.square_n(2);
151
152 return r;
153 }
154
155 static constexpr FieldElement fe_sqrt(const FieldElement& x) {
156 auto z = x;
157 z.square_n(519);
158 return z;
159 }
160
161 static constexpr Scalar scalar_invert(const Scalar& x) {
162 // Generated using https://github.com/mmcloughlin/addchain
163
164 auto t2 = x.square();
165 auto t13 = t2 * x;
166 auto t4 = t13 * x;
167 auto z = t13 * t4;
168 auto t5 = x * z;
169 auto t16 = t13 * t5;
170 auto t10 = t16 * t2;
171 auto t18 = t10 * t2;
172 auto t1 = t18 * t2;
173 auto t12 = t1 * t2;
174 auto t15 = t12 * t4;
175 auto t0 = t15 * t2;
176 auto t3 = t0 * t2;
177 auto t6 = t2 * t3;
178 auto t11 = t5 * t6;
179 auto t14 = t11 * t4;
180 auto t9 = t14 * t4;
181 auto t17 = t2 * t9;
182 auto t7 = t17 * t4;
183 t4 *= t7;
184 auto t8 = t2 * t4;
185 t5 = t2 * t8;
186 t2 *= t5;
187 auto t19 = t2;
188 t19.square_n(3);
189 t15 *= t19;
190 t19 = t15.square();
191 auto t20 = t19;
192 t20.square_n(8);
193 t20 *= t15;
194 t20.square_n(10);
195 t19 *= t20;
196 t20 = t19;
197 t20.square_n(8);
198 t20 *= t15;
199 t20.square_n(28);
200 t19 *= t20;
201 t20 = t19;
202 t20.square_n(63);
203 t19 *= t20;
204 t20 = t19;
205 t20.square_n(8);
206 t20 *= t15;
207 t20.square_n(127);
208 t19 *= t20;
209 t19 *= x;
210 t19.square_n(7);
211 t19 *= t11;
212 t19.square_n(5);
213 t19 *= t13;
214 t19.square_n(8);
215 t19 *= t10;
216 t19.square_n(8);
217 t19 *= t18;
218 t19.square_n(11);
219 t19 *= t5;
220 t19.square_n(4);
221 t18 *= t19;
222 t18.square_n(8);
223 t17 *= t18;
224 t17.square_n(6);
225 t17 *= t11;
226 t17.square_n(5);
227 t17 *= t12;
228 t17.square_n(5);
229 t16 *= t17;
230 t16.square_n(10);
231 t15 *= t16;
232 t15.square_n(4);
233 t15 *= t13;
234 t15.square_n(15);
235 t14 *= t15;
236 t14.square_n(9);
237 t14 *= t2;
238 t14.square_n(2);
239 t13 *= t14;
240 t13.square_n(9);
241 t12 *= t13;
242 t12.square_n(7);
243 t11 *= t12;
244 t11.square_n(4);
245 t10 *= t11;
246 t10.square_n(12);
247 t10 *= t5;
248 t10.square_n(6);
249 t9 *= t10;
250 t9.square_n(7);
251 t8 *= t9;
252 t8.square_n(8);
253 t8 *= t4;
254 t8.square_n(8);
255 t8 *= t1;
256 t8.square_n(8);
257 t7 *= t8;
258 t7.square_n(5);
259 t7 *= t1;
260 t7.square_n(9);
261 t7 *= t2;
262 t7.square_n(6);
263 t6 *= t7;
264 t6.square_n(7);
265 t5 *= t6;
266 t5.square_n(7);
267 t4 *= t5;
268 t4.square_n(5);
269 t3 *= t4;
270 t3.square_n(4);
271 t3 *= z;
272 t3.square_n(9);
273 t2 *= t3;
274 t2.square_n(7);
275 t1 *= t2;
276 t1.square_n(5);
277 t1 *= z;
278 t1.square_n(9);
279 t0 *= t1;
280 t0.square_n(10);
281 z *= t0;
282
283 return z;
284 }
285};
286
287} // namespace secp521r1
288
289} // namespace
290
291std::shared_ptr<const PrimeOrderCurve> PCurveInstance::secp521r1() {
293}
294
295} // namespace Botan::PCurve
static constexpr Mask< T > is_zero(T x)
Definition ct_utils.h:437
static std::shared_ptr< const PrimeOrderCurve > instance()
constexpr auto word_sub(W x, W y, W *carry) -> W
Definition mp_asmi.h:320
constexpr auto word_add(W x, W y, W *carry) -> W
Definition mp_asmi.h:231
void carry(int64_t &h0, int64_t &h1)