7#include <botan/internal/ec_h2c.h>
8#include <botan/internal/fmt.h>
9#include <botan/ec_group.h>
10#include <botan/numthry.h>
11#include <botan/reducer.h>
12#include <botan/hash.h>
19 const uint8_t input[],
21 const uint8_t domain_sep[],
22 size_t domain_sep_len)
24 if(domain_sep_len > 0xFF)
28 const size_t block_size = hash->hash_block_size();
32 const size_t hash_output_size = hash->output_length();
33 if(output_len > 255*hash_output_size || output_len > 0xFFFF)
34 throw Invalid_Argument(
"expand_message_xmd requested output length too long");
38 hash->update(std::vector<uint8_t>(block_size));
39 hash->update(input, input_len);
40 hash->update_be(
static_cast<uint16_t
>(output_len));
42 hash->update(domain_sep, domain_sep_len);
43 hash->update(
static_cast<uint8_t
>(domain_sep_len));
51 hash->update(domain_sep, domain_sep_len);
52 hash->update(
static_cast<uint8_t
>(domain_sep_len));
59 const size_t produced = std::min(output_len, hash_output_size);
61 copy_mem(output, b_i.data(), produced);
63 output_len -= produced;
70 hash->update(domain_sep, domain_sep_len);
71 hash->update(
static_cast<uint8_t
>(domain_sep_len));
72 hash->final(b_i.data());
80hash_to_field(
const EC_Group& group,
81 const Modular_Reducer& mod_p,
82 std::string_view hash_fn,
84 const uint8_t input[],
size_t input_len,
85 const uint8_t domain_sep[],
size_t domain_sep_len)
87 const size_t k = (group.get_order_bits() + 1) / 2;
88 const size_t L = (group.get_p_bits() + k + 7) / 8;
90 std::vector<BigInt> results;
91 results.reserve(count);
93 secure_vector<uint8_t> output(L * count);
95 output.data(), output.size(),
97 domain_sep, domain_sep_len);
99 for(
size_t i = 0; i != count; ++i)
101 BigInt v(&output[i*L], L);
102 results.push_back(mod_p.reduce(v));
108BigInt sswu_z(
const EC_Group& group)
110 const BigInt& p = group.get_p();
111 const OID& oid = group.get_curve_oid();
113 if(oid == OID{1,2,840,10045,3,1,7})
115 if(oid == OID{1,3,132,0,34})
117 if(oid == OID{1,3,132,0,35})
123BigInt ct_choose(
bool first,
const BigInt& x,
const BigInt&
y)
126 z.ct_cond_assign(first, x);
130EC_Point map_to_curve_sswu(
const EC_Group& group,
const Modular_Reducer& mod_p,
const BigInt& u)
132 const BigInt& p = group.get_p();
133 const BigInt& A = group.get_a();
134 const BigInt& B = group.get_b();
135 const BigInt
Z = sswu_z(group);
137 if(
Z.
is_zero() || A.is_zero() || B.is_zero() || p % 4 != 3)
138 throw Invalid_Argument(
"map_to_curve_sswu does not support this curve");
141 const BigInt c1 = mod_p.multiply(p - B,
inverse_mod(A, p));
142 const BigInt c2 = mod_p.multiply(p - 1,
inverse_mod(
Z, p));
148 const BigInt tv1 = mod_p.multiply(
Z, mod_p.square(u));
149 const BigInt tv2 = mod_p.square(tv1);
152 const bool e1 = x1.is_zero();
154 x1.ct_cond_assign(e1, c2);
155 x1 = mod_p.multiply(x1, c1);
158 BigInt gx1 = mod_p.square(x1);
160 gx1 = mod_p.multiply(gx1, x1);
162 gx1 = mod_p.reduce(gx1);
164 const BigInt x2 = mod_p.multiply(tv1, x1);
167 const BigInt gx2 = mod_p.multiply(gx1, mod_p.multiply(tv1, tv2));
170 const bool gx1_is_square = (
power_mod(gx1, (p-1)/2, p) <= 1);
172 const BigInt x = ct_choose(gx1_is_square, x1, x2);
173 const BigInt y2 = ct_choose(gx1_is_square, gx1, gx2);
177 const BigInt neg_y = p -
y;
179 const bool uy_sign = u.get_bit(0) !=
y.get_bit(0);
180 return group.point(x, ct_choose(uy_sign, neg_y,
y));
186 std::string_view hash_fn,
187 const uint8_t input[],
189 const uint8_t domain_sep[],
190 size_t domain_sep_len,
195 const uint8_t count = (random_oracle ? 2 : 1);
197 const auto u = hash_to_field(group, mod_p, hash_fn, count,
199 domain_sep, domain_sep_len);
201 EC_Point pt = map_to_curve_sswu(group, mod_p, u[0]);
203 for(
size_t i = 1; i != u.size(); ++i)
204 pt += map_to_curve_sswu(group, mod_p, u[i]);
const BigInt & get_p() const
static std::unique_ptr< HashFunction > create_or_throw(std::string_view algo_spec, std::string_view provider="")
void expand_message_xmd(std::string_view hash_fn, uint8_t output[], size_t output_len, const uint8_t input[], size_t input_len, const uint8_t domain_sep[], size_t domain_sep_len)
BigInt power_mod(const BigInt &base, const BigInt &exp, const BigInt &mod)
std::string fmt(std::string_view format, const T &... args)
constexpr void copy_mem(T *out, const T *in, size_t n)
EC_Point hash_to_curve_sswu(const EC_Group &group, std::string_view hash_fn, const uint8_t input[], size_t input_len, const uint8_t domain_sep[], size_t domain_sep_len, bool random_oracle)
BigInt inverse_mod(const BigInt &n, const BigInt &mod)
std::vector< T, secure_allocator< T > > secure_vector