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.
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)54 static int expand_message_xmd(const EVP_MD *md, uint8_t *out, size_t out_len,
55 const uint8_t *msg, size_t msg_len,
56 const uint8_t *dst, size_t dst_len) {
57 int ret = 0;
58 const size_t block_size = EVP_MD_block_size(md);
59 const size_t md_size = EVP_MD_size(md);
60 EVP_MD_CTX ctx;
61 EVP_MD_CTX_init(&ctx);
62
63 // Long DSTs are hashed down to size. See section 5.3.3.
64 OPENSSL_STATIC_ASSERT(EVP_MAX_MD_SIZE < 256, "hashed DST still too large");
65 uint8_t dst_buf[EVP_MAX_MD_SIZE];
66 if (dst_len >= 256) {
67 static const char kPrefix[] = "H2C-OVERSIZE-DST-";
68 if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
69 !EVP_DigestUpdate(&ctx, kPrefix, sizeof(kPrefix) - 1) ||
70 !EVP_DigestUpdate(&ctx, dst, dst_len) ||
71 !EVP_DigestFinal_ex(&ctx, dst_buf, NULL)) {
72 goto err;
73 }
74 dst = dst_buf;
75 dst_len = md_size;
76 }
77 uint8_t dst_len_u8 = (uint8_t)dst_len;
78
79 // Compute b_0.
80 static const uint8_t kZeros[EVP_MAX_MD_BLOCK_SIZE] = {0};
81 // If |out_len| exceeds 16 bits then |i| will wrap below causing an error to
82 // be returned. This depends on the static assert above.
83 uint8_t l_i_b_str_zero[3] = {out_len >> 8, out_len, 0};
84 uint8_t b_0[EVP_MAX_MD_SIZE];
85 if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
86 !EVP_DigestUpdate(&ctx, kZeros, block_size) ||
87 !EVP_DigestUpdate(&ctx, msg, msg_len) ||
88 !EVP_DigestUpdate(&ctx, l_i_b_str_zero, sizeof(l_i_b_str_zero)) ||
89 !EVP_DigestUpdate(&ctx, dst, dst_len) ||
90 !EVP_DigestUpdate(&ctx, &dst_len_u8, 1) ||
91 !EVP_DigestFinal_ex(&ctx, b_0, NULL)) {
92 goto err;
93 }
94
95 uint8_t b_i[EVP_MAX_MD_SIZE];
96 uint8_t i = 1;
97 while (out_len > 0) {
98 if (i == 0) {
99 // Input was too large.
100 OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
101 goto err;
102 }
103 if (i > 1) {
104 for (size_t j = 0; j < md_size; j++) {
105 b_i[j] ^= b_0[j];
106 }
107 } else {
108 OPENSSL_memcpy(b_i, b_0, md_size);
109 }
110
111 if (!EVP_DigestInit_ex(&ctx, md, NULL) ||
112 !EVP_DigestUpdate(&ctx, b_i, md_size) ||
113 !EVP_DigestUpdate(&ctx, &i, 1) ||
114 !EVP_DigestUpdate(&ctx, dst, dst_len) ||
115 !EVP_DigestUpdate(&ctx, &dst_len_u8, 1) ||
116 !EVP_DigestFinal_ex(&ctx, b_i, NULL)) {
117 goto err;
118 }
119
120 size_t todo = out_len >= md_size ? md_size : out_len;
121 OPENSSL_memcpy(out, b_i, todo);
122 out += todo;
123 out_len -= todo;
124 i++;
125 }
126
127 ret = 1;
128
129 err:
130 EVP_MD_CTX_cleanup(&ctx);
131 return ret;
132 }
133
134 // num_bytes_to_derive determines the number of bytes to derive when hashing to
135 // a number modulo |modulus|. See the hash_to_field operation defined in
136 // section 5.2 of draft-irtf-cfrg-hash-to-curve-07.
num_bytes_to_derive(size_t * out,const BIGNUM * modulus,unsigned k)137 static int num_bytes_to_derive(size_t *out, const BIGNUM *modulus, unsigned k) {
138 size_t bits = BN_num_bits(modulus);
139 size_t L = (bits + k + 7) / 8;
140 // We require 2^(8*L) < 2^(2*bits - 2) <= n^2 so to fit in bounds for
141 // |felem_reduce| and |ec_scalar_reduce|. All defined hash-to-curve suites
142 // define |k| to be well under this bound. (|k| is usually around half of
143 // |p_bits|.)
144 if (L * 8 >= 2 * bits - 2 ||
145 L > 2 * EC_MAX_BYTES) {
146 assert(0);
147 OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
148 return 0;
149 }
150
151 *out = L;
152 return 1;
153 }
154
155 // big_endian_to_words decodes |in| as a big-endian integer and writes the
156 // 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)157 static void big_endian_to_words(BN_ULONG *out, size_t num_words,
158 const uint8_t *in, size_t len) {
159 assert(len <= num_words * sizeof(BN_ULONG));
160 // Ensure any excess bytes are zeroed.
161 OPENSSL_memset(out, 0, num_words * sizeof(BN_ULONG));
162 uint8_t *out_u8 = (uint8_t *)out;
163 for (size_t i = 0; i < len; i++) {
164 out_u8[len - 1 - i] = in[i];
165 }
166 }
167
168 // hash_to_field implements the operation described in section 5.2
169 // of draft-irtf-cfrg-hash-to-curve-07, with count = 2. |k| is the security
170 // 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)171 static int hash_to_field2(const EC_GROUP *group, const EVP_MD *md,
172 EC_FELEM *out1, EC_FELEM *out2, const uint8_t *dst,
173 size_t dst_len, unsigned k, const uint8_t *msg,
174 size_t msg_len) {
175 size_t L;
176 uint8_t buf[4 * EC_MAX_BYTES];
177 if (!num_bytes_to_derive(&L, &group->field, k) ||
178 !expand_message_xmd(md, buf, 2 * L, msg, msg_len, dst, dst_len)) {
179 return 0;
180 }
181 BN_ULONG words[2 * EC_MAX_WORDS];
182 size_t num_words = 2 * group->field.width;
183 big_endian_to_words(words, num_words, buf, L);
184 group->meth->felem_reduce(group, out1, words, num_words);
185 big_endian_to_words(words, num_words, buf + L, L);
186 group->meth->felem_reduce(group, out2, words, num_words);
187 return 1;
188 }
189
190 // hash_to_scalar behaves like |hash_to_field2| but returns a value modulo the
191 // 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)192 static int hash_to_scalar(const EC_GROUP *group, const EVP_MD *md,
193 EC_SCALAR *out, const uint8_t *dst, size_t dst_len,
194 unsigned k, const uint8_t *msg, size_t msg_len) {
195 size_t L;
196 uint8_t buf[EC_MAX_BYTES * 2];
197 if (!num_bytes_to_derive(&L, &group->order, k) ||
198 !expand_message_xmd(md, buf, L, msg, msg_len, dst, dst_len)) {
199 return 0;
200 }
201
202 BN_ULONG words[2 * EC_MAX_WORDS];
203 size_t num_words = 2 * group->order.width;
204 big_endian_to_words(words, num_words, buf, L);
205 ec_scalar_reduce(group, out, words, num_words);
206 return 1;
207 }
208
mul_A(const EC_GROUP * group,EC_FELEM * out,const EC_FELEM * in)209 static inline void mul_A(const EC_GROUP *group, EC_FELEM *out,
210 const EC_FELEM *in) {
211 assert(group->a_is_minus3);
212 EC_FELEM tmp;
213 ec_felem_add(group, &tmp, in, in); // tmp = 2*in
214 ec_felem_add(group, &tmp, &tmp, &tmp); // tmp = 4*in
215 ec_felem_sub(group, out, in, &tmp); // out = -3*in
216 }
217
mul_minus_A(const EC_GROUP * group,EC_FELEM * out,const EC_FELEM * in)218 static inline void mul_minus_A(const EC_GROUP *group, EC_FELEM *out,
219 const EC_FELEM *in) {
220 assert(group->a_is_minus3);
221 EC_FELEM tmp;
222 ec_felem_add(group, &tmp, in, in); // tmp = 2*in
223 ec_felem_add(group, out, &tmp, in); // out = 3*in
224 }
225
226 // sgn0_le implements the operation described in section 4.1.2 of
227 // draft-irtf-cfrg-hash-to-curve-07.
sgn0_le(const EC_GROUP * group,const EC_FELEM * a)228 static BN_ULONG sgn0_le(const EC_GROUP *group, const EC_FELEM *a) {
229 uint8_t buf[EC_MAX_BYTES];
230 size_t len;
231 ec_felem_to_bytes(group, buf, &len, a);
232 return buf[len - 1] & 1;
233 }
234
235 // map_to_curve_simple_swu implements the operation described in section 6.6.2
236 // of draft-irtf-cfrg-hash-to-curve-07, using the optimization in appendix
237 // 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)238 static int map_to_curve_simple_swu(const EC_GROUP *group, const EC_FELEM *Z,
239 const BN_ULONG *c1, size_t num_c1,
240 const EC_FELEM *c2, EC_RAW_POINT *out,
241 const EC_FELEM *u) {
242 void (*const felem_mul)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
243 const EC_FELEM *b) = group->meth->felem_mul;
244 void (*const felem_sqr)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a) =
245 group->meth->felem_sqr;
246
247 // This function requires the prime be 3 mod 4, and that A = -3.
248 if (group->field.width == 0 || (group->field.d[0] & 3) != 3 ||
249 !group->a_is_minus3) {
250 OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
251 return 0;
252 }
253
254 EC_FELEM tv1, tv2, tv3, tv4, xd, x1n, x2n, tmp, gxd, gx1, y1, y2;
255 felem_sqr(group, &tv1, u); // tv1 = u^2
256 felem_mul(group, &tv3, Z, &tv1); // tv3 = Z * tv1
257 felem_sqr(group, &tv2, &tv3); // tv2 = tv3^2
258 ec_felem_add(group, &xd, &tv2, &tv3); // xd = tv2 + tv3
259 ec_felem_add(group, &x1n, &xd, &group->one); // x1n = xd + 1
260 felem_mul(group, &x1n, &x1n, &group->b); // x1n = x1n * B
261 mul_minus_A(group, &xd, &xd); // xd = -A * xd
262 BN_ULONG e1 = ec_felem_non_zero_mask(group, &xd); // e1 = xd == 0 [flipped]
263 mul_A(group, &tmp, Z);
264 ec_felem_select(group, &xd, e1, &xd, &tmp); // xd = CMOV(xd, Z * A, e1)
265 felem_sqr(group, &tv2, &xd); // tv2 = xd^2
266 felem_mul(group, &gxd, &tv2, &xd); // gxd = tv2 * xd = xd^3
267 mul_A(group, &tv2, &tv2); // tv2 = A * tv2
268 felem_sqr(group, &gx1, &x1n); // gx1 = x1n^2
269 ec_felem_add(group, &gx1, &gx1, &tv2); // gx1 = gx1 + tv2
270 felem_mul(group, &gx1, &gx1, &x1n); // gx1 = gx1 * x1n
271 felem_mul(group, &tv2, &group->b, &gxd); // tv2 = B * gxd
272 ec_felem_add(group, &gx1, &gx1, &tv2); // gx1 = gx1 + tv2
273 felem_sqr(group, &tv4, &gxd); // tv4 = gxd^2
274 felem_mul(group, &tv2, &gx1, &gxd); // tv2 = gx1 * gxd
275 felem_mul(group, &tv4, &tv4, &tv2); // tv4 = tv4 * tv2
276 group->meth->felem_exp(group, &y1, &tv4, c1, num_c1); // y1 = tv4^c1
277 felem_mul(group, &y1, &y1, &tv2); // y1 = y1 * tv2
278 felem_mul(group, &x2n, &tv3, &x1n); // x2n = tv3 * x1n
279 felem_mul(group, &y2, &y1, c2); // y2 = y1 * c2
280 felem_mul(group, &y2, &y2, &tv1); // y2 = y2 * tv1
281 felem_mul(group, &y2, &y2, u); // y2 = y2 * u
282 felem_sqr(group, &tv2, &y1); // tv2 = y1^2
283 felem_mul(group, &tv2, &tv2, &gxd); // tv2 = tv2 * gxd
284 ec_felem_sub(group, &tv3, &tv2, &gx1);
285 BN_ULONG e2 =
286 ec_felem_non_zero_mask(group, &tv3); // e2 = tv2 == gx1 [flipped]
287 ec_felem_select(group, &x1n, e2, &x2n, &x1n); // xn = CMOV(x2n, x1n, e2)
288 ec_felem_select(group, &y1, e2, &y2, &y1); // y = CMOV(y2, y1, e2)
289 BN_ULONG sgn0_u = sgn0_le(group, u);
290 BN_ULONG sgn0_y = sgn0_le(group, &y1);
291 BN_ULONG e3 = sgn0_u ^ sgn0_y;
292 e3 = ((BN_ULONG)0) - e3; // e3 = sgn0(u) == sgn0(y) [flipped]
293 ec_felem_neg(group, &y2, &y1);
294 ec_felem_select(group, &y1, e3, &y2, &y1); // y = CMOV(-y, y, e3)
295
296 // Appendix D.1 describes how to convert (x1n, xd, y1, 1) to Jacobian
297 // coordinates. Note yd = 1. Also note that gxd computed above is xd^3.
298 felem_mul(group, &out->X, &x1n, &xd); // X = xn * xd
299 felem_mul(group, &out->Y, &y1, &gxd); // Y = yn * gxd = yn * xd^3
300 out->Z = xd; // Z = xd
301 return 1;
302 }
303
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)304 static int hash_to_curve(const EC_GROUP *group, const EVP_MD *md,
305 const EC_FELEM *Z, const EC_FELEM *c2, unsigned k,
306 EC_RAW_POINT *out, const uint8_t *dst, size_t dst_len,
307 const uint8_t *msg, size_t msg_len) {
308 EC_FELEM u0, u1;
309 if (!hash_to_field2(group, md, &u0, &u1, dst, dst_len, k, msg, msg_len)) {
310 return 0;
311 }
312
313 // Compute |c1| = (p - 3) / 4.
314 BN_ULONG c1[EC_MAX_WORDS];
315 size_t num_c1 = group->field.width;
316 if (!bn_copy_words(c1, num_c1, &group->field)) {
317 return 0;
318 }
319 bn_rshift_words(c1, c1, /*shift=*/2, /*num=*/num_c1);
320
321 EC_RAW_POINT Q0, Q1;
322 if (!map_to_curve_simple_swu(group, Z, c1, num_c1, c2, &Q0, &u0) ||
323 !map_to_curve_simple_swu(group, Z, c1, num_c1, c2, &Q1, &u1)) {
324 return 0;
325 }
326
327 group->meth->add(group, out, &Q0, &Q1); // R = Q0 + Q1
328 // All our curves have cofactor one, so |clear_cofactor| is a no-op.
329 return 1;
330 }
331
felem_from_u8(const EC_GROUP * group,EC_FELEM * out,uint8_t a)332 static int felem_from_u8(const EC_GROUP *group, EC_FELEM *out, uint8_t a) {
333 uint8_t bytes[EC_MAX_BYTES] = {0};
334 size_t len = BN_num_bytes(&group->field);
335 bytes[len - 1] = a;
336 return ec_felem_from_bytes(group, out, bytes, len);
337 }
338
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)339 int ec_hash_to_curve_p384_xmd_sha512_sswu_draft07(
340 const EC_GROUP *group, EC_RAW_POINT *out, const uint8_t *dst,
341 size_t dst_len, const uint8_t *msg, size_t msg_len) {
342 // See section 8.3 of draft-irtf-cfrg-hash-to-curve-07.
343 if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
344 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
345 return 0;
346 }
347
348 // kSqrt1728 was computed as follows in python3:
349 //
350 // p = 2**384 - 2**128 - 2**96 + 2**32 - 1
351 // z3 = 12**3
352 // c2 = pow(z3, (p+1)//4, p)
353 // assert z3 == pow(c2, 2, p)
354 // ", ".join("0x%02x" % b for b in c2.to_bytes(384//8, 'big')
355
356 static const uint8_t kSqrt1728[] = {
357 0x01, 0x98, 0x77, 0xcc, 0x10, 0x41, 0xb7, 0x55, 0x57, 0x43, 0xc0, 0xae,
358 0x2e, 0x3a, 0x3e, 0x61, 0xfb, 0x2a, 0xaa, 0x2e, 0x0e, 0x87, 0xea, 0x55,
359 0x7a, 0x56, 0x3d, 0x8b, 0x59, 0x8a, 0x09, 0x40, 0xd0, 0xa6, 0x97, 0xa9,
360 0xe0, 0xb9, 0xe9, 0x2c, 0xfa, 0xa3, 0x14, 0xf5, 0x83, 0xc9, 0xd0, 0x66
361 };
362
363 // Z = -12, c2 = sqrt(1728)
364 EC_FELEM Z, c2;
365 if (!felem_from_u8(group, &Z, 12) ||
366 !ec_felem_from_bytes(group, &c2, kSqrt1728, sizeof(kSqrt1728))) {
367 return 0;
368 }
369 ec_felem_neg(group, &Z, &Z);
370
371 return hash_to_curve(group, EVP_sha512(), &Z, &c2, /*k=*/192, out, dst,
372 dst_len, msg, msg_len);
373 }
374
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)375 int ec_hash_to_scalar_p384_xmd_sha512_draft07(
376 const EC_GROUP *group, EC_SCALAR *out, const uint8_t *dst, size_t dst_len,
377 const uint8_t *msg, size_t msg_len) {
378 if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
379 OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
380 return 0;
381 }
382
383 return hash_to_scalar(group, EVP_sha512(), out, dst, dst_len, /*k=*/192, msg,
384 msg_len);
385 }
386