10#include <botan/ec_point.h>
12#include <botan/numthry.h>
14#include <botan/internal/ct_utils.h>
15#include <botan/internal/ec_inner_data.h>
16#include <botan/internal/mod_inv.h>
17#include <botan/internal/monty.h>
18#include <botan/internal/mp_core.h>
19#include <botan/internal/stl_util.h>
32const EC_Group_Data& CurveGFp::group()
const {
38 return this->group().a();
42 return this->group().b();
46 return this->group().p();
50 return this->group().p_words();
56 group.monty().mul_by(x, group.monty().R2(), ws);
59void from_rep(
const EC_Group_Data& group, BigInt& z, secure_vector<word>& ws) {
60 z = group.monty().redc(z, ws);
63BigInt from_rep_to_tmp(
const EC_Group_Data& group,
const BigInt& x, secure_vector<word>& ws) {
64 return group.monty().redc(x, ws);
67inline void fe_mul(
const EC_Group_Data& group, BigInt& z,
const BigInt& x,
const BigInt& y, secure_vector<word>& ws) {
68 group.monty().mul(z, x, y, ws);
72 const EC_Group_Data& group, BigInt& z,
const word x_w[],
size_t x_size,
const BigInt& y, secure_vector<word>& ws) {
73 group.monty().mul(z, y, std::span{x_w, x_size}, ws);
77inline void fe_smul(BigInt& z,
const BigInt& p, secure_vector<word>& ws) {
78 static_assert(M == 2 || M == 3 || M == 4 || M == 8);
82inline BigInt fe_mul(
const EC_Group_Data& group,
const BigInt& x,
const BigInt& y, secure_vector<word>& ws) {
83 return group.monty().mul(x, y, ws);
86void fe_sqr(
const EC_Group_Data& group, BigInt& z,
const BigInt& x, secure_vector<word>& ws) {
87 group.monty().sqr(z, x, ws);
90void fe_sqr(
const EC_Group_Data& group, BigInt& z,
const word x_w[],
size_t x_size, secure_vector<word>& ws) {
91 group.monty().sqr(z, std::span{x_w, x_size}, ws);
94BigInt fe_sqr(
const EC_Group_Data& group,
const BigInt& x, secure_vector<word>& ws) {
95 return group.monty().sqr(x, ws);
98BigInt invert_element(
const EC_Group_Data& group,
const BigInt& x, secure_vector<word>& ws) {
102size_t monty_ws_size(
const EC_Group_Data& group) {
115 m_curve(curve), m_x(std::move(x)), m_y(std::move(y)), m_z(m_curve.group().monty().R1()) {
116 const auto& group = m_curve.group();
118 if(m_x < 0 || m_x >= group.p()) {
119 throw Invalid_Argument(
"Invalid EC_Point affine x");
121 if(m_y < 0 || m_y >= group.p()) {
122 throw Invalid_Argument(
"Invalid EC_Point affine y");
127 to_rep(group, m_x, monty_ws);
128 to_rep(group, m_y, monty_ws);
132 const auto& group = m_curve.group();
142 const auto& group = m_curve.group();
153 const BigInt mask2 = fe_sqr(group, mask, ws);
154 const BigInt mask3 = fe_mul(group, mask2, mask, ws);
156 m_x = fe_mul(group, m_x, mask2, ws);
157 m_y = fe_mul(group, m_y, mask3, ws);
158 m_z = fe_mul(group, m_z, mask, ws);
163inline void resize_ws(std::vector<BigInt>& ws_bn,
size_t cap_size) {
166 for(
auto& ws : ws_bn) {
167 if(ws.size() < cap_size) {
168 ws.get_word_vector().resize(cap_size);
179 const size_t p_words = m_curve.get_p_words();
181 std::min(p_words, other.m_x.
size()),
183 std::min(p_words, other.m_y.
size()),
188 const word x_words[],
size_t x_size,
const word y_words[],
size_t y_size, std::vector<BigInt>& ws_bn) {
193 const auto& group = m_curve.group();
196 m_x.set_words(x_words, x_size);
197 m_y.set_words(y_words, y_size);
198 m_z = group.monty().R1();
202 resize_ws(ws_bn, monty_ws_size(group));
218 const BigInt& p = group.p();
220 fe_sqr(group, T3, m_z, ws);
221 fe_mul(group, T4, x_words, x_size, T3, ws);
223 fe_mul(group, T2, m_z, T3, ws);
224 fe_mul(group, T0, y_words, y_size, T2, ws);
238 m_y = group.monty().R1();
243 fe_sqr(group, T2, T4, ws);
245 fe_mul(group, T3, m_x, T2, ws);
247 fe_mul(group, T1, T2, T4, ws);
249 fe_sqr(group, m_x, T0, ws);
250 m_x.mod_sub(T1, p, sub_ws);
252 m_x.mod_sub(T3, p, sub_ws);
253 m_x.mod_sub(T3, p, sub_ws);
257 fe_mul(group, T2, T0, T3, ws);
258 fe_mul(group, T0, m_y, T1, ws);
262 fe_mul(group, T0, m_z, T4, ws);
267 BOTAN_ARG_CHECK(m_curve == other.m_curve,
"cannot add points on different curves");
269 const size_t p_words = m_curve.get_p_words();
272 std::min(p_words, other.m_x.
size()),
274 std::min(p_words, other.m_y.
size()),
276 std::min(p_words, other.m_z.
size()),
282 const word y_words[],
284 const word z_words[],
286 std::vector<BigInt>& ws_bn) {
291 const auto& group = m_curve.group();
294 m_x.set_words(x_words, x_size);
295 m_y.set_words(y_words, y_size);
296 m_z.set_words(z_words, z_size);
300 resize_ws(ws_bn, monty_ws_size(group));
316 const BigInt& p = group.p();
318 fe_sqr(group, T0, z_words, z_size, ws);
319 fe_mul(group, T1, m_x, T0, ws);
320 fe_mul(group, T3, z_words, z_size, T0, ws);
321 fe_mul(group, T2, m_y, T3, ws);
323 fe_sqr(group, T3, m_z, ws);
324 fe_mul(group, T4, x_words, x_size, T3, ws);
326 fe_mul(group, T5, m_z, T3, ws);
327 fe_mul(group, T0, y_words, y_size, T5, ws);
341 m_y = group.monty().R1();
346 fe_sqr(group, T5, T4, ws);
348 fe_mul(group, T3, T1, T5, ws);
350 fe_mul(group, T1, T5, T4, ws);
352 fe_sqr(group, m_x, T0, ws);
353 m_x.mod_sub(T1, p, sub_ws);
354 m_x.mod_sub(T3, p, sub_ws);
355 m_x.mod_sub(T3, p, sub_ws);
359 fe_mul(group, m_y, T0, T3, ws);
360 fe_mul(group, T3, T2, T1, ws);
362 m_y.mod_sub(T3, p, sub_ws);
364 fe_mul(group, T3, z_words, z_size, m_z, ws);
365 fe_mul(group, m_z, T3, T4, ws);
369 if(iterations == 0) {
382 for(
size_t i = 0; i != iterations; ++i) {
393 const auto& group = m_curve.group();
400 resize_ws(ws_bn, monty_ws_size(group));
414 const BigInt& p = group.p();
416 fe_sqr(group, T0, m_y, ws);
418 fe_mul(group, T1, m_x, T0, ws);
419 fe_smul<4>(T1, p, sub_ws);
421 if(group.a_is_zero()) {
423 fe_sqr(group, T4, m_x, ws);
424 fe_smul<3>(T4, p, sub_ws);
425 }
else if(group.a_is_minus_3()) {
430 fe_sqr(group, T3, m_z, ws);
439 fe_mul(group, T4, T2, T3, ws);
441 fe_smul<3>(T4, p, sub_ws);
443 fe_sqr(group, T3, m_z, ws);
444 fe_sqr(group, T4, T3, ws);
445 fe_mul(group, T3, group.monty_a(), T4, ws);
447 fe_sqr(group, T4, m_x, ws);
448 fe_smul<3>(T4, p, sub_ws);
452 fe_sqr(group, T2, T4, ws);
456 fe_sqr(group, T3, T0, ws);
457 fe_smul<8>(T3, p, sub_ws);
461 fe_mul(group, T0, T4, T1, ws);
466 fe_mul(group, T2, m_y, m_z, ws);
467 fe_smul<2>(T2, p, sub_ws);
493 *
this = scalar * *
this;
498 const size_t scalar_bits = scalar.
bits();
504 for(
size_t i = scalar_bits; i > 0; i--) {
505 const size_t b = scalar.
get_bit(i - 1) ? 1 : 0;
506 R[b ^ 1].
add(R[b], ws);
521 if(points.size() <= 1) {
522 for(
auto& point : points) {
523 point.force_affine();
528 for(
auto& point : points) {
529 if(point.is_zero()) {
530 throw Invalid_State(
"Cannot convert zero ECC point to affine");
543 const auto& group = points[0].m_curve.group();
544 const BigInt& rep_1 = group.monty().R1();
546 if(ws.size() < monty_ws_size(group)) {
547 ws.resize(monty_ws_size(group));
550 std::vector<BigInt> c(points.size());
551 c[0] = points[0].m_z;
553 for(
size_t i = 1; i != points.size(); ++i) {
554 fe_mul(group, c[i], c[i - 1], points[i].m_z, ws);
557 BigInt s_inv = invert_element(group, c[c.size() - 1], ws);
563 for(
size_t i = points.size() - 1; i != 0; i--) {
566 fe_mul(group, z_inv, s_inv, c[i - 1], ws);
568 s_inv = fe_mul(group, s_inv, point.m_z, ws);
570 fe_sqr(group, z2_inv, z_inv, ws);
571 fe_mul(group, z3_inv, z2_inv, z_inv, ws);
572 point.m_x = fe_mul(group, point.m_x, z2_inv, ws);
573 point.m_y = fe_mul(group, point.m_y, z3_inv, ws);
577 fe_sqr(group, z2_inv, s_inv, ws);
578 fe_mul(group, z3_inv, z2_inv, s_inv, ws);
579 points[0].m_x = fe_mul(group, points[0].m_x, z2_inv, ws);
580 points[0].m_y = fe_mul(group, points[0].m_y, z3_inv, ws);
581 points[0].m_z = rep_1;
586 throw Invalid_State(
"Cannot convert zero ECC point to affine");
591 const auto& group = m_curve.group();
593 const BigInt z_inv = invert_element(group, m_z, ws);
594 const BigInt z2_inv = fe_sqr(group, z_inv, ws);
595 const BigInt z3_inv = fe_mul(group, z_inv, z2_inv, ws);
596 m_x = fe_mul(group, m_x, z2_inv, ws);
597 m_y = fe_mul(group, m_y, z3_inv, ws);
598 m_z = group.monty().R1();
602 const auto& group = m_curve.group();
603 return m_z == group.monty().R1();
607 const auto& group = m_curve.group();
608 const size_t p_bytes = group.p_bytes();
615 const auto& group = m_curve.group();
616 const size_t p_bytes = group.p_bytes();
623 const auto& group = m_curve.group();
624 const size_t p_bytes = group.p_bytes();
638 const auto& group = m_curve.group();
641 return from_rep_to_tmp(group, m_x, monty_ws);
644 BigInt z2 = fe_sqr(group, m_z, monty_ws);
645 z2 = invert_element(group, z2, monty_ws);
648 fe_mul(group, r, m_x, z2, monty_ws);
649 from_rep(group, r, monty_ws);
658 const auto& group = m_curve.group();
662 return from_rep_to_tmp(group, m_y, monty_ws);
665 const BigInt z2 = fe_sqr(group, m_z, monty_ws);
666 const BigInt z3 = fe_mul(group, m_z, z2, monty_ws);
667 const BigInt z3_inv = invert_element(group, z3, monty_ws);
670 fe_mul(group, r, m_y, z3_inv, monty_ws);
671 from_rep(group, r, monty_ws);
686 const auto& group = m_curve.group();
689 const BigInt y2 = from_rep_to_tmp(group, fe_sqr(group, m_y, monty_ws), monty_ws);
690 const BigInt x3 = fe_mul(group, m_x, fe_sqr(group, m_x, monty_ws), monty_ws);
691 const BigInt ax = fe_mul(group, m_x, group.monty_a(), monty_ws);
692 const BigInt z2 = fe_sqr(group, m_z, monty_ws);
694 const BigInt& monty_b = group.monty_b();
698 if(y2 != from_rep_to_tmp(group, x3 + ax + monty_b, monty_ws)) {
703 const BigInt z3 = fe_mul(group, m_z, z2, monty_ws);
704 const BigInt ax_z4 = fe_mul(group, ax, fe_sqr(group, z2, monty_ws), monty_ws);
705 const BigInt b_z6 = fe_mul(group, monty_b, fe_sqr(group, z3, monty_ws), monty_ws);
707 if(y2 != from_rep_to_tmp(group, x3 + ax_z4 + b_z6, monty_ws)) {
719 const auto& group = m_curve.group();
724 if(group.has_cofactor()) {
725 return group.mod_order().reduce(this->
get_affine_x()) == v;
745 to_rep(group, vr, ws);
748 fe_sqr(group, z2, this->
get_z(), ws);
749 fe_mul(group, v_z2, vr, z2, ws);
760 if(this->
get_x() == v_z2) {
764 if(group.order_is_less_than_p()) {
765 vr = v + group.order();
767 to_rep(group, vr, ws);
768 fe_mul(group, v_z2, vr, z2, ws);
770 if(this->
get_x() == v_z2) {
782 m_curve.swap(other.m_curve);
789 if(m_curve != other.m_curve) {
804 return std::vector<uint8_t>(1);
807 const size_t p_bytes = m_curve.group().p_bytes();
814 std::vector<uint8_t> result(1 + parts * p_bytes);
838 const BigInt g = ((x * x + a) * x + b) % p;
856 return OS2ECP(data.data(), data.size(), curve);
860 if(data_len == 1 && data[0] == 0) {
870 throw Decoding_Error(
"OS2ECP: Decoded point was not on the curve");
881 const uint8_t pc = pt[0];
882 const size_t p_bytes = p.
bytes();
887 if(pc == 2 || pc == 3) {
888 if(pt_len != 1 + p_bytes) {
893 const bool y_mod_2 = ((pc & 0x01) == 1);
894 y = decompress_point(y_mod_2, x, p, a, b);
896 if(pt_len != 1 + 2 * p_bytes) {
902 }
else if(pc == 6 || pc == 7) {
903 if(pt_len != 1 + 2 * p_bytes) {
910 const bool y_mod_2 = ((pc & 0x01) == 1);
912 if(decompress_point(y_mod_2, x, p, a, b) != y) {
916 throw Decoding_Error(
"OS2ECP: Unknown format type " + std::to_string(
static_cast<int>(pc)));
919 if(x >= p || y >= p) {
923 return std::make_pair(x, y);
#define BOTAN_ASSERT_NOMSG(expr)
#define BOTAN_DEBUG_ASSERT(expr)
#define BOTAN_ASSERT_NONNULL(ptr)
#define BOTAN_ARG_CHECK(expr, msg)
#define BOTAN_ASSERT(expr, assertion_made)
void swap(BigInt &other) noexcept
static BigInt decode(const uint8_t buf[], size_t length)
static BigInt random_integer(RandomNumberGenerator &rng, const BigInt &min, const BigInt &max)
BigInt & mod_add(const BigInt &y, const BigInt &mod, secure_vector< word > &ws)
void serialize_to(std::span< uint8_t > out) const
BigInt & mod_sub(const BigInt &y, const BigInt &mod, secure_vector< word > &ws)
static secure_vector< uint8_t > encode_1363(const BigInt &n, size_t bytes)
const word * _data() const
static BigInt from_s32(int32_t n)
bool get_bit(size_t n) const
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)
CurveGFp(const CurveGFp &)=default
const BigInt & get_a() const
size_t get_p_words() const
const BigInt & get_p() const
const BigInt & get_b() const
void swap(EC_Point &other) noexcept
void randomize_repr(RandomNumberGenerator &rng)
BigInt get_affine_x() const
secure_vector< uint8_t > x_bytes() const
secure_vector< uint8_t > xy_bytes() const
void add(const EC_Point &other, std::vector< BigInt > &workspace)
void add_affine(const EC_Point &other, std::vector< BigInt > &workspace)
void mult2(std::vector< BigInt > &workspace)
void mult2i(size_t i, std::vector< BigInt > &workspace)
EC_Point & operator-=(const EC_Point &rhs)
const BigInt & get_z() const
bool on_the_curve() const
EC_Point & operator+=(const EC_Point &rhs)
bool operator==(const EC_Point &other) const
EC_Point mul(const BigInt &scalar) const
static void force_all_affine(std::span< EC_Point > points, secure_vector< word > &ws)
BigInt get_affine_y() const
EC_Point & operator*=(const BigInt &scalar)
secure_vector< uint8_t > y_bytes() const
const BigInt & get_x() const
std::vector< uint8_t > encode(EC_Point_Format format) const
bool _is_x_eq_to_v_mod_order(const BigInt &v) const
virtual bool is_seeded() const =0
constexpr CT::Mask< T > all_zeros(const T elem[], size_t len)
BigInt inverse_mod_public_prime(const BigInt &x, const BigInt &p)
std::vector< T, secure_allocator< T > > secure_vector
BigInt sqrt_modulo_prime(const BigInt &a, const BigInt &p)
std::conditional_t< HasNative64BitRegisters, std::uint64_t, uint32_t > word
EC_Point OS2ECP(std::span< const uint8_t > data, const CurveGFp &curve)