7#include <botan/internal/ec_h2c.h>
9#include <botan/ec_group.h>
10#include <botan/numthry.h>
11#include <botan/reducer.h>
12#include <botan/internal/xmd.h>
18std::vector<BigInt> hash_to_field(
const EC_Group& group,
19 const Modular_Reducer& mod_p,
20 std::string_view hash_fn,
22 std::span<const uint8_t> input,
23 std::span<const uint8_t> domain_sep) {
24 const size_t k = (group.get_order_bits() + 1) / 2;
25 const size_t L = (group.get_p_bits() + k + 7) / 8;
27 std::vector<BigInt> results;
28 results.reserve(count);
30 secure_vector<uint8_t> output(L * count);
33 for(
size_t i = 0; i != count; ++i) {
34 BigInt v(&output[i * L], L);
35 results.push_back(mod_p.reduce(v));
41BigInt sswu_z(
const EC_Group& group) {
42 const BigInt& p = group.get_p();
43 const OID& oid = group.get_curve_oid();
45 if(oid == OID{1, 2, 840, 10045, 3, 1, 7}) {
48 if(oid == OID{1, 3, 132, 0, 34}) {
51 if(oid == OID{1, 3, 132, 0, 35}) {
58BigInt ct_choose(
bool first,
const BigInt& x,
const BigInt& y) {
60 z.ct_cond_assign(first, x);
64EC_Point map_to_curve_sswu(
const EC_Group& group,
const Modular_Reducer& mod_p,
const BigInt& u) {
65 const BigInt& p = group.get_p();
66 const BigInt& A = group.get_a();
67 const BigInt& B = group.get_b();
68 const BigInt
Z = sswu_z(group);
70 if(
Z.
is_zero() || A.is_zero() || B.is_zero() || p % 4 != 3) {
71 throw Invalid_Argument(
"map_to_curve_sswu does not support this curve");
75 const BigInt c1 = mod_p.multiply(p - B,
inverse_mod(A, p));
76 const BigInt c2 = mod_p.multiply(p - 1,
inverse_mod(
Z, p));
82 const BigInt tv1 = mod_p.multiply(
Z, mod_p.square(u));
83 const BigInt tv2 = mod_p.square(tv1);
86 const bool e1 = x1.is_zero();
88 x1.ct_cond_assign(e1, c2);
89 x1 = mod_p.multiply(x1, c1);
92 BigInt gx1 = mod_p.square(x1);
94 gx1 = mod_p.multiply(gx1, x1);
96 gx1 = mod_p.reduce(gx1);
98 const BigInt x2 = mod_p.multiply(tv1, x1);
101 const BigInt gx2 = mod_p.multiply(gx1, mod_p.multiply(tv1, tv2));
104 const bool gx1_is_square = (
power_mod(gx1, (p - 1) / 2, p) <= 1);
106 const BigInt x = ct_choose(gx1_is_square, x1, x2);
107 const BigInt y2 = ct_choose(gx1_is_square, gx1, gx2);
110 const BigInt y =
power_mod(y2, (p + 1) / 4, p);
111 const BigInt neg_y = p - y;
113 const bool uy_sign = u.get_bit(0) != y.get_bit(0);
114 return group.point(x, ct_choose(uy_sign, neg_y, y));
120 std::string_view hash_fn,
121 std::span<const uint8_t> input,
122 std::span<const uint8_t> domain_sep,
123 bool random_oracle) {
126 const uint8_t count = (random_oracle ? 2 : 1);
128 const auto u = hash_to_field(group, mod_p, hash_fn, count, input, domain_sep);
130 EC_Point pt = map_to_curve_sswu(group, mod_p, u[0]);
132 for(
size_t i = 1; i != u.size(); ++i) {
133 pt += map_to_curve_sswu(group, mod_p, u[i]);
const BigInt & get_p() const
BigInt power_mod(const BigInt &base, const BigInt &exp, const BigInt &mod)
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)
EC_Point hash_to_curve_sswu(const EC_Group &group, std::string_view hash_fn, std::span< const uint8_t > input, std::span< const uint8_t > domain_sep, bool random_oracle)
BigInt inverse_mod(const BigInt &n, const BigInt &mod)