7#include <botan/internal/pcurves_generic.h>
9#include <botan/bigint.h>
10#include <botan/exceptn.h>
12#include <botan/internal/ct_utils.h>
13#include <botan/internal/loadstor.h>
14#include <botan/internal/mp_core.h>
15#include <botan/internal/pcurves_algos.h>
16#include <botan/internal/pcurves_instance.h>
17#include <botan/internal/pcurves_mul.h>
18#include <botan/internal/primality.h>
26constexpr std::optional<std::array<word, N>>
bytes_to_words(std::span<const uint8_t> bytes) {
27 if(bytes.size() > WordInfo<word>::bytes * N) {
31 std::array<word, N> r{};
33 const size_t full_words = bytes.size() / WordInfo<word>::bytes;
34 const size_t extra_bytes = bytes.size() % WordInfo<word>::bytes;
36 for(
size_t i = 0; i != full_words; ++i) {
41 const size_t shift = extra_bytes * 8;
44 for(
size_t i = 0; i != extra_bytes; ++i) {
45 const word b0 = bytes[WordInfo<word>::bytes * full_words + i];
46 r[0] |= (b0 << (8 * (extra_bytes - 1 - i)));
54T impl_pow_vartime(
const T& elem,
const T& one,
size_t bits, std::span<const word> exp) {
55 constexpr size_t WindowBits = 4;
56 constexpr size_t WindowElements = (1 << WindowBits) - 1;
58 const size_t Windows = (bits + WindowBits - 1) / WindowBits;
61 tbl.reserve(WindowElements);
65 for(
size_t i = 1; i != WindowElements; ++i) {
67 tbl.push_back(tbl[i / 2].
square());
69 tbl.push_back(tbl[i - 1] * tbl[0]);
81 for(
size_t i = 1; i != Windows; ++i) {
82 for(
size_t j = 0; j != WindowBits; ++j) {
97class GenericCurveParams final {
102 GenericCurveParams(
const BigInt& p,
105 const BigInt& base_x,
106 const BigInt& base_y,
107 const BigInt& order) :
108 m_words(p.sig_words()),
109 m_order_bits(order.bits()),
110 m_order_bytes(order.bytes()),
111 m_field_bits(p.bits()),
112 m_field_bytes(p.bytes()),
113 m_monty_order(order),
115 m_field(bn_to_fixed(p)),
116 m_field_minus_2(bn_to_fixed_rev(p - 2)),
117 m_field_monty_r1(bn_to_fixed(m_monty_field.R1())),
118 m_field_monty_r2(bn_to_fixed(m_monty_field.R2())),
119 m_field_p_plus_1_over_4(bn_to_fixed_rev((p + 1) / 4)),
120 m_field_inv_2(bn_to_fixed((p / 2) + 1)),
121 m_field_p_dash(m_monty_field.p_dash()),
123 m_order(bn_to_fixed(order)),
124 m_order_minus_2(bn_to_fixed_rev(order - 2)),
125 m_order_monty_r1(bn_to_fixed(m_monty_order.R1())),
126 m_order_monty_r2(bn_to_fixed(m_monty_order.R2())),
127 m_order_monty_r3(bn_to_fixed(m_monty_order.R3())),
128 m_order_inv_2(bn_to_fixed((order / 2) + 1)),
129 m_order_p_dash(m_monty_order.p_dash()),
131 m_a_is_minus_3(a + 3 == p),
132 m_a_is_zero(a.is_zero()),
133 m_order_is_lt_field(order < p) {
135 m_monty_curve_a = bn_to_fixed(m_monty_field.mul(a, m_monty_field.R2(), ws));
136 m_monty_curve_b = bn_to_fixed(m_monty_field.mul(b, m_monty_field.R2(), ws));
138 m_base_x = bn_to_fixed(m_monty_field.mul(base_x, m_monty_field.R2(), ws));
139 m_base_y = bn_to_fixed(m_monty_field.mul(base_y, m_monty_field.R2(), ws));
142 size_t words()
const {
return m_words; }
144 size_t order_bits()
const {
return m_order_bits; }
146 size_t order_bytes()
const {
return m_order_bytes; }
148 size_t field_bits()
const {
return m_field_bits; }
150 size_t field_bytes()
const {
return m_field_bytes; }
152 const Montgomery_Params& monty_order()
const {
return m_monty_order; }
154 const Montgomery_Params& monty_field()
const {
return m_monty_field; }
156 const StorageUnit& field()
const {
return m_field; }
158 const StorageUnit& field_minus_2()
const {
return m_field_minus_2; }
160 const StorageUnit& field_monty_r1()
const {
return m_field_monty_r1; }
162 const StorageUnit& field_monty_r2()
const {
return m_field_monty_r2; }
164 const StorageUnit& field_p_plus_1_over_4()
const {
return m_field_p_plus_1_over_4; }
166 const StorageUnit& field_inv_2()
const {
return m_field_inv_2; }
168 word field_p_dash()
const {
return m_field_p_dash; }
170 const StorageUnit& order()
const {
return m_order; }
172 const StorageUnit& order_minus_2()
const {
return m_order_minus_2; }
174 const StorageUnit& order_monty_r1()
const {
return m_order_monty_r1; }
176 const StorageUnit& order_monty_r2()
const {
return m_order_monty_r2; }
178 const StorageUnit& order_monty_r3()
const {
return m_order_monty_r3; }
180 const StorageUnit& order_inv_2()
const {
return m_order_inv_2; }
182 word order_p_dash()
const {
return m_order_p_dash; }
184 const StorageUnit& monty_curve_a()
const {
return m_monty_curve_a; }
186 const StorageUnit& monty_curve_b()
const {
return m_monty_curve_b; }
188 const StorageUnit& base_x()
const {
return m_base_x; }
190 const StorageUnit& base_y()
const {
return m_base_y; }
192 bool a_is_minus_3()
const {
return m_a_is_minus_3; }
194 bool a_is_zero()
const {
return m_a_is_zero; }
196 bool order_is_less_than_field()
const {
return m_order_is_lt_field; }
198 void mul(std::array<word, 2 * N>& z,
const std::array<word, N>& x,
const std::array<word, N>& y)
const {
203 }
else if(m_words == 6) {
205 }
else if(m_words == 8) {
207 }
else if(m_words == 9) {
210 bigint_mul(z.data(), z.size(), x.data(), m_words, m_words, y.data(), m_words, m_words,
nullptr, 0);
214 void sqr(std::array<word, 2 * N>& z,
const std::array<word, N>& x)
const {
219 }
else if(m_words == 6) {
221 }
else if(m_words == 8) {
223 }
else if(m_words == 9) {
226 bigint_sqr(z.data(), z.size(), x.data(), m_words, m_words,
nullptr, 0);
231 static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed(
const BigInt& n) {
232 const size_t n_words = n.sig_words();
235 std::array<word, PrimeOrderCurve::StorageWords> r{};
236 copy_mem(std::span{r}.first(n_words), n._as_span().first(n_words));
240 static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed_rev(
const BigInt& n) {
241 auto v = bn_to_fixed(n);
242 std::reverse(v.begin(), v.end());
249 size_t m_order_bytes;
251 size_t m_field_bytes;
253 Montgomery_Params m_monty_order;
254 Montgomery_Params m_monty_field;
257 StorageUnit m_field_minus_2;
258 StorageUnit m_field_monty_r1;
259 StorageUnit m_field_monty_r2;
260 StorageUnit m_field_p_plus_1_over_4;
261 StorageUnit m_field_inv_2;
265 StorageUnit m_order_minus_2;
266 StorageUnit m_order_monty_r1;
267 StorageUnit m_order_monty_r2;
268 StorageUnit m_order_monty_r3;
269 StorageUnit m_order_inv_2;
272 StorageUnit m_monty_curve_a{};
273 StorageUnit m_monty_curve_b{};
275 StorageUnit m_base_x{};
276 StorageUnit m_base_y{};
280 bool m_order_is_lt_field;
283class GenericScalar final {
289 static std::optional<GenericScalar> from_wide_bytes(
const GenericPrimeOrderCurve* curve,
290 std::span<const uint8_t> bytes) {
291 const size_t mlen = curve->_params().order_bytes();
293 if(bytes.size() > 2 * mlen) {
297 std::array<uint8_t, 2 *
sizeof(
word) * N> padded_bytes{};
298 copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
302 auto in_rep = wide_to_rep(curve, words.value());
303 return GenericScalar(curve, in_rep);
309 static std::optional<GenericScalar> deserialize(
const GenericPrimeOrderCurve* curve,
310 std::span<const uint8_t> bytes) {
311 const size_t len = curve->_params().order_bytes();
313 if(bytes.size() != len) {
320 if(!
bigint_ct_is_lt(words->data(), N, curve->_params().order().data(), N).as_bool()) {
325 return GenericScalar(curve, to_rep(curve, *words));
331 static GenericScalar zero(
const GenericPrimeOrderCurve* curve) {
333 return GenericScalar(curve, zeros);
336 static GenericScalar one(
const GenericPrimeOrderCurve* curve) {
337 return GenericScalar(curve, curve->_params().order_monty_r1());
340 static GenericScalar random(
const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
341 constexpr size_t MAX_ATTEMPTS = 1000;
343 const size_t bits = curve->_params().order_bits();
345 std::vector<uint8_t> buf(curve->_params().order_bytes());
347 for(
size_t i = 0; i != MAX_ATTEMPTS; ++i) {
353 const uint8_t mask = 0xFF >> (8 - (bits % 8));
357 if(
auto s = GenericScalar::deserialize(curve, buf)) {
358 if(s.value().is_nonzero().as_bool()) {
364 throw Internal_Error(
"Failed to generate random Scalar within bounded number of attempts");
367 friend GenericScalar operator+(
const GenericScalar& a,
const GenericScalar& b) {
368 const auto* curve = check_curve(a, b);
369 const size_t words = curve->_params().words();
376 return GenericScalar(curve, r);
379 friend GenericScalar operator-(
const GenericScalar& a,
const GenericScalar& b) {
return a + b.negate(); }
381 friend GenericScalar operator*(
const GenericScalar& a,
const GenericScalar& b) {
382 const auto* curve = check_curve(a, b);
384 std::array<W, 2 * N> z;
385 curve->_params().mul(z, a.value(), b.value());
386 return GenericScalar(curve, redc(curve, z));
389 GenericScalar& operator*=(
const GenericScalar& other) {
390 const auto* curve = check_curve(*
this, other);
392 std::array<W, 2 * N> z;
393 curve->_params().mul(z, value(), other.value());
394 m_val = redc(curve, z);
398 GenericScalar square()
const {
399 const auto* curve = this->m_curve;
401 std::array<W, 2 * N> z;
402 curve->_params().sqr(z, value());
403 return GenericScalar(curve, redc(curve, z));
406 GenericScalar pow_vartime(
const StorageUnit& exp)
const {
407 auto one = GenericScalar::one(curve());
408 auto bits = curve()->_params().order_bits();
409 auto words = curve()->_params().words();
410 return impl_pow_vartime(*
this, one, bits, std::span{exp}.last(words));
413 GenericScalar negate()
const {
417 bigint_sub3(r.data(), m_curve->_params().order().data(), N, this->data(), N);
418 x_is_zero.if_set_zero_out(r.data(), N);
419 return GenericScalar(m_curve, r);
422 GenericScalar invert()
const {
return pow_vartime(m_curve->_params().order_minus_2()); }
431 static void _invert_vartime_div2_helper(GenericScalar& a, GenericScalar& x) {
432 const auto& inv_2 = a.curve()->_params().order_inv_2();
435 while((a.m_val[0] & 1) != 1) {
450 GenericScalar invert_vartime()
const {
451 if(this->is_zero().as_bool()) {
455 auto x = GenericScalar(m_curve, std::array<W, N>{1});
456 auto b = GenericScalar(m_curve, from_rep(m_curve, m_val));
459 GenericScalar::_invert_vartime_div2_helper(b, x);
466 GenericScalar::_invert_vartime_div2_helper(a, y);
470 if(a.m_val == b.m_val) {
475 return GenericScalar(curve(), to_rep(curve(), r.m_val));
489 std::array<W, N> r{};
497 GenericScalar::_invert_vartime_div2_helper(b, x);
503 GenericScalar::_invert_vartime_div2_helper(a, y);
508 template <concepts::resizable_
byte_buffer T>
509 T serialize()
const {
510 T bytes(m_curve->_params().order_bytes());
511 this->serialize_to(bytes);
515 void serialize_to(std::span<uint8_t> bytes)
const {
516 auto v = from_rep(m_curve, m_val);
517 std::reverse(v.begin(), v.end());
519 const size_t flen = m_curve->_params().order_bytes();
520 BOTAN_ARG_CHECK(bytes.size() == flen,
"Expected output span provided");
523 const auto padded_bytes =
store_be(v);
524 const size_t extra = N * WordInfo<W>::bytes - flen;
525 copy_mem(bytes, std::span{padded_bytes}.subspan(extra, flen));
528 CT::Choice is_zero()
const {
return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
530 CT::Choice is_nonzero()
const {
return !is_zero(); }
532 CT::Choice operator==(
const GenericScalar& other)
const {
533 if(this->m_curve != other.m_curve) {
537 return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
543 StorageUnit to_words()
const {
return from_rep(m_curve, m_val); }
545 const StorageUnit& stash_value()
const {
return m_val; }
547 const GenericPrimeOrderCurve* curve()
const {
return m_curve; }
549 GenericScalar(
const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
552 const StorageUnit& value()
const {
return m_val; }
554 const W* data()
const {
return m_val.data(); }
556 static const GenericPrimeOrderCurve* check_curve(
const GenericScalar& a,
const GenericScalar& b) {
561 static StorageUnit redc(
const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> z) {
562 const auto& mod = curve->_params().order();
563 const size_t words = curve->_params().words();
567 r.data(), z.data(), mod.data(), words, curve->_params().order_p_dash(), ws.data(), ws.size());
571 static StorageUnit from_rep(
const GenericPrimeOrderCurve* curve, StorageUnit z) {
572 std::array<W, 2 * N> ze{};
573 copy_mem(std::span{ze}.template first<N>(), z);
574 return redc(curve, ze);
577 static StorageUnit to_rep(
const GenericPrimeOrderCurve* curve, StorageUnit x) {
578 std::array<W, 2 * N> z;
579 curve->_params().mul(z, x, curve->_params().order_monty_r2());
580 return redc(curve, z);
583 static StorageUnit wide_to_rep(
const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> x) {
584 auto redc_x = redc(curve, x);
585 std::array<W, 2 * N> z;
586 curve->_params().mul(z, redc_x, curve->_params().order_monty_r3());
587 return redc(curve, z);
590 const GenericPrimeOrderCurve* m_curve;
594class GenericField final {
600 static std::optional<GenericField> deserialize(
const GenericPrimeOrderCurve* curve,
601 std::span<const uint8_t> bytes) {
602 const size_t len = curve->_params().field_bytes();
604 if(bytes.size() != len) {
611 if(!
bigint_ct_is_lt(words->data(), N, curve->_params().field().data(), N).as_bool()) {
616 return GenericField::from_words(curve, *words);
622 static GenericField from_words(
const GenericPrimeOrderCurve* curve,
const std::array<word, N>& words) {
623 return GenericField(curve, to_rep(curve, words));
626 static GenericField zero(
const GenericPrimeOrderCurve* curve) {
628 return GenericField(curve, zeros);
631 static GenericField one(
const GenericPrimeOrderCurve* curve) {
632 return GenericField(curve, curve->_params().field_monty_r1());
635 static GenericField curve_a(
const GenericPrimeOrderCurve* curve) {
636 return GenericField(curve, curve->_params().monty_curve_a());
639 static GenericField curve_b(
const GenericPrimeOrderCurve* curve) {
640 return GenericField(curve, curve->_params().monty_curve_b());
643 static GenericField random(
const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
644 constexpr size_t MAX_ATTEMPTS = 1000;
646 const size_t bits = curve->_params().field_bits();
648 std::vector<uint8_t> buf(curve->_params().field_bytes());
650 for(
size_t i = 0; i != MAX_ATTEMPTS; ++i) {
656 const uint8_t mask = 0xFF >> (8 - (bits % 8));
660 if(
auto s = GenericField::deserialize(curve, buf)) {
661 if(s.value().is_nonzero().as_bool()) {
667 throw Internal_Error(
"Failed to generate random Scalar within bounded number of attempts");
673 GenericField div2()
const {
674 StorageUnit t = value();
678 bigint_cnd_add(borrow, t.data(), m_curve->_params().field_inv_2().data(), N);
680 return GenericField(m_curve, t);
684 GenericField mul2()
const {
685 StorageUnit t = value();
690 return GenericField(m_curve, r);
694 GenericField mul3()
const {
return mul2() + (*this); }
697 GenericField mul4()
const {
return mul2().mul2(); }
700 GenericField mul8()
const {
return mul2().mul2().mul2(); }
702 friend GenericField operator+(
const GenericField& a,
const GenericField& b) {
703 const auto* curve = check_curve(a, b);
704 const size_t words = curve->_params().words();
711 return GenericField(curve, r);
714 friend GenericField operator-(
const GenericField& a,
const GenericField& b) {
return a + b.negate(); }
716 friend GenericField operator*(
const GenericField& a,
const GenericField& b) {
717 const auto* curve = check_curve(a, b);
719 std::array<W, 2 * N> z;
720 curve->_params().mul(z, a.value(), b.value());
721 return GenericField(curve, redc(curve, z));
724 GenericField& operator*=(
const GenericField& other) {
725 const auto* curve = check_curve(*
this, other);
727 std::array<W, 2 * N> z;
728 curve->_params().mul(z, value(), other.value());
729 m_val = redc(curve, z);
733 GenericField square()
const {
734 std::array<W, 2 * N> z;
735 m_curve->_params().sqr(z, value());
736 return GenericField(m_curve, redc(m_curve, z));
739 GenericField pow_vartime(
const StorageUnit& exp)
const {
740 auto one = GenericField::one(curve());
741 auto bits = curve()->_params().field_bits();
742 auto words = curve()->_params().words();
743 return impl_pow_vartime(*
this, one, bits, std::span{exp}.last(words));
746 GenericField negate()
const {
750 bigint_sub3(r.data(), m_curve->_params().field().data(), N, this->data(), N);
751 x_is_zero.if_set_zero_out(r.data(), N);
752 return GenericField(m_curve, r);
755 GenericField invert()
const {
return pow_vartime(m_curve->_params().field_minus_2()); }
757 template <concepts::resizable_
byte_buffer T>
758 T serialize()
const {
759 T bytes(m_curve->_params().field_bytes());
764 void serialize_to(std::span<uint8_t> bytes)
const {
765 auto v = from_rep(m_curve, m_val);
766 std::reverse(v.begin(), v.end());
768 const size_t flen = m_curve->_params().field_bytes();
769 BOTAN_ARG_CHECK(bytes.size() == flen,
"Expected output span provided");
772 const auto padded_bytes =
store_be(v);
773 const size_t extra = N * WordInfo<W>::bytes - flen;
774 copy_mem(bytes, std::span{padded_bytes}.subspan(extra, flen));
777 CT::Choice is_zero()
const {
return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
779 CT::Choice is_nonzero()
const {
return !is_zero(); }
781 CT::Choice operator==(
const GenericField& other)
const {
782 if(this->m_curve != other.m_curve) {
786 return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
789 const StorageUnit& stash_value()
const {
return m_val; }
791 const GenericPrimeOrderCurve* curve()
const {
return m_curve; }
793 CT::Choice is_even()
const {
794 auto v = from_rep(m_curve, m_val);
801 StorageUnit to_words()
const {
return from_rep(m_curve, m_val); }
803 void _const_time_poison()
const {
CT::poison(m_val); }
805 void _const_time_unpoison()
const {
CT::unpoison(m_val); }
807 static void conditional_swap(CT::Choice cond, GenericField& x, GenericField& y) {
810 for(
size_t i = 0; i != N; ++i) {
811 auto nx =
choose(mask, y.m_val[i], x.m_val[i]);
812 auto ny =
choose(mask, x.m_val[i], y.m_val[i]);
818 void conditional_assign(CT::Choice cond,
const GenericField& nx) {
821 for(
size_t i = 0; i != N; ++i) {
822 m_val[i] =
choose(mask, nx.m_val[i], m_val[i]);
831 static void conditional_assign(
832 GenericField& x, GenericField& y, CT::Choice cond,
const GenericField& nx,
const GenericField& ny) {
835 for(
size_t i = 0; i != N; ++i) {
836 x.m_val[i] =
choose(mask, nx.m_val[i], x.m_val[i]);
837 y.m_val[i] =
choose(mask, ny.m_val[i], y.m_val[i]);
846 static void conditional_assign(GenericField& x,
850 const GenericField& nx,
851 const GenericField& ny,
852 const GenericField& nz) {
855 for(
size_t i = 0; i != N; ++i) {
856 x.m_val[i] =
choose(mask, nx.m_val[i], x.m_val[i]);
857 y.m_val[i] =
choose(mask, ny.m_val[i], y.m_val[i]);
858 z.m_val[i] =
choose(mask, nz.m_val[i], z.m_val[i]);
862 std::pair<GenericField, CT::Choice> sqrt()
const {
865 auto z = pow_vartime(m_curve->_params().field_p_plus_1_over_4());
866 const CT::Choice correct = (z.square() == *
this);
868 z.conditional_assign(!correct, zero(m_curve));
872 GenericField(
const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
875 const StorageUnit& value()
const {
return m_val; }
877 const W* data()
const {
return m_val.data(); }
879 static const GenericPrimeOrderCurve* check_curve(
const GenericField& a,
const GenericField& b) {
884 static StorageUnit redc(
const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> z) {
885 const auto& mod = curve->_params().field();
886 const size_t words = curve->_params().words();
890 r.data(), z.data(), mod.data(), words, curve->_params().field_p_dash(), ws.data(), ws.size());
894 static StorageUnit from_rep(
const GenericPrimeOrderCurve* curve, StorageUnit z) {
895 std::array<W, 2 * N> ze{};
896 copy_mem(std::span{ze}.template first<N>(), z);
897 return redc(curve, ze);
900 static StorageUnit to_rep(
const GenericPrimeOrderCurve* curve, StorageUnit x) {
901 std::array<W, 2 * N> z{};
902 curve->_params().mul(z, x, curve->_params().field_monty_r2());
903 return redc(curve, z);
906 const GenericPrimeOrderCurve* m_curve;
915class GenericAffinePoint final {
917 GenericAffinePoint(
const GenericField& x,
const GenericField& y) : m_x(x), m_y(y) {}
919 explicit GenericAffinePoint(
const GenericPrimeOrderCurve* curve) :
920 m_x(GenericField::zero(curve)), m_y(GenericField::zero(curve)) {}
922 static GenericAffinePoint identity(
const GenericPrimeOrderCurve* curve) {
923 return GenericAffinePoint(GenericField::zero(curve), GenericField::zero(curve));
926 static GenericAffinePoint identity(
const GenericAffinePoint& pt) {
return identity(pt.curve()); }
928 CT::Choice is_identity()
const {
return x().is_zero() && y().is_zero(); }
930 GenericAffinePoint negate()
const {
return GenericAffinePoint(x(), y().negate()); }
935 void serialize_to(std::span<uint8_t> bytes)
const {
936 const size_t fe_bytes = curve()->_params().field_bytes();
937 BOTAN_ARG_CHECK(bytes.size() == 1 + 2 * fe_bytes,
"Buffer size incorrect");
939 BufferStuffer
pack(bytes);
941 x().serialize_to(
pack.next(fe_bytes));
942 y().serialize_to(
pack.next(fe_bytes));
951 static auto ct_select(std::span<const GenericAffinePoint> pts,
size_t idx) {
953 auto result = GenericAffinePoint::identity(pts[0].curve());
956 const size_t idx1 =
static_cast<size_t>(idx - 1);
957 for(
size_t i = 0; i != pts.size(); ++i) {
959 result.conditional_assign(found, pts[i]);
968 static GenericField x3_ax_b(
const GenericField& x) {
969 return (x.square() + GenericField::curve_a(x.curve())) * x + GenericField::curve_b(x.curve());
977 static std::optional<GenericAffinePoint> deserialize(
const GenericPrimeOrderCurve* curve,
978 std::span<const uint8_t> bytes) {
979 const size_t fe_bytes = curve->_params().field_bytes();
981 if(bytes.size() == 1 + 2 * fe_bytes && bytes[0] == 0x04) {
982 auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes));
983 auto y = GenericField::deserialize(curve, bytes.subspan(1 + fe_bytes, fe_bytes));
986 const auto lhs = (*y).square();
987 const auto rhs = GenericAffinePoint::x3_ax_b(*x);
988 if((lhs == rhs).as_bool()) {
989 return GenericAffinePoint(*x, *y);
992 }
else if(bytes.size() == 1 + fe_bytes && (bytes[0] == 0x02 || bytes[0] == 0x03)) {
995 if(
auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes))) {
996 auto [y, is_square] = x3_ax_b(*x).sqrt();
998 if(is_square.as_bool()) {
999 const auto flip_y = y_is_even != y.is_even();
1000 y.conditional_assign(flip_y, y.negate());
1001 return GenericAffinePoint(*x, y);
1004 }
else if(bytes.size() == 1 && bytes[0] == 0x00) {
1006 return GenericAffinePoint::identity(curve);
1015 const GenericField& x()
const {
return m_x; }
1020 const GenericField& y()
const {
return m_y; }
1025 void conditional_assign(CT::Choice cond,
const GenericAffinePoint& pt) {
1026 GenericField::conditional_assign(m_x, m_y, cond, pt.x(), pt.y());
1029 const GenericPrimeOrderCurve* curve()
const {
return m_x.curve(); }
1040class GenericProjectivePoint final {
1042 typedef GenericProjectivePoint Self;
1044 using FieldElement = GenericField;
1049 static Self from_affine(
const GenericAffinePoint& pt) {
1052 auto z = GenericField::one(x.curve());
1055 GenericField::conditional_swap(pt.is_identity(), y, z);
1056 return GenericProjectivePoint(x, y, z);
1062 static Self identity(
const GenericPrimeOrderCurve* curve) {
1063 return Self(GenericField::zero(curve), GenericField::one(curve), GenericField::zero(curve));
1069 explicit GenericProjectivePoint(
const GenericPrimeOrderCurve* curve) :
1070 m_x(GenericField::zero(curve)), m_y(GenericField::one(curve)), m_z(GenericField::zero(curve)) {}
1075 GenericProjectivePoint(
const GenericField& x,
const GenericField& y) :
1076 m_x(x), m_y(y), m_z(GenericField::one(m_x.curve())) {}
1081 GenericProjectivePoint(
const GenericField& x,
const GenericField& y,
const GenericField& z) :
1082 m_x(x), m_y(y), m_z(z) {}
1084 friend Self operator+(
const Self& a,
const Self& b) {
return Self::add(a, b); }
1086 friend Self operator+(
const Self& a,
const GenericAffinePoint& b) {
return Self::add_mixed(a, b); }
1088 friend Self operator+(
const GenericAffinePoint& a,
const Self& b) {
return Self::add_mixed(b, a); }
1090 Self& operator+=(
const Self& other) {
1091 (*this) = (*this) + other;
1095 Self& operator+=(
const GenericAffinePoint& other) {
1096 (*this) = (*this) + other;
1100 CT::Choice is_identity()
const {
return z().is_zero(); }
1105 static Self add_mixed(
const Self& a,
const GenericAffinePoint& b) {
1117 Self dbl_n(
size_t n)
const {
1118 if(curve()->_params().a_is_minus_3()) {
1120 }
else if(curve()->_params().a_is_zero()) {
1123 const auto A = GenericField::curve_a(curve());
1132 if(curve()->_params().a_is_minus_3()) {
1134 }
else if(curve()->_params().a_is_zero()) {
1137 const auto A = GenericField::curve_a(curve());
1145 Self negate()
const {
return Self(x(), y().negate(), z()); }
1153 void randomize_rep(RandomNumberGenerator& rng) {
1157 if(rng.is_seeded()) {
1158 auto r = GenericField::random(curve(), rng);
1160 auto r2 = r.square();
1172 const GenericField& x()
const {
return m_x; }
1177 const GenericField& y()
const {
return m_y; }
1182 const GenericField& z()
const {
return m_z; }
1184 const GenericPrimeOrderCurve* curve()
const {
return m_x.curve(); }
1186 void _const_time_poison()
const {
CT::poison_all(m_x, m_y, m_z); }
1196class GenericCurve final {
1198 typedef GenericField FieldElement;
1199 typedef GenericScalar Scalar;
1200 typedef GenericAffinePoint AffinePoint;
1201 typedef GenericProjectivePoint ProjectivePoint;
1203 typedef word WordType;
1207class GenericBlindedScalarBits final {
1209 GenericBlindedScalarBits(
const GenericScalar& scalar, RandomNumberGenerator& rng,
size_t wb) {
1213 const auto& params = scalar.curve()->_params();
1215 const size_t order_bits = params.order_bits();
1216 const size_t blinder_bits = blinding_bits(order_bits);
1218 const size_t mask_words = blinder_bits / WordInfo<word>::bits;
1219 const size_t mask_bytes = mask_words * WordInfo<word>::bytes;
1221 const size_t words = params.words();
1224 if(rng.is_seeded()) {
1225 rng.randomize(maskb);
1227 auto sbytes = scalar.serialize<std::vector<uint8_t>>();
1228 for(
size_t i = 0; i != sbytes.size(); ++i) {
1229 maskb[i % mask_bytes] ^= sbytes[i];
1233 std::array<word, PrimeOrderCurve::StorageWords> mask{};
1234 load_le(mask.data(), maskb.data(), mask_words);
1235 mask[mask_words - 1] |= WordInfo<word>::top_bit;
1238 std::array<word, 2 * PrimeOrderCurve::StorageWords> mask_n{};
1240 const auto sw = scalar.to_words();
1243 params.mul(mask_n, mask, params.order());
1244 bigint_add2(mask_n.data(), 2 * words, sw.data(), words);
1246 std::reverse(mask_n.begin(), mask_n.end());
1248 m_bits = order_bits + blinder_bits;
1250 m_windows = (order_bits + blinder_bits + wb - 1) / wb;
1253 size_t windows()
const {
return m_windows; }
1255 size_t bits()
const {
return m_bits; }
1257 size_t get_window(
size_t offset)
const {
1258 if(m_window_bits == 3) {
1260 }
else if(m_window_bits == 4) {
1262 }
else if(m_window_bits == 5) {
1269 static size_t blinding_bits(
size_t order_bits) {
1270 if(order_bits > 512) {
1271 return blinding_bits(512);
1274 const size_t wb =
sizeof(
word) * 8;
1275 return ((order_bits / 4 + wb - 1) / wb) * wb;
1279 std::vector<uint8_t> m_bytes;
1282 size_t m_window_bits;
1285class GenericWindowedMul final {
1287 static constexpr size_t WindowBits = VarPointWindowBits;
1288 static constexpr size_t TableSize = (1 << WindowBits) - 1;
1290 explicit GenericWindowedMul(
const GenericAffinePoint& pt) :
1293 GenericProjectivePoint mul(
const GenericScalar& s, RandomNumberGenerator& rng) {
1294 GenericBlindedScalarBits bits(s, rng, WindowBits);
1300 AffinePointTable<GenericCurve> m_table;
1303class GenericBaseMulTable final {
1305 static constexpr size_t WindowBits = BasePointWindowBits;
1307 static constexpr size_t WindowElements = (1 << WindowBits) - 1;
1309 explicit GenericBaseMulTable(
const GenericAffinePoint& pt) :
1310 m_table(
basemul_setup<GenericCurve, WindowBits>(pt, blinded_scalar_bits(*pt.curve()))) {}
1312 GenericProjectivePoint mul(
const GenericScalar& s, RandomNumberGenerator& rng) {
1313 GenericBlindedScalarBits scalar(s, rng, WindowBits);
1318 static size_t blinded_scalar_bits(
const GenericPrimeOrderCurve& curve) {
1319 const size_t order_bits = curve.order_bits();
1320 return order_bits + GenericBlindedScalarBits::blinding_bits(order_bits);
1323 std::vector<GenericAffinePoint> m_table;
1326class GenericWindowedMul2 final {
1328 static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1330 GenericWindowedMul2(
const GenericWindowedMul2& other) =
delete;
1331 GenericWindowedMul2(GenericWindowedMul2&& other) =
delete;
1332 GenericWindowedMul2& operator=(
const GenericWindowedMul2& other) =
delete;
1333 GenericWindowedMul2& operator=(GenericWindowedMul2&& other) =
delete;
1335 ~GenericWindowedMul2() =
default;
1337 GenericWindowedMul2(
const GenericAffinePoint& p,
const GenericAffinePoint& q) :
1338 m_table(
mul2_setup<GenericCurve, WindowBits>(p, q)) {}
1340 GenericProjectivePoint mul2(
const GenericScalar& x,
const GenericScalar& y, RandomNumberGenerator& rng)
const {
1341 GenericBlindedScalarBits x_bits(x, rng, WindowBits);
1342 GenericBlindedScalarBits y_bits(y, rng, WindowBits);
1347 AffinePointTable<GenericCurve> m_table;
1352 static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1354 GenericVartimeWindowedMul2(
const GenericVartimeWindowedMul2& other) =
delete;
1355 GenericVartimeWindowedMul2(GenericVartimeWindowedMul2&& other) =
delete;
1356 GenericVartimeWindowedMul2& operator=(
const GenericVartimeWindowedMul2& other) =
delete;
1357 GenericVartimeWindowedMul2& operator=(GenericVartimeWindowedMul2&& other) =
delete;
1359 ~GenericVartimeWindowedMul2()
override =
default;
1361 GenericVartimeWindowedMul2(
const GenericAffinePoint& p,
const GenericAffinePoint& q) :
1364 GenericProjectivePoint mul2_vartime(
const GenericScalar& x,
const GenericScalar& y)
const {
1365 const auto x_bits = x.serialize<std::vector<uint8_t>>();
1366 const auto y_bits = y.serialize<std::vector<uint8_t>>();
1368 const auto& curve = m_table[0].curve();
1369 auto accum = GenericProjectivePoint(curve);
1371 const size_t order_bits = curve->order_bits();
1373 const size_t windows = (order_bits + WindowBits - 1) / WindowBits;
1375 for(
size_t i = 0; i != windows; ++i) {
1380 accum = accum.dbl_n(WindowBits);
1383 const size_t idx = (y_i << WindowBits) + x_i;
1386 accum += m_table[idx - 1];
1394 std::vector<GenericAffinePoint> m_table;
1399 m_params(std::make_unique<GenericCurveParams>(p, a, b, base_x, base_y, order)) {}
1403 m_basemul = std::make_unique<GenericBaseMulTable>(from_stash(
generator()));
1407 return _params().order_bits();
1411 return _params().order_bytes();
1415 return _params().field_bytes();
1421 return stash(m_basemul->mul(from_stash(scalar), rng));
1427 auto pt_s = m_basemul->mul(from_stash(scalar), rng);
1429 if(
auto s = GenericScalar::from_wide_bytes(
this, x_bytes)) {
1432 throw Internal_Error(
"Failed to convert x coordinate to integer modulo scalar");
1439 GenericWindowedMul pt_table(from_stash(pt));
1440 return stash(pt_table.mul(from_stash(scalar), rng));
1446 GenericWindowedMul pt_table(from_stash(pt));
1447 auto pt_s = pt_table.mul(from_stash(scalar), rng);
1453 return std::make_unique<GenericVartimeWindowedMul2>(from_stash(
generator()), from_stash(q));
1458 const Scalar& s2)
const {
1459 const auto& tbl =
dynamic_cast<const GenericVartimeWindowedMul2&
>(tableb);
1460 auto pt = tbl.mul2_vartime(from_stash(s1), from_stash(s2));
1461 if(pt.is_identity().as_bool()) {
1470 GenericWindowedMul2 table(from_stash(p), from_stash(q));
1471 auto pt = table.mul2(from_stash(x), from_stash(y), rng);
1472 if(pt.is_identity().as_bool()) {
1482 const Scalar& s2)
const {
1483 const auto& tbl =
dynamic_cast<const GenericVartimeWindowedMul2&
>(tableb);
1484 auto pt = tbl.mul2_vartime(from_stash(s1), from_stash(s2));
1486 if(!pt.is_identity().as_bool()) {
1487 const auto z2 = pt.z().square();
1489 const auto v_bytes = from_stash(v).serialize<std::vector<uint8_t>>();
1491 if(
auto fe_v = GenericField::deserialize(
this, v_bytes)) {
1492 if((*fe_v * z2 == pt.x()).as_bool()) {
1496 if(
_params().order_is_less_than_field()) {
1497 const auto n = GenericField::from_words(
this,
_params().order());
1498 const auto neg_n = n.negate().to_words();
1500 const auto vw = fe_v->to_words();
1501 if(
bigint_ct_is_lt(vw.data(), vw.size(), neg_n.data(), neg_n.size()).as_bool()) {
1502 return (((*fe_v + n) * z2) == pt.x()).as_bool();
1518 const auto y2 = affine.y().square();
1519 const auto x3_ax_b = GenericCurve::AffinePoint::x3_ax_b(affine.x());
1520 const auto valid_point = affine.is_identity() || (y2 == x3_ax_b);
1522 BOTAN_ASSERT(valid_point.as_bool(),
"Computed point is on the curve");
1524 return stash(affine);
1528 return stash(GenericProjectivePoint::from_affine(from_stash(a)) + from_stash(b));
1532 return stash(from_stash(pt).negate());
1536 return from_stash(pt).is_identity().as_bool();
1540 from_stash(pt).serialize_to(bytes);
1545 from_stash(scalar).serialize_to(bytes);
1549 std::span<const uint8_t> bytes)
const {
1550 if(
auto s = GenericScalar::deserialize(
this, bytes)) {
1551 return stash(s.value());
1558 std::span<const uint8_t> bytes)
const {
1559 if(
auto s = GenericScalar::from_wide_bytes(
this, bytes)) {
1560 return stash(s.value());
1567 std::span<const uint8_t> bytes)
const {
1568 if(
auto pt = GenericAffinePoint::deserialize(
this, bytes)) {
1569 return stash(pt.value());
1576 return stash(from_stash(a) + from_stash(b));
1580 return stash(from_stash(a) - from_stash(b));
1584 return stash(from_stash(a) * from_stash(b));
1588 return stash(from_stash(s).
square());
1592 return stash(from_stash(s).invert());
1596 return stash(from_stash(s).invert_vartime());
1600 return stash(from_stash(s).negate());
1604 return from_stash(s).is_zero().as_bool();
1608 return (from_stash(a) == from_stash(b)).as_bool();
1612 return stash(GenericScalar::one(
this));
1616 return stash(GenericScalar::random(
this, rng));
1620 return Scalar::_create(shared_from_this(), s.stash_value());
1623GenericScalar GenericPrimeOrderCurve::from_stash(
const PrimeOrderCurve::Scalar& s)
const {
1625 return GenericScalar(
this, s._value());
1628PrimeOrderCurve::AffinePoint GenericPrimeOrderCurve::stash(
const GenericAffinePoint& pt)
const {
1629 auto x_w = pt.x().stash_value();
1630 auto y_w = pt.y().stash_value();
1631 return AffinePoint::_create(shared_from_this(), x_w, y_w);
1636 auto x = GenericField(
this, pt._x());
1637 auto y = GenericField(
this, pt._y());
1638 return GenericAffinePoint(x, y);
1642 auto x_w = pt.x().stash_value();
1643 auto y_w = pt.y().stash_value();
1644 auto z_w = pt.z().stash_value();
1645 return ProjectivePoint::_create(shared_from_this(), x_w, y_w, z_w);
1650 auto x = GenericField(
this, pt._x());
1651 auto y = GenericField(
this, pt._y());
1652 auto z = GenericField(
this, pt._z());
1653 return GenericProjectivePoint(x, y, z);
1657 std::function<
void(std::span<uint8_t>)> expand_message)
const {
1659 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
1663 std::function<
void(std::span<uint8_t>)> expand_message)
const {
1665 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
1668std::shared_ptr<const PrimeOrderCurve> PCurveInstance::from_params(
1678 const size_t p_bits = p.
bits();
1687 if(p_bits != 521 && p_bits != 239 && (p_bits < 128 || p_bits > 512 || p_bits % 32 != 0)) {
1697 if(p_bits != order.
bits()) {
1701 auto gpoc = std::make_shared<GenericPrimeOrderCurve>(p, a, b, base_x, base_y, order);
1711 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 > from_choice(Choice c)
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 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
auto to_affine_batch(std::span< const typename C::ProjectivePoint > projective)
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)
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)
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)
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)
constexpr ProjectivePoint dbl_a_zero(const ProjectivePoint &pt)
C::ProjectivePoint basemul_exec(std::span< const typename C::AffinePoint > table, const BlindedScalar &scalar, RandomNumberGenerator &rng)
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)
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)
constexpr W bigint_cnd_add(W cnd, W x[], const W y[], size_t size)
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 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)
std::vector< typename C::AffinePoint > basemul_setup(const typename C::AffinePoint &p, size_t max_scalar_bits)
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)