7#include <botan/internal/pcurves_generic.h>
9#include <botan/bigint.h>
10#include <botan/exceptn.h>
12#include <botan/internal/barrett.h>
13#include <botan/internal/buffer_stuffer.h>
14#include <botan/internal/ct_utils.h>
15#include <botan/internal/loadstor.h>
16#include <botan/internal/mp_core.h>
17#include <botan/internal/pcurves_algos.h>
18#include <botan/internal/pcurves_instance.h>
19#include <botan/internal/pcurves_mul.h>
20#include <botan/internal/primality.h>
28constexpr std::optional<std::array<word, N>>
bytes_to_words(std::span<const uint8_t> bytes) {
29 if(bytes.size() > WordInfo<word>::bytes * N) {
33 std::array<word, N> r{};
35 const size_t full_words = bytes.size() / WordInfo<word>::bytes;
36 const size_t extra_bytes = bytes.size() % WordInfo<word>::bytes;
38 for(
size_t i = 0; i != full_words; ++i) {
43 const size_t shift = extra_bytes * 8;
46 for(
size_t i = 0; i != extra_bytes; ++i) {
47 const word b0 = bytes[WordInfo<word>::bytes * full_words + i];
48 r[0] |= (b0 << (8 * (extra_bytes - 1 - i)));
56T impl_pow_vartime(
const T& elem,
const T& one,
size_t bits, std::span<const word> exp) {
57 constexpr size_t WindowBits = 4;
58 constexpr size_t WindowElements = (1 << WindowBits) - 1;
60 const size_t Windows = (bits + WindowBits - 1) / WindowBits;
63 tbl.reserve(WindowElements);
67 for(
size_t i = 1; i != WindowElements; ++i) {
69 tbl.push_back(tbl[i / 2].
square());
71 tbl.push_back(tbl[i - 1] * tbl[0]);
83 for(
size_t i = 1; i != Windows; ++i) {
84 for(
size_t j = 0; j != WindowBits; ++j) {
99class GenericCurveParams final {
104 GenericCurveParams(
const BigInt& p,
107 const BigInt& base_x,
108 const BigInt& base_y,
109 const BigInt& order) :
110 m_words(p.sig_words()),
111 m_order_bits(order.bits()),
112 m_order_bytes(order.bytes()),
113 m_field_bits(p.bits()),
114 m_field_bytes(p.bytes()),
115 m_monty_order(order),
117 m_field(bn_to_fixed(p)),
118 m_field_minus_2(bn_to_fixed_rev(p - 2)),
119 m_field_monty_r1(bn_to_fixed(m_monty_field.
R1())),
120 m_field_monty_r2(bn_to_fixed(m_monty_field.
R2())),
121 m_field_p_plus_1_over_4(bn_to_fixed_rev((p + 1) / 4)),
122 m_field_inv_2(bn_to_fixed((p / 2) + 1)),
123 m_field_p_dash(m_monty_field.p_dash()),
125 m_order(bn_to_fixed(order)),
126 m_order_minus_2(bn_to_fixed_rev(order - 2)),
127 m_order_monty_r1(bn_to_fixed(m_monty_order.
R1())),
128 m_order_monty_r2(bn_to_fixed(m_monty_order.
R2())),
129 m_order_monty_r3(bn_to_fixed(m_monty_order.R3())),
130 m_order_inv_2(bn_to_fixed((order / 2) + 1)),
131 m_order_p_dash(m_monty_order.p_dash()),
133 m_a_is_minus_3(a + 3 == p),
134 m_a_is_zero(a.is_zero()),
135 m_order_is_lt_field(order < p) {
137 m_monty_curve_a = bn_to_fixed(m_monty_field.mul(a, m_monty_field.R2(), ws));
138 m_monty_curve_b = bn_to_fixed(m_monty_field.mul(b, m_monty_field.R2(), ws));
140 m_base_x = bn_to_fixed(m_monty_field.mul(base_x, m_monty_field.R2(), ws));
141 m_base_y = bn_to_fixed(m_monty_field.mul(base_y, m_monty_field.R2(), ws));
144 size_t words()
const {
return m_words; }
146 size_t order_bits()
const {
return m_order_bits; }
148 size_t order_bytes()
const {
return m_order_bytes; }
150 size_t field_bits()
const {
return m_field_bits; }
152 size_t field_bytes()
const {
return m_field_bytes; }
154 const Montgomery_Params& monty_order()
const {
return m_monty_order; }
156 const Montgomery_Params& monty_field()
const {
return m_monty_field; }
158 const StorageUnit& field()
const {
return m_field; }
160 const StorageUnit& field_minus_2()
const {
return m_field_minus_2; }
162 const StorageUnit& field_monty_r1()
const {
return m_field_monty_r1; }
164 const StorageUnit& field_monty_r2()
const {
return m_field_monty_r2; }
166 const StorageUnit& field_p_plus_1_over_4()
const {
return m_field_p_plus_1_over_4; }
168 const StorageUnit& field_inv_2()
const {
return m_field_inv_2; }
170 word field_p_dash()
const {
return m_field_p_dash; }
172 const StorageUnit& order()
const {
return m_order; }
174 const StorageUnit& order_minus_2()
const {
return m_order_minus_2; }
176 const StorageUnit& order_monty_r1()
const {
return m_order_monty_r1; }
178 const StorageUnit& order_monty_r2()
const {
return m_order_monty_r2; }
180 const StorageUnit& order_monty_r3()
const {
return m_order_monty_r3; }
182 const StorageUnit& order_inv_2()
const {
return m_order_inv_2; }
184 word order_p_dash()
const {
return m_order_p_dash; }
186 const StorageUnit& monty_curve_a()
const {
return m_monty_curve_a; }
188 const StorageUnit& monty_curve_b()
const {
return m_monty_curve_b; }
190 const StorageUnit& base_x()
const {
return m_base_x; }
192 const StorageUnit& base_y()
const {
return m_base_y; }
194 bool a_is_minus_3()
const {
return m_a_is_minus_3; }
196 bool a_is_zero()
const {
return m_a_is_zero; }
198 bool order_is_less_than_field()
const {
return m_order_is_lt_field; }
200 void mul(std::array<word, 2 * N>& z,
const std::array<word, N>& x,
const std::array<word, N>& y)
const {
205 }
else if(m_words == 6) {
207 }
else if(m_words == 8) {
209 }
else if(m_words == 9) {
212 bigint_mul(z.data(), z.size(), x.data(), m_words, m_words, y.data(), m_words, m_words,
nullptr, 0);
216 void sqr(std::array<word, 2 * N>& z,
const std::array<word, N>& x)
const {
221 }
else if(m_words == 6) {
223 }
else if(m_words == 8) {
225 }
else if(m_words == 9) {
228 bigint_sqr(z.data(), z.size(), x.data(), m_words, m_words,
nullptr, 0);
233 static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed(
const BigInt& n) {
234 const size_t n_words = n.sig_words();
237 std::array<word, PrimeOrderCurve::StorageWords> r{};
238 copy_mem(std::span{r}.first(n_words), n._as_span().first(n_words));
242 static std::array<word, PrimeOrderCurve::StorageWords> bn_to_fixed_rev(
const BigInt& n) {
243 auto v = bn_to_fixed(n);
244 std::reverse(v.begin(), v.end());
251 size_t m_order_bytes;
253 size_t m_field_bytes;
255 Montgomery_Params m_monty_order;
256 Montgomery_Params m_monty_field;
259 StorageUnit m_field_minus_2;
260 StorageUnit m_field_monty_r1;
261 StorageUnit m_field_monty_r2;
262 StorageUnit m_field_p_plus_1_over_4;
263 StorageUnit m_field_inv_2;
267 StorageUnit m_order_minus_2;
268 StorageUnit m_order_monty_r1;
269 StorageUnit m_order_monty_r2;
270 StorageUnit m_order_monty_r3;
271 StorageUnit m_order_inv_2;
274 StorageUnit m_monty_curve_a{};
275 StorageUnit m_monty_curve_b{};
277 StorageUnit m_base_x{};
278 StorageUnit m_base_y{};
282 bool m_order_is_lt_field;
285class GenericScalar final {
291 static std::optional<GenericScalar> from_wide_bytes(
const GenericPrimeOrderCurve* curve,
292 std::span<const uint8_t> bytes) {
293 const size_t mlen = curve->_params().order_bytes();
295 if(bytes.size() > 2 * mlen) {
299 std::array<uint8_t, 2 *
sizeof(
word) * N> padded_bytes{};
300 copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
304 auto in_rep = wide_to_rep(curve, words.value());
305 return GenericScalar(curve, in_rep);
311 static std::optional<GenericScalar> deserialize(
const GenericPrimeOrderCurve* curve,
312 std::span<const uint8_t> bytes) {
313 const size_t len = curve->_params().order_bytes();
315 if(bytes.size() != len) {
322 if(!
bigint_ct_is_lt(words->data(), N, curve->_params().order().data(), N).as_bool()) {
327 return GenericScalar(curve, to_rep(curve, *words));
333 static GenericScalar zero(
const GenericPrimeOrderCurve* curve) {
334 const StorageUnit zeros{};
335 return GenericScalar(curve, zeros);
338 static GenericScalar one(
const GenericPrimeOrderCurve* curve) {
339 return GenericScalar(curve, curve->_params().order_monty_r1());
342 static GenericScalar random(
const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
343 constexpr size_t MAX_ATTEMPTS = 1000;
345 const size_t bits = curve->_params().order_bits();
347 std::vector<uint8_t> buf(curve->_params().order_bytes());
349 for(
size_t i = 0; i != MAX_ATTEMPTS; ++i) {
355 const uint8_t mask = 0xFF >> (8 - (bits % 8));
359 if(
auto s = GenericScalar::deserialize(curve, buf)) {
360 if(s.value().is_nonzero().as_bool()) {
366 throw Internal_Error(
"Failed to generate random Scalar within bounded number of attempts");
369 friend GenericScalar operator+(
const GenericScalar& a,
const GenericScalar& b) {
370 const auto* curve = check_curve(a, b);
371 const size_t words = curve->_params().words();
378 return GenericScalar(curve, r);
381 friend GenericScalar operator-(
const GenericScalar& a,
const GenericScalar& b) {
return a + b.negate(); }
383 friend GenericScalar operator*(
const GenericScalar& a,
const GenericScalar& b) {
384 const auto* curve = check_curve(a, b);
386 std::array<W, 2 * N> z;
387 curve->_params().mul(z, a.value(), b.value());
388 return GenericScalar(curve, redc(curve, z));
391 GenericScalar& operator*=(
const GenericScalar& other) {
392 const auto* curve = check_curve(*
this, other);
394 std::array<W, 2 * N> z;
395 curve->_params().mul(z, value(), other.value());
396 m_val = redc(curve, z);
400 GenericScalar square()
const {
401 const auto* curve = this->m_curve;
403 std::array<W, 2 * N> z;
404 curve->_params().sqr(z, value());
405 return GenericScalar(curve, redc(curve, z));
408 GenericScalar pow_vartime(
const StorageUnit& exp)
const {
409 auto one = GenericScalar::one(curve());
410 auto bits = curve()->_params().order_bits();
411 auto words = curve()->_params().words();
412 return impl_pow_vartime(*
this, one, bits, std::span{exp}.last(words));
415 GenericScalar negate()
const {
419 bigint_sub3(r.data(), m_curve->_params().order().data(), N, this->data(), N);
420 x_is_zero.if_set_zero_out(r.data(), N);
421 return GenericScalar(m_curve, r);
424 GenericScalar invert()
const {
return pow_vartime(m_curve->_params().order_minus_2()); }
433 static void _invert_vartime_div2_helper(GenericScalar& a, GenericScalar& x) {
434 const auto& inv_2 = a.curve()->_params().order_inv_2();
437 while((a.m_val[0] & 1) != 1) {
452 GenericScalar invert_vartime()
const {
453 if(this->is_zero().as_bool()) {
457 auto x = GenericScalar(m_curve, std::array<W, N>{1});
458 auto b = GenericScalar(m_curve, from_rep(m_curve, m_val));
461 GenericScalar::_invert_vartime_div2_helper(b, x);
468 GenericScalar::_invert_vartime_div2_helper(a, y);
472 if(a.m_val == b.m_val) {
477 return GenericScalar(curve(), to_rep(curve(), r.m_val));
491 std::array<W, N> r{};
499 GenericScalar::_invert_vartime_div2_helper(b, x);
505 GenericScalar::_invert_vartime_div2_helper(a, y);
510 template <concepts::resizable_
byte_buffer T>
511 T serialize()
const {
512 T bytes(m_curve->_params().order_bytes());
513 this->serialize_to(bytes);
517 void serialize_to(std::span<uint8_t> bytes)
const {
518 auto v = from_rep(m_curve, m_val);
519 std::reverse(v.begin(), v.end());
521 const size_t flen = m_curve->_params().order_bytes();
522 BOTAN_ARG_CHECK(bytes.size() == flen,
"Expected output span provided");
525 const auto padded_bytes =
store_be(v);
526 const size_t extra = N * WordInfo<W>::bytes - flen;
527 copy_mem(bytes, std::span{padded_bytes}.subspan(extra, flen));
530 CT::Choice is_zero()
const {
return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
532 CT::Choice is_nonzero()
const {
return !is_zero(); }
534 CT::Choice operator==(
const GenericScalar& other)
const {
535 if(this->m_curve != other.m_curve) {
539 return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
545 StorageUnit to_words()
const {
return from_rep(m_curve, m_val); }
547 const StorageUnit& stash_value()
const {
return m_val; }
549 const GenericPrimeOrderCurve* curve()
const {
return m_curve; }
551 GenericScalar(
const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
554 const StorageUnit& value()
const {
return m_val; }
556 const W* data()
const {
return m_val.data(); }
558 static const GenericPrimeOrderCurve* check_curve(
const GenericScalar& a,
const GenericScalar& b) {
563 static StorageUnit redc(
const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> z) {
564 const auto& mod = curve->_params().order();
565 const size_t words = curve->_params().words();
569 r.data(), z.data(), mod.data(), words, curve->_params().order_p_dash(), ws.data(), ws.size());
573 static StorageUnit from_rep(
const GenericPrimeOrderCurve* curve, StorageUnit z) {
574 std::array<W, 2 * N> ze{};
575 copy_mem(std::span{ze}.template first<N>(), z);
576 return redc(curve, ze);
579 static StorageUnit to_rep(
const GenericPrimeOrderCurve* curve, StorageUnit x) {
580 std::array<W, 2 * N> z;
581 curve->_params().mul(z, x, curve->_params().order_monty_r2());
582 return redc(curve, z);
585 static StorageUnit wide_to_rep(
const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> x) {
586 auto redc_x = redc(curve, x);
587 std::array<W, 2 * N> z;
588 curve->_params().mul(z, redc_x, curve->_params().order_monty_r3());
589 return redc(curve, z);
592 const GenericPrimeOrderCurve* m_curve;
598class GenericField final {
604 static std::optional<GenericField> deserialize(
const GenericPrimeOrderCurve* curve,
605 std::span<const uint8_t> bytes) {
606 const size_t len = curve->_params().field_bytes();
608 if(bytes.size() != len) {
615 if(!
bigint_ct_is_lt(words->data(), N, curve->_params().field().data(), N).as_bool()) {
620 return GenericField::from_words(curve, *words);
626 static GenericField from_words(
const GenericPrimeOrderCurve* curve,
const std::array<word, N>& words) {
627 return GenericField(curve, to_rep(curve, words));
630 static GenericField zero(
const GenericPrimeOrderCurve* curve) {
631 const StorageUnit zeros{};
632 return GenericField(curve, zeros);
635 static GenericField one(
const GenericPrimeOrderCurve* curve) {
636 return GenericField(curve, curve->_params().field_monty_r1());
639 static GenericField curve_a(
const GenericPrimeOrderCurve* curve) {
640 return GenericField(curve, curve->_params().monty_curve_a());
643 static GenericField curve_b(
const GenericPrimeOrderCurve* curve) {
644 return GenericField(curve, curve->_params().monty_curve_b());
647 static GenericField random(
const GenericPrimeOrderCurve* curve, RandomNumberGenerator& rng) {
648 constexpr size_t MAX_ATTEMPTS = 1000;
650 const size_t bits = curve->_params().field_bits();
652 std::vector<uint8_t> buf(curve->_params().field_bytes());
654 for(
size_t i = 0; i != MAX_ATTEMPTS; ++i) {
660 const uint8_t mask = 0xFF >> (8 - (bits % 8));
664 if(
auto s = GenericField::deserialize(curve, buf)) {
665 if(s.value().is_nonzero().as_bool()) {
671 throw Internal_Error(
"Failed to generate random Scalar within bounded number of attempts");
677 GenericField div2()
const {
678 StorageUnit t = value();
682 bigint_cnd_add(borrow, t.data(), m_curve->_params().field_inv_2().data(), N);
684 return GenericField(m_curve, t);
688 GenericField mul2()
const {
689 StorageUnit t = value();
694 return GenericField(m_curve, r);
698 GenericField mul3()
const {
return mul2() + (*this); }
701 GenericField mul4()
const {
return mul2().mul2(); }
704 GenericField mul8()
const {
return mul2().mul2().mul2(); }
706 friend GenericField
operator+(
const GenericField& a,
const GenericField& b) {
707 const auto* curve = check_curve(a, b);
708 const size_t words = curve->_params().words();
715 return GenericField(curve, r);
718 friend GenericField
operator-(
const GenericField& a,
const GenericField& b) {
return a + b.negate(); }
720 friend GenericField
operator*(
const GenericField& a,
const GenericField& b) {
721 const auto* curve = check_curve(a, b);
723 std::array<W, 2 * N> z;
724 curve->_params().mul(z, a.value(), b.value());
725 return GenericField(curve, redc(curve, z));
728 GenericField&
operator*=(
const GenericField& other) {
729 const auto* curve = check_curve(*
this, other);
731 std::array<W, 2 * N> z;
732 curve->_params().mul(z, value(), other.value());
733 m_val = redc(curve, z);
737 GenericField
square()
const {
738 std::array<W, 2 * N> z;
739 m_curve->_params().sqr(z, value());
740 return GenericField(m_curve, redc(m_curve, z));
743 GenericField pow_vartime(
const StorageUnit& exp)
const {
744 auto one = GenericField::one(curve());
745 auto bits = curve()->_params().field_bits();
746 auto words = curve()->_params().words();
747 return impl_pow_vartime(*
this, one, bits, std::span{exp}.last(words));
750 GenericField negate()
const {
754 bigint_sub3(r.data(), m_curve->_params().field().data(), N, this->data(), N);
755 x_is_zero.if_set_zero_out(r.data(), N);
756 return GenericField(m_curve, r);
759 GenericField invert()
const {
return pow_vartime(m_curve->_params().field_minus_2()); }
761 GenericField invert_vartime()
const {
767 template <concepts::resizable_
byte_buffer T>
768 T serialize()
const {
769 T bytes(m_curve->_params().field_bytes());
774 void serialize_to(std::span<uint8_t> bytes)
const {
775 auto v = from_rep(m_curve, m_val);
776 std::reverse(v.begin(), v.end());
778 const size_t flen = m_curve->_params().field_bytes();
779 BOTAN_ARG_CHECK(bytes.size() == flen,
"Expected output span provided");
782 const auto padded_bytes =
store_be(v);
783 const size_t extra = N * WordInfo<W>::bytes - flen;
784 copy_mem(bytes, std::span{padded_bytes}.subspan(extra, flen));
787 CT::Choice is_zero()
const {
return CT::all_zeros(m_val.data(), m_curve->_params().words()).as_choice(); }
789 CT::Choice is_nonzero()
const {
return !is_zero(); }
791 CT::Choice
operator==(
const GenericField& other)
const {
792 if(this->m_curve != other.m_curve) {
796 return CT::is_equal(m_val.data(), other.m_val.data(), m_curve->_params().words()).as_choice();
799 const StorageUnit& stash_value()
const {
return m_val; }
801 const GenericPrimeOrderCurve* curve()
const {
return m_curve; }
803 CT::Choice is_even()
const {
804 auto v = from_rep(m_curve, m_val);
811 StorageUnit to_words()
const {
return from_rep(m_curve, m_val); }
813 void _const_time_poison()
const {
CT::poison(m_val); }
815 void _const_time_unpoison()
const {
CT::unpoison(m_val); }
817 static void conditional_swap(CT::Choice cond, GenericField& x, GenericField& y) {
818 const W mask = cond.into_bitmask<W>();
820 for(
size_t i = 0; i != N; ++i) {
821 auto nx =
choose(mask, y.m_val[i], x.m_val[i]);
822 auto ny =
choose(mask, x.m_val[i], y.m_val[i]);
828 void conditional_assign(CT::Choice cond,
const GenericField& nx) {
829 const W mask = cond.into_bitmask<W>();
831 for(
size_t i = 0; i != N; ++i) {
832 m_val[i] =
choose(mask, nx.m_val[i], m_val[i]);
841 static void conditional_assign(
842 GenericField& x, GenericField& y, CT::Choice cond,
const GenericField& nx,
const GenericField& ny) {
843 const W mask = cond.into_bitmask<W>();
845 for(
size_t i = 0; i != N; ++i) {
846 x.m_val[i] =
choose(mask, nx.m_val[i], x.m_val[i]);
847 y.m_val[i] =
choose(mask, ny.m_val[i], y.m_val[i]);
856 static void conditional_assign(GenericField& x,
860 const GenericField& nx,
861 const GenericField& ny,
862 const GenericField& nz) {
863 const W mask = cond.into_bitmask<W>();
865 for(
size_t i = 0; i != N; ++i) {
866 x.m_val[i] =
choose(mask, nx.m_val[i], x.m_val[i]);
867 y.m_val[i] =
choose(mask, ny.m_val[i], y.m_val[i]);
868 z.m_val[i] =
choose(mask, nz.m_val[i], z.m_val[i]);
872 std::pair<GenericField, CT::Choice> sqrt()
const {
875 auto z = pow_vartime(m_curve->_params().field_p_plus_1_over_4());
876 const CT::Choice correct = (z.square() == *
this);
878 z.conditional_assign(!correct, zero(m_curve));
882 GenericField(
const GenericPrimeOrderCurve* curve, StorageUnit val) : m_curve(curve), m_val(val) {}
885 const StorageUnit& value()
const {
return m_val; }
887 const W* data()
const {
return m_val.data(); }
889 static const GenericPrimeOrderCurve* check_curve(
const GenericField& a,
const GenericField& b) {
894 static StorageUnit redc(
const GenericPrimeOrderCurve* curve, std::array<W, 2 * N> z) {
895 const auto& mod = curve->_params().field();
896 const size_t words = curve->_params().words();
900 r.data(), z.data(), mod.data(), words, curve->_params().field_p_dash(), ws.data(), ws.size());
904 static StorageUnit from_rep(
const GenericPrimeOrderCurve* curve, StorageUnit z) {
905 std::array<W, 2 * N> ze{};
906 copy_mem(std::span{ze}.template first<N>(), z);
907 return redc(curve, ze);
910 static StorageUnit to_rep(
const GenericPrimeOrderCurve* curve, StorageUnit x) {
911 std::array<W, 2 * N> z{};
912 curve->_params().mul(z, x, curve->_params().field_monty_r2());
913 return redc(curve, z);
916 const GenericPrimeOrderCurve* m_curve;
927class GenericAffinePoint final {
929 GenericAffinePoint(
const GenericField& x,
const GenericField& y) : m_x(x), m_y(y) {}
931 explicit GenericAffinePoint(
const GenericPrimeOrderCurve* curve) :
932 m_x(GenericField::zero(curve)), m_y(GenericField::zero(curve)) {}
934 static GenericAffinePoint identity(
const GenericPrimeOrderCurve* curve) {
935 return GenericAffinePoint(GenericField::zero(curve), GenericField::zero(curve));
938 static GenericAffinePoint identity(
const GenericAffinePoint& pt) {
return identity(pt.curve()); }
940 CT::Choice is_identity()
const {
return x().is_zero() && y().is_zero(); }
942 GenericAffinePoint negate()
const {
return GenericAffinePoint(x(), y().negate()); }
947 void serialize_to(std::span<uint8_t> bytes)
const {
948 const size_t fe_bytes = curve()->_params().field_bytes();
949 BOTAN_ARG_CHECK(bytes.size() == 1 + 2 * fe_bytes,
"Buffer size incorrect");
951 BufferStuffer
pack(bytes);
953 x().serialize_to(
pack.next(fe_bytes));
954 y().serialize_to(
pack.next(fe_bytes));
963 static auto ct_select(std::span<const GenericAffinePoint> pts,
size_t idx) {
965 auto result = GenericAffinePoint::identity(pts[0].curve());
968 const size_t idx1 =
static_cast<size_t>(idx - 1);
969 for(
size_t i = 0; i != pts.size(); ++i) {
971 result.conditional_assign(found, pts[i]);
980 static GenericField x3_ax_b(
const GenericField& x) {
981 return (x.square() + GenericField::curve_a(x.curve())) * x + GenericField::curve_b(x.curve());
987 static std::optional<GenericAffinePoint> deserialize_uncompressed(
const GenericPrimeOrderCurve* curve,
988 std::span<const uint8_t> bytes) {
989 const size_t fe_bytes = curve->_params().field_bytes();
991 if(bytes.size() == 1 + 2 * fe_bytes && bytes[0] == 0x04) {
992 auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes));
993 auto y = GenericField::deserialize(curve, bytes.subspan(1 + fe_bytes, fe_bytes));
996 const auto lhs = (*y).square();
997 const auto rhs = GenericAffinePoint::x3_ax_b(*x);
998 if((lhs == rhs).as_bool()) {
999 return GenericAffinePoint(*x, *y);
1010 static std::optional<GenericAffinePoint> deserialize_compressed(
const GenericPrimeOrderCurve* curve,
1011 std::span<const uint8_t> bytes) {
1012 const size_t fe_bytes = curve->_params().field_bytes();
1014 if(bytes.size() == 1 + fe_bytes && (bytes[0] == 0x02 || bytes[0] == 0x03)) {
1017 if(
auto x = GenericField::deserialize(curve, bytes.subspan(1, fe_bytes))) {
1018 auto [y, is_square] = x3_ax_b(*x).sqrt();
1020 if(is_square.as_bool()) {
1021 const auto flip_y = y_is_even != y.is_even();
1022 y.conditional_assign(flip_y, y.negate());
1023 return GenericAffinePoint(*x, y);
1034 const GenericField& x()
const {
return m_x; }
1039 const GenericField& y()
const {
return m_y; }
1044 void conditional_assign(CT::Choice cond,
const GenericAffinePoint& pt) {
1045 GenericField::conditional_assign(m_x, m_y, cond, pt.x(), pt.y());
1048 const GenericPrimeOrderCurve* curve()
const {
return m_x.curve(); }
1059class GenericProjectivePoint final {
1061 typedef GenericProjectivePoint Self;
1063 using FieldElement = GenericField;
1068 static Self from_affine(
const GenericAffinePoint& pt) {
1071 auto z = GenericField::one(x.curve());
1074 GenericField::conditional_swap(pt.is_identity(), y, z);
1075 return GenericProjectivePoint(x, y, z);
1081 static Self identity(
const GenericPrimeOrderCurve* curve) {
1082 return Self(GenericField::zero(curve), GenericField::one(curve), GenericField::zero(curve));
1088 explicit GenericProjectivePoint(
const GenericPrimeOrderCurve* curve) :
1089 m_x(GenericField::zero(curve)), m_y(GenericField::one(curve)), m_z(GenericField::zero(curve)) {}
1094 GenericProjectivePoint(
const GenericField& x,
const GenericField& y) :
1095 m_x(x), m_y(y), m_z(GenericField::one(m_x.curve())) {}
1100 GenericProjectivePoint(
const GenericField& x,
const GenericField& y,
const GenericField& z) :
1101 m_x(x), m_y(y), m_z(z) {}
1103 friend Self operator+(
const Self& a,
const Self& b) {
return Self::add(a, b); }
1105 friend Self operator+(
const Self& a,
const GenericAffinePoint& b) {
return Self::add_mixed(a, b); }
1107 friend Self operator+(
const GenericAffinePoint& a,
const Self& b) {
return Self::add_mixed(b, a); }
1109 Self& operator+=(
const Self& other) {
1110 (*this) = (*this) + other;
1114 Self& operator+=(
const GenericAffinePoint& other) {
1115 (*this) = (*this) + other;
1119 CT::Choice is_identity()
const {
return z().is_zero(); }
1121 void conditional_assign(CT::Choice cond,
const Self& pt) {
1122 GenericField::conditional_assign(m_x, m_y, m_z, cond, pt.x(), pt.y(), pt.z());
1128 static Self add_mixed(
const Self& a,
const GenericAffinePoint& b) {
1132 static Self add_or_sub(
const Self& a,
const GenericAffinePoint& b, CT::Choice sub) {
1144 Self dbl_n(
size_t n)
const {
1145 if(curve()->_params().a_is_minus_3()) {
1147 }
else if(curve()->_params().a_is_zero()) {
1150 const auto A = GenericField::curve_a(curve());
1159 if(curve()->_params().a_is_minus_3()) {
1161 }
else if(curve()->_params().a_is_zero()) {
1164 const auto A = GenericField::curve_a(curve());
1172 Self negate()
const {
return Self(x(), y().negate(), z()); }
1180 void randomize_rep(RandomNumberGenerator& rng) {
1184 if(rng.is_seeded()) {
1185 auto r = GenericField::random(curve(), rng);
1187 auto r2 = r.square();
1199 const GenericField& x()
const {
return m_x; }
1204 const GenericField& y()
const {
return m_y; }
1209 const GenericField& z()
const {
return m_z; }
1211 const GenericPrimeOrderCurve* curve()
const {
return m_x.curve(); }
1213 void _const_time_poison()
const {
CT::poison_all(m_x, m_y, m_z); }
1225class GenericCurve final {
1227 typedef GenericField FieldElement;
1228 typedef GenericScalar Scalar;
1229 typedef GenericAffinePoint AffinePoint;
1230 typedef GenericProjectivePoint ProjectivePoint;
1232 typedef word WordType;
1235class GenericBlindedScalarBits final {
1237 GenericBlindedScalarBits(
const GenericScalar& scalar, RandomNumberGenerator& rng,
size_t wb) {
1238 BOTAN_ASSERT_NOMSG(wb == 1 || wb == 2 || wb == 3 || wb == 4 || wb == 5 || wb == 6 || wb == 7);
1240 const auto& params = scalar.curve()->_params();
1242 const size_t order_bits = params.order_bits();
1247 if(blinder_bits > 0 && rng.is_seeded()) {
1248 const size_t mask_words = (blinder_bits + WordInfo<word>::bits - 1) / WordInfo<word>::bits;
1249 const size_t mask_bytes = mask_words * WordInfo<word>::bytes;
1251 const size_t words = params.words();
1254 rng.randomize(maskb);
1256 std::array<word, PrimeOrderCurve::StorageWords> mask{};
1257 load_le(mask.data(), maskb.data(), mask_words);
1260 const size_t excess = mask_words * WordInfo<word>::bits - blinder_bits;
1262 mask[mask_words - 1] &= (
static_cast<word>(1) << (WordInfo<word>::bits - excess)) - 1;
1264 const size_t msb_pos = (blinder_bits - 1) % WordInfo<word>::bits;
1265 mask[(blinder_bits - 1) / WordInfo<word>::bits] |=
static_cast<word>(1) << msb_pos;
1268 std::array<word, 2 * PrimeOrderCurve::StorageWords> mask_n{};
1270 const auto sw = scalar.to_words();
1273 params.mul(mask_n, mask, params.order());
1274 bigint_add2(mask_n.data(), 2 * words, sw.data(), words);
1276 std::reverse(mask_n.begin(), mask_n.end());
1278 m_bits = order_bits + blinder_bits;
1281 m_bytes = scalar.serialize<std::vector<uint8_t>>();
1282 m_bits = order_bits;
1285 m_windows = (m_bits + wb - 1) / wb;
1288 size_t windows()
const {
return m_windows; }
1290 size_t bits()
const {
return m_bits; }
1292 size_t get_window(
size_t offset)
const {
1293 if(m_window_bits == 1) {
1295 }
else if(m_window_bits == 2) {
1297 }
else if(m_window_bits == 3) {
1299 }
else if(m_window_bits == 4) {
1301 }
else if(m_window_bits == 5) {
1303 }
else if(m_window_bits == 6) {
1305 }
else if(m_window_bits == 7) {
1313 std::vector<uint8_t> m_bytes;
1316 size_t m_window_bits;
1319class GenericWindowedMul final {
1321 static constexpr size_t WindowBits = VarPointWindowBits;
1322 static constexpr size_t TableSize = (1 << WindowBits) - 1;
1324 explicit GenericWindowedMul(
const GenericAffinePoint& pt) :
1327 GenericProjectivePoint mul(
const GenericScalar& s, RandomNumberGenerator& rng) {
1328 const GenericBlindedScalarBits bits(s, rng, WindowBits);
1334 AffinePointTable<GenericCurve> m_table;
1339class GenericBaseMulTable final {
1341 static constexpr size_t WindowBits = BasePointWindowBits;
1344 explicit GenericBaseMulTable(
const GenericAffinePoint& pt) :
1345 m_table(
basemul_booth_setup<GenericCurve, WindowBits>(pt, blinded_scalar_bits(*pt.curve()) + 1)) {}
1347 GenericProjectivePoint mul(
const GenericScalar& s, RandomNumberGenerator& rng) {
1349 const GenericBlindedScalarBits scalar(s, rng, WindowBits + 1);
1354 static size_t blinded_scalar_bits(
const GenericPrimeOrderCurve& curve) {
1355 const size_t order_bits = curve.order_bits();
1359 std::vector<GenericAffinePoint> m_table;
1364class GenericWindowedMul2 final {
1366 static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1368 GenericWindowedMul2(
const GenericWindowedMul2& other) =
delete;
1369 GenericWindowedMul2(GenericWindowedMul2&& other) =
delete;
1370 GenericWindowedMul2& operator=(
const GenericWindowedMul2& other) =
delete;
1371 GenericWindowedMul2& operator=(GenericWindowedMul2&& other) =
delete;
1373 ~GenericWindowedMul2() =
default;
1375 GenericWindowedMul2(
const GenericAffinePoint& p,
const GenericAffinePoint& q) :
1376 m_table(
mul2_setup<GenericCurve, WindowBits>(p, q)) {}
1378 GenericProjectivePoint mul2(
const GenericScalar& x,
const GenericScalar& y, RandomNumberGenerator& rng)
const {
1379 const GenericBlindedScalarBits x_bits(x, rng, WindowBits);
1380 const GenericBlindedScalarBits y_bits(y, rng, WindowBits);
1385 AffinePointTable<GenericCurve> m_table;
1390 static constexpr size_t WindowBits = Mul2PrecompWindowBits;
1392 GenericVartimeWindowedMul2(
const GenericVartimeWindowedMul2& other) =
delete;
1393 GenericVartimeWindowedMul2(GenericVartimeWindowedMul2&& other) =
delete;
1394 GenericVartimeWindowedMul2& operator=(
const GenericVartimeWindowedMul2& other) =
delete;
1395 GenericVartimeWindowedMul2& operator=(GenericVartimeWindowedMul2&& other) =
delete;
1397 ~GenericVartimeWindowedMul2()
override =
default;
1399 GenericVartimeWindowedMul2(
const GenericAffinePoint& p,
const GenericAffinePoint& q) :
1402 GenericProjectivePoint mul2_vartime(
const GenericScalar& x,
const GenericScalar& y)
const {
1403 const auto x_bits = x.serialize<std::vector<uint8_t>>();
1404 const auto y_bits = y.serialize<std::vector<uint8_t>>();
1406 const auto& curve = m_table[0].curve();
1407 auto accum = GenericProjectivePoint(curve);
1409 const size_t order_bits = curve->order_bits();
1411 const size_t windows = (order_bits + WindowBits - 1) / WindowBits;
1413 for(
size_t i = 0; i != windows; ++i) {
1418 accum = accum.dbl_n(WindowBits);
1421 const size_t idx = (y_i << WindowBits) + x_i;
1424 accum += m_table[idx - 1];
1432 std::vector<GenericAffinePoint> m_table;
1439 m_params(std::make_unique<GenericCurveParams>(p, a, b, base_x, base_y, order)) {}
1443 m_basemul = std::make_unique<GenericBaseMulTable>(from_stash(
generator()));
1447 return _params().order_bits();
1451 return _params().order_bytes();
1455 return _params().field_bytes();
1461 return stash(m_basemul->mul(from_stash(scalar), rng));
1467 auto pt_s = m_basemul->mul(from_stash(scalar), rng);
1470 if(
auto s = GenericScalar::from_wide_bytes(
this, x_bytes)) {
1473 throw Internal_Error(
"Failed to convert x coordinate to integer modulo scalar");
1480 GenericWindowedMul pt_table(from_stash(pt));
1481 return stash(pt_table.mul(from_stash(scalar), rng));
1487 GenericWindowedMul pt_table(from_stash(pt));
1488 auto pt_s = pt_table.mul(from_stash(scalar), rng);
1495 return std::make_unique<GenericVartimeWindowedMul2>(from_stash(
generator()), from_stash(q));
1500 const Scalar& s2)
const {
1501 const auto& tbl =
dynamic_cast<const GenericVartimeWindowedMul2&
>(tableb);
1502 auto pt = tbl.mul2_vartime(from_stash(s1), from_stash(s2));
1503 if(pt.is_identity().as_bool()) {
1512 const GenericWindowedMul2 table(from_stash(p), from_stash(q));
1513 auto pt = table.mul2(from_stash(x), from_stash(y), rng);
1514 if(pt.is_identity().as_bool()) {
1524 const Scalar& s2)
const {
1525 const auto& tbl =
dynamic_cast<const GenericVartimeWindowedMul2&
>(tableb);
1526 auto pt = tbl.mul2_vartime(from_stash(s1), from_stash(s2));
1528 if(!pt.is_identity().as_bool()) {
1529 const auto z2 = pt.z().square();
1531 const auto v_bytes = from_stash(v).serialize<std::vector<uint8_t>>();
1533 if(
auto fe_v = GenericField::deserialize(
this, v_bytes)) {
1534 if((*fe_v * z2 == pt.x()).as_bool()) {
1538 if(
_params().order_is_less_than_field()) {
1539 const auto n = GenericField::from_words(
this,
_params().order());
1540 const auto neg_n = n.negate().to_words();
1542 const auto vw = fe_v->to_words();
1543 if(
bigint_ct_is_lt(vw.data(), vw.size(), neg_n.data(), neg_n.size()).as_bool()) {
1544 return (((*fe_v + n) * z2) == pt.x()).as_bool();
1558 return stash(GenericAffinePoint::identity(
this));
1564 const auto y2 = affine.y().square();
1565 const auto x3_ax_b = GenericCurve::AffinePoint::x3_ax_b(affine.x());
1566 const auto valid_point = affine.is_identity() || (y2 == x3_ax_b);
1568 BOTAN_ASSERT(valid_point.as_bool(),
"Computed point is on the curve");
1570 return stash(affine);
1574 return stash(GenericProjectivePoint::from_affine(from_stash(a)) + from_stash(b));
1578 return stash(from_stash(pt).negate());
1582 return from_stash(pt).is_identity().as_bool();
1586 from_stash(pt).serialize_to(bytes);
1591 from_stash(scalar).serialize_to(bytes);
1595 std::span<const uint8_t> bytes)
const {
1596 if(
auto s = GenericScalar::deserialize(
this, bytes)) {
1597 if(s->is_nonzero().as_bool()) {
1598 return stash(s.value());
1606 std::span<const uint8_t> bytes)
const {
1607 if(
auto s = GenericScalar::from_wide_bytes(
this, bytes)) {
1608 return stash(s.value());
1615 std::span<const uint8_t> bytes)
const {
1616 if(
auto pt = GenericAffinePoint::deserialize_uncompressed(
this, bytes)) {
1617 return stash(pt.value());
1624 std::span<const uint8_t> bytes)
const {
1625 if(
auto pt = GenericAffinePoint::deserialize_compressed(
this, bytes)) {
1626 return stash(pt.value());
1633 return stash(from_stash(a) + from_stash(b));
1637 return stash(from_stash(a) - from_stash(b));
1641 return stash(from_stash(a) * from_stash(b));
1645 return stash(from_stash(s).
square());
1649 return stash(from_stash(s).invert());
1653 return stash(from_stash(s).invert_vartime());
1657 return stash(from_stash(s).negate());
1661 return from_stash(s).is_zero().as_bool();
1665 return (from_stash(a) == from_stash(b)).as_bool();
1669 return stash(GenericScalar::one(
this));
1673 return stash(GenericScalar::random(
this, rng));
1677 return Scalar::_create(shared_from_this(), s.stash_value());
1680GenericScalar GenericPrimeOrderCurve::from_stash(
const PrimeOrderCurve::Scalar& s)
const {
1682 return GenericScalar(
this, s._value());
1685PrimeOrderCurve::AffinePoint GenericPrimeOrderCurve::stash(
const GenericAffinePoint& pt)
const {
1686 auto x_w = pt.x().stash_value();
1687 auto y_w = pt.y().stash_value();
1688 return AffinePoint::_create(shared_from_this(), x_w, y_w);
1693 auto x = GenericField(
this, pt._x());
1694 auto y = GenericField(
this, pt._y());
1695 return GenericAffinePoint(x, y);
1699 auto x_w = pt.x().stash_value();
1700 auto y_w = pt.y().stash_value();
1701 auto z_w = pt.z().stash_value();
1702 return ProjectivePoint::_create(shared_from_this(), x_w, y_w, z_w);
1707 auto x = GenericField(
this, pt._x());
1708 auto y = GenericField(
this, pt._y());
1709 auto z = GenericField(
this, pt._z());
1710 return GenericProjectivePoint(x, y, z);
1718 std::function<
void(std::span<uint8_t>)> expand_message)
const {
1720 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
1724 std::function<
void(std::span<uint8_t>)> expand_message)
const {
1726 throw Not_Implemented(
"Hash to curve is not implemented for this curve");
1729std::shared_ptr<const PrimeOrderCurve> PCurveInstance::from_params(
1739 const size_t p_bits = p.
bits();
1748 if(p_bits != 521 && p_bits != 239 && (p_bits < 128 || p_bits > 512 || p_bits % 32 != 0)) {
1758 if(p_bits != order.
bits()) {
1764 const BigInt y2 = mod_p.square(base_y);
1765 const BigInt x3_ax_b = mod_p.reduce(mod_p.cube(base_x) + mod_p.multiply(a, base_x) + b);
1770 auto gpoc = std::make_shared<GenericPrimeOrderCurve>(p, a, b, base_x, base_y, order);
1780 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 Barrett_Reduction for_public_modulus(const BigInt &m)
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< ProjectivePoint > mul2_vartime(const PrecomputedMul2Table &tableb, const Scalar &x, const Scalar &y) const override
std::optional< AffinePoint > deserialize_point_compressed(std::span< const uint8_t > bytes) 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
bool supports_hash_to_curve() const override
AffinePoint point_identity() const override
Return the identity element (aka the point at infinity).
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.
std::optional< AffinePoint > deserialize_point_uncompressed(std::span< const uint8_t > bytes) const override
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 CT::Mask< T > is_equal(const T x[], const T y[], size_t len)
constexpr void unpoison_all(const Ts &... ts)
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 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)
constexpr void copy_mem(T *out, const T *in, size_t n)
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)
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)
bool operator==(const AlgorithmIdentifier &x, const AlgorithmIdentifier &y)
constexpr ProjectivePoint point_add(const ProjectivePoint &a, const ProjectivePoint &b)
constexpr auto operator*=(Strong< T1, Tags... > &a, T2 b)
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
The native machine word, used as the limb type for multiprecision integers.
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)