1 /* Copyright (c) 2020, Google Inc.
2 *
3 * Permission to use, copy, modify, and/or distribute this software for any
4 * purpose with or without fee is hereby granted, provided that the above
5 * copyright notice and this permission notice appear in all copies.
6 *
7 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
8 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
9 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
10 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
11 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
12 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
13 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
14
15 #include <openssl/ec.h>
16
17 #include <openssl/digest.h>
18 #include <openssl/err.h>
19 #include <openssl/nid.h>
20 #include <openssl/type_check.h>
21
22 #include <assert.h>
23
24 #include "internal.h"
25 #include "../fipsmodule/bn/internal.h"
26 #include "../fipsmodule/ec/internal.h"
27 #include "../internal.h"
28
29
30 // This file implements hash-to-curve, as described in
31 // draft-irtf-cfrg-hash-to-curve-07.
32 //
33 // This hash-to-curve implementation is written generically with the
34 // expectation that we will eventually wish to support other curves. If it
35 // becomes a performance bottleneck, some possible optimizations by
36 // specializing it to the curve:
37 //
38 // - Rather than using a generic |felem_exp|, specialize the exponentation to
39 // c2 with a faster addition chain.
40 //
41 // - |felem_mul| and |felem_sqr| are indirect calls to generic Montgomery
42 // code. Given the few curves, we could specialize
43 // |map_to_curve_simple_swu|. But doing this reasonably without duplicating
44 // code in C is difficult. (C++ templates would be useful here.)
45 //
46 // - P-521's Z and c2 have small power-of-two absolute values. We could save
47 // two multiplications in SSWU. (Other curves have reasonable values of Z
48 // and inconvenient c2.) This is unlikely to be worthwhile without C++
49 // templates to make specializing more convenient.
50
51 // expand_message_xmd implements the operation described in section 5.3.1 of
52 // draft-irtf-cfrg-hash-to-curve-07. It returns one on success and zero on
53 // allocation failure or if |out_len| was too large. If |is_draft06| is one, it
54 // implements the operation from draft-irtf-cfrg-hash-to-curve-06 instead.
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,int is_draft06)55 static int expand_message_xmd(const EVP_MD *md, uint8_t *out, size_t out_len,
56 const uint8_t *msg, size_t msg_len,
57 const uint8_t *dst, size_t dst_len,
58 int is_draft06) {
59 int ret = 0;
60 const size_t block_size = EVP_MD_block_size(md);
61 const size_t md_size = EVP_MD_size(md);
62 EVP_MD_CTX ctx;
63 EVP_MD_CTX_init(&ctx);
64
65 // Long DSTs are hashed down to size. See section 5.3.3.
66 OPENSSL_STATIC_ASSERT(EVP_MAX_MD_SIZE < 256, "hashed DST still too large");
67 uint8_t dst_buf[EVP_MAX_MD_SIZE];
68 if (dst_len >= 256) {
69 static const char kPrefix[] = "H2C-OVERSIZE-DST-";
70 if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
71 !EVP_DigestUpdate(&ctx, kPrefix, sizeof(kPrefix) - 1) ||
72 !EVP_DigestUpdate(&ctx, dst, dst_len) ||
73 !EVP_DigestFinal_ex(&ctx, dst_buf, NULL)) {
74 goto err;
75 }
76 dst = dst_buf;
77 dst_len = md_size;
78 }
79 uint8_t dst_len_u8 = (uint8_t)dst_len;
80
81 // Compute b_0.
82 static const uint8_t kZeros[EVP_MAX_MD_BLOCK_SIZE] = {0};
83 // If |out_len| exceeds 16 bits then |i| will wrap below causing an error to
84 // be returned. This depends on the static assert above.
85 uint8_t l_i_b_str_zero[3] = {out_len >> 8, out_len, 0};
86 uint8_t b_0[EVP_MAX_MD_SIZE];
87 if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
88 !EVP_DigestUpdate(&ctx, kZeros, block_size) ||
89 !EVP_DigestUpdate(&ctx, msg, msg_len) ||
90 !EVP_DigestUpdate(&ctx, l_i_b_str_zero, sizeof(l_i_b_str_zero)) ||
91 (is_draft06 && !EVP_DigestUpdate(&ctx, &dst_len_u8, 1)) ||
92 !EVP_DigestUpdate(&ctx, dst, dst_len) ||
93 (!is_draft06 && !EVP_DigestUpdate(&ctx, &dst_len_u8, 1)) ||
94 !EVP_DigestFinal_ex(&ctx, b_0, NULL)) {
95 goto err;
96 }
97
98 uint8_t b_i[EVP_MAX_MD_SIZE];
99 uint8_t i = 1;
100 while (out_len > 0) {
101 if (i == 0) {
102 // Input was too large.
103 OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
104 goto err;
105 }
106 if (i > 1) {
107 for (size_t j = 0; j < md_size; j++) {
108 b_i[j] ^= b_0[j];
109 }
110 } else {
111 OPENSSL_memcpy(b_i, b_0, md_size);
112 }
113
114 if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
115 !EVP_DigestUpdate(&ctx, b_i, md_size) ||
116 !EVP_DigestUpdate(&ctx, &i, 1) ||
117 (is_draft06 && !EVP_DigestUpdate(&ctx, &dst_len_u8, 1)) ||
118 !EVP_DigestUpdate(&ctx, dst, dst_len) ||
119 (!is_draft06 && !EVP_DigestUpdate(&ctx, &dst_len_u8, 1)) ||
120 !EVP_DigestFinal_ex(&ctx, b_i, NULL)) {
121 goto err;
122 }
123
124 size_t todo = out_len >= md_size ? md_size : out_len;
125 OPENSSL_memcpy(out, b_i, todo);
126 out += todo;
127 out_len -= todo;
128 i++;
129 }
130
131 ret = 1;
132
133 err:
134 EVP_MD_CTX_cleanup(&ctx);
135 return ret;
136 }
137
138 // num_bytes_to_derive determines the number of bytes to derive when hashing to
139 // a number modulo |modulus|. See the hash_to_field operation defined in
140 // section 5.2 of draft-irtf-cfrg-hash-to-curve-07.
num_bytes_to_derive(size_t * out,const BIGNUM * modulus,unsigned k)141 static int num_bytes_to_derive(size_t *out, const BIGNUM *modulus, unsigned k) {
142 size_t bits = BN_num_bits(modulus);
143 size_t L = (bits + k + 7) / 8;
144 // We require 2^(8*L) < 2^(2*bits - 2) <= n^2 so to fit in bounds for
145 // |felem_reduce| and |ec_scalar_reduce|. All defined hash-to-curve suites
146 // define |k| to be well under this bound. (|k| is usually around half of
147 // |p_bits|.)
148 if (L * 8 >= 2 * bits - 2 ||
149 L > 2 * EC_MAX_BYTES) {
150 assert(0);
151 OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
152 return 0;
153 }
154
155 *out = L;
156 return 1;
157 }
158
159 // big_endian_to_words decodes |in| as a big-endian integer and writes the
160 // 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)161 static void big_endian_to_words(BN_ULONG *out, size_t num_words,
162 const uint8_t *in, size_t len) {
163 assert(len <= num_words * sizeof(BN_ULONG));
164 // Ensure any excess bytes are zeroed.
165 OPENSSL_memset(out, 0, num_words * sizeof(BN_ULONG));
166 uint8_t *out_u8 = (uint8_t *)out;
167 for (size_t i = 0; i < len; i++) {
168 out_u8[len - 1 - i] = in[i];
169 }
170 }
171
172 // hash_to_field implements the operation described in section 5.2
173 // of draft-irtf-cfrg-hash-to-curve-07, with count = 2. |k| is the security
174 // 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,int is_draft06)175 static int hash_to_field2(const EC_GROUP *group, const EVP_MD *md,
176 EC_FELEM *out1, EC_FELEM *out2, const uint8_t *dst,
177 size_t dst_len, unsigned k, const uint8_t *msg,
178 size_t msg_len, int is_draft06) {
179 size_t L;
180 uint8_t buf[4 * EC_MAX_BYTES];
181 if (!num_bytes_to_derive(&L, &group->field, k) ||
182 !expand_message_xmd(md, buf, 2 * L, msg, msg_len, dst, dst_len,
183 is_draft06)) {
184 return 0;
185 }
186 BN_ULONG words[2 * EC_MAX_WORDS];
187 size_t num_words = 2 * group->field.width;
188 big_endian_to_words(words, num_words, buf, L);
189 group->meth->felem_reduce(group, out1, words, num_words);
190 big_endian_to_words(words, num_words, buf + L, L);
191 group->meth->felem_reduce(group, out2, words, num_words);
192 return 1;
193 }
194
195 // hash_to_scalar behaves like |hash_to_field2| but returns a value modulo the
196 // 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,int is_draft06)197 static int hash_to_scalar(const EC_GROUP *group, const EVP_MD *md,
198 EC_SCALAR *out, const uint8_t *dst, size_t dst_len,
199 unsigned k, const uint8_t *msg, size_t msg_len,
200 int is_draft06) {
201 size_t L;
202 uint8_t buf[EC_MAX_BYTES * 2];
203 if (!num_bytes_to_derive(&L, &group->order, k) ||
204 !expand_message_xmd(md, buf, L, msg, msg_len, dst, dst_len, is_draft06)) {
205 return 0;
206 }
207
208 BN_ULONG words[2 * EC_MAX_WORDS];
209 size_t num_words = 2 * group->order.width;
210 big_endian_to_words(words, num_words, buf, L);
211 ec_scalar_reduce(group, out, words, num_words);
212 return 1;
213 }
214
mul_A(const EC_GROUP * group,EC_FELEM * out,const EC_FELEM * in)215 static inline void mul_A(const EC_GROUP *group, EC_FELEM *out,
216 const EC_FELEM *in) {
217 assert(group->a_is_minus3);
218 EC_FELEM tmp;
219 ec_felem_add(group, &tmp, in, in); // tmp = 2*in
220 ec_felem_add(group, &tmp, &tmp, &tmp); // tmp = 4*in
221 ec_felem_sub(group, out, in, &tmp); // out = -3*in
222 }
223
mul_minus_A(const EC_GROUP * group,EC_FELEM * out,const EC_FELEM * in)224 static inline void mul_minus_A(const EC_GROUP *group, EC_FELEM *out,
225 const EC_FELEM *in) {
226 assert(group->a_is_minus3);
227 EC_FELEM tmp;
228 ec_felem_add(group, &tmp, in, in); // tmp = 2*in
229 ec_felem_add(group, out, &tmp, in); // out = 3*in
230 }
231
232 // sgn0_le implements the operation described in section 4.1.2 of
233 // draft-irtf-cfrg-hash-to-curve-07.
sgn0_le(const EC_GROUP * group,const EC_FELEM * a)234 static BN_ULONG sgn0_le(const EC_GROUP *group, const EC_FELEM *a) {
235 uint8_t buf[EC_MAX_BYTES];
236 size_t len;
237 ec_felem_to_bytes(group, buf, &len, a);
238 return buf[len - 1] & 1;
239 }
240
241 // map_to_curve_simple_swu implements the operation described in section 6.6.2
242 // of draft-irtf-cfrg-hash-to-curve-07, using the optimization in appendix
243 // D.2.1. It returns one on success and zero on error.
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_RAW_POINT * out,const EC_FELEM * u)244 static int map_to_curve_simple_swu(const EC_GROUP *group, const EC_FELEM *Z,
245 const BN_ULONG *c1, size_t num_c1,
246 const EC_FELEM *c2, EC_RAW_POINT *out,
247 const EC_FELEM *u) {
248 void (*const felem_mul)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
249 const EC_FELEM *b) = group->meth->felem_mul;
250 void (*const felem_sqr)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a) =
251 group->meth->felem_sqr;
252
253 // This function requires the prime be 3 mod 4, and that A = -3.
254 if (group->field.width == 0 || (group->field.d[0] & 3) != 3 ||
255 !group->a_is_minus3) {
256 OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
257 return 0;
258 }
259
260 EC_FELEM tv1, tv2, tv3, tv4, xd, x1n, x2n, tmp, gxd, gx1, y1, y2;
261 felem_sqr(group, &tv1, u); // tv1 = u^2
262 felem_mul(group, &tv3, Z, &tv1); // tv3 = Z * tv1
263 felem_sqr(group, &tv2, &tv3); // tv2 = tv3^2
264 ec_felem_add(group, &xd, &tv2, &tv3); // xd = tv2 + tv3
265 ec_felem_add(group, &x1n, &xd, &group->one); // x1n = xd + 1
266 felem_mul(group, &x1n, &x1n, &group->b); // x1n = x1n * B
267 mul_minus_A(group, &xd, &xd); // xd = -A * xd
268 BN_ULONG e1 = ec_felem_non_zero_mask(group, &xd); // e1 = xd == 0 [flipped]
269 mul_A(group, &tmp, Z);
270 ec_felem_select(group, &xd, e1, &xd, &tmp); // xd = CMOV(xd, Z * A, e1)
271 felem_sqr(group, &tv2, &xd); // tv2 = xd^2
272 felem_mul(group, &gxd, &tv2, &xd); // gxd = tv2 * xd = xd^3
273 mul_A(group, &tv2, &tv2); // tv2 = A * tv2
274 felem_sqr(group, &gx1, &x1n); // gx1 = x1n^2
275 ec_felem_add(group, &gx1, &gx1, &tv2); // gx1 = gx1 + tv2
276 felem_mul(group, &gx1, &gx1, &x1n); // gx1 = gx1 * x1n
277 felem_mul(group, &tv2, &group->b, &gxd); // tv2 = B * gxd
278 ec_felem_add(group, &gx1, &gx1, &tv2); // gx1 = gx1 + tv2
279 felem_sqr(group, &tv4, &gxd); // tv4 = gxd^2
280 felem_mul(group, &tv2, &gx1, &gxd); // tv2 = gx1 * gxd
281 felem_mul(group, &tv4, &tv4, &tv2); // tv4 = tv4 * tv2
282 group->meth->felem_exp(group, &y1, &tv4, c1, num_c1); // y1 = tv4^c1
283 felem_mul(group, &y1, &y1, &tv2); // y1 = y1 * tv2
284 felem_mul(group, &x2n, &tv3, &x1n); // x2n = tv3 * x1n
285 felem_mul(group, &y2, &y1, c2); // y2 = y1 * c2
286 felem_mul(group, &y2, &y2, &tv1); // y2 = y2 * tv1
287 felem_mul(group, &y2, &y2, u); // y2 = y2 * u
288 felem_sqr(group, &tv2, &y1); // tv2 = y1^2
289 felem_mul(group, &tv2, &tv2, &gxd); // tv2 = tv2 * gxd
290 ec_felem_sub(group, &tv3, &tv2, &gx1);
291 BN_ULONG e2 =
292 ec_felem_non_zero_mask(group, &tv3); // e2 = tv2 == gx1 [flipped]
293 ec_felem_select(group, &x1n, e2, &x2n, &x1n); // xn = CMOV(x2n, x1n, e2)
294 ec_felem_select(group, &y1, e2, &y2, &y1); // y = CMOV(y2, y1, e2)
295 BN_ULONG sgn0_u = sgn0_le(group, u);
296 BN_ULONG sgn0_y = sgn0_le(group, &y1);
297 BN_ULONG e3 = sgn0_u ^ sgn0_y;
298 e3 = ((BN_ULONG)0) - e3; // e3 = sgn0(u) == sgn0(y) [flipped]
299 ec_felem_neg(group, &y2, &y1);
300 ec_felem_select(group, &y1, e3, &y2, &y1); // y = CMOV(-y, y, e3)
301
302 // Appendix D.1 describes how to convert (x1n, xd, y1, 1) to Jacobian
303 // coordinates. Note yd = 1. Also note that gxd computed above is xd^3.
304 felem_mul(group, &out->X, &x1n, &xd); // X = xn * xd
305 felem_mul(group, &out->Y, &y1, &gxd); // Y = yn * gxd = yn * xd^3
306 out->Z = xd; // Z = xd
307 return 1;
308 }
309
hash_to_curve(const EC_GROUP * group,const EVP_MD * md,const EC_FELEM * Z,const EC_FELEM * c2,unsigned k,EC_RAW_POINT * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len,int is_draft06)310 static int hash_to_curve(const EC_GROUP *group, const EVP_MD *md,
311 const EC_FELEM *Z, const EC_FELEM *c2, unsigned k,
312 EC_RAW_POINT *out, const uint8_t *dst, size_t dst_len,
313 const uint8_t *msg, size_t msg_len, int is_draft06) {
314 EC_FELEM u0, u1;
315 if (!hash_to_field2(group, md, &u0, &u1, dst, dst_len, k, msg, msg_len,
316 is_draft06)) {
317 return 0;
318 }
319
320 // Compute |c1| = (p - 3) / 4.
321 BN_ULONG c1[EC_MAX_WORDS];
322 size_t num_c1 = group->field.width;
323 if (!bn_copy_words(c1, num_c1, &group->field)) {
324 return 0;
325 }
326 bn_rshift_words(c1, c1, /*shift=*/2, /*num=*/num_c1);
327
328 EC_RAW_POINT Q0, Q1;
329 if (!map_to_curve_simple_swu(group, Z, c1, num_c1, c2, &Q0, &u0) ||
330 !map_to_curve_simple_swu(group, Z, c1, num_c1, c2, &Q1, &u1)) {
331 return 0;
332 }
333
334 group->meth->add(group, out, &Q0, &Q1); // R = Q0 + Q1
335 // All our curves have cofactor one, so |clear_cofactor| is a no-op.
336 return 1;
337 }
338
felem_from_u8(const EC_GROUP * group,EC_FELEM * out,uint8_t a)339 static int felem_from_u8(const EC_GROUP *group, EC_FELEM *out, uint8_t a) {
340 uint8_t bytes[EC_MAX_BYTES] = {0};
341 size_t len = BN_num_bytes(&group->field);
342 bytes[len - 1] = a;
343 return ec_felem_from_bytes(group, out, bytes, len);
344 }
345
ec_hash_to_curve_p384_xmd_sha512_sswu_draft07(const EC_GROUP * group,EC_RAW_POINT * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)346 int ec_hash_to_curve_p384_xmd_sha512_sswu_draft07(
347 const EC_GROUP *group, EC_RAW_POINT *out, const uint8_t *dst,
348 size_t dst_len, const uint8_t *msg, size_t msg_len) {
349 // See section 8.3 of draft-irtf-cfrg-hash-to-curve-07.
350 if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
351 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
352 return 0;
353 }
354
355 // kSqrt1728 was computed as follows in python3:
356 //
357 // p = 2**384 - 2**128 - 2**96 + 2**32 - 1
358 // z3 = 12**3
359 // c2 = pow(z3, (p+1)//4, p)
360 // assert z3 == pow(c2, 2, p)
361 // ", ".join("0x%02x" % b for b in c2.to_bytes(384//8, 'big')
362
363 static const uint8_t kSqrt1728[] = {
364 0x01, 0x98, 0x77, 0xcc, 0x10, 0x41, 0xb7, 0x55, 0x57, 0x43, 0xc0, 0xae,
365 0x2e, 0x3a, 0x3e, 0x61, 0xfb, 0x2a, 0xaa, 0x2e, 0x0e, 0x87, 0xea, 0x55,
366 0x7a, 0x56, 0x3d, 0x8b, 0x59, 0x8a, 0x09, 0x40, 0xd0, 0xa6, 0x97, 0xa9,
367 0xe0, 0xb9, 0xe9, 0x2c, 0xfa, 0xa3, 0x14, 0xf5, 0x83, 0xc9, 0xd0, 0x66
368 };
369
370 // Z = -12, c2 = sqrt(1728)
371 EC_FELEM Z, c2;
372 if (!felem_from_u8(group, &Z, 12) ||
373 !ec_felem_from_bytes(group, &c2, kSqrt1728, sizeof(kSqrt1728))) {
374 return 0;
375 }
376 ec_felem_neg(group, &Z, &Z);
377
378 return hash_to_curve(group, EVP_sha512(), &Z, &c2, /*k=*/192, out, dst,
379 dst_len, msg, msg_len, /*is_draft06=*/0);
380 }
381
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)382 int ec_hash_to_scalar_p384_xmd_sha512_draft07(
383 const EC_GROUP *group, EC_SCALAR *out, const uint8_t *dst, size_t dst_len,
384 const uint8_t *msg, size_t msg_len) {
385 if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
386 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
387 return 0;
388 }
389
390 return hash_to_scalar(group, EVP_sha512(), out, dst, dst_len, /*k=*/192, msg,
391 msg_len, /*is_draft06=*/0);
392 }
393
ec_hash_to_curve_p521_xmd_sha512_sswu_draft06(const EC_GROUP * group,EC_RAW_POINT * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)394 int ec_hash_to_curve_p521_xmd_sha512_sswu_draft06(
395 const EC_GROUP *group, EC_RAW_POINT *out, const uint8_t *dst,
396 size_t dst_len, const uint8_t *msg, size_t msg_len) {
397 // See section 8.3 of draft-irtf-cfrg-hash-to-curve-06.
398 if (EC_GROUP_get_curve_name(group) != NID_secp521r1) {
399 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
400 return 0;
401 }
402
403 // Z = -4, c2 = 8.
404 EC_FELEM Z, c2;
405 if (!felem_from_u8(group, &Z, 4) ||
406 !felem_from_u8(group, &c2, 8)) {
407 return 0;
408 }
409 ec_felem_neg(group, &Z, &Z);
410
411 return hash_to_curve(group, EVP_sha512(), &Z, &c2, /*k=*/256, out, dst,
412 dst_len, msg, msg_len, /*is_draft06=*/1);
413 }
414
ec_hash_to_scalar_p521_xmd_sha512_draft06(const EC_GROUP * group,EC_SCALAR * out,const uint8_t * dst,size_t dst_len,const uint8_t * msg,size_t msg_len)415 int ec_hash_to_scalar_p521_xmd_sha512_draft06(
416 const EC_GROUP *group, EC_SCALAR *out, const uint8_t *dst, size_t dst_len,
417 const uint8_t *msg, size_t msg_len) {
418 if (EC_GROUP_get_curve_name(group) != NID_secp521r1) {
419 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
420 return 0;
421 }
422
423 return hash_to_scalar(group, EVP_sha512(), out, dst, dst_len, /*k=*/256, msg,
424 msg_len, /*is_draft06=*/1);
425 }
426