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/stl_util.h>
31const EC_Group_Data& CurveGFp::group()
const {
37 return this->group().a();
41 return this->group().b();
45 return this->group().p();
49 return this->group().p_words();
55 group.monty().mul_by(x, group.monty().R2(), ws);
58void from_rep(
const EC_Group_Data& group, BigInt& z, secure_vector<word>& ws) {
59 z = group.monty().redc(z, ws);
62BigInt from_rep_to_tmp(
const EC_Group_Data& group,
const BigInt& x, secure_vector<word>& ws) {
63 return group.monty().redc(x, ws);
66inline void fe_mul(
const EC_Group_Data& group, BigInt& z,
const BigInt& x,
const BigInt& y, secure_vector<word>& ws) {
67 group.monty().mul(z, x, y, ws);
71 const EC_Group_Data& group, BigInt& z,
const word x_w[],
size_t x_size,
const BigInt& y, secure_vector<word>& ws) {
72 group.monty().mul(z, y, std::span{x_w, x_size}, ws);
76inline void fe_smul(BigInt& z,
const BigInt& p, secure_vector<word>& ws) {
77 static_assert(M == 2 || M == 3 || M == 4 || M == 8);
81inline BigInt fe_mul(
const EC_Group_Data& group,
const BigInt& x,
const BigInt& y, secure_vector<word>& ws) {
82 return group.monty().mul(x, y, ws);
85void fe_sqr(
const EC_Group_Data& group, BigInt& z,
const BigInt& x, secure_vector<word>& ws) {
86 group.monty().sqr(z, x, ws);
89void fe_sqr(
const EC_Group_Data& group, BigInt& z,
const word x_w[],
size_t x_size, secure_vector<word>& ws) {
90 group.monty().sqr(z, std::span{x_w, x_size}, ws);
93BigInt fe_sqr(
const EC_Group_Data& group,
const BigInt& x, secure_vector<word>& ws) {
94 return group.monty().sqr(x, ws);
97BigInt invert_element(
const EC_Group_Data& group,
const BigInt& x, secure_vector<word>& ws) {
101size_t monty_ws_size(
const EC_Group_Data& group) {
114 m_curve(curve), m_x(std::move(x)), m_y(std::move(y)), m_z(m_curve.group().monty().R1()) {
115 const auto& group = m_curve.group();
117 if(m_x < 0 || m_x >= group.p()) {
118 throw Invalid_Argument(
"Invalid EC_Point affine x");
120 if(m_y < 0 || m_y >= group.p()) {
121 throw Invalid_Argument(
"Invalid EC_Point affine y");
126 to_rep(group, m_x, monty_ws);
127 to_rep(group, m_y, monty_ws);
131 const auto& group = m_curve.group();
141 const auto& group = m_curve.group();
152 const BigInt mask2 = fe_sqr(group, mask, ws);
153 const BigInt mask3 = fe_mul(group, mask2, mask, ws);
155 m_x = fe_mul(group, m_x, mask2, ws);
156 m_y = fe_mul(group, m_y, mask3, ws);
157 m_z = fe_mul(group, m_z, mask, ws);
162inline void resize_ws(std::vector<BigInt>& ws_bn,
size_t cap_size) {
165 for(
auto& ws : ws_bn) {
166 if(ws.size() < cap_size) {
167 ws.get_word_vector().resize(cap_size);
178 const size_t p_words = m_curve.get_p_words();
180 std::min(p_words, other.m_x.
size()),
182 std::min(p_words, other.m_y.
size()),
187 const word x_words[],
size_t x_size,
const word y_words[],
size_t y_size, std::vector<BigInt>& ws_bn) {
192 const auto& group = m_curve.group();
195 m_x.set_words(x_words, x_size);
196 m_y.set_words(y_words, y_size);
197 m_z = group.monty().R1();
201 resize_ws(ws_bn, monty_ws_size(group));
217 const BigInt& p = group.p();
219 fe_sqr(group, T3, m_z, ws);
220 fe_mul(group, T4, x_words, x_size, T3, ws);
222 fe_mul(group, T2, m_z, T3, ws);
223 fe_mul(group, T0, y_words, y_size, T2, ws);
237 m_y = group.monty().R1();
242 fe_sqr(group, T2, T4, ws);
244 fe_mul(group, T3, m_x, T2, ws);
246 fe_mul(group, T1, T2, T4, ws);
248 fe_sqr(group, m_x, T0, ws);
249 m_x.mod_sub(T1, p, sub_ws);
251 m_x.mod_sub(T3, p, sub_ws);
252 m_x.mod_sub(T3, p, sub_ws);
256 fe_mul(group, T2, T0, T3, ws);
257 fe_mul(group, T0, m_y, T1, ws);
261 fe_mul(group, T0, m_z, T4, ws);
266 BOTAN_ARG_CHECK(m_curve == other.m_curve,
"cannot add points on different curves");
268 const size_t p_words = m_curve.get_p_words();
271 std::min(p_words, other.m_x.
size()),
273 std::min(p_words, other.m_y.
size()),
275 std::min(p_words, other.m_z.
size()),
281 const word y_words[],
283 const word z_words[],
285 std::vector<BigInt>& ws_bn) {
290 const auto& group = m_curve.group();
293 m_x.set_words(x_words, x_size);
294 m_y.set_words(y_words, y_size);
295 m_z.set_words(z_words, z_size);
299 resize_ws(ws_bn, monty_ws_size(group));
315 const BigInt& p = group.p();
317 fe_sqr(group, T0, z_words, z_size, ws);
318 fe_mul(group, T1, m_x, T0, ws);
319 fe_mul(group, T3, z_words, z_size, T0, ws);
320 fe_mul(group, T2, m_y, T3, ws);
322 fe_sqr(group, T3, m_z, ws);
323 fe_mul(group, T4, x_words, x_size, T3, ws);
325 fe_mul(group, T5, m_z, T3, ws);
326 fe_mul(group, T0, y_words, y_size, T5, ws);
340 m_y = group.monty().R1();
345 fe_sqr(group, T5, T4, ws);
347 fe_mul(group, T3, T1, T5, ws);
349 fe_mul(group, T1, T5, T4, ws);
351 fe_sqr(group, m_x, T0, ws);
352 m_x.mod_sub(T1, p, sub_ws);
353 m_x.mod_sub(T3, p, sub_ws);
354 m_x.mod_sub(T3, p, sub_ws);
358 fe_mul(group, m_y, T0, T3, ws);
359 fe_mul(group, T3, T2, T1, ws);
361 m_y.mod_sub(T3, p, sub_ws);
363 fe_mul(group, T3, z_words, z_size, m_z, ws);
364 fe_mul(group, m_z, T3, T4, ws);
368 if(iterations == 0) {
381 for(
size_t i = 0; i != iterations; ++i) {
392 const auto& group = m_curve.group();
399 resize_ws(ws_bn, monty_ws_size(group));
413 const BigInt& p = group.p();
415 fe_sqr(group, T0, m_y, ws);
417 fe_mul(group, T1, m_x, T0, ws);
418 fe_smul<4>(T1, p, sub_ws);
420 if(group.a_is_zero()) {
422 fe_sqr(group, T4, m_x, ws);
423 fe_smul<3>(T4, p, sub_ws);
424 }
else if(group.a_is_minus_3()) {
429 fe_sqr(group, T3, m_z, ws);
438 fe_mul(group, T4, T2, T3, ws);
440 fe_smul<3>(T4, p, sub_ws);
442 fe_sqr(group, T3, m_z, ws);
443 fe_sqr(group, T4, T3, ws);
444 fe_mul(group, T3, group.monty_a(), T4, ws);
446 fe_sqr(group, T4, m_x, ws);
447 fe_smul<3>(T4, p, sub_ws);
451 fe_sqr(group, T2, T4, ws);
455 fe_sqr(group, T3, T0, ws);
456 fe_smul<8>(T3, p, sub_ws);
460 fe_mul(group, T0, T4, T1, ws);
465 fe_mul(group, T2, m_y, m_z, ws);
466 fe_smul<2>(T2, p, sub_ws);
492 *
this = scalar * *
this;
497 const size_t scalar_bits = scalar.
bits();
503 for(
size_t i = scalar_bits; i > 0; i--) {
504 const size_t b = scalar.
get_bit(i - 1) ? 1 : 0;
505 R[b ^ 1].
add(R[b], ws);
520 if(points.size() <= 1) {
521 for(
auto& point : points) {
522 point.force_affine();
527 for(
auto& point : points) {
528 if(point.is_zero()) {
529 throw Invalid_State(
"Cannot convert zero ECC point to affine");
542 const auto& group = points[0].m_curve.group();
543 const BigInt& rep_1 = group.monty().R1();
545 if(ws.size() < monty_ws_size(group)) {
546 ws.resize(monty_ws_size(group));
549 std::vector<BigInt> c(points.size());
550 c[0] = points[0].m_z;
552 for(
size_t i = 1; i != points.size(); ++i) {
553 fe_mul(group, c[i], c[i - 1], points[i].m_z, ws);
556 BigInt s_inv = invert_element(group, c[c.size() - 1], ws);
562 for(
size_t i = points.size() - 1; i != 0; i--) {
565 fe_mul(group, z_inv, s_inv, c[i - 1], ws);
567 s_inv = fe_mul(group, s_inv, point.m_z, ws);
569 fe_sqr(group, z2_inv, z_inv, ws);
570 fe_mul(group, z3_inv, z2_inv, z_inv, ws);
571 point.m_x = fe_mul(group, point.m_x, z2_inv, ws);
572 point.m_y = fe_mul(group, point.m_y, z3_inv, ws);
576 fe_sqr(group, z2_inv, s_inv, ws);
577 fe_mul(group, z3_inv, z2_inv, s_inv, ws);
578 points[0].m_x = fe_mul(group, points[0].m_x, z2_inv, ws);
579 points[0].m_y = fe_mul(group, points[0].m_y, z3_inv, ws);
580 points[0].m_z = rep_1;
585 throw Invalid_State(
"Cannot convert zero ECC point to affine");
590 const auto& group = m_curve.group();
592 const BigInt z_inv = invert_element(group, m_z, ws);
593 const BigInt z2_inv = fe_sqr(group, z_inv, ws);
594 const BigInt z3_inv = fe_mul(group, z_inv, z2_inv, ws);
595 m_x = fe_mul(group, m_x, z2_inv, ws);
596 m_y = fe_mul(group, m_y, z3_inv, ws);
597 m_z = group.monty().R1();
601 const auto& group = m_curve.group();
602 return m_z == group.monty().R1();
606 const auto& group = m_curve.group();
607 const size_t p_bytes = group.p_bytes();
614 const auto& group = m_curve.group();
615 const size_t p_bytes = group.p_bytes();
622 const auto& group = m_curve.group();
623 const size_t p_bytes = group.p_bytes();
637 const auto& group = m_curve.group();
640 return from_rep_to_tmp(group, m_x, monty_ws);
643 BigInt z2 = fe_sqr(group, m_z, monty_ws);
644 z2 = invert_element(group, z2, monty_ws);
647 fe_mul(group, r, m_x, z2, monty_ws);
648 from_rep(group, r, monty_ws);
657 const auto& group = m_curve.group();
661 return from_rep_to_tmp(group, m_y, monty_ws);
664 const BigInt z2 = fe_sqr(group, m_z, monty_ws);
665 const BigInt z3 = fe_mul(group, m_z, z2, monty_ws);
666 const BigInt z3_inv = invert_element(group, z3, monty_ws);
669 fe_mul(group, r, m_y, z3_inv, monty_ws);
670 from_rep(group, r, monty_ws);
685 const auto& group = m_curve.group();
688 const BigInt y2 = from_rep_to_tmp(group, fe_sqr(group, m_y, monty_ws), monty_ws);
689 const BigInt x3 = fe_mul(group, m_x, fe_sqr(group, m_x, monty_ws), monty_ws);
690 const BigInt ax = fe_mul(group, m_x, group.monty_a(), monty_ws);
691 const BigInt z2 = fe_sqr(group, m_z, monty_ws);
693 const BigInt& monty_b = group.monty_b();
697 if(y2 != from_rep_to_tmp(group, x3 + ax + monty_b, monty_ws)) {
702 const BigInt z3 = fe_mul(group, m_z, z2, monty_ws);
703 const BigInt ax_z4 = fe_mul(group, ax, fe_sqr(group, z2, monty_ws), monty_ws);
704 const BigInt b_z6 = fe_mul(group, monty_b, fe_sqr(group, z3, monty_ws), monty_ws);
706 if(y2 != from_rep_to_tmp(group, x3 + ax_z4 + b_z6, monty_ws)) {
718 const auto& group = m_curve.group();
723 if(group.has_cofactor()) {
724 return group.mod_order().reduce(this->
get_affine_x()) == v;
744 to_rep(group, vr, ws);
747 fe_sqr(group, z2, this->
get_z(), ws);
748 fe_mul(group, v_z2, vr, z2, ws);
759 if(this->
get_x() == v_z2) {
763 if(group.order_is_less_than_p()) {
764 vr = v + group.order();
766 to_rep(group, vr, ws);
767 fe_mul(group, v_z2, vr, z2, ws);
769 if(this->
get_x() == v_z2) {
781 m_curve.swap(other.m_curve);
788 if(m_curve != other.m_curve) {
803 return std::vector<uint8_t>(1);
806 const size_t p_bytes = m_curve.group().p_bytes();
813 std::vector<uint8_t> result(1 + parts * p_bytes);
837 const BigInt g = ((x * x + a) * x + b) % p;
855 return OS2ECP(data.data(), data.size(), curve);
859 if(data_len == 1 && data[0] == 0) {
869 throw Decoding_Error(
"OS2ECP: Decoded point was not on the curve");
880 const uint8_t pc = pt[0];
881 const size_t p_bytes = p.
bytes();
886 if(pc == 2 || pc == 3) {
887 if(pt_len != 1 + p_bytes) {
892 const bool y_mod_2 = ((pc & 0x01) == 1);
893 y = decompress_point(y_mod_2, x, p, a, b);
895 if(pt_len != 1 + 2 * p_bytes) {
901 }
else if(pc == 6 || pc == 7) {
902 if(pt_len != 1 + 2 * p_bytes) {
909 const bool y_mod_2 = ((pc & 0x01) == 1);
911 if(decompress_point(y_mod_2, x, p, a, b) != y) {
915 throw Decoding_Error(
"OS2ECP: Unknown format type " + std::to_string(
static_cast<int>(pc)));
918 if(x >= p || y >= p) {
922 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)