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