7#include <botan/internal/pcurves_generic.h>
9#include <botan/bigint.h>
10#include <botan/exceptn.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>
27constexpr std::optional<std::array<word, N>>
bytes_to_words(std::span<const uint8_t> bytes) {
28 if(bytes.size() > WordInfo<word>::bytes * N) {
32 std::array<word, N> r{};
34 const size_t full_words = bytes.size() / WordInfo<word>::bytes;
35 const size_t extra_bytes = bytes.size() % WordInfo<word>::bytes;
37 for(
size_t i = 0; i != full_words; ++i) {
42 const size_t shift = extra_bytes * 8;
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)));
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;
59 const size_t Windows = (bits + WindowBits - 1) / WindowBits;
62 tbl.reserve(WindowElements);
66 for(
size_t i = 1; i != WindowElements; ++i) {
68 tbl.push_back(tbl[i / 2].
square());
70 tbl.push_back(tbl[i - 1] * tbl[0]);
82 for(
size_t i = 1; i != Windows; ++i) {
83 for(
size_t j = 0; j != WindowBits; ++j) {
98class GenericCurveParams final {
103 GenericCurveParams(
const BigInt& p,
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),
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()),
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()),
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));
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));
143 size_t words()
const {
return m_words; }
145 size_t order_bits()
const {
return m_order_bits; }
147 size_t order_bytes()
const {
return m_order_bytes; }
149 size_t field_bits()
const {
return m_field_bits; }
151 size_t field_bytes()
const {
return m_field_bytes; }
153 const Montgomery_Params& monty_order()
const {
return m_monty_order; }
155 const Montgomery_Params& monty_field()
const {
return m_monty_field; }
157 const StorageUnit& field()
const {
return m_field; }
159 const StorageUnit& field_minus_2()
const {
return m_field_minus_2; }
161 const StorageUnit& field_monty_r1()
const {
return m_field_monty_r1; }
163 const StorageUnit& field_monty_r2()
const {
return m_field_monty_r2; }
165 const StorageUnit& field_p_plus_1_over_4()
const {
return m_field_p_plus_1_over_4; }
167 const StorageUnit& field_inv_2()
const {
return m_field_inv_2; }
169 word field_p_dash()
const {
return m_field_p_dash; }
171 const StorageUnit& order()
const {
return m_order; }
173 const StorageUnit& order_minus_2()
const {
return m_order_minus_2; }
175 const StorageUnit& order_monty_r1()
const {
return m_order_monty_r1; }
177 const StorageUnit& order_monty_r2()
const {
return m_order_monty_r2; }
179 const StorageUnit& order_monty_r3()
const {
return m_order_monty_r3; }
181 const StorageUnit& order_inv_2()
const {
return m_order_inv_2; }
183 word order_p_dash()
const {
return m_order_p_dash; }
185 const StorageUnit& monty_curve_a()
const {
return m_monty_curve_a; }
187 const StorageUnit& monty_curve_b()
const {
return m_monty_curve_b; }
189 const StorageUnit& base_x()
const {
return m_base_x; }
191 const StorageUnit& base_y()
const {
return m_base_y; }
193 bool a_is_minus_3()
const {
return m_a_is_minus_3; }
195 bool a_is_zero()
const {
return m_a_is_zero; }
197 bool order_is_less_than_field()
const {
return m_order_is_lt_field; }
199 void mul(std::array<word, 2 * N>& z,
const std::array<word, N>& x,
const std::array<word, N>& y)
const {
204 }
else if(m_words == 6) {
206 }
else if(m_words == 8) {
208 }
else if(m_words == 9) {
211 bigint_mul(z.data(), z.size(), x.data(), m_words, m_words, y.data(), m_words, m_words,
nullptr, 0);
215 void sqr(std::array<word, 2 * N>& z,
const std::array<word, N>& x)
const {
220 }
else if(m_words == 6) {
222 }
else if(m_words == 8) {
224 }
else if(m_words == 9) {
227 bigint_sqr(z.data(), z.size(), x.data(), m_words, m_words,
nullptr, 0);
232 static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed(
const BigInt& n) {
233 const size_t n_words = n.sig_words();
236 std::array<word, PrimeOrderCurve::StorageWords> r{};
237 copy_mem(std::span{r}.first(n_words), n._as_span().first(n_words));
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());
250 size_t m_order_bytes;
252 size_t m_field_bytes;
254 Montgomery_Params m_monty_order;
255 Montgomery_Params m_monty_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;
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;
273 StorageUnit m_monty_curve_a{};
274 StorageUnit m_monty_curve_b{};
276 StorageUnit m_base_x{};
277 StorageUnit m_base_y{};
281 bool m_order_is_lt_field;
284class GenericScalar final {
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();
294 if(bytes.size() > 2 * mlen) {
298 std::array<uint8_t, 2 *
sizeof(
word) * N> padded_bytes{};
299 copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
303 auto in_rep = wide_to_rep(curve, words.value());
304 return GenericScalar(curve, in_rep);
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();
314 if(bytes.size() != len) {
321 if(!
bigint_ct_is_lt(words->data(), N, curve->_params().order().data(), N).as_bool()) {
326 return GenericScalar(curve, to_rep(curve, *words));
332 static GenericScalar zero(
const GenericPrimeOrderCurve* curve) {
333 const StorageUnit zeros{};
334 return GenericScalar(curve, zeros);
337 static GenericScalar one(
const GenericPrimeOrderCurve* curve) {
338 return GenericScalar(curve, curve->_params().order_monty_r1());
341 static GenericScalar random(
const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
342 constexpr size_t MAX_ATTEMPTS = 1000;
344 const size_t bits = curve->_params().order_bits();
346 std::vector<uint8_t> buf(curve->_params().order_bytes());
348 for(
size_t i = 0; i != MAX_ATTEMPTS; ++i) {
354 const uint8_t mask = 0xFF >> (8 - (bits % 8));
358 if(
auto s = GenericScalar::deserialize(curve, buf)) {
359 if(s.value().is_nonzero().as_bool()) {
365 throw Internal_Error(
"Failed to generate random Scalar within bounded number of attempts");
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();
377 return GenericScalar(curve, r);
380 friend GenericScalar operator-(
const GenericScalar& a,
const GenericScalar& b) {
return a + b.negate(); }
382 friend GenericScalar operator*(
const GenericScalar& a,
const GenericScalar& b) {
383 const auto* curve = check_curve(a, b);
385 std::array<W, 2 * N> z;
386 curve->_params().mul(z, a.value(), b.value());
387 return GenericScalar(curve, redc(curve, z));
390 GenericScalar& operator*=(
const GenericScalar& other) {
391 const auto* curve = check_curve(*
this, other);
393 std::array<W, 2 * N> z;
394 curve->_params().mul(z, value(), other.value());
395 m_val = redc(curve, z);
399 GenericScalar square()
const {
400 const auto* curve = this->m_curve;
402 std::array<W, 2 * N> z;
403 curve->_params().sqr(z, value());
404 return GenericScalar(curve, redc(curve, z));
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));
414 GenericScalar negate()
const {
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);
423 GenericScalar invert()
const {
return pow_vartime(m_curve->_params().order_minus_2()); }
432 static void _invert_vartime_div2_helper(GenericScalar& a, GenericScalar& x) {
433 const auto& inv_2 = a.curve()->_params().order_inv_2();
436 while((a.m_val[0] & 1) != 1) {
451 GenericScalar invert_vartime()
const {
452 if(this->is_zero().as_bool()) {
456 auto x = GenericScalar(m_curve, std::array<W, N>{1});
457 auto b = GenericScalar(m_curve, from_rep(m_curve, m_val));
460 GenericScalar::_invert_vartime_div2_helper(b, x);
467 GenericScalar::_invert_vartime_div2_helper(a, y);
471 if(a.m_val == b.m_val) {
476 return GenericScalar(curve(), to_rep(curve(), r.m_val));
490 std::array<W, N> r{};
498 GenericScalar::_invert_vartime_div2_helper(b, x);
504 GenericScalar::_invert_vartime_div2_helper(a, y);
509 template <concepts::resizable_
byte_buffer T>
510 T serialize()
const {
511 T bytes(m_curve->_params().order_bytes());
512 this->serialize_to(bytes);
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());
520 const size_t flen = m_curve->_params().order_bytes();
521 BOTAN_ARG_CHECK(bytes.size() == flen,
"Expected output span provided");
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));
529 CT::Choice is_zero()
const {
return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
531 CT::Choice is_nonzero()
const {
return !is_zero(); }
533 CT::Choice operator==(
const GenericScalar& other)
const {
534 if(this->m_curve != other.m_curve) {
538 return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
544 StorageUnit to_words()
const {
return from_rep(m_curve, m_val); }
546 const StorageUnit& stash_value()
const {
return m_val; }
548 const GenericPrimeOrderCurve* curve()
const {
return m_curve; }
550 GenericScalar(
const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
553 const StorageUnit& value()
const {
return m_val; }
555 const W* data()
const {
return m_val.data(); }
557 static const GenericPrimeOrderCurve* check_curve(
const GenericScalar& a,
const GenericScalar& b) {
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();
568 r.data(), z.data(), mod.data(), words, curve->_params().order_p_dash(), ws.data(), ws.size());
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);
578 static StorageUnit to_rep(
const GenericPrimeOrderCurve* curve, StorageUnit x) {
579 std::array<W, 2 * N> z;
580 curve->_params().mul(z, x, curve->_params().order_monty_r2());
581 return redc(curve, z);
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;
587 curve->_params().mul(z, redc_x, curve->_params().order_monty_r3());
588 return redc(curve, z);
591 const GenericPrimeOrderCurve* m_curve;
597class GenericField final {
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();
607 if(bytes.size() != len) {
614 if(!
bigint_ct_is_lt(words->data(), N, curve->_params().field().data(), N).as_bool()) {
619 return GenericField::from_words(curve, *words);
625 static GenericField from_words(
const GenericPrimeOrderCurve* curve,
const std::array<word, N>& words) {
626 return GenericField(curve, to_rep(curve, words));
629 static GenericField zero(
const GenericPrimeOrderCurve* curve) {
630 const StorageUnit zeros{};
631 return GenericField(curve, zeros);
634 static GenericField one(
const GenericPrimeOrderCurve* curve) {
635 return GenericField(curve, curve->_params().field_monty_r1());
638 static GenericField curve_a(
const GenericPrimeOrderCurve* curve) {
639 return GenericField(curve, curve->_params().monty_curve_a());
642 static GenericField curve_b(
const GenericPrimeOrderCurve* curve) {
643 return GenericField(curve, curve->_params().monty_curve_b());
646 static GenericField random(
const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
647 constexpr size_t MAX_ATTEMPTS = 1000;
649 const size_t bits = curve->_params().field_bits();
651 std::vector<uint8_t> buf(curve->_params().field_bytes());
653 for(
size_t i = 0; i != MAX_ATTEMPTS; ++i) {
659 const uint8_t mask = 0xFF >> (8 - (bits % 8));
663 if(
auto s = GenericField::deserialize(curve, buf)) {
664 if(s.value().is_nonzero().as_bool()) {
670 throw Internal_Error(
"Failed to generate random Scalar within bounded number of attempts");
676 GenericField div2()
const {
677 StorageUnit t = value();
681 bigint_cnd_add(borrow, t.data(), m_curve->_params().field_inv_2().data(), N);
683 return GenericField(m_curve, t);
687 GenericField mul2()
const {
688 StorageUnit t = value();
693 return GenericField(m_curve, r);
697 GenericField mul3()
const {
return mul2() + (*this); }
700 GenericField mul4()
const {
return mul2().mul2(); }
703 GenericField mul8()
const {
return mul2().mul2().mul2(); }
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();
714 return GenericField(curve, r);
717 friend GenericField
operator-(
const GenericField& a,
const GenericField& b) {
return a + b.negate(); }
719 friend GenericField
operator*(
const GenericField& a,
const GenericField& b) {
720 const auto* curve = check_curve(a, b);
722 std::array<W, 2 * N> z;
723 curve->_params().mul(z, a.value(), b.value());
724 return GenericField(curve, redc(curve, z));
727 GenericField&
operator*=(
const GenericField& other) {
728 const auto* curve = check_curve(*
this, other);
730 std::array<W, 2 * N> z;
731 curve->_params().mul(z, value(), other.value());
732 m_val = redc(curve, z);
736 GenericField
square()
const {
737 std::array<W, 2 * N> z;
738 m_curve->_params().sqr(z, value());
739 return GenericField(m_curve, redc(m_curve, z));
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));
749 GenericField negate()
const {
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);
758 GenericField invert()
const {
return pow_vartime(m_curve->_params().field_minus_2()); }
760 GenericField invert_vartime()
const {
766 template <concepts::resizable_
byte_buffer T>
767 T serialize()
const {
768 T bytes(m_curve->_params().field_bytes());
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());
777 const size_t flen = m_curve->_params().field_bytes();
778 BOTAN_ARG_CHECK(bytes.size() == flen,
"Expected output span provided");
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));
786 CT::Choice is_zero()
const {
return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
788 CT::Choice is_nonzero()
const {
return !is_zero(); }
790 CT::Choice
operator==(
const GenericField& other)
const {
791 if(this->m_curve != other.m_curve) {
795 return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
798 const StorageUnit& stash_value()
const {
return m_val; }
800 const GenericPrimeOrderCurve* curve()
const {
return m_curve; }
802 CT::Choice is_even()
const {
803 auto v = from_rep(m_curve, m_val);
810 StorageUnit to_words()
const {
return from_rep(m_curve, m_val); }
812 void _const_time_poison()
const {
CT::poison(m_val); }
814 void _const_time_unpoison()
const {
CT::unpoison(m_val); }
816 static void conditional_swap(CT::Choice cond, GenericField& x, GenericField& y) {
817 const W mask = cond.into_bitmask<W>();
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]);
827 void conditional_assign(CT::Choice cond,
const GenericField& nx) {
828 const W mask = cond.into_bitmask<W>();
830 for(
size_t i = 0; i != N; ++i) {
831 m_val[i] =
choose(mask, nx.m_val[i], m_val[i]);
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>();
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]);
855 static void conditional_assign(GenericField& x,
859 const GenericField& nx,
860 const GenericField& ny,
861 const GenericField& nz) {
862 const W mask = cond.into_bitmask<W>();
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]);
871 std::pair<GenericField, CT::Choice> sqrt()
const {
874 auto z = pow_vartime(m_curve->_params().field_p_plus_1_over_4());
875 const CT::Choice correct = (z.square() == *
this);
877 z.conditional_assign(!correct, zero(m_curve));
881 GenericField(
const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
884 const StorageUnit& value()
const {
return m_val; }
886 const W* data()
const {
return m_val.data(); }
888 static const GenericPrimeOrderCurve* check_curve(
const GenericField& a,
const GenericField& b) {
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();
899 r.data(), z.data(), mod.data(), words, curve->_params().field_p_dash(), ws.data(), ws.size());
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);
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);
915 const GenericPrimeOrderCurve* m_curve;
926class GenericAffinePoint final {
928 GenericAffinePoint(
const GenericField& x,
const GenericField& y) : m_x(x), m_y(y) {}
930 explicit GenericAffinePoint(
const GenericPrimeOrderCurve* curve) :
931 m_x(GenericField::zero(curve)), m_y(GenericField::zero(curve)) {}
933 static GenericAffinePoint identity(
const GenericPrimeOrderCurve* curve) {
934 return GenericAffinePoint(GenericField::zero(curve), GenericField::zero(curve));
937 static GenericAffinePoint identity(
const GenericAffinePoint& pt) {
return identity(pt.curve()); }
939 CT::Choice is_identity()
const {
return x().is_zero() && y().is_zero(); }
941 GenericAffinePoint negate()
const {
return GenericAffinePoint(x(), y().negate()); }
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");
950 BufferStuffer
pack(bytes);
952 x().serialize_to(
pack.next(fe_bytes));
953 y().serialize_to(
pack.next(fe_bytes));
962 static auto ct_select(std::span<const GenericAffinePoint> pts,
size_t idx) {
964 auto result = GenericAffinePoint::identity(pts[0].curve());
967 const size_t idx1 =
static_cast<size_t>(idx - 1);
968 for(
size_t i = 0; i != pts.size(); ++i) {
970 result.conditional_assign(found, pts[i]);
979 static GenericField x3_ax_b(
const GenericField& x) {
980 return (x.square() + GenericField::curve_a(x.curve())) * x + GenericField::curve_b(x.curve());
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();
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));
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);
1003 }
else if(bytes.size() == 1 + fe_bytes && (bytes[0] == 0x02 || bytes[0] == 0x03)) {
1006 if(
auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes))) {
1007 auto [y, is_square] = x3_ax_b(*x).sqrt();
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);
1015 }
else if(bytes.size() == 1 && bytes[0] == 0x00) {
1017 return GenericAffinePoint::identity(curve);
1026 const GenericField& x()
const {
return m_x; }
1031 const GenericField& y()
const {
return m_y; }
1036 void conditional_assign(CT::Choice cond,
const GenericAffinePoint& pt) {
1037 GenericField::conditional_assign(m_x, m_y, cond, pt.x(), pt.y());
1040 const GenericPrimeOrderCurve* curve()
const {
return m_x.curve(); }
1051class GenericProjectivePoint final {
1053 typedef GenericProjectivePoint Self;
1055 using FieldElement = GenericField;
1060 static Self from_affine(
const GenericAffinePoint& pt) {
1063 auto z = GenericField::one(x.curve());
1066 GenericField::conditional_swap(pt.is_identity(), y, z);
1067 return GenericProjectivePoint(x, y, z);
1073 static Self identity(
const GenericPrimeOrderCurve* curve) {
1074 return Self(GenericField::zero(curve), GenericField::one(curve), GenericField::zero(curve));
1080 explicit GenericProjectivePoint(
const GenericPrimeOrderCurve* curve) :
1081 m_x(GenericField::zero(curve)), m_y(GenericField::one(curve)), m_z(GenericField::zero(curve)) {}
1086 GenericProjectivePoint(
const GenericField& x,
const GenericField& y) :
1087 m_x(x), m_y(y), m_z(GenericField::one(m_x.curve())) {}
1092 GenericProjectivePoint(
const GenericField& x,
const GenericField& y,
const GenericField& z) :
1093 m_x(x), m_y(y), m_z(z) {}
1095 friend Self operator+(
const Self& a,
const Self& b) {
return Self::add(a, b); }
1097 friend Self operator+(
const Self& a,
const GenericAffinePoint& b) {
return Self::add_mixed(a, b); }
1099 friend Self operator+(
const GenericAffinePoint& a,
const Self& b) {
return Self::add_mixed(b, a); }
1101 Self& operator+=(
const Self& other) {
1102 (*this) = (*this) + other;
1106 Self& operator+=(
const GenericAffinePoint& other) {
1107 (*this) = (*this) + other;
1111 CT::Choice is_identity()
const {
return z().is_zero(); }
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());
1120 static Self add_mixed(
const Self& a,
const GenericAffinePoint& b) {
1124 static Self add_or_sub(
const Self& a,
const GenericAffinePoint& b, CT::Choice sub) {
1136 Self dbl_n(
size_t n)
const {
1137 if(curve()->_params().a_is_minus_3()) {
1139 }
else if(curve()->_params().a_is_zero()) {
1142 const auto A = GenericField::curve_a(curve());
1151 if(curve()->_params().a_is_minus_3()) {
1153 }
else if(curve()->_params().a_is_zero()) {
1156 const auto A = GenericField::curve_a(curve());
1164 Self negate()
const {
return Self(x(), y().negate(), z()); }
1172 void randomize_rep(RandomNumberGenerator& rng) {
1176 if(rng.is_seeded()) {
1177 auto r = GenericField::random(curve(), rng);
1179 auto r2 = r.square();
1191 const GenericField& x()
const {
return m_x; }
1196 const GenericField& y()
const {
return m_y; }
1201 const GenericField& z()
const {
return m_z; }
1203 const GenericPrimeOrderCurve* curve()
const {
return m_x.curve(); }
1205 void _const_time_poison()
const {
CT::poison_all(m_x, m_y, m_z); }
1217class GenericCurve final {
1219 typedef GenericField FieldElement;
1220 typedef GenericScalar Scalar;
1221 typedef GenericAffinePoint AffinePoint;
1222 typedef GenericProjectivePoint ProjectivePoint;
1224 typedef word WordType;
1227class GenericBlindedScalarBits final {
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);
1232 const auto& params = scalar.curve()->_params();
1234 const size_t order_bits = params.order_bits();
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;
1243 const size_t words = params.words();
1246 rng.randomize(maskb);
1248 std::array<word, PrimeOrderCurve::StorageWords> mask{};
1249 load_le(mask.data(), maskb.data(), mask_words);
1252 const size_t excess = mask_words * WordInfo<word>::bits - blinder_bits;
1254 mask[mask_words - 1] &= (
static_cast<word>(1) << (WordInfo<word>::bits - excess)) - 1;
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;
1260 std::array<word, 2 * PrimeOrderCurve::StorageWords> mask_n{};
1262 const auto sw = scalar.to_words();
1265 params.mul(mask_n, mask, params.order());
1266 bigint_add2(mask_n.data(), 2 * words, sw.data(), words);
1268 std::reverse(mask_n.begin(), mask_n.end());
1270 m_bits = order_bits + blinder_bits;
1273 m_bytes = scalar.serialize<std::vector<uint8_t>>();
1274 m_bits = order_bits;
1277 m_windows = (m_bits + wb - 1) / wb;
1280 size_t windows()
const {
return m_windows; }
1282 size_t bits()
const {
return m_bits; }
1284 size_t get_window(
size_t offset)
const {
1285 if(m_window_bits == 1) {
1287 }
else if(m_window_bits == 2) {
1289 }
else if(m_window_bits == 3) {
1291 }
else if(m_window_bits == 4) {
1293 }
else if(m_window_bits == 5) {
1295 }
else if(m_window_bits == 6) {
1297 }
else if(m_window_bits == 7) {
1305 std::vector<uint8_t> m_bytes;
1308 size_t m_window_bits;
1311class GenericWindowedMul final {
1313 static constexpr size_t WindowBits = VarPointWindowBits;
1314 static constexpr size_t TableSize = (1 << WindowBits) - 1;
1316 explicit GenericWindowedMul(
const GenericAffinePoint& pt) :
1319 GenericProjectivePoint mul(
const GenericScalar& s, RandomNumberGenerator& rng) {
1320 const GenericBlindedScalarBits bits(s, rng, WindowBits);
1326 AffinePointTable<GenericCurve> m_table;
1331class GenericBaseMulTable final {
1333 static constexpr size_t WindowBits = BasePointWindowBits;
1336 explicit GenericBaseMulTable(
const GenericAffinePoint& pt) :
1337 m_table(
basemul_booth_setup<GenericCurve, WindowBits>(pt, blinded_scalar_bits(*pt.curve()) + 1)) {}
1339 GenericProjectivePoint mul(
const GenericScalar& s, RandomNumberGenerator& rng) {
1341 const GenericBlindedScalarBits scalar(s, rng, WindowBits + 1);
1346 static size_t blinded_scalar_bits(
const GenericPrimeOrderCurve& curve) {
1347 const size_t order_bits = curve.order_bits();
1351 std::vector<GenericAffinePoint> m_table;
1356class GenericWindowedMul2 final {
1358 static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1360 GenericWindowedMul2(
const GenericWindowedMul2& other) =
delete;
1361 GenericWindowedMul2(GenericWindowedMul2&& other) =
delete;
1362 GenericWindowedMul2& operator=(
const GenericWindowedMul2& other) =
delete;
1363 GenericWindowedMul2& operator=(GenericWindowedMul2&& other) =
delete;
1365 ~GenericWindowedMul2() =
default;
1367 GenericWindowedMul2(
const GenericAffinePoint& p,
const GenericAffinePoint& q) :
1368 m_table(
mul2_setup<GenericCurve, WindowBits>(p, q)) {}
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);
1377 AffinePointTable<GenericCurve> m_table;
1382 static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1384 GenericVartimeWindowedMul2(
const GenericVartimeWindowedMul2& other) =
delete;
1385 GenericVartimeWindowedMul2(GenericVartimeWindowedMul2&& other) =
delete;
1386 GenericVartimeWindowedMul2& operator=(
const GenericVartimeWindowedMul2& other) =
delete;
1387 GenericVartimeWindowedMul2& operator=(GenericVartimeWindowedMul2&& other) =
delete;
1389 ~GenericVartimeWindowedMul2()
override =
default;
1391 GenericVartimeWindowedMul2(
const GenericAffinePoint& p,
const GenericAffinePoint& q) :
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>>();
1398 const auto& curve = m_table[0].curve();
1399 auto accum = GenericProjectivePoint(curve);
1401 const size_t order_bits = curve->order_bits();
1403 const size_t windows = (order_bits + WindowBits - 1) / WindowBits;
1405 for(
size_t i = 0; i != windows; ++i) {
1410 accum = accum.dbl_n(WindowBits);
1413 const size_t idx = (y_i << WindowBits) + x_i;
1416 accum += m_table[idx - 1];
1424 std::vector<GenericAffinePoint> m_table;
1431 m_params(std::make_unique<GenericCurveParams>(p, a, b, base_x, base_y, order)) {}
1435 m_basemul = std::make_unique<GenericBaseMulTable>(from_stash(
generator()));
1439 return _params().order_bits();
1443 return _params().order_bytes();
1447 return _params().field_bytes();
1453 return stash(m_basemul->mul(from_stash(scalar), rng));
1459 auto pt_s = m_basemul->mul(from_stash(scalar), rng);
1461 if(
auto s = GenericScalar::from_wide_bytes(
this, x_bytes)) {
1464 throw Internal_Error(
"Failed to convert x coordinate to integer modulo scalar");
1471 GenericWindowedMul pt_table(from_stash(pt));
1472 return stash(pt_table.mul(from_stash(scalar), rng));
1478 GenericWindowedMul pt_table(from_stash(pt));
1479 auto pt_s = pt_table.mul(from_stash(scalar), rng);
1485 return std::make_unique<GenericVartimeWindowedMul2>(from_stash(
generator()), from_stash(q));
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()) {
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()) {
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));
1518 if(!pt.is_identity().as_bool()) {
1519 const auto z2 = pt.z().square();
1521 const auto v_bytes = from_stash(v).serialize<std::vector<uint8_t>>();
1523 if(
auto fe_v = GenericField::deserialize(
this, v_bytes)) {
1524 if((*fe_v * z2 == pt.x()).as_bool()) {
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();
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();
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);
1554 BOTAN_ASSERT(valid_point.as_bool(),
"Computed point is on the curve");
1556 return stash(affine);
1560 return stash(GenericProjectivePoint::from_affine(from_stash(a)) + from_stash(b));
1564 return stash(from_stash(pt).negate());
1568 return from_stash(pt).is_identity().as_bool();
1572 from_stash(pt).serialize_to(bytes);
1577 from_stash(scalar).serialize_to(bytes);
1581 std::span<const uint8_t> bytes)
const {
1582 if(
auto s = GenericScalar::deserialize(
this, bytes)) {
1583 return stash(s.value());
1590 std::span<const uint8_t> bytes)
const {
1591 if(
auto s = GenericScalar::from_wide_bytes(
this, bytes)) {
1592 return stash(s.value());
1599 std::span<const uint8_t> bytes)
const {
1600 if(
auto pt = GenericAffinePoint::deserialize(
this, bytes)) {
1601 return stash(pt.value());
1608 return stash(from_stash(a) + from_stash(b));
1612 return stash(from_stash(a) - from_stash(b));
1616 return stash(from_stash(a) * from_stash(b));
1620 return stash(from_stash(s).
square());
1624 return stash(from_stash(s).invert());
1628 return stash(from_stash(s).invert_vartime());
1632 return stash(from_stash(s).negate());
1636 return from_stash(s).is_zero().as_bool();
1640 return (from_stash(a) == from_stash(b)).as_bool();
1644 return stash(GenericScalar::one(
this));
1648 return stash(GenericScalar::random(
this, rng));
1652 return Scalar::_create(shared_from_this(), s.stash_value());
1655GenericScalar GenericPrimeOrderCurve::from_stash(
const PrimeOrderCurve::Scalar& s)
const {
1657 return GenericScalar(
this, s._value());
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);
1668 auto x = GenericField(
this, pt._x());
1669 auto y = GenericField(
this, pt._y());
1670 return GenericAffinePoint(x, y);
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);
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);
1689 std::function<
void(std::span<uint8_t>)> expand_message)
const {
1691 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
1695 std::function<
void(std::span<uint8_t>)> expand_message)
const {
1697 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
1700std::shared_ptr<const PrimeOrderCurve> PCurveInstance::from_params(
1710 const size_t p_bits = p.
bits();
1719 if(p_bits != 521 && p_bits != 239 && (p_bits < 128 || p_bits > 512 || p_bits % 32 != 0)) {
1729 if(p_bits != order.
bits()) {
1733 auto gpoc = std::make_shared<GenericPrimeOrderCurve>(p, a, b, base_x, base_y, order);
1743 gpoc->_precompute_base_mul();
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_DEBUG_ASSERT(expr)
#define BOTAN_STATE_CHECK(expr)
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
#define BOTAN_ASSERT_UNREACHABLE()
static constexpr Choice from_int(T v)
static constexpr Choice no()
static constexpr Mask< T > is_equal(T x, T y)
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
void _precompute_base_mul()
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
size_t field_element_bytes() const override
ProjectivePoint mul(const AffinePoint &pt, const Scalar &scalar, RandomNumberGenerator &rng) const override
Scalar scalar_one() 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)
static constexpr size_t StorageWords
Number of words used to store MaximumByteLength.
std::array< word, StorageWords > StorageUnit
constexpr void pack(const Polynomial< PolyTrait, D > &p, BufferStuffer &stuffer, MapFnT map)
constexpr void conditional_swap(bool cnd, T &x, T &y)
constexpr void poison_all(const Ts &... ts)
constexpr void unpoison_all(const Ts &... ts)
constexpr CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
constexpr void unpoison(const T *p, size_t n)
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
constexpr void poison(const T *p, size_t n)
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
constexpr auto bigint_add3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
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)
constexpr void copy_mem(T *out, const T *in, size_t n)
constexpr ProjectivePoint dbl_n_generic(const ProjectivePoint &pt, const FieldElement &A, size_t n)
BigInt operator*(const BigInt &x, const BigInt &y)
constexpr size_t read_window_bits(std::span< const W, N > words, size_t offset)
void bigint_comba_sqr4(word z[8], const word x[4])
void bigint_comba_sqr6(word z[12], const word x[6])
constexpr ProjectivePoint dbl_a_minus_3(const ProjectivePoint &pt)
constexpr size_t scalar_blinding_bits(size_t scalar_bits)
void bigint_comba_mul4(word z[8], const word x[4], const word y[4])
BigInt square(const BigInt &x)
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)
OctetString operator+(const OctetString &k1, const OctetString &k2)
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
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)
void bigint_comba_mul6(word z[12], const word x[6], const word y[6])
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)
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)
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)
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)
bool operator==(const AlgorithmIdentifier &a1, const AlgorithmIdentifier &a2)
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)
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[])
void bigint_comba_mul9(word z[18], const word x[9], const word y[9])
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)
void carry(int64_t &h0, int64_t &h1)
BOTAN_FORCE_INLINE constexpr T choose(T mask, T a, T b)
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)
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 >
std::vector< T, secure_allocator< T > > secure_vector
void bigint_comba_sqr8(word z[16], const word x[8])
void bigint_comba_sqr9(word z[18], const word x[9])
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
void bigint_comba_mul8(word z[16], const word x[8], const word y[8])
constexpr auto store_be(ParamTs &&... params)
constexpr void clear_mem(T *ptr, size_t n)
constexpr auto load_be(ParamTs &&... params)
constexpr W shift_right(std::array< W, N > &x)
constexpr auto operator*=(Strong< T1, Tags... > &a, T2 b)