Botan 3.9.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
84class Params final : public EllipticCurveParameters<
85 "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF",
86 "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFC",
87 "51953EB9618E1C9A1F929A21A0B68540EEA2DA725B99B315F3B8B489918EF109E156193951EC7E937B1652C0BD3BB1BF073573DF883D2C34F1EF451FD46B503F00",
88 "1FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFA51868783BF2F966B7FCC0148F709A5D03BB5C9B8899C47AEBB6FB71E91386409",
89 "C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66",
90 "11839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650",
91 -4> {
92};
93
94// clang-format on
95
96class Curve final : public EllipticCurve<Params, P521Rep> {
97 public:
98 // Return the square of the inverse of x
99 static constexpr FieldElement fe_invert2(const FieldElement& x) {
100 // Addition chain from https://eprint.iacr.org/2014/852.pdf page 6
101
102 FieldElement r = x.square();
103 r *= x;
104 r = r.square();
105 r *= x;
106 FieldElement rl = r;
107 r.square_n(3);
108 r *= rl;
109 r.square_n(1);
110 r *= x;
111 const auto a7 = r;
112 r.square_n(1);
113 r *= x;
114 rl = r;
115 r.square_n(8);
116 r *= rl;
117 rl = r;
118 r.square_n(16);
119 r *= rl;
120 rl = r;
121 r.square_n(32);
122 r *= rl;
123 rl = r;
124 r.square_n(64);
125 r *= rl;
126 rl = r;
127 r.square_n(128);
128 r *= rl;
129 rl = r;
130 r.square_n(256);
131 r *= rl;
132 r.square_n(7);
133 r *= a7;
134 r.square_n(2);
135
136 return r;
137 }
138
139 static constexpr FieldElement fe_sqrt(const FieldElement& x) {
140 auto z = x;
141 z.square_n(519);
142 return z;
143 }
144
145 static constexpr Scalar scalar_invert(const Scalar& x) {
146 // Generated using https://github.com/mmcloughlin/addchain
147
148 auto t2 = x.square();
149 auto t13 = t2 * x;
150 auto t4 = t13 * x;
151 auto z = t13 * t4;
152 auto t5 = x * z;
153 auto t16 = t13 * t5;
154 auto t10 = t16 * t2;
155 auto t18 = t10 * t2;
156 auto t1 = t18 * t2;
157 auto t12 = t1 * t2;
158 auto t15 = t12 * t4;
159 auto t0 = t15 * t2;
160 auto t3 = t0 * t2;
161 auto t6 = t2 * t3;
162 auto t11 = t5 * t6;
163 auto t14 = t11 * t4;
164 auto t9 = t14 * t4;
165 auto t17 = t2 * t9;
166 auto t7 = t17 * t4;
167 t4 *= t7;
168 auto t8 = t2 * t4;
169 t5 = t2 * t8;
170 t2 *= t5;
171 auto t19 = t2;
172 t19.square_n(3);
173 t15 *= t19;
174 t19 = t15.square();
175 auto t20 = t19;
176 t20.square_n(8);
177 t20 *= t15;
178 t20.square_n(10);
179 t19 *= t20;
180 t20 = t19;
181 t20.square_n(8);
182 t20 *= t15;
183 t20.square_n(28);
184 t19 *= t20;
185 t20 = t19;
186 t20.square_n(63);
187 t19 *= t20;
188 t20 = t19;
189 t20.square_n(8);
190 t20 *= t15;
191 t20.square_n(127);
192 t19 *= t20;
193 t19 *= x;
194 t19.square_n(7);
195 t19 *= t11;
196 t19.square_n(5);
197 t19 *= t13;
198 t19.square_n(8);
199 t19 *= t10;
200 t19.square_n(8);
201 t19 *= t18;
202 t19.square_n(11);
203 t19 *= t5;
204 t19.square_n(4);
205 t18 *= t19;
206 t18.square_n(8);
207 t17 *= t18;
208 t17.square_n(6);
209 t17 *= t11;
210 t17.square_n(5);
211 t17 *= t12;
212 t17.square_n(5);
213 t16 *= t17;
214 t16.square_n(10);
215 t15 *= t16;
216 t15.square_n(4);
217 t15 *= t13;
218 t15.square_n(15);
219 t14 *= t15;
220 t14.square_n(9);
221 t14 *= t2;
222 t14.square_n(2);
223 t13 *= t14;
224 t13.square_n(9);
225 t12 *= t13;
226 t12.square_n(7);
227 t11 *= t12;
228 t11.square_n(4);
229 t10 *= t11;
230 t10.square_n(12);
231 t10 *= t5;
232 t10.square_n(6);
233 t9 *= t10;
234 t9.square_n(7);
235 t8 *= t9;
236 t8.square_n(8);
237 t8 *= t4;
238 t8.square_n(8);
239 t8 *= t1;
240 t8.square_n(8);
241 t7 *= t8;
242 t7.square_n(5);
243 t7 *= t1;
244 t7.square_n(9);
245 t7 *= t2;
246 t7.square_n(6);
247 t6 *= t7;
248 t6.square_n(7);
249 t5 *= t6;
250 t5.square_n(7);
251 t4 *= t5;
252 t4.square_n(5);
253 t3 *= t4;
254 t3.square_n(4);
255 t3 *= z;
256 t3.square_n(9);
257 t2 *= t3;
258 t2.square_n(7);
259 t1 *= t2;
260 t1.square_n(5);
261 t1 *= z;
262 t1.square_n(9);
263 t0 *= t1;
264 t0.square_n(10);
265 z *= t0;
266
267 return z;
268 }
269};
270
271} // namespace secp521r1
272
273} // namespace
274
275std::shared_ptr<const PrimeOrderCurve> PCurveInstance::secp521r1() {
277}
278
279} // 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:280
constexpr auto word_add(W x, W y, W *carry) -> W
Definition mp_asmi.h:191
void carry(int64_t &h0, int64_t &h1)