7#ifndef BOTAN_PCURVES_IMPL_H_
8#define BOTAN_PCURVES_IMPL_H_
11#include <botan/internal/ct_utils.h>
12#include <botan/internal/loadstor.h>
13#include <botan/internal/pcurves_util.h>
14#include <botan/internal/stl_util.h>
15#include <botan/internal/xmd.h>
20template <
typename Params>
25 static constexpr auto P = Params::P;
26 static constexpr size_t N = Params::N;
27 typedef typename Params::W
W;
29 static_assert(
N > 0 && (Params::P[0] & 1) == 1,
"Invalid Montgomery modulus");
33 static constexpr auto R1 = montygomery_r(
P);
34 static constexpr auto R2 = mul_mod(
R1,
R1,
P);
35 static constexpr auto R3 = mul_mod(
R1,
R2,
P);
37 constexpr static std::array<W, N>
one() {
return R1; }
39 constexpr static std::array<W, N>
redc(
const std::array<W, 2 * N>& z) {
40 if constexpr(
P_dash == 1) {
41 return monty_redc_pdash1(z,
P);
43 return monty_redc(z,
P,
P_dash);
47 constexpr static std::array<W, N>
to_rep(
const std::array<W, N>& x) {
48 std::array<W, 2 * N> z;
53 constexpr static std::array<W, N>
wide_to_rep(
const std::array<W, 2 * N>& x) {
55 std::array<W, 2 * N> z;
60 constexpr static std::array<W, N>
from_rep(
const std::array<W, N>& z) {
61 std::array<W, 2 * N> ze = {};
62 copy_mem(std::span{ze}.template first<N>(), z);
67template <
typename Rep>
70 static constexpr auto P = Rep::P;
71 static constexpr size_t N = Rep::N;
72 typedef typename Rep::W W;
74 static constexpr auto P_MINUS_2 = p_minus<2>(P);
75 static constexpr auto P_PLUS_1_OVER_4 = p_plus_1_over_4(P);
76 static constexpr auto P_MINUS_1_OVER_2 = p_minus_1_over_2(P);
79 static constexpr size_t BITS = count_bits(P);
99 std::array<W, 1> v{x};
105 if constexpr(L == N) {
106 return Self(Rep::to_rep(w));
108 static_assert(L < N);
109 std::array<W, N> ew = {};
110 copy_mem(std::span{ew}.template first<L>(), w);
111 return Self(Rep::to_rep(ew));
122 auto v = Rep::from_rep(m_val);
139 std::array<W, N> t = value();
157 std::array<W, 2 * N> z;
159 return Self(Rep::redc(z));
163 std::array<W, 2 * N> z;
165 m_val = Rep::redc(z);
175 std::array<W, 2 * N> z;
177 return Self(Rep::redc(z));
185 bigint_sub3(r.data(), P.data(), N, this->data(), N);
186 x_is_zero.if_set_zero_out(r.data(), N);
191 constexpr size_t WindowBits = (
Self::BITS <= 256) ? 4 : 5;
192 constexpr size_t WindowElements = (1 << WindowBits) - 1;
194 constexpr size_t Windows = (
Self::BITS + WindowBits - 1) / WindowBits;
196 std::array<Self, WindowElements> tbl;
200 for(
size_t i = 1; i != WindowElements; ++i) {
202 tbl[i] = tbl[i / 2].square();
204 tbl[i] = tbl[i - 1] * tbl[0];
210 const size_t w0 = read_window_bits<WindowBits>(std::span{exp}, (Windows - 1) * WindowBits);
216 for(
size_t i = 1; i != Windows; ++i) {
217 for(
size_t j = 0; j != WindowBits; ++j) {
221 const size_t w = read_window_bits<WindowBits>(std::span{exp}, (Windows - i - 1) * WindowBits);
249 const CT::Choice correct = (z.square() == *
this);
264 return CT::is_equal(this->data(), other.data(), N).as_choice();
271 constexpr std::array<W, Self::N>
to_words()
const {
return Rep::from_rep(m_val); }
273 constexpr void serialize_to(std::span<uint8_t, Self::BYTES> bytes)
const {
274 auto v = Rep::from_rep(m_val);
275 std::reverse(v.begin(), v.end());
281 const auto padded_bytes =
store_be(v);
283 copy_mem(bytes, std::span{padded_bytes}.template subspan<extra, Self::BYTES>());
289 static_assert(L >= N);
290 std::array<W, L> stash = {};
291 for(
size_t i = 0; i != N; ++i) {
299 static_assert(L >= N);
300 std::array<W, N> val = {};
301 for(
size_t i = 0; i != N; ++i) {
308 constexpr static std::optional<Self>
deserialize(std::span<const uint8_t> bytes) {
316 const auto words = bytes_to_words<W, N, BYTES>(bytes.first<
Self::BYTES>());
329 const size_t bit_length = bytes.size() * 8;
333 std::array<uint8_t, 2 * BYTES> padded_bytes = {};
334 copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
335 return Self(Rep::wide_to_rep(bytes_to_words<W, 2 * N, 2 * BYTES>(std::span{padded_bytes})));
341 const size_t new_length = bytes.size() - (shift / 8);
345 throw Not_Implemented(
"Bit shifting for hash to scalar conversion not implemented");
354 std::array<uint8_t, 2 * BYTES> padded_bytes = {};
355 copy_mem(std::span{padded_bytes}.template last<L>(), bytes);
356 return Self(Rep::wide_to_rep(bytes_to_words<W, 2 * N, 2 * BYTES>(std::span{padded_bytes})));
364 std::array<uint8_t, 2 * BYTES> padded_bytes = {};
365 copy_mem(std::span{padded_bytes}.last(bytes.size()), bytes);
366 return Self(Rep::wide_to_rep(bytes_to_words<W, 2 * N, 2 * BYTES>(std::span{padded_bytes})));
370 constexpr size_t MAX_ATTEMPTS = 1000;
372 std::array<uint8_t, Self::BYTES> buf;
374 for(
size_t i = 0; i != MAX_ATTEMPTS; ++i) {
380 constexpr uint8_t mask = 0xFF >> (8 - (
Self::BITS % 8));
385 if(s.value().is_nonzero().as_bool()) {
391 throw Internal_Error(
"Failed to generate random Scalar within bounded number of attempts");
396 v[0] = (x >= 0) ? x : -x;
398 return (x >= 0) ? s : s.negate();
406 constexpr const std::array<W, N>& value()
const {
return m_val; }
408 constexpr const W* data()
const {
return m_val.data(); }
410 explicit constexpr IntMod(std::array<W, N> v) : m_val(v) {}
412 std::array<W, N> m_val;
415template <
typename FieldElement,
typename Params>
421 static constexpr FieldElement
A = FieldElement::from_words(Params::AW);
422 static constexpr FieldElement
B = FieldElement::from_words(Params::BW);
424 static constexpr size_t BYTES = 1 + 2 * FieldElement::BYTES;
433 static constexpr Self identity() {
return Self(FieldElement::zero(), FieldElement::zero()); }
444 constexpr void serialize_to(std::span<uint8_t, Self::BYTES> bytes)
const {
447 x().serialize_to(pack.
next<FieldElement::BYTES>());
448 y().serialize_to(pack.
next<FieldElement::BYTES>());
457 x().serialize_to(pack.
next<FieldElement::BYTES>());
466 static constexpr auto ct_select(std::span<const Self> pts,
size_t idx) {
470 const size_t idx1 =
static_cast<size_t>(idx - 1);
471 for(
size_t i = 0; i != pts.size(); ++i) {
473 result.conditional_assign(found, pts[i]);
481 static constexpr std::optional<Self>
deserialize(std::span<const uint8_t> bytes) {
483 if(bytes[0] != 0x04) {
486 auto x = FieldElement::deserialize(bytes.subspan(1, FieldElement::BYTES));
487 auto y = FieldElement::deserialize(bytes.subspan(1 + FieldElement::BYTES, FieldElement::BYTES));
490 const auto lhs = (*y).square();
492 if((lhs == rhs).as_bool()) {
499 if(bytes[0] != 0x02 && bytes[0] != 0x03) {
504 if(
auto x = FieldElement::deserialize(bytes.subspan(1, FieldElement::BYTES))) {
506 y.conditional_assign(y_is_even && !
y.is_even(),
y.negate());
516 constexpr const FieldElement&
x()
const {
return m_x; }
518 constexpr const FieldElement&
y()
const {
return m_y; }
521 m_x.conditional_assign(cond, pt.
x());
522 m_y.conditional_assign(cond, pt.
y());
540template <
typename FieldElement,
typename Params>
546 static constexpr FieldElement
A = FieldElement::from_words(Params::AW);
549 static constexpr bool A_is_minus_3 = (
A == FieldElement::constant(-3)).as_bool();
562 static constexpr Self identity() {
return Self(FieldElement::zero(), FieldElement::one(), FieldElement::zero()); }
565 m_x(FieldElement::zero()), m_y(FieldElement::one()), m_z(FieldElement::zero()) {}
568 m_x(
x), m_y(
y), m_z(FieldElement::one()) {}
571 m_x(
x), m_y(
y), m_z(
z) {}
585 (*this) = (*this) + other;
590 (*this) = (*this) + other;
599 m_x.conditional_assign(cond, pt.
x());
600 m_y.conditional_assign(cond, pt.
y());
601 m_z.conditional_assign(cond, pt.
z());
607 if((a_is_identity && b_is_identity).as_bool()) {
617 const auto Z1Z1 = a.
z().square();
618 const auto U2 = b.
x() * Z1Z1;
619 const auto S2 = b.
y() * a.
z() * Z1Z1;
620 const auto H = U2 - a.
x();
621 const auto r = S2 - a.
y();
624 if(r.is_zero().as_bool()) {
628 const auto HH = H.square();
629 const auto HHH = H * HH;
630 const auto V = a.
x() * HH;
631 const auto t2 = r.square();
632 const auto t3 = V + V;
633 const auto t4 = t2 - HHH;
635 const auto t5 = V - X3;
636 const auto t6 = a.
y() * HHH;
637 const auto t7 = r * t5;
643 X3.conditional_assign(a_is_identity, b.
x());
644 Y3.conditional_assign(a_is_identity, b.
y());
645 Z3.conditional_assign(a_is_identity, FieldElement::one());
648 X3.conditional_assign(b_is_identity, a.
x());
649 Y3.conditional_assign(b_is_identity, a.
y());
650 Z3.conditional_assign(b_is_identity, a.
z());
652 return Self(X3, Y3, Z3);
658 if((a_is_identity && b_is_identity).as_bool()) {
666 const auto Z1Z1 = a.
z().square();
667 const auto Z2Z2 = b.
z().square();
668 const auto U1 = a.
x() * Z2Z2;
669 const auto U2 = b.
x() * Z1Z1;
670 const auto S1 = a.
y() * b.
z() * Z2Z2;
671 const auto S2 = b.
y() * a.
z() * Z1Z1;
672 const auto H = U2 - U1;
673 const auto r = S2 - S1;
675 if(r.is_zero().as_bool()) {
679 const auto HH = H.square();
680 const auto HHH = H * HH;
681 const auto V = U1 * HH;
682 const auto t2 = r.square();
683 const auto t3 = V + V;
684 const auto t4 = t2 - HHH;
686 const auto t5 = V - X3;
687 const auto t6 = S1 * HHH;
688 const auto t7 = r * t5;
690 const auto t8 = b.
z() * H;
691 auto Z3 = a.
z() * t8;
695 X3.conditional_assign(a_is_identity, b.
x());
696 Y3.conditional_assign(a_is_identity, b.
y());
697 Z3.conditional_assign(a_is_identity, b.
z());
700 X3.conditional_assign(b_is_identity, a.
x());
701 Y3.conditional_assign(b_is_identity, a.
y());
702 Z3.conditional_assign(b_is_identity, a.
z());
704 return Self(X3, Y3, Z3);
712 for(
size_t i = 0; i != n; ++i) {
721 FieldElement m = FieldElement::zero();
730 const auto z2 =
z().square();
731 m = (
x() - z2).mul3() * (
x() + z2);
735 m =
x().square().mul3();
738 const auto z2 =
z().square();
739 m =
x().square().mul3() +
A * z2.square();
742 const auto y2 =
y().square();
743 const auto s =
x().mul4() * y2;
744 const auto nx = m.square() - s.mul2();
745 const auto ny = m * (s - nx) - y2.square().mul8();
746 const auto nz =
y().mul2() *
z();
748 return Self(nx, ny, nz);
760 const auto z_inv = m_z.invert();
761 const auto z2_inv = z_inv.square();
762 const auto z3_inv = z_inv * z2_inv;
764 const auto x = m_x * z2_inv;
765 const auto y = m_y * z3_inv;
770 const size_t N = projective.size();
773 bool any_identity =
false;
774 for(
size_t i = 0; i != N; ++i) {
783 if(N <= 2 || any_identity) {
784 for(
size_t i = 0; i != N; ++i) {
785 affine[i] = projective[i].to_affine();
788 std::vector<FieldElement> c(N);
797 c[0] = projective[0].z();
798 for(
size_t i = 1; i != N; ++i) {
799 c[i] = c[i - 1] * projective[i].z();
802 auto s_inv = c[N - 1].invert();
804 for(
size_t i = N - 1; i > 0; --i) {
805 const auto& p = projective[i];
807 const auto z_inv = s_inv * c[i - 1];
808 const auto z2_inv = z_inv.square();
809 const auto z3_inv = z_inv * z2_inv;
811 s_inv = s_inv * p.z();
813 affine[i] =
AffinePoint(p.x() * z2_inv, p.y() * z3_inv);
816 const auto z2_inv = s_inv.square();
817 const auto z3_inv = s_inv * z2_inv;
818 affine[0] =
AffinePoint(projective[0].
x() * z2_inv, projective[0].
y() * z3_inv);
825 auto r = FieldElement::random(rng);
827 auto r2 = r.square();
835 constexpr const FieldElement&
x()
const {
return m_x; }
837 constexpr const FieldElement&
y()
const {
return m_y; }
839 constexpr const FieldElement&
z()
const {
return m_z; }
859template <StringLiteral PS,
877 static constexpr int8_t
Z = ZI;
880template <WordType WI,
size_t NI, std::array<WI, NI> PI>
884 static constexpr size_t N = NI;
885 static constexpr auto P = PI;
888template <
typename Params,
template <
typename FieldParamsT>
typename FieldRep =
MontgomeryRep>
891 typedef typename Params::W
W;
893 static constexpr auto PW = Params::PW;
894 static constexpr auto NW = Params::NW;
895 static constexpr auto AW = Params::AW;
898 static_assert(
PW.size() ==
NW.size());
939 static const auto C2 = (
B * (
SSWU_Z *
A).invert());
950template <
typename C,
size_t WindowBits>
953 typedef typename C::W W;
955 static constexpr bool BlindingEnabled =
true;
958 static constexpr size_t BlindingBits =
962 static_assert(BlindingBits < C::Scalar::BITS);
965 static constexpr size_t Bits = C::Scalar::BITS + (BlindingEnabled ? BlindingBits : 0);
969 if constexpr(BlindingEnabled) {
973 constexpr size_t n_words = C::NW.size();
975 uint8_t maskb[mask_bytes] = {0};
978 W mask[n_words] = {0};
979 load_le(mask, maskb, mask_words);
982 W mask_n[2 * n_words] = {0};
984 const auto sw = scalar.to_words();
990 std::reverse(mask_n, mask_n + 2 * n_words);
993 static_assert(
Bytes == C::Scalar::BYTES);
994 m_bytes.resize(
Bytes);
995 scalar.serialize_to(std::span{m_bytes}.template first<Bytes>());
1003 return read_window_bits<WindowBits>(std::span{m_bytes}, offset);
1013 std::vector<uint8_t> m_bytes;
1016template <
typename C,
size_t WindowBits>
1019 static constexpr size_t Bits = C::Scalar::BITS;
1025 return read_window_bits<WindowBits>(std::span{m_bytes}, offset);
1029 std::array<uint8_t, C::Scalar::BYTES> m_bytes;
1069template <
typename C,
size_t W>
1091 std::vector<ProjectivePoint> table;
1094 auto accum = ProjectivePoint::from_affine(p);
1097 table.push_back(accum);
1101 table.emplace_back(table[i + j / 2].dbl());
1103 table.emplace_back(table[i + j - 1] + table[i]);
1110 m_table = ProjectivePoint::to_affine_batch(table);
1117 auto table = std::span{m_table};
1119 auto accum = [&]() {
1122 auto pt = ProjectivePoint::from_affine(AffinePoint::ct_select(tbl_0, w_0));
1124 pt.randomize_rep(rng);
1128 for(
size_t i = 1; i !=
Windows; ++i) {
1137 accum += AffinePoint::ct_select(tbl_i, w_i);
1140 accum.randomize_rep(rng);
1144 accum.ct_unpoison();
1149 std::vector<AffinePoint> m_table;
1157template <
typename C,
size_t W>
1177 std::vector<ProjectivePoint> table;
1180 table.push_back(ProjectivePoint::from_affine(p));
1181 for(
size_t i = 1; i !=
TableSize; ++i) {
1183 table.push_back(table[i / 2].dbl());
1185 table.push_back(table[i - 1] + table[0]);
1189 m_table = ProjectivePoint::to_affine_batch(table);
1195 auto accum = [&]() {
1199 auto pt = ProjectivePoint::from_affine(AffinePoint::ct_select(m_table, w_0));
1201 pt.randomize_rep(rng);
1205 for(
size_t i = 1; i !=
Windows; ++i) {
1234 accum += AffinePoint::ct_select(m_table, w_i);
1237 accum.randomize_rep(rng);
1241 accum.ct_unpoison();
1246 std::vector<AffinePoint> m_table;
1269template <
typename C,
size_t W>
1273 static_assert(W >= 1 && W <= 4);
1289 std::vector<ProjectivePoint> table;
1292 for(
size_t i = 0; i !=
TableSize; ++i) {
1293 const size_t t_i = (i + 1);
1298 auto next_tbl_e = [&]() {
1299 if(x_i % 2 == 0 && y_i % 2 == 0) {
1302 return table[(t_i / 2) - 1].dbl();
1303 }
else if(x_i > 0 && y_i > 0) {
1305 return table[x_i - 1] + table[(y_i <<
WindowBits) - 1];
1306 }
else if(x_i > 0 && y_i == 0) {
1310 return ProjectivePoint::from_affine(x);
1313 return x + table[x_i - 1 - 1];
1315 }
else if(x_i == 0 && y_i > 0) {
1318 return ProjectivePoint::from_affine(y);
1321 return y + table[((y_i - 1) <<
WindowBits) - 1];
1328 table.emplace_back(next_tbl_e());
1331 m_table = ProjectivePoint::to_affine_batch(table);
1352 auto accum = ProjectivePoint::identity();
1354 for(
size_t i = 0; i !=
Windows; ++i) {
1362 const size_t window = w_1 + (w_2 <<
WindowBits);
1365 accum += m_table[window - 1];
1373 std::vector<AffinePoint> m_table;
1376template <
typename C>
1379 const auto z_u2 = C::SSWU_Z * u.square();
1380 const auto z2_u4 = z_u2.square();
1381 const auto tv1 = (z2_u4 + z_u2).invert();
1382 auto x1 = C::SSWU_C1() * (C::FieldElement::one() + tv1);
1383 x1.conditional_assign(tv1.is_zero(), C::SSWU_C2());
1384 const auto gx1 = C::AffinePoint::x3_ax_b(x1);
1386 const auto x2 = C::SSWU_Z * u.square() * x1;
1387 const auto gx2 = C::AffinePoint::x3_ax_b(x2);
1389 const auto gx1_is_square = gx1.is_square();
1392 auto y = gx2.sqrt();
1394 x.conditional_assign(gx1_is_square, x1);
1395 y.conditional_assign(gx1_is_square, gx1.sqrt());
1397 const auto flip_y = y.is_even() != u.is_even();
1398 y.conditional_assign(flip_y, y.negate());
1400 auto pt =
typename C::AffinePoint(x, y);
1406template <
typename C>
1409 std::span<const uint8_t> pw,
1410 std::span<const uint8_t> dst) ->
typename C::ProjectivePoint {
1411 static_assert(C::ValidForSswuHash);
1413 const size_t SecurityLevel = (C::OrderBits + 1) / 2;
1414 const size_t L = (C::PrimeFieldBits + SecurityLevel + 7) / 8;
1416 const size_t Cnt = (random_oracle ? 2 : 1);
1418 std::vector<uint8_t> xmd(L * Cnt);
1422 const auto u = C::FieldElement::from_wide_bytes(std::span<const uint8_t, L>(xmd));
1425 const auto u0 = C::FieldElement::from_wide_bytes(std::span<const uint8_t, L>(xmd.data(), L));
1426 const auto u1 = C::FieldElement::from_wide_bytes(std::span<const uint8_t, L>(xmd.data() + L, L));
#define BOTAN_DEBUG_ASSERT(expr)
#define BOTAN_ASSERT_UNREACHABLE()
constexpr const FieldElement & y() const
static constexpr size_t BYTES
constexpr void ct_poison() const
AffineCurvePoint & operator=(const Self &other)=default
static constexpr FieldElement B
constexpr void ct_unpoison() const
static constexpr Self identity()
constexpr const FieldElement & x() const
constexpr AffineCurvePoint(const FieldElement &x, const FieldElement &y)
static constexpr std::optional< Self > deserialize(std::span< const uint8_t > bytes)
static constexpr auto ct_select(std::span< const Self > pts, size_t idx)
constexpr void serialize_compressed_to(std::span< uint8_t, Self::COMPRESSED_BYTES > bytes) const
AffineCurvePoint & operator=(Self &&other)=default
static constexpr FieldElement x3_ax_b(const FieldElement &x)
constexpr Self negate() const
constexpr CT::Choice is_identity() const
constexpr void conditional_assign(CT::Choice cond, const Self &pt)
AffineCurvePoint(const Self &other)=default
AffineCurvePoint(Self &&other)=default
static constexpr size_t COMPRESSED_BYTES
constexpr void serialize_to(std::span< uint8_t, Self::BYTES > bytes) const
AffineCurvePoint< FieldElement, Params > Self
constexpr AffineCurvePoint()
static constexpr FieldElement A
size_t get_window(size_t offset) const
static constexpr size_t Bytes
BlindedScalarBits(const typename C::Scalar &scalar, RandomNumberGenerator &rng)
static constexpr size_t Bits
Helper class to ease in-place marshalling of concatenated fixed-length values.
constexpr void append(std::span< const uint8_t > buffer)
constexpr std::span< uint8_t > next(size_t bytes)
constexpr bool full() const
static constexpr Choice from_int(T v)
constexpr bool as_bool() const
static constexpr Mask< T > from_choice(Choice c)
static constexpr Mask< T > is_equal(T x, T y)
static constexpr int8_t Z
static constexpr auto GXW
static constexpr auto GYW
static const FieldElement & SSWU_C2()
static constexpr size_t PrimeFieldBits
static constexpr FieldElement SSWU_Z
static const FieldElement & SSWU_C1()
static constexpr bool ValidForSswuHash
static constexpr FieldElement A
AffineCurvePoint< FieldElement, Params > AffinePoint
static constexpr size_t OrderBits
static constexpr AffinePoint G
static constexpr FieldElement B
constexpr Self & operator*=(const Self &other)
static constexpr auto P_MOD_4
constexpr Self sqrt() const
friend constexpr Self operator*(const Self &a, const Self &b)
constexpr void ct_poison() const
static constexpr std::optional< Self > from_wide_bytes_varlen(std::span< const uint8_t > bytes)
constexpr void serialize_to(std::span< uint8_t, Self::BYTES > bytes) const
static constexpr size_t BITS
constexpr CT::Choice is_zero() const
std::array< W, L > stash_value() const
constexpr CT::Choice is_nonzero() const
static constexpr Self from_word(W x)
friend constexpr Self operator-(const Self &a, const Self &b)
Self mul2() const
Return (*this) multiplied by 2.
IntMod(const Self &other)=default
constexpr Self negate() const
static consteval Self constant(int8_t x)
constexpr std::array< W, Self::N > to_words() const
static constexpr Self zero()
constexpr CT::Choice is_square() const
static Self from_stash(const std::array< W, L > &stash)
IntMod(Self &&other)=default
constexpr Self mul8() const
Return (*this) multiplied by 8.
static constexpr std::optional< Self > deserialize(std::span< const uint8_t > bytes)
constexpr Self pow_vartime(const std::array< W, N > &exp) const
friend constexpr Self operator+(const Self &a, const Self &b)
static constexpr size_t BYTES
static constexpr Self one()
constexpr void ct_unpoison() const
constexpr CT::Choice operator==(const Self &other) const
constexpr Self invert() const
constexpr Self mul3() const
Return (*this) multiplied by 3.
constexpr CT::Choice is_even() const
IntMod & operator=(const Self &other)=default
constexpr void conditional_assign(CT::Choice cond, const Self &other)
static constexpr Self from_words(std::array< W, L > w)
IntMod & operator=(Self &&other)=default
constexpr Self mul4() const
Return (*this) multiplied by 4.
static constexpr Self from_wide_bytes(std::span< const uint8_t, L > bytes)
static Self random(RandomNumberGenerator &rng)
constexpr CT::Choice is_one() const
constexpr Self square() const
static Self from_bits_with_trunc(std::span< const uint8_t > bytes)
constexpr CT::Choice operator!=(const Self &other) const
static constexpr std::array< W, N > wide_to_rep(const std::array< W, 2 *N > &x)
static constexpr auto P_dash
static constexpr std::array< W, N > from_rep(const std::array< W, N > &z)
static constexpr size_t N
static constexpr std::array< W, N > one()
static constexpr std::array< W, N > to_rep(const std::array< W, N > &x)
static constexpr std::array< W, N > redc(const std::array< W, 2 *N > &z)
C::AffinePoint AffinePoint
static constexpr size_t Windows
static constexpr size_t WindowBits
PrecomputedBaseMulTable(const AffinePoint &p)
C::ProjectivePoint ProjectivePoint
static constexpr size_t WindowElements
ProjectivePoint mul(const Scalar &s, RandomNumberGenerator &rng) const
static constexpr size_t TableSize
ProjectiveCurvePoint< FieldElement, Params > Self
ProjectiveCurvePoint(const Self &other)=default
constexpr void ct_unpoison() const
friend constexpr Self operator+(const AffinePoint &a, const Self &b)
ProjectiveCurvePoint(Self &&other)=default
static constexpr bool A_is_zero
ProjectiveCurvePoint & operator=(Self &&other)=default
constexpr const FieldElement & x() const
constexpr ProjectiveCurvePoint()
friend constexpr Self operator-(const Self &a, const Self &b)
friend constexpr Self operator+(const Self &a, const AffinePoint &b)
static constexpr bool A_is_minus_3
constexpr void ct_poison() const
static std::vector< AffinePoint > to_affine_batch(std::span< const Self > projective)
ProjectiveCurvePoint & operator=(const Self &other)=default
static constexpr Self from_affine(const AffinePoint &pt)
static constexpr Self add(const Self &a, const Self &b)
constexpr Self & operator+=(const AffinePoint &other)
constexpr void conditional_assign(CT::Choice cond, const Self &pt)
constexpr const FieldElement & z() const
constexpr const FieldElement & y() const
constexpr AffinePoint to_affine() const
void randomize_rep(RandomNumberGenerator &rng)
constexpr CT::Choice is_identity() const
constexpr Self negate() const
friend constexpr Self operator+(const Self &a, const Self &b)
static constexpr FieldElement A
AffineCurvePoint< FieldElement, Params > AffinePoint
constexpr ProjectiveCurvePoint(const FieldElement &x, const FieldElement &y)
static constexpr Self add_mixed(const Self &a, const AffinePoint &b)
static constexpr Self identity()
constexpr Self dbl_n(size_t n) const
constexpr ProjectiveCurvePoint(const FieldElement &x, const FieldElement &y, const FieldElement &z)
constexpr Self dbl() const
constexpr Self & operator+=(const Self &other)
void randomize(std::span< uint8_t > output)
static constexpr size_t Bits
UnblindedScalarBits(const typename C::Scalar &scalar)
size_t get_window(size_t offset) const
ProjectivePoint mul2_vartime(const Scalar &s1, const Scalar &s2) const
static constexpr size_t TableSize
static constexpr size_t WindowBits
static constexpr size_t Windows
C::ProjectivePoint ProjectivePoint
static constexpr size_t WindowSize
WindowedMul2Table(const AffinePoint &x, const AffinePoint &y)
C::AffinePoint AffinePoint
C::ProjectivePoint ProjectivePoint
static constexpr size_t Windows
WindowedMulTable(const AffinePoint &p)
static constexpr size_t TableSize
C::AffinePoint AffinePoint
ProjectivePoint mul(const Scalar &s, RandomNumberGenerator &rng) const
static constexpr size_t WindowBits
int(* final)(unsigned char *, CTX *)
constexpr Mask< T > conditional_assign_mem(T cnd, T *sink, const T *src, size_t elems)
constexpr CT::Mask< T > is_not_equal(const T x[], const T y[], size_t len)
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)
auto map_to_curve_sswu(const typename C::FieldElement &u) -> typename C::AffinePoint
constexpr auto bigint_add(std::span< W, N > z, std::span< const W, N > x, std::span< const W, N > y) -> W
auto hash_to_curve_sswu(std::string_view hash, bool random_oracle, std::span< const uint8_t > pw, std::span< const uint8_t > dst) -> typename C::ProjectivePoint
constexpr W shift_left(std::array< W, N > &x)
constexpr void comba_sqr(W z[2 *N], const W x[N])
constexpr void comba_mul(W z[2 *N], const W x[N], const W y[N])
constexpr auto bigint_sub3(W z[], const W x[], size_t x_size, const W y[], size_t y_size) -> W
constexpr auto monty_inverse(W a) -> W
void secure_scrub_memory(void *ptr, size_t n)
void expand_message_xmd(std::string_view hash_fn, std::span< uint8_t > output, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep)
constexpr void bigint_monty_maybe_sub(size_t N, W z[], W x0, const W x[], const W p[])
void carry(int64_t &h0, int64_t &h1)
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 >
constexpr auto hex_to_words(const char(&s)[N])
constexpr auto bigint_add2_nc(W x[], size_t x_size, const W y[], size_t y_size) -> W
constexpr void copy_mem(T *out, const T *in, size_t n)
constexpr auto store_be(ParamTs &&... params)
static constexpr size_t N