Botan 3.11.0
Crypto and TLS for C&
pcurves_generic.cpp
Go to the documentation of this file.
1/*
2* (C) 2025 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/internal/pcurves_generic.h>
8
9#include <botan/bigint.h>
10#include <botan/exceptn.h>
11#include <botan/rng.h>
12#include <botan/internal/buffer_stuffer.h>
13#include <botan/internal/ct_utils.h>
14#include <botan/internal/loadstor.h>
15#include <botan/internal/mp_core.h>
16#include <botan/internal/pcurves_algos.h>
17#include <botan/internal/pcurves_instance.h>
18#include <botan/internal/pcurves_mul.h>
19#include <botan/internal/primality.h>
20#include <algorithm>
21
22namespace Botan::PCurve {
23
24namespace {
25
26template <size_t N>
27constexpr std::optional<std::array<word, N>> bytes_to_words(std::span<const uint8_t> bytes) {
28 if(bytes.size() > WordInfo<word>::bytes * N) {
29 return std::nullopt;
30 }
31
32 std::array<word, N> r{};
33
34 const size_t full_words = bytes.size() / WordInfo<word>::bytes;
35 const size_t extra_bytes = bytes.size() % WordInfo<word>::bytes;
36
37 for(size_t i = 0; i != full_words; ++i) {
38 r[i] = load_be<word>(bytes.data(), full_words - 1 - i);
39 }
40
41 if(extra_bytes > 0) {
42 const size_t shift = extra_bytes * 8;
43 bigint_shl1(r.data(), r.size(), r.size(), shift);
44
45 for(size_t i = 0; i != extra_bytes; ++i) {
46 const word b0 = bytes[WordInfo<word>::bytes * full_words + i];
47 r[0] |= (b0 << (8 * (extra_bytes - 1 - i)));
48 }
49 }
50
51 return r;
52}
53
54template <typename T>
55T impl_pow_vartime(const T& elem, const T& one, size_t bits, std::span<const word> exp) {
56 constexpr size_t WindowBits = 4;
57 constexpr size_t WindowElements = (1 << WindowBits) - 1;
58
59 const size_t Windows = (bits + WindowBits - 1) / WindowBits;
60
61 std::vector<T> tbl;
62 tbl.reserve(WindowElements);
63
64 tbl.push_back(elem);
65
66 for(size_t i = 1; i != WindowElements; ++i) {
67 if(i % 2 == 1) {
68 tbl.push_back(tbl[i / 2].square());
69 } else {
70 tbl.push_back(tbl[i - 1] * tbl[0]);
71 }
72 }
73
74 auto r = one;
75
76 const size_t w0 = read_window_bits<WindowBits>(exp, (Windows - 1) * WindowBits);
77
78 if(w0 > 0) {
79 r = tbl[w0 - 1];
80 }
81
82 for(size_t i = 1; i != Windows; ++i) {
83 for(size_t j = 0; j != WindowBits; ++j) {
84 r = r.square();
85 }
86 const size_t w = read_window_bits<WindowBits>(exp, (Windows - i - 1) * WindowBits);
87
88 if(w > 0) {
89 r *= tbl[w - 1];
90 }
91 }
92
93 return r;
94}
95
96} // namespace
97
98class GenericCurveParams final {
99 public:
100 typedef PrimeOrderCurve::StorageUnit StorageUnit;
101 static constexpr size_t N = PrimeOrderCurve::StorageWords;
102
103 GenericCurveParams(const BigInt& p,
104 const BigInt& a,
105 const BigInt& b,
106 const BigInt& base_x,
107 const BigInt& base_y,
108 const BigInt& order) :
109 m_words(p.sig_words()),
110 m_order_bits(order.bits()),
111 m_order_bytes(order.bytes()),
112 m_field_bits(p.bits()),
113 m_field_bytes(p.bytes()),
114 m_monty_order(order),
115 m_monty_field(p),
116 m_field(bn_to_fixed(p)),
117 m_field_minus_2(bn_to_fixed_rev(p - 2)),
118 m_field_monty_r1(bn_to_fixed(m_monty_field.R1())),
119 m_field_monty_r2(bn_to_fixed(m_monty_field.R2())),
120 m_field_p_plus_1_over_4(bn_to_fixed_rev((p + 1) / 4)),
121 m_field_inv_2(bn_to_fixed((p / 2) + 1)),
122 m_field_p_dash(m_monty_field.p_dash()),
123
124 m_order(bn_to_fixed(order)),
125 m_order_minus_2(bn_to_fixed_rev(order - 2)),
126 m_order_monty_r1(bn_to_fixed(m_monty_order.R1())),
127 m_order_monty_r2(bn_to_fixed(m_monty_order.R2())),
128 m_order_monty_r3(bn_to_fixed(m_monty_order.R3())),
129 m_order_inv_2(bn_to_fixed((order / 2) + 1)),
130 m_order_p_dash(m_monty_order.p_dash()),
131
132 m_a_is_minus_3(a + 3 == p),
133 m_a_is_zero(a.is_zero()),
134 m_order_is_lt_field(order < p) {
136 m_monty_curve_a = bn_to_fixed(m_monty_field.mul(a, m_monty_field.R2(), ws));
137 m_monty_curve_b = bn_to_fixed(m_monty_field.mul(b, m_monty_field.R2(), ws));
138
139 m_base_x = bn_to_fixed(m_monty_field.mul(base_x, m_monty_field.R2(), ws));
140 m_base_y = bn_to_fixed(m_monty_field.mul(base_y, m_monty_field.R2(), ws));
141 }
142
143 size_t words() const { return m_words; }
144
145 size_t order_bits() const { return m_order_bits; }
146
147 size_t order_bytes() const { return m_order_bytes; }
148
149 size_t field_bits() const { return m_field_bits; }
150
151 size_t field_bytes() const { return m_field_bytes; }
152
153 const Montgomery_Params& monty_order() const { return m_monty_order; }
154
155 const Montgomery_Params& monty_field() const { return m_monty_field; }
156
157 const StorageUnit& field() const { return m_field; }
158
159 const StorageUnit& field_minus_2() const { return m_field_minus_2; }
160
161 const StorageUnit& field_monty_r1() const { return m_field_monty_r1; }
162
163 const StorageUnit& field_monty_r2() const { return m_field_monty_r2; }
164
165 const StorageUnit& field_p_plus_1_over_4() const { return m_field_p_plus_1_over_4; }
166
167 const StorageUnit& field_inv_2() const { return m_field_inv_2; }
168
169 word field_p_dash() const { return m_field_p_dash; }
170
171 const StorageUnit& order() const { return m_order; }
172
173 const StorageUnit& order_minus_2() const { return m_order_minus_2; }
174
175 const StorageUnit& order_monty_r1() const { return m_order_monty_r1; }
176
177 const StorageUnit& order_monty_r2() const { return m_order_monty_r2; }
178
179 const StorageUnit& order_monty_r3() const { return m_order_monty_r3; }
180
181 const StorageUnit& order_inv_2() const { return m_order_inv_2; }
182
183 word order_p_dash() const { return m_order_p_dash; }
184
185 const StorageUnit& monty_curve_a() const { return m_monty_curve_a; }
186
187 const StorageUnit& monty_curve_b() const { return m_monty_curve_b; }
188
189 const StorageUnit& base_x() const { return m_base_x; }
190
191 const StorageUnit& base_y() const { return m_base_y; }
192
193 bool a_is_minus_3() const { return m_a_is_minus_3; }
194
195 bool a_is_zero() const { return m_a_is_zero; }
196
197 bool order_is_less_than_field() const { return m_order_is_lt_field; }
198
199 void mul(std::array<word, 2 * N>& z, const std::array<word, N>& x, const std::array<word, N>& y) const {
200 clear_mem(z);
201
202 if(m_words == 4) {
203 bigint_comba_mul4(z.data(), x.data(), y.data());
204 } else if(m_words == 6) {
205 bigint_comba_mul6(z.data(), x.data(), y.data());
206 } else if(m_words == 8) {
207 bigint_comba_mul8(z.data(), x.data(), y.data());
208 } else if(m_words == 9) {
209 bigint_comba_mul9(z.data(), x.data(), y.data());
210 } else {
211 bigint_mul(z.data(), z.size(), x.data(), m_words, m_words, y.data(), m_words, m_words, nullptr, 0);
212 }
213 }
214
215 void sqr(std::array<word, 2 * N>& z, const std::array<word, N>& x) const {
216 clear_mem(z);
217
218 if(m_words == 4) {
219 bigint_comba_sqr4(z.data(), x.data());
220 } else if(m_words == 6) {
221 bigint_comba_sqr6(z.data(), x.data());
222 } else if(m_words == 8) {
223 bigint_comba_sqr8(z.data(), x.data());
224 } else if(m_words == 9) {
225 bigint_comba_sqr9(z.data(), x.data());
226 } else {
227 bigint_sqr(z.data(), z.size(), x.data(), m_words, m_words, nullptr, 0);
228 }
229 }
230
231 private:
232 static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed(const BigInt& n) {
233 const size_t n_words = n.sig_words();
235
236 std::array<word, PrimeOrderCurve::StorageWords> r{};
237 copy_mem(std::span{r}.first(n_words), n._as_span().first(n_words));
238 return r;
239 }
240
241 static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed_rev(const BigInt& n) {
242 auto v = bn_to_fixed(n);
243 std::reverse(v.begin(), v.end());
244 return v;
245 }
246
247 private:
248 size_t m_words;
249 size_t m_order_bits;
250 size_t m_order_bytes;
251 size_t m_field_bits;
252 size_t m_field_bytes;
253
254 Montgomery_Params m_monty_order;
255 Montgomery_Params m_monty_field;
256
257 StorageUnit m_field;
258 StorageUnit m_field_minus_2;
259 StorageUnit m_field_monty_r1;
260 StorageUnit m_field_monty_r2;
261 StorageUnit m_field_p_plus_1_over_4;
262 StorageUnit m_field_inv_2;
263 word m_field_p_dash;
264
265 StorageUnit m_order;
266 StorageUnit m_order_minus_2;
267 StorageUnit m_order_monty_r1;
268 StorageUnit m_order_monty_r2;
269 StorageUnit m_order_monty_r3;
270 StorageUnit m_order_inv_2;
271 word m_order_p_dash;
272
273 StorageUnit m_monty_curve_a{};
274 StorageUnit m_monty_curve_b{};
275
276 StorageUnit m_base_x{};
277 StorageUnit m_base_y{};
278
279 bool m_a_is_minus_3;
280 bool m_a_is_zero;
281 bool m_order_is_lt_field;
282};
283
284class GenericScalar final {
285 public:
286 typedef word W;
287 typedef PrimeOrderCurve::StorageUnit StorageUnit;
288 static constexpr size_t N = PrimeOrderCurve::StorageWords;
289
290 static std::optional<GenericScalar> from_wide_bytes(const GenericPrimeOrderCurve* curve,
291 std::span<const uint8_t> bytes) {
292 const size_t mlen = curve->_params().order_bytes();
293
294 if(bytes.size() > 2 * mlen) {
295 return {};
296 }
297
298 std::array<uint8_t, 2 * sizeof(word) * N> padded_bytes{};
299 copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
300
301 auto words = bytes_to_words<2 * N>(std::span{padded_bytes});
302 if(words) {
303 auto in_rep = wide_to_rep(curve, words.value());
304 return GenericScalar(curve, in_rep);
305 } else {
306 return {};
307 }
308 }
309
310 static std::optional<GenericScalar> deserialize(const GenericPrimeOrderCurve* curve,
311 std::span<const uint8_t> bytes) {
312 const size_t len = curve->_params().order_bytes();
313
314 if(bytes.size() != len) {
315 return {};
316 }
317
318 const auto words = bytes_to_words<N>(bytes);
319
320 if(words) {
321 if(!bigint_ct_is_lt(words->data(), N, curve->_params().order().data(), N).as_bool()) {
322 return {};
323 }
324
325 // Safe because we checked above that words is an integer < P
326 return GenericScalar(curve, to_rep(curve, *words));
327 } else {
328 return {};
329 }
330 }
331
332 static GenericScalar zero(const GenericPrimeOrderCurve* curve) {
333 const StorageUnit zeros{};
334 return GenericScalar(curve, zeros);
335 }
336
337 static GenericScalar one(const GenericPrimeOrderCurve* curve) {
338 return GenericScalar(curve, curve->_params().order_monty_r1());
339 }
340
341 static GenericScalar random(const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
342 constexpr size_t MAX_ATTEMPTS = 1000;
343
344 const size_t bits = curve->_params().order_bits();
345
346 std::vector<uint8_t> buf(curve->_params().order_bytes());
347
348 for(size_t i = 0; i != MAX_ATTEMPTS; ++i) {
349 rng.randomize(buf);
350
351 // Zero off high bits that if set would certainly cause us
352 // to be out of range
353 if(bits % 8 != 0) {
354 const uint8_t mask = 0xFF >> (8 - (bits % 8));
355 buf[0] &= mask;
356 }
357
358 if(auto s = GenericScalar::deserialize(curve, buf)) {
359 if(s.value().is_nonzero().as_bool()) {
360 return s.value();
361 }
362 }
363 }
364
365 throw Internal_Error("Failed to generate random Scalar within bounded number of attempts");
366 }
367
368 friend GenericScalar operator+(const GenericScalar& a, const GenericScalar& b) {
369 const auto* curve = check_curve(a, b);
370 const size_t words = curve->_params().words();
371
372 StorageUnit t{};
373 const W carry = bigint_add3(t.data(), a.data(), words, b.data(), words);
374
375 StorageUnit r{};
376 bigint_monty_maybe_sub(words, r.data(), carry, t.data(), curve->_params().order().data());
377 return GenericScalar(curve, r);
378 }
379
380 friend GenericScalar operator-(const GenericScalar& a, const GenericScalar& b) { return a + b.negate(); }
381
382 friend GenericScalar operator*(const GenericScalar& a, const GenericScalar& b) {
383 const auto* curve = check_curve(a, b);
384
385 std::array<W, 2 * N> z; // NOLINT(*-member-init)
386 curve->_params().mul(z, a.value(), b.value());
387 return GenericScalar(curve, redc(curve, z));
388 }
389
390 GenericScalar& operator*=(const GenericScalar& other) {
391 const auto* curve = check_curve(*this, other);
392
393 std::array<W, 2 * N> z; // NOLINT(*-member-init)
394 curve->_params().mul(z, value(), other.value());
395 m_val = redc(curve, z);
396 return (*this);
397 }
398
399 GenericScalar square() const {
400 const auto* curve = this->m_curve;
401
402 std::array<W, 2 * N> z; // NOLINT(*-member-init)
403 curve->_params().sqr(z, value());
404 return GenericScalar(curve, redc(curve, z));
405 }
406
407 GenericScalar pow_vartime(const StorageUnit& exp) const {
408 auto one = GenericScalar::one(curve());
409 auto bits = curve()->_params().order_bits();
410 auto words = curve()->_params().words();
411 return impl_pow_vartime(*this, one, bits, std::span{exp}.last(words));
412 }
413
414 GenericScalar negate() const {
415 auto x_is_zero = CT::all_zeros(this->data(), N);
416
417 StorageUnit r;
418 bigint_sub3(r.data(), m_curve->_params().order().data(), N, this->data(), N);
419 x_is_zero.if_set_zero_out(r.data(), N);
420 return GenericScalar(m_curve, r);
421 }
422
423 GenericScalar invert() const { return pow_vartime(m_curve->_params().order_minus_2()); }
424
425 /**
426 * Helper for variable time BEEA
427 *
428 * Note this function assumes that its arguments are in the standard
429 * domain, not the Montgomery domain. invert_vartime converts its argument
430 * out of Montgomery, and then back to Montgomery when returning the result.
431 */
432 static void _invert_vartime_div2_helper(GenericScalar& a, GenericScalar& x) {
433 const auto& inv_2 = a.curve()->_params().order_inv_2();
434
435 // Conditional ok: this function is variable time
436 while((a.m_val[0] & 1) != 1) {
437 shift_right<1>(a.m_val);
438
439 const W borrow = shift_right<1>(x.m_val);
440
441 // Conditional ok: this function is variable time
442 if(borrow > 0) {
443 bigint_add2(x.m_val.data(), N, inv_2.data(), N);
444 }
445 }
446 }
447
448 /*
449 * See the comments on invert_vartime in pcurves_impl.h for background
450 */
451 GenericScalar invert_vartime() const {
452 if(this->is_zero().as_bool()) {
453 return (*this);
454 }
455
456 auto x = GenericScalar(m_curve, std::array<W, N>{1});
457 auto b = GenericScalar(m_curve, from_rep(m_curve, m_val));
458
459 // First loop iteration
460 GenericScalar::_invert_vartime_div2_helper(b, x);
461
462 auto a = b.negate();
463 // y += x but y is zero at the outset
464 auto y = x;
465
466 // First half of second loop iteration
467 GenericScalar::_invert_vartime_div2_helper(a, y);
468
469 for(;;) {
470 // Conditional ok: this function is variable time
471 if(a.m_val == b.m_val) {
472 // At this point it should be that a == b == 1
473 auto r = y.negate();
474
475 // Convert back to Montgomery
476 return GenericScalar(curve(), to_rep(curve(), r.m_val));
477 }
478
479 auto nx = x + y;
480
481 /*
482 * Otherwise either b > a or a > b
483 *
484 * If b > a we want to set b to b - a
485 * Otherwise we want to set a to a - b
486 *
487 * Compute r = b - a and check if it underflowed
488 * If it did not then we are in the b > a path
489 */
490 std::array<W, N> r{};
491 const word carry = bigint_sub3(r.data(), b.data(), N, a.data(), N);
492
493 // Conditional ok: this function is variable time
494 if(carry == 0) {
495 // b > a
496 b.m_val = r;
497 x = nx;
498 GenericScalar::_invert_vartime_div2_helper(b, x);
499 } else {
500 // We know this can't underflow because a > b
501 bigint_sub3(r.data(), a.data(), N, b.data(), N);
502 a.m_val = r;
503 y = nx;
504 GenericScalar::_invert_vartime_div2_helper(a, y);
505 }
506 }
507 }
508
509 template <concepts::resizable_byte_buffer T>
510 T serialize() const {
511 T bytes(m_curve->_params().order_bytes());
512 this->serialize_to(bytes);
513 return bytes;
514 }
515
516 void serialize_to(std::span<uint8_t> bytes) const {
517 auto v = from_rep(m_curve, m_val);
518 std::reverse(v.begin(), v.end());
519
520 const size_t flen = m_curve->_params().order_bytes();
521 BOTAN_ARG_CHECK(bytes.size() == flen, "Expected output span provided");
522
523 // Remove leading zero bytes
524 const auto padded_bytes = store_be(v);
525 const size_t extra = N * WordInfo<W>::bytes - flen;
526 copy_mem(bytes, std::span{padded_bytes}.subspan(extra, flen));
527 }
528
529 CT::Choice is_zero() const { return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
530
531 CT::Choice is_nonzero() const { return !is_zero(); }
532
533 CT::Choice operator==(const GenericScalar& other) const {
534 if(this->m_curve != other.m_curve) {
535 return CT::Choice::no();
536 }
537
538 return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
539 }
540
541 /**
542 * Convert the integer to standard representation and return the sequence of words
543 */
544 StorageUnit to_words() const { return from_rep(m_curve, m_val); }
545
546 const StorageUnit& stash_value() const { return m_val; }
547
548 const GenericPrimeOrderCurve* curve() const { return m_curve; }
549
550 GenericScalar(const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
551
552 private:
553 const StorageUnit& value() const { return m_val; }
554
555 const W* data() const { return m_val.data(); }
556
557 static const GenericPrimeOrderCurve* check_curve(const GenericScalar& a, const GenericScalar& b) {
558 BOTAN_STATE_CHECK(a.m_curve == b.m_curve);
559 return a.m_curve;
560 }
561
562 static StorageUnit redc(const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> z) {
563 const auto& mod = curve->_params().order();
564 const size_t words = curve->_params().words();
565 StorageUnit r{};
566 StorageUnit ws{};
568 r.data(), z.data(), mod.data(), words, curve->_params().order_p_dash(), ws.data(), ws.size());
569 return r;
570 }
571
572 static StorageUnit from_rep(const GenericPrimeOrderCurve* curve, StorageUnit z) {
573 std::array<W, 2 * N> ze{};
574 copy_mem(std::span{ze}.template first<N>(), z);
575 return redc(curve, ze);
576 }
577
578 static StorageUnit to_rep(const GenericPrimeOrderCurve* curve, StorageUnit x) {
579 std::array<W, 2 * N> z; // NOLINT(*-member-init)
580 curve->_params().mul(z, x, curve->_params().order_monty_r2());
581 return redc(curve, z);
582 }
583
584 static StorageUnit wide_to_rep(const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> x) {
585 auto redc_x = redc(curve, x);
586 std::array<W, 2 * N> z; // NOLINT(*-member-init)
587 curve->_params().mul(z, redc_x, curve->_params().order_monty_r3());
588 return redc(curve, z);
589 }
590
591 const GenericPrimeOrderCurve* m_curve;
592 StorageUnit m_val;
593};
594
595namespace {
596
597class GenericField final {
598 public:
599 typedef word W;
600 typedef PrimeOrderCurve::StorageUnit StorageUnit;
601 static constexpr size_t N = PrimeOrderCurve::StorageWords;
602
603 static std::optional<GenericField> deserialize(const GenericPrimeOrderCurve* curve,
604 std::span<const uint8_t> bytes) {
605 const size_t len = curve->_params().field_bytes();
606
607 if(bytes.size() != len) {
608 return {};
609 }
610
611 const auto words = bytes_to_words<N>(bytes);
612
613 if(words) {
614 if(!bigint_ct_is_lt(words->data(), N, curve->_params().field().data(), N).as_bool()) {
615 return {};
616 }
617
618 // Safe because we checked above that words is an integer < P
619 return GenericField::from_words(curve, *words);
620 } else {
621 return {};
622 }
623 }
624
625 static GenericField from_words(const GenericPrimeOrderCurve* curve, const std::array<word, N>& words) {
626 return GenericField(curve, to_rep(curve, words));
627 }
628
629 static GenericField zero(const GenericPrimeOrderCurve* curve) {
630 const StorageUnit zeros{};
631 return GenericField(curve, zeros);
632 }
633
634 static GenericField one(const GenericPrimeOrderCurve* curve) {
635 return GenericField(curve, curve->_params().field_monty_r1());
636 }
637
638 static GenericField curve_a(const GenericPrimeOrderCurve* curve) {
639 return GenericField(curve, curve->_params().monty_curve_a());
640 }
641
642 static GenericField curve_b(const GenericPrimeOrderCurve* curve) {
643 return GenericField(curve, curve->_params().monty_curve_b());
644 }
645
646 static GenericField random(const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
647 constexpr size_t MAX_ATTEMPTS = 1000;
648
649 const size_t bits = curve->_params().field_bits();
650
651 std::vector<uint8_t> buf(curve->_params().field_bytes());
652
653 for(size_t i = 0; i != MAX_ATTEMPTS; ++i) {
654 rng.randomize(buf);
655
656 // Zero off high bits that if set would certainly cause us
657 // to be out of range
658 if(bits % 8 != 0) {
659 const uint8_t mask = 0xFF >> (8 - (bits % 8));
660 buf[0] &= mask;
661 }
662
663 if(auto s = GenericField::deserialize(curve, buf)) {
664 if(s.value().is_nonzero().as_bool()) {
665 return s.value();
666 }
667 }
668 }
669
670 throw Internal_Error("Failed to generate random Scalar within bounded number of attempts");
671 }
672
673 /**
674 * Return the value of this divided by 2
675 */
676 GenericField div2() const {
677 StorageUnit t = value();
678 const W borrow = shift_right<1>(t);
679
680 // If value was odd, add (P/2)+1
681 bigint_cnd_add(borrow, t.data(), m_curve->_params().field_inv_2().data(), N);
682
683 return GenericField(m_curve, t);
684 }
685
686 /// Return (*this) multiplied by 2
687 GenericField mul2() const {
688 StorageUnit t = value();
689 const W carry = shift_left<1>(t);
690
691 StorageUnit r;
692 bigint_monty_maybe_sub<N>(r.data(), carry, t.data(), m_curve->_params().field().data());
693 return GenericField(m_curve, r);
694 }
695
696 /// Return (*this) multiplied by 3
697 GenericField mul3() const { return mul2() + (*this); }
698
699 /// Return (*this) multiplied by 4
700 GenericField mul4() const { return mul2().mul2(); }
701
702 /// Return (*this) multiplied by 8
703 GenericField mul8() const { return mul2().mul2().mul2(); }
704
705 friend GenericField operator+(const GenericField& a, const GenericField& b) {
706 const auto* curve = check_curve(a, b);
707 const size_t words = curve->_params().words();
708
709 StorageUnit t{};
710 const W carry = bigint_add3(t.data(), a.data(), words, b.data(), words);
711
712 StorageUnit r{};
713 bigint_monty_maybe_sub(words, r.data(), carry, t.data(), curve->_params().field().data());
714 return GenericField(curve, r);
715 }
716
717 friend GenericField operator-(const GenericField& a, const GenericField& b) { return a + b.negate(); }
718
719 friend GenericField operator*(const GenericField& a, const GenericField& b) {
720 const auto* curve = check_curve(a, b);
721
722 std::array<W, 2 * N> z; // NOLINT(*-member-init)
723 curve->_params().mul(z, a.value(), b.value());
724 return GenericField(curve, redc(curve, z));
725 }
726
727 GenericField& operator*=(const GenericField& other) {
728 const auto* curve = check_curve(*this, other);
729
730 std::array<W, 2 * N> z; // NOLINT(*-member-init)
731 curve->_params().mul(z, value(), other.value());
732 m_val = redc(curve, z);
733 return (*this);
734 }
735
736 GenericField square() const {
737 std::array<W, 2 * N> z; // NOLINT(*-member-init)
738 m_curve->_params().sqr(z, value());
739 return GenericField(m_curve, redc(m_curve, z));
740 }
741
742 GenericField pow_vartime(const StorageUnit& exp) const {
743 auto one = GenericField::one(curve());
744 auto bits = curve()->_params().field_bits();
745 auto words = curve()->_params().words();
746 return impl_pow_vartime(*this, one, bits, std::span{exp}.last(words));
747 }
748
749 GenericField negate() const {
750 auto x_is_zero = CT::all_zeros(this->data(), N);
751
752 StorageUnit r;
753 bigint_sub3(r.data(), m_curve->_params().field().data(), N, this->data(), N);
754 x_is_zero.if_set_zero_out(r.data(), N);
755 return GenericField(m_curve, r);
756 }
757
758 GenericField invert() const { return pow_vartime(m_curve->_params().field_minus_2()); }
759
760 GenericField invert_vartime() const {
761 // TODO take advantage of variable time here using eg BEEA
762 // see IntMod::invert_vartime in pcurves_impl.h
763 return invert();
764 }
765
766 template <concepts::resizable_byte_buffer T>
767 T serialize() const {
768 T bytes(m_curve->_params().field_bytes());
769 serialize_to(bytes);
770 return bytes;
771 }
772
773 void serialize_to(std::span<uint8_t> bytes) const {
774 auto v = from_rep(m_curve, m_val);
775 std::reverse(v.begin(), v.end());
776
777 const size_t flen = m_curve->_params().field_bytes();
778 BOTAN_ARG_CHECK(bytes.size() == flen, "Expected output span provided");
779
780 // Remove leading zero bytes
781 const auto padded_bytes = store_be(v);
782 const size_t extra = N * WordInfo<W>::bytes - flen;
783 copy_mem(bytes, std::span{padded_bytes}.subspan(extra, flen));
784 }
785
786 CT::Choice is_zero() const { return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
787
788 CT::Choice is_nonzero() const { return !is_zero(); }
789
790 CT::Choice operator==(const GenericField& other) const {
791 if(this->m_curve != other.m_curve) {
792 return CT::Choice::no();
793 }
794
795 return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
796 }
797
798 const StorageUnit& stash_value() const { return m_val; }
799
800 const GenericPrimeOrderCurve* curve() const { return m_curve; }
801
802 CT::Choice is_even() const {
803 auto v = from_rep(m_curve, m_val);
804 return !CT::Choice::from_int(v[0] & 0x01);
805 }
806
807 /**
808 * Convert the integer to standard representation and return the sequence of words
809 */
810 StorageUnit to_words() const { return from_rep(m_curve, m_val); }
811
812 void _const_time_poison() const { CT::poison(m_val); }
813
814 void _const_time_unpoison() const { CT::unpoison(m_val); }
815
816 static void conditional_swap(CT::Choice cond, GenericField& x, GenericField& y) {
817 const W mask = cond.into_bitmask<W>();
818
819 for(size_t i = 0; i != N; ++i) {
820 auto nx = choose(mask, y.m_val[i], x.m_val[i]);
821 auto ny = choose(mask, x.m_val[i], y.m_val[i]);
822 x.m_val[i] = nx;
823 y.m_val[i] = ny;
824 }
825 }
826
827 void conditional_assign(CT::Choice cond, const GenericField& nx) {
828 const W mask = cond.into_bitmask<W>();
829
830 for(size_t i = 0; i != N; ++i) {
831 m_val[i] = choose(mask, nx.m_val[i], m_val[i]);
832 }
833 }
834
835 /**
836 * Conditional assignment
837 *
838 * If `cond` is true, sets `x` to `nx` and `y` to `ny`
839 */
840 static void conditional_assign(
841 GenericField& x, GenericField& y, CT::Choice cond, const GenericField& nx, const GenericField& ny) {
842 const W mask = cond.into_bitmask<W>();
843
844 for(size_t i = 0; i != N; ++i) {
845 x.m_val[i] = choose(mask, nx.m_val[i], x.m_val[i]);
846 y.m_val[i] = choose(mask, ny.m_val[i], y.m_val[i]);
847 }
848 }
849
850 /**
851 * Conditional assignment
852 *
853 * If `cond` is true, sets `x` to `nx`, `y` to `ny`, and `z` to `nz`
854 */
855 static void conditional_assign(GenericField& x,
856 GenericField& y,
857 GenericField& z,
858 CT::Choice cond,
859 const GenericField& nx,
860 const GenericField& ny,
861 const GenericField& nz) {
862 const W mask = cond.into_bitmask<W>();
863
864 for(size_t i = 0; i != N; ++i) {
865 x.m_val[i] = choose(mask, nx.m_val[i], x.m_val[i]);
866 y.m_val[i] = choose(mask, ny.m_val[i], y.m_val[i]);
867 z.m_val[i] = choose(mask, nz.m_val[i], z.m_val[i]);
868 }
869 }
870
871 std::pair<GenericField, CT::Choice> sqrt() const {
872 BOTAN_STATE_CHECK(m_curve->_params().field()[0] % 4 == 3);
873
874 auto z = pow_vartime(m_curve->_params().field_p_plus_1_over_4());
875 const CT::Choice correct = (z.square() == *this);
876 // Zero out the return value if it would otherwise be incorrect
877 z.conditional_assign(!correct, zero(m_curve));
878 return {z, correct};
879 }
880
881 GenericField(const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
882
883 private:
884 const StorageUnit& value() const { return m_val; }
885
886 const W* data() const { return m_val.data(); }
887
888 static const GenericPrimeOrderCurve* check_curve(const GenericField& a, const GenericField& b) {
889 BOTAN_STATE_CHECK(a.m_curve == b.m_curve);
890 return a.m_curve;
891 }
892
893 static StorageUnit redc(const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> z) {
894 const auto& mod = curve->_params().field();
895 const size_t words = curve->_params().words();
896 StorageUnit r{};
897 StorageUnit ws{};
899 r.data(), z.data(), mod.data(), words, curve->_params().field_p_dash(), ws.data(), ws.size());
900 return r;
901 }
902
903 static StorageUnit from_rep(const GenericPrimeOrderCurve* curve, StorageUnit z) {
904 std::array<W, 2 * N> ze{};
905 copy_mem(std::span{ze}.template first<N>(), z);
906 return redc(curve, ze);
907 }
908
909 static StorageUnit to_rep(const GenericPrimeOrderCurve* curve, StorageUnit x) {
910 std::array<W, 2 * N> z{};
911 curve->_params().mul(z, x, curve->_params().field_monty_r2());
912 return redc(curve, z);
913 }
914
915 const GenericPrimeOrderCurve* m_curve;
916 StorageUnit m_val;
917};
918
919} // namespace
920
921/**
922* Affine Curve Point
923*
924* This contains a pair of integers (x,y) which satisfy the curve equation
925*/
926class GenericAffinePoint final {
927 public:
928 GenericAffinePoint(const GenericField& x, const GenericField& y) : m_x(x), m_y(y) {}
929
930 explicit GenericAffinePoint(const GenericPrimeOrderCurve* curve) :
931 m_x(GenericField::zero(curve)), m_y(GenericField::zero(curve)) {}
932
933 static GenericAffinePoint identity(const GenericPrimeOrderCurve* curve) {
934 return GenericAffinePoint(GenericField::zero(curve), GenericField::zero(curve));
935 }
936
937 static GenericAffinePoint identity(const GenericAffinePoint& pt) { return identity(pt.curve()); }
938
939 CT::Choice is_identity() const { return x().is_zero() && y().is_zero(); }
940
941 GenericAffinePoint negate() const { return GenericAffinePoint(x(), y().negate()); }
942
943 /**
944 * Serialize the point in uncompressed format
945 */
946 void serialize_to(std::span<uint8_t> bytes) const {
947 const size_t fe_bytes = curve()->_params().field_bytes();
948 BOTAN_ARG_CHECK(bytes.size() == 1 + 2 * fe_bytes, "Buffer size incorrect");
949 BOTAN_STATE_CHECK(this->is_identity().as_bool() == false);
950 BufferStuffer pack(bytes);
951 pack.append(0x04);
952 x().serialize_to(pack.next(fe_bytes));
953 y().serialize_to(pack.next(fe_bytes));
954 BOTAN_DEBUG_ASSERT(pack.full());
955 }
956
957 /**
958 * If idx is zero then return the identity element. Otherwise return pts[idx - 1]
959 *
960 * Returns the identity element also if idx is out of range
961 */
962 static auto ct_select(std::span<const GenericAffinePoint> pts, size_t idx) {
963 BOTAN_ARG_CHECK(!pts.empty(), "Cannot select from an empty set");
964 auto result = GenericAffinePoint::identity(pts[0].curve());
965
966 // Intentionally wrapping; set to maximum size_t if idx == 0
967 const size_t idx1 = static_cast<size_t>(idx - 1);
968 for(size_t i = 0; i != pts.size(); ++i) {
969 const auto found = CT::Mask<size_t>::is_equal(idx1, i).as_choice();
970 result.conditional_assign(found, pts[i]);
971 }
972
973 return result;
974 }
975
976 /**
977 * Return (x^3 + A*x + B) mod p
978 */
979 static GenericField x3_ax_b(const GenericField& x) {
980 return (x.square() + GenericField::curve_a(x.curve())) * x + GenericField::curve_b(x.curve());
981 }
982
983 /**
984 * Point deserialization
985 *
986 * This accepts compressed or uncompressed formats.
987 */
988 static std::optional<GenericAffinePoint> deserialize(const GenericPrimeOrderCurve* curve,
989 std::span<const uint8_t> bytes) {
990 const size_t fe_bytes = curve->_params().field_bytes();
991
992 if(bytes.size() == 1 + 2 * fe_bytes && bytes[0] == 0x04) {
993 auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes));
994 auto y = GenericField::deserialize(curve, bytes.subspan(1 + fe_bytes, fe_bytes));
995
996 if(x && y) {
997 const auto lhs = (*y).square();
998 const auto rhs = GenericAffinePoint::x3_ax_b(*x);
999 if((lhs == rhs).as_bool()) {
1000 return GenericAffinePoint(*x, *y);
1001 }
1002 }
1003 } else if(bytes.size() == 1 + fe_bytes && (bytes[0] == 0x02 || bytes[0] == 0x03)) {
1004 const CT::Choice y_is_even = CT::Mask<uint8_t>::is_equal(bytes[0], 0x02).as_choice();
1005
1006 if(auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes))) {
1007 auto [y, is_square] = x3_ax_b(*x).sqrt();
1008
1009 if(is_square.as_bool()) {
1010 const auto flip_y = y_is_even != y.is_even();
1011 y.conditional_assign(flip_y, y.negate());
1012 return GenericAffinePoint(*x, y);
1013 }
1014 }
1015 } else if(bytes.size() == 1 && bytes[0] == 0x00) {
1016 // See SEC1 section 2.3.4
1017 return GenericAffinePoint::identity(curve);
1018 }
1019
1020 return {};
1021 }
1022
1023 /**
1024 * Return the affine x coordinate
1025 */
1026 const GenericField& x() const { return m_x; }
1027
1028 /**
1029 * Return the affine y coordinate
1030 */
1031 const GenericField& y() const { return m_y; }
1032
1033 /**
1034 * Conditional assignment of an affine point
1035 */
1036 void conditional_assign(CT::Choice cond, const GenericAffinePoint& pt) {
1037 GenericField::conditional_assign(m_x, m_y, cond, pt.x(), pt.y());
1038 }
1039
1040 const GenericPrimeOrderCurve* curve() const { return m_x.curve(); }
1041
1042 void _const_time_poison() const { CT::poison_all(m_x, m_y); }
1043
1044 void _const_time_unpoison() const { CT::unpoison_all(m_x, m_y); }
1045
1046 private:
1047 GenericField m_x;
1048 GenericField m_y;
1049};
1050
1051class GenericProjectivePoint final {
1052 public:
1053 typedef GenericProjectivePoint Self;
1054
1055 using FieldElement = GenericField;
1056
1057 /**
1058 * Convert a point from affine to projective form
1059 */
1060 static Self from_affine(const GenericAffinePoint& pt) {
1061 auto x = pt.x();
1062 auto y = pt.y();
1063 auto z = GenericField::one(x.curve());
1064
1065 // If pt is identity (0,0) swap y/z to convert (0,0,1) into (0,1,0)
1066 GenericField::conditional_swap(pt.is_identity(), y, z);
1067 return GenericProjectivePoint(x, y, z);
1068 }
1069
1070 /**
1071 * Return the identity element
1072 */
1073 static Self identity(const GenericPrimeOrderCurve* curve) {
1074 return Self(GenericField::zero(curve), GenericField::one(curve), GenericField::zero(curve));
1075 }
1076
1077 /**
1078 * Default constructor: the identity element
1079 */
1080 explicit GenericProjectivePoint(const GenericPrimeOrderCurve* curve) :
1081 m_x(GenericField::zero(curve)), m_y(GenericField::one(curve)), m_z(GenericField::zero(curve)) {}
1082
1083 /**
1084 * Affine constructor: take x/y coordinates
1085 */
1086 GenericProjectivePoint(const GenericField& x, const GenericField& y) :
1087 m_x(x), m_y(y), m_z(GenericField::one(m_x.curve())) {}
1088
1089 /**
1090 * Projective constructor: take x/y/z coordinates
1091 */
1092 GenericProjectivePoint(const GenericField& x, const GenericField& y, const GenericField& z) :
1093 m_x(x), m_y(y), m_z(z) {}
1094
1095 friend Self operator+(const Self& a, const Self& b) { return Self::add(a, b); }
1096
1097 friend Self operator+(const Self& a, const GenericAffinePoint& b) { return Self::add_mixed(a, b); }
1098
1099 friend Self operator+(const GenericAffinePoint& a, const Self& b) { return Self::add_mixed(b, a); }
1100
1101 Self& operator+=(const Self& other) {
1102 (*this) = (*this) + other;
1103 return (*this);
1104 }
1105
1106 Self& operator+=(const GenericAffinePoint& other) {
1107 (*this) = (*this) + other;
1108 return (*this);
1109 }
1110
1111 CT::Choice is_identity() const { return z().is_zero(); }
1112
1113 void conditional_assign(CT::Choice cond, const Self& pt) {
1114 GenericField::conditional_assign(m_x, m_y, m_z, cond, pt.x(), pt.y(), pt.z());
1115 }
1116
1117 /**
1118 * Mixed (projective + affine) point addition
1119 */
1120 static Self add_mixed(const Self& a, const GenericAffinePoint& b) {
1121 return point_add_mixed<Self, GenericAffinePoint, GenericField>(a, b, GenericField::one(a.curve()));
1122 }
1123
1124 static Self add_or_sub(const Self& a, const GenericAffinePoint& b, CT::Choice sub) {
1125 return point_add_or_sub_mixed<Self, GenericAffinePoint, GenericField>(a, b, sub, GenericField::one(a.curve()));
1126 }
1127
1128 /**
1129 * Projective point addition
1130 */
1131 static Self add(const Self& a, const Self& b) { return point_add<Self, GenericField>(a, b); }
1132
1133 /**
1134 * Iterated point doubling
1135 */
1136 Self dbl_n(size_t n) const {
1137 if(curve()->_params().a_is_minus_3()) {
1138 return dbl_n_a_minus_3(*this, n);
1139 } else if(curve()->_params().a_is_zero()) {
1140 return dbl_n_a_zero(*this, n);
1141 } else {
1142 const auto A = GenericField::curve_a(curve());
1143 return dbl_n_generic(*this, A, n);
1144 }
1145 }
1146
1147 /**
1148 * Point doubling
1149 */
1150 Self dbl() const {
1151 if(curve()->_params().a_is_minus_3()) {
1152 return dbl_a_minus_3(*this);
1153 } else if(curve()->_params().a_is_zero()) {
1154 return dbl_a_zero(*this);
1155 } else {
1156 const auto A = GenericField::curve_a(curve());
1157 return dbl_generic(*this, A);
1158 }
1159 }
1160
1161 /**
1162 * Point negation
1163 */
1164 Self negate() const { return Self(x(), y().negate(), z()); }
1165
1166 /**
1167 * Randomize the point representation
1168 *
1169 * Projective coordinates are redundant; if (x,y,z) is a projective
1170 * point then so is (x*r^2,y*r^3,z*r) for any non-zero r.
1171 */
1172 void randomize_rep(RandomNumberGenerator& rng) {
1173 // In certain contexts we may be called with a Null_RNG; in that case the
1174 // caller is accepting that randomization will not occur
1175
1176 if(rng.is_seeded()) {
1177 auto r = GenericField::random(curve(), rng);
1178
1179 auto r2 = r.square();
1180 auto r3 = r2 * r;
1181
1182 m_x *= r2;
1183 m_y *= r3;
1184 m_z *= r;
1185 }
1186 }
1187
1188 /**
1189 * Return the projective x coordinate
1190 */
1191 const GenericField& x() const { return m_x; }
1192
1193 /**
1194 * Return the projective y coordinate
1195 */
1196 const GenericField& y() const { return m_y; }
1197
1198 /**
1199 * Return the projective z coordinate
1200 */
1201 const GenericField& z() const { return m_z; }
1202
1203 const GenericPrimeOrderCurve* curve() const { return m_x.curve(); }
1204
1205 void _const_time_poison() const { CT::poison_all(m_x, m_y, m_z); }
1206
1207 void _const_time_unpoison() const { CT::unpoison_all(m_x, m_y, m_z); }
1208
1209 private:
1210 GenericField m_x;
1211 GenericField m_y;
1212 GenericField m_z;
1213};
1214
1215namespace {
1216
1217class GenericCurve final {
1218 public:
1219 typedef GenericField FieldElement;
1220 typedef GenericScalar Scalar;
1221 typedef GenericAffinePoint AffinePoint;
1222 typedef GenericProjectivePoint ProjectivePoint;
1223
1224 typedef word WordType;
1225};
1226
1227class GenericBlindedScalarBits final {
1228 public:
1229 GenericBlindedScalarBits(const GenericScalar& scalar, RandomNumberGenerator& rng, size_t wb) {
1230 BOTAN_ASSERT_NOMSG(wb == 1 || wb == 2 || wb == 3 || wb == 4 || wb == 5 || wb == 6 || wb == 7);
1231
1232 const auto& params = scalar.curve()->_params();
1233
1234 const size_t order_bits = params.order_bits();
1235 m_window_bits = wb;
1236
1237 const size_t blinder_bits = scalar_blinding_bits(order_bits);
1238
1239 if(blinder_bits > 0 && rng.is_seeded()) {
1240 const size_t mask_words = (blinder_bits + WordInfo<word>::bits - 1) / WordInfo<word>::bits;
1241 const size_t mask_bytes = mask_words * WordInfo<word>::bytes;
1242
1243 const size_t words = params.words();
1244
1245 secure_vector<uint8_t> maskb(mask_bytes);
1246 rng.randomize(maskb);
1247
1248 std::array<word, PrimeOrderCurve::StorageWords> mask{};
1249 load_le(mask.data(), maskb.data(), mask_words);
1250
1251 // Mask to exactly blinder_bits and set MSB and LSB
1252 const size_t excess = mask_words * WordInfo<word>::bits - blinder_bits;
1253 if(excess > 0) {
1254 mask[mask_words - 1] &= (static_cast<word>(1) << (WordInfo<word>::bits - excess)) - 1;
1255 }
1256 const size_t msb_pos = (blinder_bits - 1) % WordInfo<word>::bits;
1257 mask[(blinder_bits - 1) / WordInfo<word>::bits] |= static_cast<word>(1) << msb_pos;
1258 mask[0] |= 1;
1259
1260 std::array<word, 2 * PrimeOrderCurve::StorageWords> mask_n{};
1261
1262 const auto sw = scalar.to_words();
1263
1264 // Compute masked scalar s + k*n
1265 params.mul(mask_n, mask, params.order());
1266 bigint_add2(mask_n.data(), 2 * words, sw.data(), words);
1267
1268 std::reverse(mask_n.begin(), mask_n.end());
1269 m_bytes = store_be<std::vector<uint8_t>>(mask_n);
1270 m_bits = order_bits + blinder_bits;
1271 } else {
1272 // No RNG available, skip blinding
1273 m_bytes = scalar.serialize<std::vector<uint8_t>>();
1274 m_bits = order_bits;
1275 }
1276
1277 m_windows = (m_bits + wb - 1) / wb;
1278 }
1279
1280 size_t windows() const { return m_windows; }
1281
1282 size_t bits() const { return m_bits; }
1283
1284 size_t get_window(size_t offset) const {
1285 if(m_window_bits == 1) {
1286 return read_window_bits<1>(std::span{m_bytes}, offset);
1287 } else if(m_window_bits == 2) {
1288 return read_window_bits<2>(std::span{m_bytes}, offset);
1289 } else if(m_window_bits == 3) {
1290 return read_window_bits<3>(std::span{m_bytes}, offset);
1291 } else if(m_window_bits == 4) {
1292 return read_window_bits<4>(std::span{m_bytes}, offset);
1293 } else if(m_window_bits == 5) {
1294 return read_window_bits<5>(std::span{m_bytes}, offset);
1295 } else if(m_window_bits == 6) {
1296 return read_window_bits<6>(std::span{m_bytes}, offset);
1297 } else if(m_window_bits == 7) {
1298 return read_window_bits<7>(std::span{m_bytes}, offset);
1299 } else {
1301 }
1302 }
1303
1304 private:
1305 std::vector<uint8_t> m_bytes;
1306 size_t m_bits;
1307 size_t m_windows;
1308 size_t m_window_bits;
1309};
1310
1311class GenericWindowedMul final {
1312 public:
1313 static constexpr size_t WindowBits = VarPointWindowBits;
1314 static constexpr size_t TableSize = (1 << WindowBits) - 1;
1315
1316 explicit GenericWindowedMul(const GenericAffinePoint& pt) :
1317 m_table(varpoint_setup<GenericCurve, TableSize>(pt)) {}
1318
1319 GenericProjectivePoint mul(const GenericScalar& s, RandomNumberGenerator& rng) {
1320 const GenericBlindedScalarBits bits(s, rng, WindowBits);
1321
1322 return varpoint_exec<GenericCurve, WindowBits>(m_table, bits, rng);
1323 }
1324
1325 private:
1326 AffinePointTable<GenericCurve> m_table;
1327};
1328
1329} // namespace
1330
1331class GenericBaseMulTable final {
1332 public:
1333 static constexpr size_t WindowBits = BasePointWindowBits;
1334
1335 // +1 for Booth carry from the top window
1336 explicit GenericBaseMulTable(const GenericAffinePoint& pt) :
1337 m_table(basemul_booth_setup<GenericCurve, WindowBits>(pt, blinded_scalar_bits(*pt.curve()) + 1)) {}
1338
1339 GenericProjectivePoint mul(const GenericScalar& s, RandomNumberGenerator& rng) {
1340 // W+1 bit windows for Booth recoding overlap
1341 const GenericBlindedScalarBits scalar(s, rng, WindowBits + 1);
1342 return basemul_booth_exec<GenericCurve, WindowBits>(m_table, scalar, rng);
1343 }
1344
1345 private:
1346 static size_t blinded_scalar_bits(const GenericPrimeOrderCurve& curve) {
1347 const size_t order_bits = curve.order_bits();
1348 return order_bits + scalar_blinding_bits(order_bits);
1349 }
1350
1351 std::vector<GenericAffinePoint> m_table;
1352};
1353
1354namespace {
1355
1356class GenericWindowedMul2 final {
1357 public:
1358 static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1359
1360 GenericWindowedMul2(const GenericWindowedMul2& other) = delete;
1361 GenericWindowedMul2(GenericWindowedMul2&& other) = delete;
1362 GenericWindowedMul2& operator=(const GenericWindowedMul2& other) = delete;
1363 GenericWindowedMul2& operator=(GenericWindowedMul2&& other) = delete;
1364
1365 ~GenericWindowedMul2() = default;
1366
1367 GenericWindowedMul2(const GenericAffinePoint& p, const GenericAffinePoint& q) :
1368 m_table(mul2_setup<GenericCurve, WindowBits>(p, q)) {}
1369
1370 GenericProjectivePoint mul2(const GenericScalar& x, const GenericScalar& y, RandomNumberGenerator& rng) const {
1371 const GenericBlindedScalarBits x_bits(x, rng, WindowBits);
1372 const GenericBlindedScalarBits y_bits(y, rng, WindowBits);
1373 return mul2_exec<GenericCurve, WindowBits>(m_table, x_bits, y_bits, rng);
1374 }
1375
1376 private:
1377 AffinePointTable<GenericCurve> m_table;
1378};
1379
1380class GenericVartimeWindowedMul2 final : public PrimeOrderCurve::PrecomputedMul2Table {
1381 public:
1382 static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1383
1384 GenericVartimeWindowedMul2(const GenericVartimeWindowedMul2& other) = delete;
1385 GenericVartimeWindowedMul2(GenericVartimeWindowedMul2&& other) = delete;
1386 GenericVartimeWindowedMul2& operator=(const GenericVartimeWindowedMul2& other) = delete;
1387 GenericVartimeWindowedMul2& operator=(GenericVartimeWindowedMul2&& other) = delete;
1388
1389 ~GenericVartimeWindowedMul2() override = default;
1390
1391 GenericVartimeWindowedMul2(const GenericAffinePoint& p, const GenericAffinePoint& q) :
1392 m_table(to_affine_batch<GenericCurve, true>(mul2_setup<GenericCurve, WindowBits>(p, q))) {}
1393
1394 GenericProjectivePoint mul2_vartime(const GenericScalar& x, const GenericScalar& y) const {
1395 const auto x_bits = x.serialize<std::vector<uint8_t>>();
1396 const auto y_bits = y.serialize<std::vector<uint8_t>>();
1397
1398 const auto& curve = m_table[0].curve();
1399 auto accum = GenericProjectivePoint(curve);
1400
1401 const size_t order_bits = curve->order_bits();
1402
1403 const size_t windows = (order_bits + WindowBits - 1) / WindowBits;
1404
1405 for(size_t i = 0; i != windows; ++i) {
1406 auto x_i = read_window_bits<WindowBits>(std::span{x_bits}, (windows - i - 1) * WindowBits);
1407 auto y_i = read_window_bits<WindowBits>(std::span{y_bits}, (windows - i - 1) * WindowBits);
1408
1409 if(i > 0) {
1410 accum = accum.dbl_n(WindowBits);
1411 }
1412
1413 const size_t idx = (y_i << WindowBits) + x_i;
1414
1415 if(idx > 0) {
1416 accum += m_table[idx - 1];
1417 }
1418 }
1419
1420 return accum;
1421 }
1422
1423 private:
1424 std::vector<GenericAffinePoint> m_table;
1425};
1426
1427} // namespace
1428
1430 const BigInt& p, const BigInt& a, const BigInt& b, const BigInt& base_x, const BigInt& base_y, const BigInt& order) :
1431 m_params(std::make_unique<GenericCurveParams>(p, a, b, base_x, base_y, order)) {}
1432
1434 BOTAN_STATE_CHECK(m_basemul == nullptr);
1435 m_basemul = std::make_unique<GenericBaseMulTable>(from_stash(generator()));
1436}
1437
1439 return _params().order_bits();
1440}
1441
1443 return _params().order_bytes();
1444}
1445
1447 return _params().field_bytes();
1448}
1449
1451 RandomNumberGenerator& rng) const {
1452 BOTAN_STATE_CHECK(m_basemul != nullptr);
1453 return stash(m_basemul->mul(from_stash(scalar), rng));
1454}
1455
1457 RandomNumberGenerator& rng) const {
1458 BOTAN_STATE_CHECK(m_basemul != nullptr);
1459 auto pt_s = m_basemul->mul(from_stash(scalar), rng);
1460 const auto x_bytes = to_affine_x<GenericCurve>(pt_s).serialize<secure_vector<uint8_t>>();
1461 if(auto s = GenericScalar::from_wide_bytes(this, x_bytes)) {
1462 return stash(*s);
1463 } else {
1464 throw Internal_Error("Failed to convert x coordinate to integer modulo scalar");
1465 }
1466}
1467
1469 const Scalar& scalar,
1470 RandomNumberGenerator& rng) const {
1471 GenericWindowedMul pt_table(from_stash(pt));
1472 return stash(pt_table.mul(from_stash(scalar), rng));
1473}
1474
1476 const Scalar& scalar,
1477 RandomNumberGenerator& rng) const {
1478 GenericWindowedMul pt_table(from_stash(pt));
1479 auto pt_s = pt_table.mul(from_stash(scalar), rng);
1480 return to_affine_x<GenericCurve>(pt_s).serialize<secure_vector<uint8_t>>();
1481}
1482
1483std::unique_ptr<const PrimeOrderCurve::PrecomputedMul2Table> GenericPrimeOrderCurve::mul2_setup_g(
1484 const AffinePoint& q) const {
1485 return std::make_unique<GenericVartimeWindowedMul2>(from_stash(generator()), from_stash(q));
1486}
1487
1488std::optional<PrimeOrderCurve::ProjectivePoint> GenericPrimeOrderCurve::mul2_vartime(const PrecomputedMul2Table& tableb,
1489 const Scalar& s1,
1490 const Scalar& s2) const {
1491 const auto& tbl = dynamic_cast<const GenericVartimeWindowedMul2&>(tableb);
1492 auto pt = tbl.mul2_vartime(from_stash(s1), from_stash(s2));
1493 if(pt.is_identity().as_bool()) {
1494 return {};
1495 } else {
1496 return stash(pt);
1497 }
1498}
1499
1500std::optional<PrimeOrderCurve::ProjectivePoint> GenericPrimeOrderCurve::mul_px_qy(
1501 const AffinePoint& p, const Scalar& x, const AffinePoint& q, const Scalar& y, RandomNumberGenerator& rng) const {
1502 const GenericWindowedMul2 table(from_stash(p), from_stash(q));
1503 auto pt = table.mul2(from_stash(x), from_stash(y), rng);
1504 if(pt.is_identity().as_bool()) {
1505 return {};
1506 } else {
1507 return stash(pt);
1508 }
1509}
1510
1512 const Scalar& v,
1513 const Scalar& s1,
1514 const Scalar& s2) const {
1515 const auto& tbl = dynamic_cast<const GenericVartimeWindowedMul2&>(tableb);
1516 auto pt = tbl.mul2_vartime(from_stash(s1), from_stash(s2));
1517
1518 if(!pt.is_identity().as_bool()) {
1519 const auto z2 = pt.z().square();
1520
1521 const auto v_bytes = from_stash(v).serialize<std::vector<uint8_t>>();
1522
1523 if(auto fe_v = GenericField::deserialize(this, v_bytes)) {
1524 if((*fe_v * z2 == pt.x()).as_bool()) {
1525 return true;
1526 }
1527
1528 if(_params().order_is_less_than_field()) {
1529 const auto n = GenericField::from_words(this, _params().order());
1530 const auto neg_n = n.negate().to_words();
1531
1532 const auto vw = fe_v->to_words();
1533 if(bigint_ct_is_lt(vw.data(), vw.size(), neg_n.data(), neg_n.size()).as_bool()) {
1534 return (((*fe_v + n) * z2) == pt.x()).as_bool();
1535 }
1536 }
1537 }
1538 }
1539
1540 return false;
1541}
1542
1544 return PrimeOrderCurve::AffinePoint::_create(shared_from_this(), _params().base_x(), _params().base_y());
1545}
1546
1548 auto affine = to_affine<GenericCurve>(from_stash(pt));
1549
1550 const auto y2 = affine.y().square();
1551 const auto x3_ax_b = GenericCurve::AffinePoint::x3_ax_b(affine.x());
1552 const auto valid_point = affine.is_identity() || (y2 == x3_ax_b);
1553
1554 BOTAN_ASSERT(valid_point.as_bool(), "Computed point is on the curve");
1555
1556 return stash(affine);
1557}
1558
1560 return stash(GenericProjectivePoint::from_affine(from_stash(a)) + from_stash(b));
1561}
1562
1564 return stash(from_stash(pt).negate());
1565}
1566
1568 return from_stash(pt).is_identity().as_bool();
1569}
1570
1571void GenericPrimeOrderCurve::serialize_point(std::span<uint8_t> bytes, const AffinePoint& pt) const {
1572 from_stash(pt).serialize_to(bytes);
1573}
1574
1575void GenericPrimeOrderCurve::serialize_scalar(std::span<uint8_t> bytes, const Scalar& scalar) const {
1576 BOTAN_ARG_CHECK(bytes.size() == _params().order_bytes(), "Invalid length to serialize_scalar");
1577 from_stash(scalar).serialize_to(bytes);
1578}
1579
1580std::optional<PrimeOrderCurve::Scalar> GenericPrimeOrderCurve::deserialize_scalar(
1581 std::span<const uint8_t> bytes) const {
1582 if(auto s = GenericScalar::deserialize(this, bytes)) {
1583 return stash(s.value());
1584 } else {
1585 return {};
1586 }
1587}
1588
1589std::optional<PrimeOrderCurve::Scalar> GenericPrimeOrderCurve::scalar_from_wide_bytes(
1590 std::span<const uint8_t> bytes) const {
1591 if(auto s = GenericScalar::from_wide_bytes(this, bytes)) {
1592 return stash(s.value());
1593 } else {
1594 return {};
1595 }
1596}
1597
1598std::optional<PrimeOrderCurve::AffinePoint> GenericPrimeOrderCurve::deserialize_point(
1599 std::span<const uint8_t> bytes) const {
1600 if(auto pt = GenericAffinePoint::deserialize(this, bytes)) {
1601 return stash(pt.value());
1602 } else {
1603 return {};
1604 }
1605}
1606
1608 return stash(from_stash(a) + from_stash(b));
1609}
1610
1612 return stash(from_stash(a) - from_stash(b));
1613}
1614
1616 return stash(from_stash(a) * from_stash(b));
1617}
1618
1620 return stash(from_stash(s).square());
1621}
1622
1624 return stash(from_stash(s).invert());
1625}
1626
1628 return stash(from_stash(s).invert_vartime());
1629}
1630
1632 return stash(from_stash(s).negate());
1633}
1634
1636 return from_stash(s).is_zero().as_bool();
1637}
1638
1640 return (from_stash(a) == from_stash(b)).as_bool();
1641}
1642
1644 return stash(GenericScalar::one(this));
1645}
1646
1648 return stash(GenericScalar::random(this, rng));
1649}
1650
1651PrimeOrderCurve::Scalar GenericPrimeOrderCurve::stash(const GenericScalar& s) const {
1652 return Scalar::_create(shared_from_this(), s.stash_value());
1653}
1654
1655GenericScalar GenericPrimeOrderCurve::from_stash(const PrimeOrderCurve::Scalar& s) const {
1656 BOTAN_ARG_CHECK(s._curve().get() == this, "Curve mismatch");
1657 return GenericScalar(this, s._value());
1658}
1659
1660PrimeOrderCurve::AffinePoint GenericPrimeOrderCurve::stash(const GenericAffinePoint& pt) const {
1661 auto x_w = pt.x().stash_value();
1662 auto y_w = pt.y().stash_value();
1663 return AffinePoint::_create(shared_from_this(), x_w, y_w);
1664}
1665
1666GenericAffinePoint GenericPrimeOrderCurve::from_stash(const PrimeOrderCurve::AffinePoint& pt) const {
1667 BOTAN_ARG_CHECK(pt._curve().get() == this, "Curve mismatch");
1668 auto x = GenericField(this, pt._x());
1669 auto y = GenericField(this, pt._y());
1670 return GenericAffinePoint(x, y);
1671}
1672
1673PrimeOrderCurve::ProjectivePoint GenericPrimeOrderCurve::stash(const GenericProjectivePoint& pt) const {
1674 auto x_w = pt.x().stash_value();
1675 auto y_w = pt.y().stash_value();
1676 auto z_w = pt.z().stash_value();
1677 return ProjectivePoint::_create(shared_from_this(), x_w, y_w, z_w);
1678}
1679
1680GenericProjectivePoint GenericPrimeOrderCurve::from_stash(const PrimeOrderCurve::ProjectivePoint& pt) const {
1681 BOTAN_ARG_CHECK(pt._curve().get() == this, "Curve mismatch");
1682 auto x = GenericField(this, pt._x());
1683 auto y = GenericField(this, pt._y());
1684 auto z = GenericField(this, pt._z());
1685 return GenericProjectivePoint(x, y, z);
1686}
1687
1689 std::function<void(std::span<uint8_t>)> expand_message) const {
1690 BOTAN_UNUSED(expand_message);
1691 throw Not_Implemented("Hash to curve is not implemented for this curve");
1692}
1693
1695 std::function<void(std::span<uint8_t>)> expand_message) const {
1696 BOTAN_UNUSED(expand_message);
1697 throw Not_Implemented("Hash to curve is not implemented for this curve");
1698}
1699
1700std::shared_ptr<const PrimeOrderCurve> PCurveInstance::from_params(
1701 const BigInt& p, const BigInt& a, const BigInt& b, const BigInt& base_x, const BigInt& base_y, const BigInt& order) {
1702 // We don't check that p and order are prime here on the assumption this has
1703 // been checked already by EC_Group
1704
1705 BOTAN_ARG_CHECK(a >= 0 && a < p, "a is invalid");
1706 BOTAN_ARG_CHECK(b > 0 && b < p, "b is invalid");
1707 BOTAN_ARG_CHECK(base_x >= 0 && base_x < p, "base_x is invalid");
1708 BOTAN_ARG_CHECK(base_y >= 0 && base_y < p, "base_y is invalid");
1709
1710 const size_t p_bits = p.bits();
1711
1712 // Same size restrictions as EC_Group however here we do not require
1713 // exactly the primes for the 521 or 239 bit exceptions; this code
1714 // should work fine with any such prime and we are relying on the higher
1715 // levels to prevent creating such a group in the first place
1716 //
1717 // TODO(Botan4) increase the 128 here to 192 when the corresponding EC_Group constructor is changed
1718 //
1719 if(p_bits != 521 && p_bits != 239 && (p_bits < 128 || p_bits > 512 || p_bits % 32 != 0)) {
1720 return {};
1721 }
1722
1723 // We don't want to deal with Shanks-Tonelli in the generic case
1724 if(p % 4 != 3) {
1725 return {};
1726 }
1727
1728 // The bit length of the field and order being the same simplifies things
1729 if(p_bits != order.bits()) {
1730 return {};
1731 }
1732
1733 auto gpoc = std::make_shared<GenericPrimeOrderCurve>(p, a, b, base_x, base_y, order);
1734 /*
1735 The implementation of this needs to call shared_from_this which is not usable
1736 until after the constructor has completed, so we have to do a two-stage
1737 construction process. This is certainly not so clean but it is contained to
1738 this single file so seems tolerable.
1739
1740 Alternately we could lazily compute the base mul table but this brings in
1741 locking issues which seem a worse alternative overall.
1742 */
1743 gpoc->_precompute_base_mul();
1744 return gpoc;
1745}
1746
1747} // namespace Botan::PCurve
#define BOTAN_UNUSED
Definition assert.h:144
#define BOTAN_ASSERT_NOMSG(expr)
Definition assert.h:75
#define BOTAN_DEBUG_ASSERT(expr)
Definition assert.h:129
#define BOTAN_STATE_CHECK(expr)
Definition assert.h:49
#define BOTAN_ARG_CHECK(expr, msg)
Definition assert.h:33
#define BOTAN_ASSERT(expr, assertion_made)
Definition assert.h:62
#define BOTAN_ASSERT_UNREACHABLE()
Definition assert.h:163
size_t bits() const
Definition bigint.cpp:307
static constexpr Choice from_int(T v)
Definition ct_utils.h:268
static constexpr Choice no()
Definition ct_utils.h:307
static constexpr Mask< T > is_equal(T x, T y)
Definition ct_utils.h:442
Scalar random_scalar(RandomNumberGenerator &rng) const override
AffinePoint point_negate(const AffinePoint &pt) const override
bool mul2_vartime_x_mod_order_eq(const PrecomputedMul2Table &tableb, const Scalar &v, const Scalar &s1, const Scalar &s2) const override
ProjectivePoint mul_by_g(const Scalar &scalar, RandomNumberGenerator &rng) const override
std::optional< ProjectivePoint > mul_px_qy(const AffinePoint &p, const Scalar &x, const AffinePoint &q, const Scalar &y, RandomNumberGenerator &rng) const override
ProjectivePoint hash_to_curve_ro(std::function< void(std::span< uint8_t >)> expand_message) const override
void serialize_scalar(std::span< uint8_t > bytes, const Scalar &scalar) const override
Scalar scalar_square(const Scalar &s) const override
Scalar squaring.
std::optional< Scalar > deserialize_scalar(std::span< const uint8_t > bytes) const override
std::optional< Scalar > scalar_from_wide_bytes(std::span< const uint8_t > bytes) const override
std::unique_ptr< const PrecomputedMul2Table > mul2_setup_g(const AffinePoint &q) const override
Setup a table for 2-ary multiplication where the first point is the generator.
GenericPrimeOrderCurve(const BigInt &p, const BigInt &a, const BigInt &b, const BigInt &base_x, const BigInt &base_y, const BigInt &order)
AffinePoint generator() const override
Return the standard generator.
const GenericCurveParams & _params() const
AffinePoint hash_to_curve_nu(std::function< void(std::span< uint8_t >)> expand_message) const override
ProjectivePoint point_add(const AffinePoint &a, const AffinePoint &b) const override
Scalar scalar_mul(const Scalar &a, const Scalar &b) const override
Scalar multiplication.
Scalar scalar_invert(const Scalar &s) const override
Scalar inversion.
std::optional< AffinePoint > deserialize_point(std::span< const uint8_t > bytes) const override
std::optional< ProjectivePoint > mul2_vartime(const PrecomputedMul2Table &tableb, const Scalar &x, const Scalar &y) const override
void serialize_point(std::span< uint8_t > bytes, const AffinePoint &pt) const override
bool scalar_is_zero(const Scalar &s) const override
Test if scalar is zero.
Scalar scalar_negate(const Scalar &s) const override
Scalar negation.
secure_vector< uint8_t > mul_x_only(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const override
ProjectivePoint mul(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const override
Scalar base_point_mul_x_mod_order(const Scalar &scalar, RandomNumberGenerator &rng) const override
Scalar scalar_invert_vartime(const Scalar &s) const override
Scalar inversion (variable time).
bool affine_point_is_identity(const AffinePoint &pt) const override
size_t scalar_bytes() const override
Return the byte length of the scalar element.
Scalar scalar_sub(const Scalar &a, const Scalar &b) const override
Scalar subtraction.
AffinePoint point_to_affine(const ProjectivePoint &pt) const override
bool scalar_equal(const Scalar &a, const Scalar &b) const override
Test if two scalars are equal.
Scalar scalar_add(const Scalar &a, const Scalar &b) const override
Scalar addition.
size_t order_bits() const override
Return the bit length of the group order.
static AffinePoint _create(CurvePtr curve, StorageUnit x, StorageUnit y)
Definition pcurves.h:110
static constexpr size_t StorageWords
Number of words used to store MaximumByteLength.
Definition pcurves.h:42
std::array< word, StorageWords > StorageUnit
Definition pcurves.h:59
constexpr void pack(const Polynomial< PolyTrait, D > &p, BufferStuffer &stuffer, MapFnT map)
constexpr void conditional_swap(bool cnd, T &x, T &y)
Definition ct_utils.h:768
constexpr void poison_all(const Ts &... ts)
Definition ct_utils.h:201
constexpr void unpoison_all(const Ts &... ts)
Definition ct_utils.h:207
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
Definition ct_utils.h:798
constexpr void unpoison(const T *p, size_t n)
Definition ct_utils.h:67
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
Definition ct_utils.h:785
constexpr void poison(const T *p, size_t n)
Definition ct_utils.h:56
C::ProjectivePoint varpoint_exec(const AffinePointTable< C > &table, const BlindedScalar &scalar, RandomNumberGenerator &rng)
constexpr auto bigint_add2(W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:94
constexpr auto bigint_add3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:120
auto to_affine_x(const typename C::ProjectivePoint &pt)
constexpr auto bytes_to_words(std::span< const uint8_t, L > bytes)
constexpr W shift_left(std::array< W, N > &x)
Definition mp_core.h:712
constexpr void copy_mem(T *out, const T *in, size_t n)
Definition mem_ops.h:144
constexpr ProjectivePoint dbl_n_generic(const ProjectivePoint &pt, const FieldElement &A, size_t n)
BigInt operator*(const BigInt &x, const BigInt &y)
Definition big_ops3.cpp:57
constexpr size_t read_window_bits(std::span< const W, N > words, size_t offset)
Definition mp_core.h:1054
void bigint_comba_sqr4(word z[8], const word x[4])
Definition mp_comba.cpp:16
void bigint_comba_sqr6(word z[12], const word x[6])
Definition mp_comba.cpp:74
constexpr ProjectivePoint dbl_a_minus_3(const ProjectivePoint &pt)
constexpr size_t scalar_blinding_bits(size_t scalar_bits)
Definition pcurves_mul.h:41
void bigint_comba_mul4(word z[8], const word x[4], const word y[4])
Definition mp_comba.cpp:42
BigInt square(const BigInt &x)
Definition numthry.cpp:184
void bigint_sqr(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, word workspace[], size_t ws_size)
Definition mp_karat.cpp:327
OctetString operator+(const OctetString &k1, const OctetString &k2)
Definition symkey.cpp:99
C::ProjectivePoint mul2_exec(const AffinePointTable< C > &table, const BlindedScalar &x, const BlindedScalar &y, RandomNumberGenerator &rng)
constexpr auto bigint_sub3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
Definition mp_core.h:192
void bigint_mul(word z[], size_t z_size, const word x[], size_t x_size, size_t x_sw, const word y[], size_t y_size, size_t y_sw, word workspace[], size_t ws_size)
Definition mp_karat.cpp:283
void bigint_comba_mul6(word z[12], const word x[6], const word y[6])
Definition mp_comba.cpp:115
constexpr ProjectivePoint dbl_n_a_zero(const ProjectivePoint &pt, size_t n)
auto to_affine_batch(std::span< const typename C::ProjectivePoint > projective)
constexpr ProjectivePoint dbl_a_zero(const ProjectivePoint &pt)
C::ProjectivePoint basemul_booth_exec(std::span< const typename C::AffinePoint > table, const BlindedScalar &scalar, RandomNumberGenerator &rng)
BigInt operator-(const BigInt &x, const BigInt &y)
Definition bigint.h:1111
std::vector< typename C::ProjectivePoint > mul2_setup(const typename C::AffinePoint &p, const typename C::AffinePoint &q)
constexpr void bigint_shl1(W x[], size_t x_size, size_t x_words, size_t shift)
Definition mp_core.h:307
constexpr auto to_affine(const typename C::ProjectivePoint &pt)
void R2(uint32_t A, uint32_t &B, uint32_t C, uint32_t &D, uint32_t E, uint32_t &F, uint32_t G, uint32_t &H, uint32_t TJ, uint32_t Wi, uint32_t Wj)
Definition sm3_fn.h:43
constexpr ProjectivePoint point_add_mixed(const ProjectivePoint &a, const AffinePoint &b, const FieldElement &one)
void bigint_monty_redc(word r[], const word z[], const word p[], size_t p_size, word p_dash, word ws[], size_t ws_size)
Definition mp_core.h:906
bool operator==(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
Definition alg_id.cpp:53
std::vector< typename C::AffinePoint > basemul_booth_setup(const typename C::AffinePoint &p, size_t max_scalar_bits)
constexpr W bigint_cnd_add(W cnd, W x[], const W y[], size_t size)
Definition mp_core.h:45
constexpr ProjectivePoint point_add_or_sub_mixed(const ProjectivePoint &a, const AffinePoint &b, CT::Choice sub, const FieldElement &one)
constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[])
Definition mp_core.h:225
void bigint_comba_mul9(word z[18], const word x[9], const word y[9])
Definition mp_comba.cpp:511
void R1(uint32_t A, uint32_t &B, uint32_t C, uint32_t &D, uint32_t E, uint32_t &F, uint32_t G, uint32_t &H, uint32_t TJ, uint32_t Wi, uint32_t Wj)
Definition sm3_fn.h:21
void carry(int64_t &h0, int64_t &h1)
BOTAN_FORCE_INLINE constexpr T choose(T mask, T a, T b)
Definition bit_ops.h:216
constexpr ProjectivePoint dbl_n_a_minus_3(const ProjectivePoint &pt, size_t n)
AffinePointTable< C > varpoint_setup(const typename C::AffinePoint &p)
constexpr auto load_le(ParamTs &&... params)
Definition loadstor.h:495
constexpr auto bigint_ct_is_lt(const W x[], size_t x_size, const W y[], size_t y_size, bool lt_or_equal=false) -> CT::Mask< W >
Definition mp_core.h:473
std::vector< T, secure_allocator< T > > secure_vector
Definition secmem.h:68
void bigint_comba_sqr8(word z[16], const word x[8])
Definition mp_comba.cpp:292
void bigint_comba_sqr9(word z[18], const word x[9])
Definition mp_comba.cpp:440
constexpr ProjectivePoint dbl_generic(const ProjectivePoint &pt, const FieldElement &A)
constexpr ProjectivePoint point_add(const ProjectivePoint &a, const ProjectivePoint &b)
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
Definition types.h:119
void bigint_comba_mul8(word z[16], const word x[8], const word y[8])
Definition mp_comba.cpp:352
constexpr auto store_be(ParamTs &&... params)
Definition loadstor.h:745
constexpr void clear_mem(T *ptr, size_t n)
Definition mem_ops.h:118
constexpr auto load_be(ParamTs &&... params)
Definition loadstor.h:504
constexpr W shift_right(std::array< W, N > &x)
Definition mp_core.h:727
constexpr auto operator*=(Strong< T1, Tags... > &a, T2 b)