1 // Copyright 2020 The BoringSSL Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 #include <openssl/ec.h>
16
17 #include <openssl/digest.h>
18 #include <openssl/err.h>
19 #include <openssl/nid.h>
20
21 #include <assert.h>
22
23 #include "../fipsmodule/bn/internal.h"
24 #include "../fipsmodule/ec/internal.h"
25 #include "../internal.h"
26 #include "internal.h"
27
28
29 // This file implements hash-to-curve, as described in RFC 9380.
30 //
31 // This hash-to-curve implementation is written generically with the
32 // expectation that we will eventually wish to support other curves. If it
33 // becomes a performance bottleneck, some possible optimizations by
34 // specializing it to the curve:
35 //
36 // - Rather than using a generic |felem_exp|, specialize the exponentation to
37 // c2 with a faster addition chain.
38 //
39 // - |felem_mul| and |felem_sqr| are indirect calls to generic Montgomery
40 // code. Given the few curves, we could specialize
41 // |map_to_curve_simple_swu|. But doing this reasonably without duplicating
42 // code in C is difficult. (C++ templates would be useful here.)
43 //
44 // - P-521's Z and c2 have small power-of-two absolute values. We could save
45 // two multiplications in SSWU. (Other curves have reasonable values of Z
46 // and inconvenient c2.) This is unlikely to be worthwhile without C++
47 // templates to make specializing more convenient.
48
49 // expand_message_xmd implements the operation described in section 5.3.1 of
50 // RFC 9380. It returns one on success and zero on error.
expand_message_xmd(const EVP_MD * md,uint8_t * out,size_t out_len,const uint8_t * msg,size_t msg_len,const uint8_t * dst,size_t dst_len)51 static int expand_message_xmd(const EVP_MD *md, uint8_t *out, size_t out_len,
52 const uint8_t *msg, size_t msg_len,
53 const uint8_t *dst, size_t dst_len) {
54 // See https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/issues/352
55 if (dst_len == 0) {
56 OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
57 return 0;
58 }
59
60 const size_t block_size = EVP_MD_block_size(md);
61 const size_t md_size = EVP_MD_size(md);
62 bssl::ScopedEVP_MD_CTX ctx;
63
64 // Long DSTs are hashed down to size. See section 5.3.3.
65 static_assert(EVP_MAX_MD_SIZE < 256, "hashed DST still too large");
66 uint8_t dst_buf[EVP_MAX_MD_SIZE];
67 if (dst_len >= 256) {
68 static const char kPrefix[] = "H2C-OVERSIZE-DST-";
69 if (!EVP_DigestInit_ex(ctx.get(), md, nullptr) ||
70 !EVP_DigestUpdate(ctx.get(), kPrefix, sizeof(kPrefix) - 1) ||
71 !EVP_DigestUpdate(ctx.get(), dst, dst_len) ||
72 !EVP_DigestFinal_ex(ctx.get(), dst_buf, nullptr)) {
73 return 0;
74 }
75 dst = dst_buf;
76 dst_len = md_size;
77 }
78 uint8_t dst_len_u8 = (uint8_t)dst_len;
79
80 // Compute b_0.
81 static const uint8_t kZeros[EVP_MAX_MD_BLOCK_SIZE] = {0};
82 // If |out_len| exceeds 16 bits then |i| will wrap below causing an error to
83 // be returned. This depends on the static assert above.
84 uint8_t l_i_b_str_zero[3] = {static_cast<uint8_t>(out_len >> 8),
85 static_cast<uint8_t>(out_len), 0};
86 uint8_t b_0[EVP_MAX_MD_SIZE];
87 if (!EVP_DigestInit_ex(ctx.get(), md, nullptr) ||
88 !EVP_DigestUpdate(ctx.get(), kZeros, block_size) ||
89 !EVP_DigestUpdate(ctx.get(), msg, msg_len) ||
90 !EVP_DigestUpdate(ctx.get(), l_i_b_str_zero, sizeof(l_i_b_str_zero)) ||
91 !EVP_DigestUpdate(ctx.get(), dst, dst_len) ||
92 !EVP_DigestUpdate(ctx.get(), &dst_len_u8, 1) ||
93 !EVP_DigestFinal_ex(ctx.get(), b_0, nullptr)) {
94 return 0;
95 }
96
97 uint8_t b_i[EVP_MAX_MD_SIZE];
98 uint8_t i = 1;
99 while (out_len > 0) {
100 if (i == 0) {
101 // Input was too large.
102 OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
103 return 0;
104 }
105 if (i > 1) {
106 for (size_t j = 0; j < md_size; j++) {
107 b_i[j] ^= b_0[j];
108 }
109 } else {
110 OPENSSL_memcpy(b_i, b_0, md_size);
111 }
112
113 if (!EVP_DigestInit_ex(ctx.get(), md, nullptr) ||
114 !EVP_DigestUpdate(ctx.get(), b_i, md_size) ||
115 !EVP_DigestUpdate(ctx.get(), &i, 1) ||
116 !EVP_DigestUpdate(ctx.get(), dst, dst_len) ||
117 !EVP_DigestUpdate(ctx.get(), &dst_len_u8, 1) ||
118 !EVP_DigestFinal_ex(ctx.get(), b_i, nullptr)) {
119 return 0;
120 }
121
122 size_t todo = out_len >= md_size ? md_size : out_len;
123 OPENSSL_memcpy(out, b_i, todo);
124 out += todo;
125 out_len -= todo;
126 i++;
127 }
128
129 return 1;
130 }
131
132 // num_bytes_to_derive determines the number of bytes to derive when hashing to
133 // a number modulo |modulus|. See the hash_to_field operation defined in
134 // section 5.2 of RFC 9380.
num_bytes_to_derive(size_t * out,const BIGNUM * modulus,unsigned k)135 static int num_bytes_to_derive(size_t *out, const BIGNUM *modulus, unsigned k) {
136 size_t bits = BN_num_bits(modulus);
137 size_t L = (bits + k + 7) / 8;
138 // We require 2^(8*L) < 2^(2*bits - 2) <= n^2 so to fit in bounds for
139 // |felem_reduce| and |ec_scalar_reduce|. All defined hash-to-curve suites
140 // define |k| to be well under this bound. (|k| is usually around half of
141 // |p_bits|.)
142 if (L * 8 >= 2 * bits - 2 || L > 2 * EC_MAX_BYTES) {
143 assert(0);
144 OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
145 return 0;
146 }
147
148 *out = L;
149 return 1;
150 }
151
152 // big_endian_to_words decodes |in| as a big-endian integer and writes the
153 // result to |out|. |num_words| must be large enough to contain the output.
big_endian_to_words(BN_ULONG * out,size_t num_words,const uint8_t * in,size_t len)154 static void big_endian_to_words(BN_ULONG *out, size_t num_words,
155 const uint8_t *in, size_t len) {
156 assert(len <= num_words * sizeof(BN_ULONG));
157 // Ensure any excess bytes are zeroed.
158 OPENSSL_memset(out, 0, num_words * sizeof(BN_ULONG));
159 uint8_t *out_u8 = (uint8_t *)out;
160 for (size_t i = 0; i < len; i++) {
161 out_u8[len - 1 - i] = in[i];
162 }
163 }
164
165 // hash_to_field implements the operation described in section 5.2
166 // of RFC 9380, with count = 2. |k| is the security factor.
hash_to_field2(const EC_GROUP * group,const EVP_MD * md,EC_FELEM * out1,EC_FELEM * out2,const uint8_t * dst,size_t dst_len,unsigned k,const uint8_t * msg,size_t msg_len)167 static int hash_to_field2(const EC_GROUP *group, const EVP_MD *md,
168 EC_FELEM *out1, EC_FELEM *out2, const uint8_t *dst,
169 size_t dst_len, unsigned k, const uint8_t *msg,
170 size_t msg_len) {
171 size_t L;
172 uint8_t buf[4 * EC_MAX_BYTES];
173 if (!num_bytes_to_derive(&L, &group->field.N, k) ||
174 !expand_message_xmd(md, buf, 2 * L, msg, msg_len, dst, dst_len)) {
175 return 0;
176 }
177 BN_ULONG words[2 * EC_MAX_WORDS];
178 size_t num_words = 2 * group->field.N.width;
179 big_endian_to_words(words, num_words, buf, L);
180 group->meth->felem_reduce(group, out1, words, num_words);
181 big_endian_to_words(words, num_words, buf + L, L);
182 group->meth->felem_reduce(group, out2, words, num_words);
183 return 1;
184 }
185
186 // hash_to_scalar behaves like |hash_to_field2| but returns a value modulo the
187 // group order rather than a field element. |k| is the security factor.
hash_to_scalar(const EC_GROUP * group,const EVP_MD * md,EC_SCALAR * out,const uint8_t * dst,size_t dst_len,unsigned k,const uint8_t * msg,size_t msg_len)188 static int hash_to_scalar(const EC_GROUP *group, const EVP_MD *md,
189 EC_SCALAR *out, const uint8_t *dst, size_t dst_len,
190 unsigned k, const uint8_t *msg, size_t msg_len) {
191 const BIGNUM *order = EC_GROUP_get0_order(group);
192 size_t L;
193 uint8_t buf[EC_MAX_BYTES * 2];
194 if (!num_bytes_to_derive(&L, order, k) ||
195 !expand_message_xmd(md, buf, L, msg, msg_len, dst, dst_len)) {
196 return 0;
197 }
198
199 BN_ULONG words[2 * EC_MAX_WORDS];
200 size_t num_words = 2 * order->width;
201 big_endian_to_words(words, num_words, buf, L);
202 ec_scalar_reduce(group, out, words, num_words);
203 return 1;
204 }
205
mul_A(const EC_GROUP * group,EC_FELEM * out,const EC_FELEM * in)206 static inline void mul_A(const EC_GROUP *group, EC_FELEM *out,
207 const EC_FELEM *in) {
208 assert(group->a_is_minus3);
209 EC_FELEM tmp;
210 ec_felem_add(group, &tmp, in, in); // tmp = 2*in
211 ec_felem_add(group, &tmp, &tmp, &tmp); // tmp = 4*in
212 ec_felem_sub(group, out, in, &tmp); // out = -3*in
213 }
214
215 // sgn0 implements the operation described in section 4.1.2 of RFC 9380.
sgn0(const EC_GROUP * group,const EC_FELEM * a)216 static BN_ULONG sgn0(const EC_GROUP *group, const EC_FELEM *a) {
217 uint8_t buf[EC_MAX_BYTES];
218 size_t len;
219 ec_felem_to_bytes(group, buf, &len, a);
220 return buf[len - 1] & 1;
221 }
222
is_3mod4(const EC_GROUP * group)223 [[maybe_unused]] static int is_3mod4(const EC_GROUP *group) {
224 return group->field.N.width > 0 && (group->field.N.d[0] & 3) == 3;
225 }
226
227 // sqrt_ratio_3mod4 implements the operation described in appendix F.2.1.2
228 // of RFC 9380.
sqrt_ratio_3mod4(const EC_GROUP * group,const EC_FELEM * Z,const BN_ULONG * c1,size_t num_c1,const EC_FELEM * c2,EC_FELEM * out_y,const EC_FELEM * u,const EC_FELEM * v)229 static BN_ULONG sqrt_ratio_3mod4(const EC_GROUP *group, const EC_FELEM *Z,
230 const BN_ULONG *c1, size_t num_c1,
231 const EC_FELEM *c2, EC_FELEM *out_y,
232 const EC_FELEM *u, const EC_FELEM *v) {
233 assert(is_3mod4(group));
234
235 void (*const felem_mul)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
236 const EC_FELEM *b) = group->meth->felem_mul;
237 void (*const felem_sqr)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a) =
238 group->meth->felem_sqr;
239
240 EC_FELEM tv1, tv2, tv3, y1, y2;
241 felem_sqr(group, &tv1, v); // 1. tv1 = v^2
242 felem_mul(group, &tv2, u, v); // 2. tv2 = u * v
243 felem_mul(group, &tv1, &tv1, &tv2); // 3. tv1 = tv1 * tv2
244 group->meth->felem_exp(group, &y1, &tv1, c1, num_c1); // 4. y1 = tv1^c1
245 felem_mul(group, &y1, &y1, &tv2); // 5. y1 = y1 * tv2
246 felem_mul(group, &y2, &y1, c2); // 6. y2 = y1 * c2
247 felem_sqr(group, &tv3, &y1); // 7. tv3 = y1^2
248 felem_mul(group, &tv3, &tv3, v); // 8. tv3 = tv3 * v
249
250 // 9. isQR = tv3 == u
251 // 10. y = CMOV(y2, y1, isQR)
252 // 11. return (isQR, y)
253 //
254 // Note the specification's CMOV function and our |ec_felem_select| have the
255 // opposite argument order.
256 ec_felem_sub(group, &tv1, &tv3, u);
257 const BN_ULONG isQR = ~ec_felem_non_zero_mask(group, &tv1);
258 ec_felem_select(group, out_y, isQR, &y1, &y2);
259 return isQR;
260 }
261
262 // map_to_curve_simple_swu implements the operation described in section 6.6.2
263 // of RFC 9380, using the straight-line implementation in appendix F.2.
map_to_curve_simple_swu(const EC_GROUP * group,const EC_FELEM * Z,const BN_ULONG * c1,size_t num_c1,const EC_FELEM * c2,EC_JACOBIAN * out,const EC_FELEM * u)264 static void map_to_curve_simple_swu(const EC_GROUP *group, const EC_FELEM *Z,
265 const BN_ULONG *c1, size_t num_c1,
266 const EC_FELEM *c2, EC_JACOBIAN *out,
267 const EC_FELEM *u) {
268 // This function requires the prime be 3 mod 4, and that A = -3.
269 assert(is_3mod4(group));
270 assert(group->a_is_minus3);
271
272 void (*const felem_mul)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
273 const EC_FELEM *b) = group->meth->felem_mul;
274 void (*const felem_sqr)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a) =
275 group->meth->felem_sqr;
276
277 EC_FELEM tv1, tv2, tv3, tv4, tv5, tv6, x, y, y1;
278 felem_sqr(group, &tv1, u); // 1. tv1 = u^2
279 felem_mul(group, &tv1, Z, &tv1); // 2. tv1 = Z * tv1
280 felem_sqr(group, &tv2, &tv1); // 3. tv2 = tv1^2
281 ec_felem_add(group, &tv2, &tv2, &tv1); // 4. tv2 = tv2 + tv1
282 ec_felem_add(group, &tv3, &tv2, ec_felem_one(group)); // 5. tv3 = tv2 + 1
283 felem_mul(group, &tv3, &group->b, &tv3); // 6. tv3 = B * tv3
284
285 // 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
286 const BN_ULONG tv2_non_zero = ec_felem_non_zero_mask(group, &tv2);
287 ec_felem_neg(group, &tv4, &tv2);
288 ec_felem_select(group, &tv4, tv2_non_zero, &tv4, Z);
289
290 mul_A(group, &tv4, &tv4); // 8. tv4 = A * tv4
291 felem_sqr(group, &tv2, &tv3); // 9. tv2 = tv3^2
292 felem_sqr(group, &tv6, &tv4); // 10. tv6 = tv4^2
293 mul_A(group, &tv5, &tv6); // 11. tv5 = A * tv6
294 ec_felem_add(group, &tv2, &tv2, &tv5); // 12. tv2 = tv2 + tv5
295 felem_mul(group, &tv2, &tv2, &tv3); // 13. tv2 = tv2 * tv3
296 felem_mul(group, &tv6, &tv6, &tv4); // 14. tv6 = tv6 * tv4
297 felem_mul(group, &tv5, &group->b, &tv6); // 15. tv5 = B * tv6
298 ec_felem_add(group, &tv2, &tv2, &tv5); // 16. tv2 = tv2 + tv5
299 felem_mul(group, &x, &tv1, &tv3); // 17. x = tv1 * tv3
300
301 // 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
302 const BN_ULONG is_gx1_square =
303 sqrt_ratio_3mod4(group, Z, c1, num_c1, c2, &y1, &tv2, &tv6);
304
305 felem_mul(group, &y, &tv1, u); // 19. y = tv1 * u
306 felem_mul(group, &y, &y, &y1); // 20. y = y * y1
307
308 // 21. x = CMOV(x, tv3, is_gx1_square)
309 ec_felem_select(group, &x, is_gx1_square, &tv3, &x);
310 // 22. y = CMOV(y, y1, is_gx1_square)
311 ec_felem_select(group, &y, is_gx1_square, &y1, &y);
312
313 // 23. e1 = sgn0(u) == sgn0(y)
314 BN_ULONG sgn0_u = sgn0(group, u);
315 BN_ULONG sgn0_y = sgn0(group, &y);
316 BN_ULONG not_e1 = sgn0_u ^ sgn0_y;
317 not_e1 = ((BN_ULONG)0) - not_e1;
318
319 // 24. y = CMOV(-y, y, e1)
320 ec_felem_neg(group, &tv1, &y);
321 ec_felem_select(group, &y, not_e1, &tv1, &y);
322
323 // 25. x = x / tv4
324 //
325 // Our output is in projective coordinates, so rather than inverting |tv4|
326 // now, represent (x / tv4, y) as (x * tv4, y * tv4^3, tv4). This is much more
327 // efficient if the caller will do further computation on the output. (If the
328 // caller will immediately convert to affine coordinates, it is slightly less
329 // efficient, but only by a few field multiplications.)
330 felem_mul(group, &out->X, &x, &tv4);
331 felem_mul(group, &out->Y, &y, &tv6);
332 out->Z = tv4;
333 }
334
hash_to_curve(const EC_GROUP * group,const EVP_MD * md,const EC_FELEM * Z,const EC_FELEM * c2,unsigned k,EC_JACOBIAN * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)335 static int hash_to_curve(const EC_GROUP *group, const EVP_MD *md,
336 const EC_FELEM *Z, const EC_FELEM *c2, unsigned k,
337 EC_JACOBIAN *out, const uint8_t *dst, size_t dst_len,
338 const uint8_t *msg, size_t msg_len) {
339 EC_FELEM u0, u1;
340 if (!hash_to_field2(group, md, &u0, &u1, dst, dst_len, k, msg, msg_len)) {
341 return 0;
342 }
343
344 // Compute |c1| = (p - 3) / 4.
345 BN_ULONG c1[EC_MAX_WORDS];
346 size_t num_c1 = group->field.N.width;
347 if (!bn_copy_words(c1, num_c1, &group->field.N)) {
348 return 0;
349 }
350 bn_rshift_words(c1, c1, /*shift=*/2, /*num=*/num_c1);
351
352 EC_JACOBIAN Q0, Q1;
353 map_to_curve_simple_swu(group, Z, c1, num_c1, c2, &Q0, &u0);
354 map_to_curve_simple_swu(group, Z, c1, num_c1, c2, &Q1, &u1);
355
356 group->meth->add(group, out, &Q0, &Q1); // R = Q0 + Q1
357 // All our curves have cofactor one, so |clear_cofactor| is a no-op.
358 return 1;
359 }
360
felem_from_u8(const EC_GROUP * group,EC_FELEM * out,uint8_t a)361 static int felem_from_u8(const EC_GROUP *group, EC_FELEM *out, uint8_t a) {
362 uint8_t bytes[EC_MAX_BYTES] = {0};
363 size_t len = BN_num_bytes(&group->field.N);
364 bytes[len - 1] = a;
365 return ec_felem_from_bytes(group, out, bytes, len);
366 }
367
368 // kP256Sqrt10 is sqrt(10) in P-256's field. It was computed as follows in
369 // python3:
370 //
371 // p = 2**256 - 2**224 + 2**192 + 2**96 - 1
372 // c2 = pow(10, (p+1)//4, p)
373 // assert pow(c2, 2, p) == 10
374 // ", ".join("0x%02x" % b for b in c2.to_bytes(256//8, 'big'))
375 static const uint8_t kP256Sqrt10[] = {
376 0xda, 0x53, 0x8e, 0x3b, 0xe1, 0xd8, 0x9b, 0x99, 0xc9, 0x78, 0xfc,
377 0x67, 0x51, 0x80, 0xaa, 0xb2, 0x7b, 0x8d, 0x1f, 0xf8, 0x4c, 0x55,
378 0xd5, 0xb6, 0x2c, 0xcd, 0x34, 0x27, 0xe4, 0x33, 0xc4, 0x7f};
379
380 // kP384Sqrt12 is sqrt(12) in P-384's field. It was computed as follows in
381 // python3:
382 //
383 // p = 2**384 - 2**128 - 2**96 + 2**32 - 1
384 // c2 = pow(12, (p+1)//4, p)
385 // assert pow(c2, 2, p) == 12
386 // ", ".join("0x%02x" % b for b in c2.to_bytes(384//8, 'big'))
387 static const uint8_t kP384Sqrt12[] = {
388 0x2a, 0xcc, 0xb4, 0xa6, 0x56, 0xb0, 0x24, 0x9c, 0x71, 0xf0, 0x50, 0x0e,
389 0x83, 0xda, 0x2f, 0xdd, 0x7f, 0x98, 0xe3, 0x83, 0xd6, 0x8b, 0x53, 0x87,
390 0x1f, 0x87, 0x2f, 0xcb, 0x9c, 0xcb, 0x80, 0xc5, 0x3c, 0x0d, 0xe1, 0xf8,
391 0xa8, 0x0f, 0x7e, 0x19, 0x14, 0xe2, 0xec, 0x69, 0xf5, 0xa6, 0x26, 0xb3};
392
ec_hash_to_curve_p256_xmd_sha256_sswu(const EC_GROUP * group,EC_JACOBIAN * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)393 int ec_hash_to_curve_p256_xmd_sha256_sswu(const EC_GROUP *group,
394 EC_JACOBIAN *out, const uint8_t *dst,
395 size_t dst_len, const uint8_t *msg,
396 size_t msg_len) {
397 // See section 8.3 of RFC 9380.
398 if (EC_GROUP_get_curve_name(group) != NID_X9_62_prime256v1) {
399 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
400 return 0;
401 }
402
403 // Z = -10, c2 = sqrt(10)
404 EC_FELEM Z, c2;
405 if (!felem_from_u8(group, &Z, 10) ||
406 !ec_felem_from_bytes(group, &c2, kP256Sqrt10, sizeof(kP256Sqrt10))) {
407 return 0;
408 }
409 ec_felem_neg(group, &Z, &Z);
410
411 return hash_to_curve(group, EVP_sha256(), &Z, &c2, /*k=*/128, out, dst,
412 dst_len, msg, msg_len);
413 }
414
EC_hash_to_curve_p256_xmd_sha256_sswu(const EC_GROUP * group,EC_POINT * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)415 int EC_hash_to_curve_p256_xmd_sha256_sswu(const EC_GROUP *group, EC_POINT *out,
416 const uint8_t *dst, size_t dst_len,
417 const uint8_t *msg, size_t msg_len) {
418 if (EC_GROUP_cmp(group, out->group, NULL) != 0) {
419 OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
420 return 0;
421 }
422 return ec_hash_to_curve_p256_xmd_sha256_sswu(group, &out->raw, dst, dst_len,
423 msg, msg_len);
424 }
425
ec_hash_to_curve_p384_xmd_sha384_sswu(const EC_GROUP * group,EC_JACOBIAN * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)426 int ec_hash_to_curve_p384_xmd_sha384_sswu(const EC_GROUP *group,
427 EC_JACOBIAN *out, const uint8_t *dst,
428 size_t dst_len, const uint8_t *msg,
429 size_t msg_len) {
430 // See section 8.3 of RFC 9380.
431 if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
432 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
433 return 0;
434 }
435
436 // Z = -12, c2 = sqrt(12)
437 EC_FELEM Z, c2;
438 if (!felem_from_u8(group, &Z, 12) ||
439 !ec_felem_from_bytes(group, &c2, kP384Sqrt12, sizeof(kP384Sqrt12))) {
440 return 0;
441 }
442 ec_felem_neg(group, &Z, &Z);
443
444 return hash_to_curve(group, EVP_sha384(), &Z, &c2, /*k=*/192, out, dst,
445 dst_len, msg, msg_len);
446 }
447
EC_hash_to_curve_p384_xmd_sha384_sswu(const EC_GROUP * group,EC_POINT * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)448 int EC_hash_to_curve_p384_xmd_sha384_sswu(const EC_GROUP *group, EC_POINT *out,
449 const uint8_t *dst, size_t dst_len,
450 const uint8_t *msg, size_t msg_len) {
451 if (EC_GROUP_cmp(group, out->group, NULL) != 0) {
452 OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
453 return 0;
454 }
455 return ec_hash_to_curve_p384_xmd_sha384_sswu(group, &out->raw, dst, dst_len,
456 msg, msg_len);
457 }
458
ec_hash_to_scalar_p384_xmd_sha384(const EC_GROUP * group,EC_SCALAR * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)459 int ec_hash_to_scalar_p384_xmd_sha384(const EC_GROUP *group, EC_SCALAR *out,
460 const uint8_t *dst, size_t dst_len,
461 const uint8_t *msg, size_t msg_len) {
462 if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
463 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
464 return 0;
465 }
466
467 return hash_to_scalar(group, EVP_sha384(), out, dst, dst_len, /*k=*/192, msg,
468 msg_len);
469 }
470
ec_hash_to_curve_p384_xmd_sha512_sswu_draft07(const EC_GROUP * group,EC_JACOBIAN * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)471 int ec_hash_to_curve_p384_xmd_sha512_sswu_draft07(
472 const EC_GROUP *group, EC_JACOBIAN *out, const uint8_t *dst, size_t dst_len,
473 const uint8_t *msg, size_t msg_len) {
474 // See section 8.3 of draft-irtf-cfrg-hash-to-curve-07.
475 if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
476 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
477 return 0;
478 }
479
480 // Z = -12, c2 = sqrt(12)
481 EC_FELEM Z, c2;
482 if (!felem_from_u8(group, &Z, 12) ||
483 !ec_felem_from_bytes(group, &c2, kP384Sqrt12, sizeof(kP384Sqrt12))) {
484 return 0;
485 }
486 ec_felem_neg(group, &Z, &Z);
487
488 return hash_to_curve(group, EVP_sha512(), &Z, &c2, /*k=*/192, out, dst,
489 dst_len, msg, msg_len);
490 }
491
ec_hash_to_scalar_p384_xmd_sha512_draft07(const EC_GROUP * group,EC_SCALAR * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)492 int ec_hash_to_scalar_p384_xmd_sha512_draft07(
493 const EC_GROUP *group, EC_SCALAR *out, const uint8_t *dst, size_t dst_len,
494 const uint8_t *msg, size_t msg_len) {
495 if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
496 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
497 return 0;
498 }
499
500 return hash_to_scalar(group, EVP_sha512(), out, dst, dst_len, /*k=*/192, msg,
501 msg_len);
502 }
503