Packages
hackney
3.0.3
4.7.2
4.7.1
4.7.0
4.6.1
4.6.0
4.5.2
4.5.1
4.5.0
4.4.5
4.4.3
4.4.2
4.4.1
4.4.0
4.3.0
4.2.3
4.2.2
4.2.1
4.2.0
4.1.0
4.0.3
4.0.2
4.0.1
4.0.0
3.2.1
3.2.0
3.1.2
3.1.1
3.1.0
3.0.3
3.0.2
3.0.1
3.0.0
retired
2.0.1
2.0.0
2.0.0-beta.1
1.25.0
1.24.1
1.24.0
1.23.0
1.22.0
1.21.0
1.20.1
1.20.0
1.19.1
1.19.0
1.18.2
1.18.1
1.18.0
1.17.4
1.17.3
1.17.2
1.17.1
1.17.0
1.16.0
1.15.2
1.15.1
1.15.0
1.14.3
1.14.2
1.14.0
1.13.0
1.12.1
1.12.0
1.11.0
1.10.1
1.10.0
1.9.0
1.8.6
1.8.5
1.8.4
1.8.3
1.8.2
1.8.0
1.7.1
1.7.0
1.6.6
retired
1.6.5
1.6.4
retired
1.6.3
1.6.2
1.6.1
1.6.0
1.5.7
1.5.6
1.5.5
1.5.4
1.5.3
1.5.2
1.5.1
1.5.0
1.4.10
1.4.8
1.4.7
1.4.6
1.4.5
1.4.4
1.4.3
1.4.2
1.4.1
1.4.0
1.3.2
1.3.1
1.3.0
1.2.0
1.1.0
1.0.6
1.0.5
1.0.2
1.0.1
0.15.2
0.15.0
0.14.3
0.14.2
0.14.1
0.14.0
0.13.1
Simple HTTP client with HTTP/1.1, HTTP/2, and HTTP/3 support
Security advisory:
This version has known vulnerabilities.
View advisories
Current section
Files
Jump to
Current section
Files
c_src/boringssl/crypto/ec/hash_to_curve.cc
// Copyright 2020 The BoringSSL Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include <openssl/ec.h>
#include <openssl/digest.h>
#include <openssl/err.h>
#include <openssl/nid.h>
#include <assert.h>
#include "../fipsmodule/bn/internal.h"
#include "../fipsmodule/ec/internal.h"
#include "../internal.h"
#include "internal.h"
// This file implements hash-to-curve, as described in RFC 9380.
//
// This hash-to-curve implementation is written generically with the
// expectation that we will eventually wish to support other curves. If it
// becomes a performance bottleneck, some possible optimizations by
// specializing it to the curve:
//
// - Rather than using a generic |felem_exp|, specialize the exponentiation to
// c2 with a faster addition chain.
//
// - |felem_mul| and |felem_sqr| are indirect calls to generic Montgomery
// code. Given the few curves, we could specialize
// |map_to_curve_simple_swu|. But doing this reasonably without duplicating
// code in C is difficult. (C++ templates would be useful here.)
//
// - P-521's Z and c2 have small power-of-two absolute values. We could save
// two multiplications in SSWU. (Other curves have reasonable values of Z
// and inconvenient c2.) This is unlikely to be worthwhile without C++
// templates to make specializing more convenient.
// expand_message_xmd implements the operation described in section 5.3.1 of
// RFC 9380. It returns one on success and zero on error.
static int 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) {
// See https://github.com/cfrg/draft-irtf-cfrg-hash-to-curve/issues/352
if (dst_len == 0) {
OPENSSL_PUT_ERROR(EC, ERR_R_SHOULD_NOT_HAVE_BEEN_CALLED);
return 0;
}
const size_t block_size = EVP_MD_block_size(md);
const size_t md_size = EVP_MD_size(md);
bssl::ScopedEVP_MD_CTX ctx;
// Long DSTs are hashed down to size. See section 5.3.3.
static_assert(EVP_MAX_MD_SIZE < 256, "hashed DST still too large");
uint8_t dst_buf[EVP_MAX_MD_SIZE];
if (dst_len >= 256) {
static const char kPrefix[] = "H2C-OVERSIZE-DST-";
if (!EVP_DigestInit_ex(ctx.get(), md, nullptr) ||
!EVP_DigestUpdate(ctx.get(), kPrefix, sizeof(kPrefix) - 1) ||
!EVP_DigestUpdate(ctx.get(), dst, dst_len) ||
!EVP_DigestFinal_ex(ctx.get(), dst_buf, nullptr)) {
return 0;
}
dst = dst_buf;
dst_len = md_size;
}
uint8_t dst_len_u8 = (uint8_t)dst_len;
// Compute b_0.
static const uint8_t kZeros[EVP_MAX_MD_BLOCK_SIZE] = {0};
// If |out_len| exceeds 16 bits then |i| will wrap below causing an error to
// be returned. This depends on the static assert above.
uint8_t l_i_b_str_zero[3] = {static_cast<uint8_t>(out_len >> 8),
static_cast<uint8_t>(out_len), 0};
uint8_t b_0[EVP_MAX_MD_SIZE];
if (!EVP_DigestInit_ex(ctx.get(), md, nullptr) ||
!EVP_DigestUpdate(ctx.get(), kZeros, block_size) ||
!EVP_DigestUpdate(ctx.get(), msg, msg_len) ||
!EVP_DigestUpdate(ctx.get(), l_i_b_str_zero, sizeof(l_i_b_str_zero)) ||
!EVP_DigestUpdate(ctx.get(), dst, dst_len) ||
!EVP_DigestUpdate(ctx.get(), &dst_len_u8, 1) ||
!EVP_DigestFinal_ex(ctx.get(), b_0, nullptr)) {
return 0;
}
uint8_t b_i[EVP_MAX_MD_SIZE];
uint8_t i = 1;
while (out_len > 0) {
if (i == 0) {
// Input was too large.
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
return 0;
}
if (i > 1) {
for (size_t j = 0; j < md_size; j++) {
b_i[j] ^= b_0[j];
}
} else {
OPENSSL_memcpy(b_i, b_0, md_size);
}
if (!EVP_DigestInit_ex(ctx.get(), md, nullptr) ||
!EVP_DigestUpdate(ctx.get(), b_i, md_size) ||
!EVP_DigestUpdate(ctx.get(), &i, 1) ||
!EVP_DigestUpdate(ctx.get(), dst, dst_len) ||
!EVP_DigestUpdate(ctx.get(), &dst_len_u8, 1) ||
!EVP_DigestFinal_ex(ctx.get(), b_i, nullptr)) {
return 0;
}
size_t todo = out_len >= md_size ? md_size : out_len;
OPENSSL_memcpy(out, b_i, todo);
out += todo;
out_len -= todo;
i++;
}
return 1;
}
// num_bytes_to_derive determines the number of bytes to derive when hashing to
// a number modulo |modulus|. See the hash_to_field operation defined in
// section 5.2 of RFC 9380.
static int num_bytes_to_derive(size_t *out, const BIGNUM *modulus, unsigned k) {
size_t bits = BN_num_bits(modulus);
size_t L = (bits + k + 7) / 8;
// We require 2^(8*L) < 2^(2*bits - 2) <= n^2 so to fit in bounds for
// |felem_reduce| and |ec_scalar_reduce|. All defined hash-to-curve suites
// define |k| to be well under this bound. (|k| is usually around half of
// |p_bits|.)
if (L * 8 >= 2 * bits - 2 || L > 2 * EC_MAX_BYTES) {
assert(0);
OPENSSL_PUT_ERROR(EC, ERR_R_INTERNAL_ERROR);
return 0;
}
*out = L;
return 1;
}
// big_endian_to_words decodes |in| as a big-endian integer and writes the
// result to |out|. |num_words| must be large enough to contain the output.
static void big_endian_to_words(BN_ULONG *out, size_t num_words,
const uint8_t *in, size_t len) {
assert(len <= num_words * sizeof(BN_ULONG));
// Ensure any excess bytes are zeroed.
OPENSSL_memset(out, 0, num_words * sizeof(BN_ULONG));
uint8_t *out_u8 = (uint8_t *)out;
for (size_t i = 0; i < len; i++) {
out_u8[len - 1 - i] = in[i];
}
}
// hash_to_field implements the operation described in section 5.2
// of RFC 9380, with count = 2. |k| is the security factor.
static int 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) {
size_t L;
uint8_t buf[4 * EC_MAX_BYTES];
if (!num_bytes_to_derive(&L, &group->field.N, k) ||
!expand_message_xmd(md, buf, 2 * L, msg, msg_len, dst, dst_len)) {
return 0;
}
BN_ULONG words[2 * EC_MAX_WORDS];
size_t num_words = 2 * group->field.N.width;
big_endian_to_words(words, num_words, buf, L);
group->meth->felem_reduce(group, out1, words, num_words);
big_endian_to_words(words, num_words, buf + L, L);
group->meth->felem_reduce(group, out2, words, num_words);
return 1;
}
// hash_to_field1 implements the operation described in section 5.2
// of RFC 9380, with count = 1. |k| is the security factor.
static int hash_to_field1(const EC_GROUP *group, const EVP_MD *md,
EC_FELEM *out, const uint8_t *dst, size_t dst_len,
unsigned k, const uint8_t *msg, size_t msg_len) {
size_t L;
uint8_t buf[2 * EC_MAX_BYTES];
if (!num_bytes_to_derive(&L, &group->field.N, k) ||
!expand_message_xmd(md, buf, L, msg, msg_len, dst, dst_len)) {
return 0;
}
BN_ULONG words[2 * EC_MAX_WORDS];
size_t num_words = 2 * group->field.N.width;
big_endian_to_words(words, num_words, buf, L);
group->meth->felem_reduce(group, out, words, num_words);
return 1;
}
// hash_to_scalar behaves like |hash_to_field2| but returns a value modulo the
// group order rather than a field element. |k| is the security factor.
static int 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) {
const BIGNUM *order = EC_GROUP_get0_order(group);
size_t L;
uint8_t buf[EC_MAX_BYTES * 2];
if (!num_bytes_to_derive(&L, order, k) ||
!expand_message_xmd(md, buf, L, msg, msg_len, dst, dst_len)) {
return 0;
}
BN_ULONG words[2 * EC_MAX_WORDS];
size_t num_words = 2 * order->width;
big_endian_to_words(words, num_words, buf, L);
ec_scalar_reduce(group, out, words, num_words);
return 1;
}
static inline void mul_A(const EC_GROUP *group, EC_FELEM *out,
const EC_FELEM *in) {
assert(group->a_is_minus3);
EC_FELEM tmp;
ec_felem_add(group, &tmp, in, in); // tmp = 2*in
ec_felem_add(group, &tmp, &tmp, &tmp); // tmp = 4*in
ec_felem_sub(group, out, in, &tmp); // out = -3*in
}
// sgn0 implements the operation described in section 4.1.2 of RFC 9380.
static BN_ULONG sgn0(const EC_GROUP *group, const EC_FELEM *a) {
uint8_t buf[EC_MAX_BYTES];
size_t len;
ec_felem_to_bytes(group, buf, &len, a);
return buf[len - 1] & 1;
}
[[maybe_unused]] static int is_3mod4(const EC_GROUP *group) {
return group->field.N.width > 0 && (group->field.N.d[0] & 3) == 3;
}
// sqrt_ratio_3mod4 implements the operation described in appendix F.2.1.2
// of RFC 9380.
static BN_ULONG 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) {
assert(is_3mod4(group));
void (*const felem_mul)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
const EC_FELEM *b) = group->meth->felem_mul;
void (*const felem_sqr)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a) =
group->meth->felem_sqr;
EC_FELEM tv1, tv2, tv3, y1, y2;
felem_sqr(group, &tv1, v); // 1. tv1 = v^2
felem_mul(group, &tv2, u, v); // 2. tv2 = u * v
felem_mul(group, &tv1, &tv1, &tv2); // 3. tv1 = tv1 * tv2
group->meth->felem_exp(group, &y1, &tv1, c1, num_c1); // 4. y1 = tv1^c1
felem_mul(group, &y1, &y1, &tv2); // 5. y1 = y1 * tv2
felem_mul(group, &y2, &y1, c2); // 6. y2 = y1 * c2
felem_sqr(group, &tv3, &y1); // 7. tv3 = y1^2
felem_mul(group, &tv3, &tv3, v); // 8. tv3 = tv3 * v
// 9. isQR = tv3 == u
// 10. y = CMOV(y2, y1, isQR)
// 11. return (isQR, y)
//
// Note the specification's CMOV function and our |ec_felem_select| have the
// opposite argument order.
ec_felem_sub(group, &tv1, &tv3, u);
const BN_ULONG isQR = ~ec_felem_non_zero_mask(group, &tv1);
ec_felem_select(group, out_y, isQR, &y1, &y2);
return isQR;
}
// map_to_curve_simple_swu implements the operation described in section 6.6.2
// of RFC 9380, using the straight-line implementation in appendix F.2.
static void 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) {
// This function requires the prime be 3 mod 4, and that A = -3.
assert(is_3mod4(group));
assert(group->a_is_minus3);
void (*const felem_mul)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a,
const EC_FELEM *b) = group->meth->felem_mul;
void (*const felem_sqr)(const EC_GROUP *, EC_FELEM *r, const EC_FELEM *a) =
group->meth->felem_sqr;
EC_FELEM tv1, tv2, tv3, tv4, tv5, tv6, x, y, y1;
felem_sqr(group, &tv1, u); // 1. tv1 = u^2
felem_mul(group, &tv1, Z, &tv1); // 2. tv1 = Z * tv1
felem_sqr(group, &tv2, &tv1); // 3. tv2 = tv1^2
ec_felem_add(group, &tv2, &tv2, &tv1); // 4. tv2 = tv2 + tv1
ec_felem_add(group, &tv3, &tv2, ec_felem_one(group)); // 5. tv3 = tv2 + 1
felem_mul(group, &tv3, &group->b, &tv3); // 6. tv3 = B * tv3
// 7. tv4 = CMOV(Z, -tv2, tv2 != 0)
const BN_ULONG tv2_non_zero = ec_felem_non_zero_mask(group, &tv2);
ec_felem_neg(group, &tv4, &tv2);
ec_felem_select(group, &tv4, tv2_non_zero, &tv4, Z);
mul_A(group, &tv4, &tv4); // 8. tv4 = A * tv4
felem_sqr(group, &tv2, &tv3); // 9. tv2 = tv3^2
felem_sqr(group, &tv6, &tv4); // 10. tv6 = tv4^2
mul_A(group, &tv5, &tv6); // 11. tv5 = A * tv6
ec_felem_add(group, &tv2, &tv2, &tv5); // 12. tv2 = tv2 + tv5
felem_mul(group, &tv2, &tv2, &tv3); // 13. tv2 = tv2 * tv3
felem_mul(group, &tv6, &tv6, &tv4); // 14. tv6 = tv6 * tv4
felem_mul(group, &tv5, &group->b, &tv6); // 15. tv5 = B * tv6
ec_felem_add(group, &tv2, &tv2, &tv5); // 16. tv2 = tv2 + tv5
felem_mul(group, &x, &tv1, &tv3); // 17. x = tv1 * tv3
// 18. (is_gx1_square, y1) = sqrt_ratio(tv2, tv6)
const BN_ULONG is_gx1_square =
sqrt_ratio_3mod4(group, Z, c1, num_c1, c2, &y1, &tv2, &tv6);
felem_mul(group, &y, &tv1, u); // 19. y = tv1 * u
felem_mul(group, &y, &y, &y1); // 20. y = y * y1
// 21. x = CMOV(x, tv3, is_gx1_square)
ec_felem_select(group, &x, is_gx1_square, &tv3, &x);
// 22. y = CMOV(y, y1, is_gx1_square)
ec_felem_select(group, &y, is_gx1_square, &y1, &y);
// 23. e1 = sgn0(u) == sgn0(y)
BN_ULONG sgn0_u = sgn0(group, u);
BN_ULONG sgn0_y = sgn0(group, &y);
BN_ULONG not_e1 = sgn0_u ^ sgn0_y;
not_e1 = ((BN_ULONG)0) - not_e1;
// 24. y = CMOV(-y, y, e1)
ec_felem_neg(group, &tv1, &y);
ec_felem_select(group, &y, not_e1, &tv1, &y);
// 25. x = x / tv4
//
// Our output is in projective coordinates, so rather than inverting |tv4|
// now, represent (x / tv4, y) as (x * tv4, y * tv4^3, tv4). This is much more
// efficient if the caller will do further computation on the output. (If the
// caller will immediately convert to affine coordinates, it is slightly less
// efficient, but only by a few field multiplications.)
felem_mul(group, &out->X, &x, &tv4);
felem_mul(group, &out->Y, &y, &tv6);
out->Z = tv4;
}
static int 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) {
EC_FELEM u0, u1;
if (!hash_to_field2(group, md, &u0, &u1, dst, dst_len, k, msg, msg_len)) {
return 0;
}
// Compute |c1| = (p - 3) / 4.
BN_ULONG c1[EC_MAX_WORDS];
size_t num_c1 = group->field.N.width;
if (!bn_copy_words(c1, num_c1, &group->field.N)) {
return 0;
}
bn_rshift_words(c1, c1, /*shift=*/2, /*num=*/num_c1);
EC_JACOBIAN Q0, Q1;
map_to_curve_simple_swu(group, Z, c1, num_c1, c2, &Q0, &u0);
map_to_curve_simple_swu(group, Z, c1, num_c1, c2, &Q1, &u1);
group->meth->add(group, out, &Q0, &Q1); // R = Q0 + Q1
// All our curves have cofactor one, so |clear_cofactor| is a no-op.
return 1;
}
static int encode_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) {
EC_FELEM u;
if (!hash_to_field1(group, md, &u, dst, dst_len, k, msg, msg_len)) {
return 0;
}
// Compute |c1| = (p - 3) / 4.
BN_ULONG c1[EC_MAX_WORDS];
size_t num_c1 = group->field.N.width;
if (!bn_copy_words(c1, num_c1, &group->field.N)) {
return 0;
}
bn_rshift_words(c1, c1, /*shift=*/2, /*num=*/num_c1);
map_to_curve_simple_swu(group, Z, c1, num_c1, c2, out, &u);
// All our curves have cofactor one, so |clear_cofactor| is a no-op.
return 1;
}
static int felem_from_u8(const EC_GROUP *group, EC_FELEM *out, uint8_t a) {
uint8_t bytes[EC_MAX_BYTES] = {0};
size_t len = BN_num_bytes(&group->field.N);
bytes[len - 1] = a;
return ec_felem_from_bytes(group, out, bytes, len);
}
// kP256Sqrt10 is sqrt(10) in P-256's field. It was computed as follows in
// python3:
//
// p = 2**256 - 2**224 + 2**192 + 2**96 - 1
// c2 = pow(10, (p+1)//4, p)
// assert pow(c2, 2, p) == 10
// ", ".join("0x%02x" % b for b in c2.to_bytes(256//8, 'big'))
static const uint8_t kP256Sqrt10[] = {
0xda, 0x53, 0x8e, 0x3b, 0xe1, 0xd8, 0x9b, 0x99, 0xc9, 0x78, 0xfc,
0x67, 0x51, 0x80, 0xaa, 0xb2, 0x7b, 0x8d, 0x1f, 0xf8, 0x4c, 0x55,
0xd5, 0xb6, 0x2c, 0xcd, 0x34, 0x27, 0xe4, 0x33, 0xc4, 0x7f};
// kP384Sqrt12 is sqrt(12) in P-384's field. It was computed as follows in
// python3:
//
// p = 2**384 - 2**128 - 2**96 + 2**32 - 1
// c2 = pow(12, (p+1)//4, p)
// assert pow(c2, 2, p) == 12
// ", ".join("0x%02x" % b for b in c2.to_bytes(384//8, 'big'))
static const uint8_t kP384Sqrt12[] = {
0x2a, 0xcc, 0xb4, 0xa6, 0x56, 0xb0, 0x24, 0x9c, 0x71, 0xf0, 0x50, 0x0e,
0x83, 0xda, 0x2f, 0xdd, 0x7f, 0x98, 0xe3, 0x83, 0xd6, 0x8b, 0x53, 0x87,
0x1f, 0x87, 0x2f, 0xcb, 0x9c, 0xcb, 0x80, 0xc5, 0x3c, 0x0d, 0xe1, 0xf8,
0xa8, 0x0f, 0x7e, 0x19, 0x14, 0xe2, 0xec, 0x69, 0xf5, 0xa6, 0x26, 0xb3};
int 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) {
// See section 8.3 of RFC 9380.
if (EC_GROUP_get_curve_name(group) != NID_X9_62_prime256v1) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
// Z = -10, c2 = sqrt(10)
EC_FELEM Z, c2;
if (!felem_from_u8(group, &Z, 10) ||
!ec_felem_from_bytes(group, &c2, kP256Sqrt10, sizeof(kP256Sqrt10))) {
return 0;
}
ec_felem_neg(group, &Z, &Z);
return hash_to_curve(group, EVP_sha256(), &Z, &c2, /*k=*/128, out, dst,
dst_len, msg, msg_len);
}
int 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) {
if (EC_GROUP_cmp(group, out->group, nullptr) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
return ec_hash_to_curve_p256_xmd_sha256_sswu(group, &out->raw, dst, dst_len,
msg, msg_len);
}
int 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) {
// See section 8.3 of RFC 9380.
if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
// Z = -12, c2 = sqrt(12)
EC_FELEM Z, c2;
if (!felem_from_u8(group, &Z, 12) ||
!ec_felem_from_bytes(group, &c2, kP384Sqrt12, sizeof(kP384Sqrt12))) {
return 0;
}
ec_felem_neg(group, &Z, &Z);
return hash_to_curve(group, EVP_sha384(), &Z, &c2, /*k=*/192, out, dst,
dst_len, msg, msg_len);
}
int 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) {
if (EC_GROUP_cmp(group, out->group, nullptr) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
return ec_hash_to_curve_p384_xmd_sha384_sswu(group, &out->raw, dst, dst_len,
msg, msg_len);
}
int ec_encode_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) {
// See section 8.3 of RFC 9380.
if (EC_GROUP_get_curve_name(group) != NID_X9_62_prime256v1) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
// Z = -10, c2 = sqrt(10)
EC_FELEM Z, c2;
if (!felem_from_u8(group, &Z, 10) ||
!ec_felem_from_bytes(group, &c2, kP256Sqrt10, sizeof(kP256Sqrt10))) {
return 0;
}
ec_felem_neg(group, &Z, &Z);
return encode_to_curve(group, EVP_sha256(), &Z, &c2, /*k=*/128, out, dst,
dst_len, msg, msg_len);
}
int EC_encode_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) {
if (EC_GROUP_cmp(group, out->group, nullptr) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
return ec_encode_to_curve_p256_xmd_sha256_sswu(group, &out->raw, dst, dst_len,
msg, msg_len);
}
int ec_encode_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) {
// See section 8.3 of RFC 9380.
if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
// Z = -12, c2 = sqrt(12)
EC_FELEM Z, c2;
if (!felem_from_u8(group, &Z, 12) ||
!ec_felem_from_bytes(group, &c2, kP384Sqrt12, sizeof(kP384Sqrt12))) {
return 0;
}
ec_felem_neg(group, &Z, &Z);
return encode_to_curve(group, EVP_sha384(), &Z, &c2, /*k=*/192, out, dst,
dst_len, msg, msg_len);
}
int EC_encode_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) {
if (EC_GROUP_cmp(group, out->group, nullptr) != 0) {
OPENSSL_PUT_ERROR(EC, EC_R_INCOMPATIBLE_OBJECTS);
return 0;
}
return ec_encode_to_curve_p384_xmd_sha384_sswu(group, &out->raw, dst, dst_len,
msg, msg_len);
}
int 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) {
if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
return hash_to_scalar(group, EVP_sha384(), out, dst, dst_len, /*k=*/192, msg,
msg_len);
}
int 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) {
// See section 8.3 of draft-irtf-cfrg-hash-to-curve-07.
if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
// Z = -12, c2 = sqrt(12)
EC_FELEM Z, c2;
if (!felem_from_u8(group, &Z, 12) ||
!ec_felem_from_bytes(group, &c2, kP384Sqrt12, sizeof(kP384Sqrt12))) {
return 0;
}
ec_felem_neg(group, &Z, &Z);
return hash_to_curve(group, EVP_sha512(), &Z, &c2, /*k=*/192, out, dst,
dst_len, msg, msg_len);
}
int 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) {
if (EC_GROUP_get_curve_name(group) != NID_secp384r1) {
OPENSSL_PUT_ERROR(EC, EC_R_GROUP_MISMATCH);
return 0;
}
return hash_to_scalar(group, EVP_sha512(), out, dst, dst_len, /*k=*/192, msg,
msg_len);
}