Botan 3.4.0
Crypto and TLS for C&
ec_h2c.cpp
Go to the documentation of this file.
1/*
2* (C) 2019,2020,2021 Jack Lloyd
3*
4* Botan is released under the Simplified BSD License (see license.txt)
5*/
6
7#include <botan/internal/ec_h2c.h>
8
9#include <botan/ec_group.h>
10#include <botan/numthry.h>
11#include <botan/reducer.h>
12#include <botan/internal/xmd.h>
13
14namespace Botan {
15
16namespace {
17
18std::vector<BigInt> hash_to_field(const EC_Group& group,
19 const Modular_Reducer& mod_p,
20 std::string_view hash_fn,
21 uint8_t count,
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;
26
27 std::vector<BigInt> results;
28 results.reserve(count);
29
30 secure_vector<uint8_t> output(L * count);
31 expand_message_xmd(hash_fn, output, input, domain_sep);
32
33 for(size_t i = 0; i != count; ++i) {
34 BigInt v(&output[i * L], L);
35 results.push_back(mod_p.reduce(v));
36 }
37
38 return results;
39}
40
41BigInt sswu_z(const EC_Group& group) {
42 const BigInt& p = group.get_p();
43 const OID& oid = group.get_curve_oid();
44
45 if(oid == OID{1, 2, 840, 10045, 3, 1, 7}) { // secp256r1
46 return p - 10;
47 }
48 if(oid == OID{1, 3, 132, 0, 34}) { // secp384r1
49 return p - 12;
50 }
51 if(oid == OID{1, 3, 132, 0, 35}) { // secp521r1
52 return p - 4;
53 }
54
55 return 0;
56}
57
58BigInt ct_choose(bool first, const BigInt& x, const BigInt& y) {
59 BigInt z = y;
60 z.ct_cond_assign(first, x);
61 return z;
62}
63
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);
69
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");
72 }
73
74 // These values could be precomputed:
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));
77
78 /*
79 * See Appendix F.2 of RFC 9380
80 */
81
82 const BigInt tv1 = mod_p.multiply(Z, mod_p.square(u));
83 const BigInt tv2 = mod_p.square(tv1);
84
85 BigInt x1 = inverse_mod(tv1 + tv2, p);
86 const bool e1 = x1.is_zero();
87 x1 += 1;
88 x1.ct_cond_assign(e1, c2);
89 x1 = mod_p.multiply(x1, c1);
90
91 // gx1 = x1^3 + A*x1 + B;
92 BigInt gx1 = mod_p.square(x1);
93 gx1 += A;
94 gx1 = mod_p.multiply(gx1, x1);
95 gx1 += B;
96 gx1 = mod_p.reduce(gx1);
97
98 const BigInt x2 = mod_p.multiply(tv1, x1);
99
100 // gx2 = (Z * u^2)^3 * gx1
101 const BigInt gx2 = mod_p.multiply(gx1, mod_p.multiply(tv1, tv2));
102
103 // assumes p % 4 == 3
104 const bool gx1_is_square = (power_mod(gx1, (p - 1) / 2, p) <= 1);
105
106 const BigInt x = ct_choose(gx1_is_square, x1, x2);
107 const BigInt y2 = ct_choose(gx1_is_square, gx1, gx2);
108
109 // assumes p % 4 == 3
110 const BigInt y = power_mod(y2, (p + 1) / 4, p);
111 const BigInt neg_y = p - y;
112
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));
115}
116
117} // namespace
118
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) {
124 const Modular_Reducer mod_p(group.get_p());
125
126 const uint8_t count = (random_oracle ? 2 : 1);
127
128 const auto u = hash_to_field(group, mod_p, hash_fn, count, input, domain_sep);
129
130 EC_Point pt = map_to_curve_sswu(group, mod_p, u[0]);
131
132 for(size_t i = 1; i != u.size(); ++i) {
133 pt += map_to_curve_sswu(group, mod_p, u[i]);
134 }
135
136 return pt;
137}
138
139} // namespace Botan
const BigInt & get_p() const
Definition ec_group.cpp:492
bool is_zero() const
Definition ed25519_fe.h:75
FE_25519 Z
Definition ge.cpp:27
BigInt power_mod(const BigInt &base, const BigInt &exp, const BigInt &mod)
Definition numthry.cpp:286
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)
Definition xmd.cpp:16
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)
Definition ec_h2c.cpp:119
BigInt inverse_mod(const BigInt &n, const BigInt &mod)
Definition mod_inv.cpp:178