mirror of
https://github.com/espressif/esp-idf.git
synced 2026-04-27 19:13:21 +00:00
fix(esp_wifi): Optimize crypto operations for SAE
- Montgomery multiplication fast path for P-256 mulmod - Jacobi symbol for legendre (replacing exp_mod) - Software Jacobian point multiplication for MPI-only chips - ECC hardware acceleration for supported chips
This commit is contained in:
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -8,6 +8,7 @@
|
||||
#include "esp_system.h"
|
||||
#include "mbedtls/bignum.h"
|
||||
#include "mbedtls/esp_mbedtls_random.h"
|
||||
#include "soc/soc_caps.h"
|
||||
#endif
|
||||
|
||||
#include "utils/includes.h"
|
||||
@@ -17,6 +18,340 @@
|
||||
#include "sha256.h"
|
||||
#include "mbedtls/pk.h"
|
||||
#include "mbedtls/psa_util.h"
|
||||
#include "p256_common.h"
|
||||
|
||||
static int mpi_is_secp256r1_prime(const mbedtls_mpi *p)
|
||||
{
|
||||
u8 p_be[P256_LEN_BYTES];
|
||||
|
||||
if (!p || mbedtls_mpi_size(p) != P256_LEN_BYTES) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_write_binary(p, p_be, sizeof(p_be)) != 0) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return os_memcmp(p_be, p256_p_be, sizeof(p_be)) == 0;
|
||||
}
|
||||
|
||||
static int p256_words_is_one(const u32 *a)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
if (a[0] != 1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
for (i = 1; i < P256_WORDS; i++) {
|
||||
if (a[i] != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static int p256_words_cmp(const u32 *a, const u32 *b)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = P256_WORDS - 1; i >= 0; i--) {
|
||||
if (a[i] < b[i]) {
|
||||
return -1;
|
||||
}
|
||||
if (a[i] > b[i]) {
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static size_t p256_words_ctz(const u32 *a)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
if (a[i] != 0) {
|
||||
return i * 32 + __builtin_ctz(a[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return P256_WORDS * 32;
|
||||
}
|
||||
|
||||
static void p256_words_rshift(u32 *a, size_t count)
|
||||
{
|
||||
size_t word_shift = count / 32;
|
||||
size_t bit_shift = count % 32;
|
||||
size_t i;
|
||||
|
||||
if (word_shift >= P256_WORDS) {
|
||||
os_memset(a, 0, sizeof(u32) * P256_WORDS);
|
||||
return;
|
||||
}
|
||||
|
||||
if (word_shift > 0) {
|
||||
for (i = 0; i + word_shift < P256_WORDS; i++) {
|
||||
a[i] = a[i + word_shift];
|
||||
}
|
||||
for (; i < P256_WORDS; i++) {
|
||||
a[i] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if (bit_shift > 0) {
|
||||
for (i = 0; i < P256_WORDS - 1; i++) {
|
||||
a[i] = (a[i] >> bit_shift) |
|
||||
(a[i + 1] << (32 - bit_shift));
|
||||
}
|
||||
a[P256_WORDS - 1] >>= bit_shift;
|
||||
}
|
||||
}
|
||||
|
||||
static void p256_words_lshift(const u32 *in, size_t count, u32 *out)
|
||||
{
|
||||
size_t word_shift = count / 32;
|
||||
size_t bit_shift = count % 32;
|
||||
size_t i;
|
||||
|
||||
os_memset(out, 0, sizeof(u32) * P256_WORDS);
|
||||
|
||||
if (word_shift >= P256_WORDS) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
u64 val;
|
||||
size_t dst;
|
||||
|
||||
if (in[i] == 0) {
|
||||
continue;
|
||||
}
|
||||
|
||||
dst = i + word_shift;
|
||||
if (dst >= P256_WORDS) {
|
||||
break;
|
||||
}
|
||||
|
||||
val = (u64) in[i] << bit_shift;
|
||||
out[dst] |= (u32) val;
|
||||
if (bit_shift > 0 && dst + 1 < P256_WORDS) {
|
||||
out[dst + 1] |= (u32)(val >> 32);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void p256_words_sub(u32 *a, const u32 *b)
|
||||
{
|
||||
size_t i;
|
||||
u64 borrow = 0;
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
u64 ai = a[i];
|
||||
u64 bi = b[i];
|
||||
u64 res = ai - bi - borrow;
|
||||
|
||||
a[i] = (u32) res;
|
||||
borrow = (ai < bi + borrow) ? 1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
static void p256_words_swap(u32 *a, u32 *b)
|
||||
{
|
||||
u32 tmp[P256_WORDS];
|
||||
|
||||
os_memcpy(tmp, a, sizeof(tmp));
|
||||
os_memcpy(a, b, sizeof(tmp));
|
||||
os_memcpy(b, tmp, sizeof(tmp));
|
||||
}
|
||||
|
||||
static void p256_words_mod(u32 *a, const u32 *n)
|
||||
{
|
||||
u32 tmp[P256_WORDS];
|
||||
|
||||
while (p256_words_cmp(a, n) >= 0) {
|
||||
size_t a_bits = p256_words_bitlen(a);
|
||||
size_t n_bits = p256_words_bitlen(n);
|
||||
size_t shift = a_bits - n_bits;
|
||||
|
||||
p256_words_lshift(n, shift, tmp);
|
||||
if (p256_words_cmp(a, tmp) < 0) {
|
||||
shift--;
|
||||
p256_words_lshift(n, shift, tmp);
|
||||
}
|
||||
p256_words_sub(a, tmp);
|
||||
}
|
||||
}
|
||||
|
||||
static int crypto_bignum_mulmod_secp256r1(const mbedtls_mpi *a,
|
||||
const mbedtls_mpi *b,
|
||||
const mbedtls_mpi *mod,
|
||||
mbedtls_mpi *out)
|
||||
{
|
||||
u32 a_words[P256_WORDS];
|
||||
u32 b_words[P256_WORDS];
|
||||
u32 b_mont[P256_WORDS];
|
||||
u32 result[P256_WORDS];
|
||||
|
||||
if (!mpi_is_secp256r1_prime(mod) ||
|
||||
p256_words_from_mpi_reduced(a, a_words) != 0 ||
|
||||
p256_words_from_mpi_reduced(b, b_words) != 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
p256_mont_mul(b_mont, b_words, p256_r2_le);
|
||||
p256_mont_mul(result, a_words, b_mont);
|
||||
|
||||
return p256_words_to_mpi(result, out) == 0 ? 0 : -1;
|
||||
}
|
||||
|
||||
static int crypto_bignum_legendre_secp256r1(const mbedtls_mpi *a,
|
||||
const mbedtls_mpi *p)
|
||||
{
|
||||
u32 A[P256_WORDS];
|
||||
u32 N[P256_WORDS];
|
||||
unsigned int n_mod8;
|
||||
unsigned int a_mod4;
|
||||
unsigned int n_mod4;
|
||||
size_t two_power;
|
||||
int sign = 1;
|
||||
|
||||
if (!mpi_is_secp256r1_prime(p) ||
|
||||
p256_words_from_mpi_reduced(a, A) != 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
os_memcpy(N, p256_p_le, sizeof(N));
|
||||
|
||||
if (p256_words_is_zero(A)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
while (!p256_words_is_zero(A)) {
|
||||
if (p256_words_is_one(A)) {
|
||||
return sign;
|
||||
}
|
||||
|
||||
n_mod8 = N[0] & 0x7;
|
||||
two_power = p256_words_ctz(A);
|
||||
if (two_power > 0) {
|
||||
p256_words_rshift(A, two_power);
|
||||
if ((n_mod8 == 3 || n_mod8 == 5) && (two_power & 1U)) {
|
||||
sign = -sign;
|
||||
}
|
||||
}
|
||||
|
||||
p256_words_swap(A, N);
|
||||
|
||||
a_mod4 = A[0] & 0x3;
|
||||
n_mod4 = N[0] & 0x3;
|
||||
if (a_mod4 == 3 && n_mod4 == 3) {
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
if (p256_words_cmp(A, N) >= 0) {
|
||||
p256_words_mod(A, N);
|
||||
}
|
||||
|
||||
if (p256_words_is_one(N)) {
|
||||
return sign;
|
||||
}
|
||||
}
|
||||
|
||||
return p256_words_is_one(N) ? sign : 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Compute Legendre symbol through Jacobi algorithm for odd prime modulus.
|
||||
* This avoids an expensive modular exponentiation in the SAE hot loop.
|
||||
*/
|
||||
static int crypto_bignum_legendre_jacobi(const mbedtls_mpi *a,
|
||||
const mbedtls_mpi *p)
|
||||
{
|
||||
mbedtls_mpi A, N;
|
||||
unsigned int n_mod8, a_mod4, n_mod4;
|
||||
size_t two_power;
|
||||
int ret = 0;
|
||||
int sign = 1;
|
||||
int res = -2;
|
||||
|
||||
if (mbedtls_mpi_cmp_int(p, 3) < 0 || mbedtls_mpi_get_bit(p, 0) == 0) {
|
||||
return -2;
|
||||
}
|
||||
|
||||
mbedtls_mpi_init(&A);
|
||||
mbedtls_mpi_init(&N);
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&N, p));
|
||||
if (mbedtls_mpi_cmp_int(a, 0) >= 0 && mbedtls_mpi_cmp_mpi(a, &N) < 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_copy(&A, a));
|
||||
} else {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, a, &N));
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_cmp_int(&A, 0) == 0) {
|
||||
res = 0;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
while (mbedtls_mpi_cmp_int(&A, 0) != 0) {
|
||||
if (mbedtls_mpi_cmp_int(&A, 1) == 0) {
|
||||
res = sign;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
n_mod8 = (mbedtls_mpi_get_bit(&N, 0) << 0) |
|
||||
(mbedtls_mpi_get_bit(&N, 1) << 1) |
|
||||
(mbedtls_mpi_get_bit(&N, 2) << 2);
|
||||
two_power = mbedtls_mpi_lsb(&A);
|
||||
if (two_power > 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_shift_r(&A, two_power));
|
||||
if ((n_mod8 == 3 || n_mod8 == 5) && (two_power & 1U)) {
|
||||
sign = -sign;
|
||||
}
|
||||
}
|
||||
|
||||
mbedtls_mpi_swap(&A, &N);
|
||||
|
||||
a_mod4 = (mbedtls_mpi_get_bit(&A, 0) << 0) |
|
||||
(mbedtls_mpi_get_bit(&A, 1) << 1);
|
||||
n_mod4 = (mbedtls_mpi_get_bit(&N, 0) << 0) |
|
||||
(mbedtls_mpi_get_bit(&N, 1) << 1);
|
||||
if (a_mod4 == 3 && n_mod4 == 3) {
|
||||
sign = -sign;
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_cmp_mpi(&A, &N) >= 0) {
|
||||
size_t a_bits = mbedtls_mpi_bitlen(&A);
|
||||
size_t n_bits = mbedtls_mpi_bitlen(&N);
|
||||
if (a_bits <= n_bits + 4) {
|
||||
while (mbedtls_mpi_cmp_mpi(&A, &N) >= 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&A, &A, &N));
|
||||
}
|
||||
} else {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&A, &A, &N));
|
||||
}
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_cmp_int(&N, 1) == 0) {
|
||||
res = sign;
|
||||
goto cleanup;
|
||||
}
|
||||
}
|
||||
|
||||
res = (mbedtls_mpi_cmp_int(&N, 1) == 0) ? sign : 0;
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&A);
|
||||
mbedtls_mpi_free(&N);
|
||||
|
||||
if (ret != 0) {
|
||||
return -2;
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
struct crypto_bignum *crypto_bignum_init(void)
|
||||
{
|
||||
@@ -122,7 +457,43 @@ int crypto_bignum_exptmod(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *c,
|
||||
struct crypto_bignum *d)
|
||||
{
|
||||
return mbedtls_mpi_exp_mod((mbedtls_mpi *) d, (const mbedtls_mpi *) a, (const mbedtls_mpi *) b, (const mbedtls_mpi *) c, NULL) ? -1 : 0;
|
||||
int ret;
|
||||
|
||||
/* Fast path for small public exponents frequently used in SAE math. */
|
||||
if (mbedtls_mpi_cmp_int((const mbedtls_mpi *) b, 0) >= 0 &&
|
||||
mbedtls_mpi_cmp_int((const mbedtls_mpi *) b, 3) <= 0) {
|
||||
if (mbedtls_mpi_cmp_int((const mbedtls_mpi *) b, 0) == 0) {
|
||||
ret = mbedtls_mpi_lset((mbedtls_mpi *) d, 1) ||
|
||||
mbedtls_mpi_mod_mpi((mbedtls_mpi *) d, (mbedtls_mpi *) d,
|
||||
(const mbedtls_mpi *) c);
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_cmp_int((const mbedtls_mpi *) b, 1) == 0) {
|
||||
ret = mbedtls_mpi_copy((mbedtls_mpi *) d, (const mbedtls_mpi *) a) ||
|
||||
mbedtls_mpi_mod_mpi((mbedtls_mpi *) d, (mbedtls_mpi *) d,
|
||||
(const mbedtls_mpi *) c);
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_cmp_int((const mbedtls_mpi *) b, 2) == 0) {
|
||||
return crypto_bignum_mulmod(a, a, c, d);
|
||||
} else {
|
||||
mbedtls_mpi tmp;
|
||||
mbedtls_mpi_init(&tmp);
|
||||
ret = crypto_bignum_mulmod(a, a, c, (struct crypto_bignum *) &tmp);
|
||||
if (ret == 0) {
|
||||
ret = crypto_bignum_mulmod((struct crypto_bignum *) &tmp,
|
||||
a, c, d);
|
||||
}
|
||||
mbedtls_mpi_free(&tmp);
|
||||
return ret ? -1 : 0;
|
||||
}
|
||||
}
|
||||
|
||||
return mbedtls_mpi_exp_mod((mbedtls_mpi *) d, (const mbedtls_mpi *) a,
|
||||
(const mbedtls_mpi *) b,
|
||||
(const mbedtls_mpi *) c, NULL) ? -1 : 0;
|
||||
|
||||
}
|
||||
|
||||
@@ -155,6 +526,13 @@ int crypto_bignum_mulmod(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *c,
|
||||
struct crypto_bignum *d)
|
||||
{
|
||||
int fast_ret = crypto_bignum_mulmod_secp256r1((const mbedtls_mpi *) a,
|
||||
(const mbedtls_mpi *) b,
|
||||
(const mbedtls_mpi *) c,
|
||||
(mbedtls_mpi *) d);
|
||||
if (fast_ret != -2) {
|
||||
return fast_ret;
|
||||
}
|
||||
return mbedtls_mpi_mul_mpi((mbedtls_mpi *)d, (const mbedtls_mpi *)a, (const mbedtls_mpi *)b) ||
|
||||
mbedtls_mpi_mod_mpi((mbedtls_mpi *)d, (mbedtls_mpi *)d, (const mbedtls_mpi *)c) ? -1 : 0;
|
||||
}
|
||||
@@ -163,17 +541,7 @@ int crypto_bignum_sqrmod(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_bignum *c)
|
||||
{
|
||||
int res;
|
||||
struct crypto_bignum *tmp = crypto_bignum_init();
|
||||
if (!tmp) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
res = mbedtls_mpi_copy((mbedtls_mpi *) tmp, (const mbedtls_mpi *) a);
|
||||
res = crypto_bignum_mulmod(a, tmp, b, c);
|
||||
|
||||
crypto_bignum_deinit(tmp, 0);
|
||||
return res ? -1 : 0;
|
||||
return crypto_bignum_mulmod(a, a, b, c);
|
||||
}
|
||||
|
||||
int crypto_bignum_rshift(const struct crypto_bignum *a, int n,
|
||||
@@ -222,8 +590,8 @@ int crypto_bignum_rand(struct crypto_bignum *r, const struct crypto_bignum *m)
|
||||
mbedtls_psa_get_random, MBEDTLS_PSA_RANDOM_STATE) != 0) ? -1 : 0);
|
||||
}
|
||||
|
||||
int crypto_bignum_legendre(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *p)
|
||||
static int mbedtls_bignum_legendre(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *p)
|
||||
{
|
||||
mbedtls_mpi exp, tmp;
|
||||
int res = -2, ret;
|
||||
@@ -255,6 +623,26 @@ cleanup:
|
||||
return res;
|
||||
}
|
||||
|
||||
int crypto_bignum_legendre(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *p)
|
||||
{
|
||||
int jacobi_res;
|
||||
|
||||
jacobi_res = crypto_bignum_legendre_secp256r1((const mbedtls_mpi *) a,
|
||||
(const mbedtls_mpi *) p);
|
||||
if (jacobi_res != -2) {
|
||||
return jacobi_res;
|
||||
}
|
||||
|
||||
jacobi_res = crypto_bignum_legendre_jacobi((const mbedtls_mpi *) a,
|
||||
(const mbedtls_mpi *) p);
|
||||
if (jacobi_res != -2) {
|
||||
return jacobi_res;
|
||||
}
|
||||
|
||||
return mbedtls_bignum_legendre(a, p);
|
||||
}
|
||||
|
||||
int crypto_bignum_addmod(const struct crypto_bignum *a,
|
||||
const struct crypto_bignum *b,
|
||||
const struct crypto_bignum *c,
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
|
||||
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
@@ -8,8 +8,12 @@
|
||||
|
||||
#ifdef ESP_PLATFORM
|
||||
#include "esp_system.h"
|
||||
#include "esp_random.h"
|
||||
#include "mbedtls/bignum.h"
|
||||
#include "mbedtls/esp_mbedtls_random.h"
|
||||
#if CONFIG_MBEDTLS_HARDWARE_ECC
|
||||
#include "ecc_impl.h"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include "utils/includes.h"
|
||||
@@ -23,7 +27,9 @@
|
||||
#include "mbedtls/asn1write.h"
|
||||
#include "mbedtls/error.h"
|
||||
#include "mbedtls/oid.h"
|
||||
#include "mbedtls/platform_util.h"
|
||||
#include <mbedtls/psa_util.h>
|
||||
#include "p256_common.h"
|
||||
#include "psa/crypto.h"
|
||||
#include "psa/crypto_sizes.h"
|
||||
#include "esp_heap_caps.h"
|
||||
@@ -39,6 +45,70 @@
|
||||
|
||||
#define ESP_SUP_MAX_ECC_KEY_SIZE 256
|
||||
|
||||
#if CONFIG_MBEDTLS_HARDWARE_ECC
|
||||
static bool crypto_ec_point_mul_curve_supported(const mbedtls_ecp_group *grp)
|
||||
{
|
||||
switch (grp->id) {
|
||||
case MBEDTLS_ECP_DP_SECP192R1:
|
||||
case MBEDTLS_ECP_DP_SECP256R1:
|
||||
#if SOC_ECC_SUPPORT_CURVE_P384
|
||||
case MBEDTLS_ECP_DP_SECP384R1:
|
||||
#endif
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static int crypto_ec_point_mul_ecc_hw(const mbedtls_ecp_group *grp,
|
||||
const mbedtls_ecp_point *p,
|
||||
const mbedtls_mpi *k,
|
||||
mbedtls_ecp_point *res)
|
||||
{
|
||||
int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
||||
ecc_point_t p_hw = { 0 };
|
||||
ecc_point_t r_hw = { 0 };
|
||||
unsigned char scalar_le[MAX_SIZE] = { 0 };
|
||||
size_t curve_len = grp->pbits / 8;
|
||||
|
||||
if (!crypto_ec_point_mul_curve_supported(grp)) {
|
||||
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
if (curve_len != P192_LEN && curve_len != P256_LEN
|
||||
#if SOC_ECC_SUPPORT_CURVE_P384
|
||||
&& curve_len != P384_LEN
|
||||
#endif
|
||||
) {
|
||||
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
/* Preserve mbedTLS input validation semantics for this fast path. */
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(grp, k));
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, p));
|
||||
|
||||
p_hw.len = curve_len;
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&p->MBEDTLS_PRIVATE(X), p_hw.x, MAX_SIZE));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(&p->MBEDTLS_PRIVATE(Y), p_hw.y, MAX_SIZE));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_write_binary_le(k, scalar_le, MAX_SIZE));
|
||||
|
||||
if (esp_ecc_point_multiply(&p_hw, scalar_le, &r_hw, false) != 0) {
|
||||
ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&res->MBEDTLS_PRIVATE(X), r_hw.x, curve_len));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_read_binary_le(&res->MBEDTLS_PRIVATE(Y), r_hw.y, curve_len));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&res->MBEDTLS_PRIVATE(Z), 1));
|
||||
|
||||
cleanup:
|
||||
mbedtls_platform_zeroize(scalar_le, sizeof(scalar_le));
|
||||
mbedtls_platform_zeroize(&p_hw, sizeof(p_hw));
|
||||
mbedtls_platform_zeroize(&r_hw, sizeof(r_hw));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_ECC
|
||||
|
||||
// Wrapper structure for EC keys that includes PSA key ID, curve info, and group
|
||||
@@ -287,6 +357,306 @@ cleanup:
|
||||
return NULL;
|
||||
}
|
||||
|
||||
#if CONFIG_MBEDTLS_HARDWARE_MPI && !CONFIG_MBEDTLS_HARDWARE_ECC
|
||||
typedef struct {
|
||||
u32 X[P256_WORDS];
|
||||
u32 Y[P256_WORDS];
|
||||
u32 Z[P256_WORDS];
|
||||
} p256_fast_jac_point;
|
||||
|
||||
static u32 p256_fast_words_add_carry(u32 *z, const u32 *x, const u32 *y)
|
||||
{
|
||||
size_t i;
|
||||
u64 carry = 0;
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
u64 sum = (u64) x[i] + y[i] + carry;
|
||||
|
||||
z[i] = (u32) sum;
|
||||
carry = sum >> 32;
|
||||
}
|
||||
|
||||
return (u32) carry;
|
||||
}
|
||||
|
||||
static void p256_fast_words_add_mod(u32 *z, const u32 *x, const u32 *y)
|
||||
{
|
||||
u32 reduced[P256_WORDS];
|
||||
u32 carry = p256_fast_words_add_carry(z, x, y);
|
||||
u32 borrow = p256_words_sub_borrow(reduced, z, p256_p_le);
|
||||
u32 use_sub = carry | (1U - borrow);
|
||||
|
||||
p256_words_cmov(z, reduced, use_sub);
|
||||
}
|
||||
|
||||
static void p256_fast_words_sub_mod(u32 *z, const u32 *x, const u32 *y)
|
||||
{
|
||||
u32 tmp[P256_WORDS];
|
||||
|
||||
if (p256_words_sub_borrow(z, x, y) != 0) {
|
||||
(void) p256_fast_words_add_carry(tmp, z, p256_p_le);
|
||||
os_memcpy(z, tmp, sizeof(tmp));
|
||||
}
|
||||
}
|
||||
|
||||
static void p256_fast_to_mont(u32 out[P256_WORDS],
|
||||
const u32 in[P256_WORDS])
|
||||
{
|
||||
p256_mont_mul(out, in, p256_r2_le);
|
||||
}
|
||||
|
||||
static void p256_fast_from_mont(u32 out[P256_WORDS],
|
||||
const u32 in[P256_WORDS])
|
||||
{
|
||||
static const u32 one[P256_WORDS] = {1};
|
||||
|
||||
p256_mont_mul(out, in, one);
|
||||
}
|
||||
|
||||
static void p256_fast_sqr(u32 out[P256_WORDS], const u32 in[P256_WORDS])
|
||||
{
|
||||
p256_mont_mul(out, in, in);
|
||||
}
|
||||
|
||||
static void p256_fast_mul(u32 out[P256_WORDS],
|
||||
const u32 a[P256_WORDS],
|
||||
const u32 b[P256_WORDS])
|
||||
{
|
||||
p256_mont_mul(out, a, b);
|
||||
}
|
||||
|
||||
static void p256_fast_dbl(u32 out[P256_WORDS], const u32 in[P256_WORDS])
|
||||
{
|
||||
p256_fast_words_add_mod(out, in, in);
|
||||
}
|
||||
|
||||
static void p256_fast_triple(u32 out[P256_WORDS], const u32 in[P256_WORDS])
|
||||
{
|
||||
u32 tmp[P256_WORDS];
|
||||
|
||||
p256_fast_dbl(tmp, in);
|
||||
p256_fast_words_add_mod(out, tmp, in);
|
||||
}
|
||||
|
||||
static void p256_fast_eight(u32 out[P256_WORDS], const u32 in[P256_WORDS])
|
||||
{
|
||||
u32 tmp[P256_WORDS];
|
||||
|
||||
p256_fast_dbl(tmp, in);
|
||||
p256_fast_dbl(tmp, tmp);
|
||||
p256_fast_dbl(out, tmp);
|
||||
}
|
||||
|
||||
static void p256_fast_point_set_zero(p256_fast_jac_point *p)
|
||||
{
|
||||
os_memset(p, 0, sizeof(*p));
|
||||
}
|
||||
|
||||
static void p256_fast_point_from_affine(p256_fast_jac_point *p,
|
||||
const u32 x[P256_WORDS],
|
||||
const u32 y[P256_WORDS],
|
||||
const u32 one_mont[P256_WORDS])
|
||||
{
|
||||
os_memcpy(p->X, x, sizeof(p->X));
|
||||
os_memcpy(p->Y, y, sizeof(p->Y));
|
||||
os_memcpy(p->Z, one_mont, sizeof(p->Z));
|
||||
}
|
||||
|
||||
static void p256_fast_point_double(p256_fast_jac_point *r)
|
||||
{
|
||||
u32 z2[P256_WORDS], y2[P256_WORDS], y4[P256_WORDS];
|
||||
u32 s[P256_WORDS], m[P256_WORDS], x3[P256_WORDS];
|
||||
u32 y3[P256_WORDS], z3[P256_WORDS], tmp1[P256_WORDS];
|
||||
u32 tmp2[P256_WORDS];
|
||||
|
||||
if (p256_words_is_zero(r->Z) || p256_words_is_zero(r->Y)) {
|
||||
p256_fast_point_set_zero(r);
|
||||
return;
|
||||
}
|
||||
|
||||
p256_fast_sqr(z2, r->Z);
|
||||
p256_fast_sqr(y2, r->Y);
|
||||
p256_fast_sqr(y4, y2);
|
||||
|
||||
p256_fast_mul(s, r->X, y2);
|
||||
p256_fast_dbl(s, s);
|
||||
p256_fast_dbl(s, s);
|
||||
|
||||
p256_fast_words_add_mod(tmp1, r->X, z2);
|
||||
p256_fast_words_sub_mod(tmp2, r->X, z2);
|
||||
p256_fast_mul(m, tmp1, tmp2);
|
||||
p256_fast_triple(m, m);
|
||||
|
||||
p256_fast_sqr(x3, m);
|
||||
p256_fast_words_sub_mod(x3, x3, s);
|
||||
p256_fast_words_sub_mod(x3, x3, s);
|
||||
|
||||
p256_fast_words_sub_mod(tmp1, s, x3);
|
||||
p256_fast_mul(y3, m, tmp1);
|
||||
p256_fast_eight(tmp2, y4);
|
||||
p256_fast_words_sub_mod(y3, y3, tmp2);
|
||||
|
||||
p256_fast_mul(z3, r->Y, r->Z);
|
||||
p256_fast_dbl(z3, z3);
|
||||
|
||||
os_memcpy(r->X, x3, sizeof(r->X));
|
||||
os_memcpy(r->Y, y3, sizeof(r->Y));
|
||||
os_memcpy(r->Z, z3, sizeof(r->Z));
|
||||
}
|
||||
|
||||
static void p256_fast_point_add_mixed(p256_fast_jac_point *r,
|
||||
const u32 qx[P256_WORDS],
|
||||
const u32 qy[P256_WORDS],
|
||||
const u32 one_mont[P256_WORDS])
|
||||
{
|
||||
u32 z1z1[P256_WORDS], z1z1z1[P256_WORDS];
|
||||
u32 u2[P256_WORDS], s2[P256_WORDS], h[P256_WORDS];
|
||||
u32 rr[P256_WORDS], hh[P256_WORDS], hhh[P256_WORDS];
|
||||
u32 v[P256_WORDS], x3[P256_WORDS], y3[P256_WORDS];
|
||||
u32 z3[P256_WORDS], tmp[P256_WORDS], y1[P256_WORDS];
|
||||
|
||||
if (p256_words_is_zero(r->Z)) {
|
||||
p256_fast_point_from_affine(r, qx, qy, one_mont);
|
||||
return;
|
||||
}
|
||||
|
||||
os_memcpy(y1, r->Y, sizeof(y1));
|
||||
|
||||
p256_fast_sqr(z1z1, r->Z);
|
||||
p256_fast_mul(z1z1z1, z1z1, r->Z);
|
||||
p256_fast_mul(u2, qx, z1z1);
|
||||
p256_fast_mul(s2, qy, z1z1z1);
|
||||
p256_fast_words_sub_mod(h, u2, r->X);
|
||||
p256_fast_words_sub_mod(rr, s2, y1);
|
||||
|
||||
if (p256_words_is_zero(h)) {
|
||||
if (p256_words_is_zero(rr)) {
|
||||
p256_fast_point_double(r);
|
||||
} else {
|
||||
p256_fast_point_set_zero(r);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
p256_fast_sqr(hh, h);
|
||||
p256_fast_mul(hhh, hh, h);
|
||||
p256_fast_mul(v, r->X, hh);
|
||||
|
||||
p256_fast_sqr(x3, rr);
|
||||
p256_fast_words_sub_mod(x3, x3, hhh);
|
||||
p256_fast_words_sub_mod(x3, x3, v);
|
||||
p256_fast_words_sub_mod(x3, x3, v);
|
||||
|
||||
p256_fast_words_sub_mod(tmp, v, x3);
|
||||
p256_fast_mul(y3, rr, tmp);
|
||||
p256_fast_mul(tmp, y1, hhh);
|
||||
p256_fast_words_sub_mod(y3, y3, tmp);
|
||||
|
||||
p256_fast_mul(z3, r->Z, h);
|
||||
|
||||
os_memcpy(r->X, x3, sizeof(r->X));
|
||||
os_memcpy(r->Y, y3, sizeof(r->Y));
|
||||
os_memcpy(r->Z, z3, sizeof(r->Z));
|
||||
}
|
||||
|
||||
static int p256_fast_point_normalize(const mbedtls_ecp_group *grp,
|
||||
const p256_fast_jac_point *p,
|
||||
mbedtls_ecp_point *res)
|
||||
{
|
||||
mbedtls_mpi z_mpi, inv_mpi;
|
||||
u32 z_std[P256_WORDS], inv_std[P256_WORDS], inv_mont[P256_WORDS];
|
||||
u32 x_std[P256_WORDS], y_std[P256_WORDS], tmp[P256_WORDS];
|
||||
int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
||||
|
||||
if (p256_words_is_zero(p->Z)) {
|
||||
return mbedtls_ecp_set_zero(res);
|
||||
}
|
||||
|
||||
mbedtls_mpi_init(&z_mpi);
|
||||
mbedtls_mpi_init(&inv_mpi);
|
||||
|
||||
p256_fast_from_mont(z_std, p->Z);
|
||||
MBEDTLS_MPI_CHK(p256_words_to_mpi(z_std, &z_mpi));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_inv_mod(&inv_mpi, &z_mpi, &grp->P));
|
||||
if (p256_words_from_mpi_reduced(&inv_mpi, inv_std) != 0) {
|
||||
ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
p256_fast_to_mont(inv_mont, inv_std);
|
||||
p256_fast_mul(y_std, p->Y, inv_mont);
|
||||
p256_fast_sqr(tmp, inv_mont);
|
||||
p256_fast_mul(x_std, p->X, tmp);
|
||||
p256_fast_mul(y_std, y_std, tmp);
|
||||
p256_fast_from_mont(x_std, x_std);
|
||||
p256_fast_from_mont(y_std, y_std);
|
||||
|
||||
MBEDTLS_MPI_CHK(p256_words_to_mpi(x_std, &res->MBEDTLS_PRIVATE(X)));
|
||||
MBEDTLS_MPI_CHK(p256_words_to_mpi(y_std, &res->MBEDTLS_PRIVATE(Y)));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&res->MBEDTLS_PRIVATE(Z), 1));
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&z_mpi);
|
||||
mbedtls_mpi_free(&inv_mpi);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int crypto_ec_point_mul_p256_jacobian_fast(const mbedtls_ecp_group *grp,
|
||||
const mbedtls_ecp_point *p,
|
||||
const mbedtls_mpi *k,
|
||||
mbedtls_ecp_point *res)
|
||||
{
|
||||
p256_fast_jac_point r;
|
||||
u32 scalar[P256_WORDS], x_std[P256_WORDS], y_std[P256_WORDS];
|
||||
u32 x_mont[P256_WORDS], y_mont[P256_WORDS], one_mont[P256_WORDS];
|
||||
static const u32 one_std[P256_WORDS] = {1};
|
||||
int bit;
|
||||
int ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
|
||||
|
||||
if (!grp || grp->id != MBEDTLS_ECP_DP_SECP256R1 ||
|
||||
mbedtls_mpi_cmp_int(&p->MBEDTLS_PRIVATE(Z), 1) != 0) {
|
||||
return MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
|
||||
}
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_check_privkey(grp, k));
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_check_pubkey(grp, p));
|
||||
|
||||
if (p256_words_from_mpi(k, scalar) != 0 ||
|
||||
p256_words_from_mpi_reduced(&p->MBEDTLS_PRIVATE(X), x_std) != 0 ||
|
||||
p256_words_from_mpi_reduced(&p->MBEDTLS_PRIVATE(Y), y_std) != 0) {
|
||||
ret = MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE;
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
bit = (int) p256_words_bitlen(scalar);
|
||||
if (bit <= 0) {
|
||||
ret = mbedtls_ecp_set_zero(res);
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
p256_fast_to_mont(x_mont, x_std);
|
||||
p256_fast_to_mont(y_mont, y_std);
|
||||
p256_fast_to_mont(one_mont, one_std);
|
||||
p256_fast_point_from_affine(&r, x_mont, y_mont, one_mont);
|
||||
|
||||
for (bit -= 2; bit >= 0; bit--) {
|
||||
p256_fast_point_double(&r);
|
||||
if ((scalar[bit / 32] >> (bit % 32)) & 1U) {
|
||||
p256_fast_point_add_mixed(&r, x_mont, y_mont, one_mont);
|
||||
}
|
||||
}
|
||||
|
||||
ret = p256_fast_point_normalize(grp, &r, res);
|
||||
|
||||
cleanup:
|
||||
mbedtls_platform_zeroize(scalar, sizeof(scalar));
|
||||
mbedtls_platform_zeroize(&r, sizeof(r));
|
||||
mbedtls_platform_zeroize(x_mont, sizeof(x_mont));
|
||||
mbedtls_platform_zeroize(y_mont, sizeof(y_mont));
|
||||
return ret;
|
||||
}
|
||||
#endif
|
||||
|
||||
int crypto_ec_point_add(struct crypto_ec *e, const struct crypto_ec_point *a,
|
||||
const struct crypto_ec_point *b,
|
||||
struct crypto_ec_point *c)
|
||||
@@ -308,7 +678,31 @@ int crypto_ec_point_mul(struct crypto_ec *e, const struct crypto_ec_point *p,
|
||||
const struct crypto_bignum *b,
|
||||
struct crypto_ec_point *res)
|
||||
{
|
||||
int ret;
|
||||
int ret = MBEDTLS_ERR_ECP_BAD_INPUT_DATA;
|
||||
|
||||
#if CONFIG_MBEDTLS_HARDWARE_ECC
|
||||
ret = crypto_ec_point_mul_ecc_hw((mbedtls_ecp_group *)e,
|
||||
(const mbedtls_ecp_point *)p,
|
||||
(const mbedtls_mpi *)b,
|
||||
(mbedtls_ecp_point *)res);
|
||||
if (ret == 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) {
|
||||
goto cleanup;
|
||||
}
|
||||
#elif CONFIG_MBEDTLS_HARDWARE_MPI
|
||||
ret = crypto_ec_point_mul_p256_jacobian_fast((mbedtls_ecp_group *) e,
|
||||
(const mbedtls_ecp_point *) p,
|
||||
(const mbedtls_mpi *) b,
|
||||
(mbedtls_ecp_point *) res);
|
||||
if (ret == 0) {
|
||||
goto cleanup;
|
||||
}
|
||||
if (ret != MBEDTLS_ERR_ECP_FEATURE_UNAVAILABLE) {
|
||||
goto cleanup;
|
||||
}
|
||||
#endif
|
||||
MBEDTLS_MPI_CHK(mbedtls_ecp_mul((mbedtls_ecp_group *)e,
|
||||
(mbedtls_ecp_point *) res,
|
||||
(const mbedtls_mpi *)b,
|
||||
@@ -401,6 +795,7 @@ struct crypto_bignum *crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
|
||||
const struct crypto_bignum *x)
|
||||
{
|
||||
mbedtls_mpi temp, temp2, num;
|
||||
mbedtls_ecp_group *grp = (mbedtls_ecp_group *) e;
|
||||
int ret = 0;
|
||||
|
||||
mbedtls_mpi *y_sqr = os_zalloc(sizeof(mbedtls_mpi));
|
||||
@@ -414,30 +809,48 @@ struct crypto_bignum *crypto_ec_point_compute_y_sqr(struct crypto_ec *e,
|
||||
mbedtls_mpi_init(y_sqr);
|
||||
|
||||
/* y^2 = x^3 + ax + b mod P */
|
||||
/* X*X*X is faster on esp32 whereas X^3 is faster on other chips */
|
||||
#if CONFIG_IDF_TARGET_ESP32
|
||||
/* Calculate x*x*x mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&temp, (const mbedtls_mpi *) x, (const mbedtls_mpi *) x));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&temp, &temp, (const mbedtls_mpi *) x));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp, &temp, &((mbedtls_ecp_group *)e)->P));
|
||||
#else
|
||||
/* Calculate x^3 mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&num, 3));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&temp, (const mbedtls_mpi *) x, &num, &((mbedtls_ecp_group *)e)->P, NULL));
|
||||
#endif
|
||||
MBEDTLS_MPI_CHK(crypto_bignum_mulmod(x, x,
|
||||
(const struct crypto_bignum *) &grp->P,
|
||||
(struct crypto_bignum *) &temp));
|
||||
MBEDTLS_MPI_CHK(crypto_bignum_mulmod((const struct crypto_bignum *) &temp, x,
|
||||
(const struct crypto_bignum *) &grp->P,
|
||||
(struct crypto_bignum *) &temp));
|
||||
|
||||
/* Calculate ax mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&num, -3));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&temp2, (const mbedtls_mpi *) x, &num));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &((mbedtls_ecp_group *)e)->P));
|
||||
if (mbedtls_ecp_group_a_is_minus_3(grp)) {
|
||||
/*
|
||||
* For NIST P-curves used in SAE, a == -3. Compute (-3x + b) mod p
|
||||
* with additions/subtractions instead of a generic multiply+mod path.
|
||||
*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, (const mbedtls_mpi *) x,
|
||||
(const mbedtls_mpi *) x));
|
||||
if (mbedtls_mpi_cmp_mpi(&temp2, &grp->P) >= 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&temp2, &temp2, &grp->P));
|
||||
}
|
||||
|
||||
/* Calculate ax + b mod P. Note that b is already < P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &((mbedtls_ecp_group *)e)->B));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &((mbedtls_ecp_group *)e)->P));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2,
|
||||
(const mbedtls_mpi *) x));
|
||||
while (mbedtls_mpi_cmp_mpi(&temp2, &grp->P) >= 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&temp2, &temp2, &grp->P));
|
||||
}
|
||||
|
||||
/* Calculate x^3 + ax + b mod P*/
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &temp));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(y_sqr, &temp2, &((mbedtls_ecp_group *)e)->P));
|
||||
if (mbedtls_mpi_cmp_int(&temp2, 0) != 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&temp2, &grp->P, &temp2));
|
||||
}
|
||||
} else {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mul_mpi(&temp2, (const mbedtls_mpi *) x,
|
||||
&grp->A));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_mod_mpi(&temp2, &temp2, &grp->P));
|
||||
}
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(&temp2, &temp2, &grp->B));
|
||||
while (mbedtls_mpi_cmp_mpi(&temp2, &grp->P) >= 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(&temp2, &temp2, &grp->P));
|
||||
}
|
||||
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_add_mpi(y_sqr, &temp2, &temp));
|
||||
while (mbedtls_mpi_cmp_mpi(y_sqr, &grp->P) >= 0) {
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_sub_mpi(y_sqr, y_sqr, &grp->P));
|
||||
}
|
||||
|
||||
cleanup:
|
||||
mbedtls_mpi_free(&temp);
|
||||
@@ -458,8 +871,9 @@ int crypto_ec_point_is_at_infinity(struct crypto_ec *e,
|
||||
return mbedtls_ecp_is_zero((mbedtls_ecp_point *) p);
|
||||
}
|
||||
|
||||
int crypto_ec_point_is_on_curve(struct crypto_ec *e,
|
||||
const struct crypto_ec_point *p)
|
||||
#if !CONFIG_MBEDTLS_HARDWARE_ECC
|
||||
static int crypto_ec_point_is_on_curve_mpi(struct crypto_ec *e,
|
||||
const struct crypto_ec_point *p)
|
||||
{
|
||||
mbedtls_mpi y_sqr_lhs, *y_sqr_rhs = NULL, two;
|
||||
int ret = 0, on_curve = 0;
|
||||
@@ -467,11 +881,15 @@ int crypto_ec_point_is_on_curve(struct crypto_ec *e,
|
||||
mbedtls_mpi_init(&y_sqr_lhs);
|
||||
mbedtls_mpi_init(&two);
|
||||
|
||||
/* Calculate y^2 mod P*/
|
||||
/* Calculate y^2 mod P */
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_lset(&two, 2));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&y_sqr_lhs, &((const mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y), &two, &((mbedtls_ecp_group *)e)->P, NULL));
|
||||
MBEDTLS_MPI_CHK(mbedtls_mpi_exp_mod(&y_sqr_lhs,
|
||||
&((const mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(Y),
|
||||
&two, &((mbedtls_ecp_group *)e)->P, NULL));
|
||||
|
||||
y_sqr_rhs = (mbedtls_mpi *) crypto_ec_point_compute_y_sqr(e, (const struct crypto_bignum *) & ((const mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X));
|
||||
y_sqr_rhs = (mbedtls_mpi *) crypto_ec_point_compute_y_sqr(
|
||||
e, (const struct crypto_bignum *)
|
||||
& ((const mbedtls_ecp_point *)p)->MBEDTLS_PRIVATE(X));
|
||||
|
||||
if (y_sqr_rhs && (mbedtls_mpi_cmp_mpi(y_sqr_rhs, &y_sqr_lhs) == 0)) {
|
||||
on_curve = 1;
|
||||
@@ -484,6 +902,20 @@ cleanup:
|
||||
os_free(y_sqr_rhs);
|
||||
return (ret == 0) && (on_curve == 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
int crypto_ec_point_is_on_curve(struct crypto_ec *e,
|
||||
const struct crypto_ec_point *p)
|
||||
{
|
||||
#if CONFIG_MBEDTLS_HARDWARE_ECC
|
||||
/* ECC HW verify path via mbedTLS alt hooks. */
|
||||
return mbedtls_ecp_check_pubkey((const mbedtls_ecp_group *)e,
|
||||
(const mbedtls_ecp_point *)p) == 0;
|
||||
#else
|
||||
/* MPI implementation. */
|
||||
return crypto_ec_point_is_on_curve_mpi(e, p);
|
||||
#endif
|
||||
}
|
||||
|
||||
int crypto_ec_point_cmp(const struct crypto_ec *e,
|
||||
const struct crypto_ec_point *a,
|
||||
|
||||
@@ -0,0 +1,236 @@
|
||||
/*
|
||||
* SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*/
|
||||
|
||||
/*
|
||||
* Shared P-256 (secp256r1) word-level and Montgomery arithmetic used by
|
||||
* both the bignum and EC fast paths. All helpers are static inline so
|
||||
* each translation unit gets its own copy without linkage issues.
|
||||
*
|
||||
* Prerequisites: the including .c file must already provide u8/u32/u64
|
||||
* typedefs, os_memcmp/os_memset/os_memcpy (via utils/common.h), and
|
||||
* mbedtls/bignum.h.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define P256_WORDS 8
|
||||
#define P256_LEN_BYTES 32
|
||||
|
||||
static const u8 p256_p_be[P256_LEN_BYTES] = {
|
||||
0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x01,
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
|
||||
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff,
|
||||
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff
|
||||
};
|
||||
|
||||
static const u32 p256_p_le[P256_WORDS] = {
|
||||
0xffffffffU, 0xffffffffU, 0xffffffffU, 0x00000000U,
|
||||
0x00000000U, 0x00000000U, 0x00000001U, 0xffffffffU
|
||||
};
|
||||
|
||||
/* R^2 mod p in little-endian word order, for Montgomery domain entry. */
|
||||
static const u32 p256_r2_le[P256_WORDS] = {
|
||||
0x00000003U, 0x00000000U, 0xffffffffU, 0xfffffffbU,
|
||||
0xfffffffeU, 0xffffffffU, 0xfffffffdU, 0x00000004U
|
||||
};
|
||||
|
||||
static inline int p256_words_is_zero(const u32 *a)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
if (a[i] != 0) {
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
static inline size_t p256_words_bitlen(const u32 *a)
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = P256_WORDS - 1; i >= 0; i--) {
|
||||
if (a[i] != 0) {
|
||||
return (size_t) i * 32 + 32 - __builtin_clz(a[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int p256_words_from_mpi(const mbedtls_mpi *in, u32 *out)
|
||||
{
|
||||
u8 in_be[P256_LEN_BYTES];
|
||||
size_t i;
|
||||
|
||||
if (!in || in->MBEDTLS_PRIVATE(s) < 0 ||
|
||||
mbedtls_mpi_size(in) > P256_LEN_BYTES ||
|
||||
mbedtls_mpi_write_binary(in, in_be, sizeof(in_be)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
size_t off = P256_LEN_BYTES - (i + 1) * 4;
|
||||
|
||||
out[i] = ((u32) in_be[off] << 24) |
|
||||
((u32) in_be[off + 1] << 16) |
|
||||
((u32) in_be[off + 2] << 8) |
|
||||
(u32) in_be[off + 3];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int p256_words_from_mpi_reduced(const mbedtls_mpi *in, u32 *out)
|
||||
{
|
||||
u8 in_be[P256_LEN_BYTES];
|
||||
size_t i;
|
||||
size_t in_size;
|
||||
|
||||
if (!in || in->MBEDTLS_PRIVATE(s) < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
in_size = mbedtls_mpi_size(in);
|
||||
if (in_size > P256_LEN_BYTES) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (mbedtls_mpi_write_binary(in, in_be, sizeof(in_be)) != 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (in_size == P256_LEN_BYTES &&
|
||||
os_memcmp(in_be, p256_p_be, sizeof(in_be)) >= 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
size_t off = P256_LEN_BYTES - (i + 1) * 4;
|
||||
|
||||
out[i] = ((u32) in_be[off] << 24) |
|
||||
((u32) in_be[off + 1] << 16) |
|
||||
((u32) in_be[off + 2] << 8) |
|
||||
(u32) in_be[off + 3];
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int p256_words_to_mpi(const u32 *in, mbedtls_mpi *out)
|
||||
{
|
||||
u8 out_be[P256_LEN_BYTES];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
size_t off = P256_LEN_BYTES - (i + 1) * 4;
|
||||
|
||||
out_be[off] = (u8)(in[i] >> 24);
|
||||
out_be[off + 1] = (u8)(in[i] >> 16);
|
||||
out_be[off + 2] = (u8)(in[i] >> 8);
|
||||
out_be[off + 3] = (u8) in[i];
|
||||
}
|
||||
|
||||
return mbedtls_mpi_read_binary(out, out_be, sizeof(out_be));
|
||||
}
|
||||
|
||||
static inline u32 p256_words_sub_borrow(u32 *z, const u32 *x, const u32 *y)
|
||||
{
|
||||
size_t i;
|
||||
u32 borrow = 0;
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
u64 diff = (u64) x[i] - y[i] - borrow;
|
||||
|
||||
z[i] = (u32) diff;
|
||||
borrow = -(u32)(diff >> 32);
|
||||
}
|
||||
|
||||
return borrow;
|
||||
}
|
||||
|
||||
static inline void p256_words_cmov(u32 *z, const u32 *x, u32 c)
|
||||
{
|
||||
size_t i;
|
||||
u32 mask = (u32) - (int) c;
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
z[i] = (z[i] & ~mask) | (x[i] & mask);
|
||||
}
|
||||
}
|
||||
|
||||
static inline u64 p256_u32_muladd64(u32 x, u32 y, u32 z, u32 t)
|
||||
{
|
||||
return (u64) x * y + z + t;
|
||||
}
|
||||
|
||||
static inline u32 p256_u288_muladd(u32 z[P256_WORDS + 1], u32 x,
|
||||
const u32 y[P256_WORDS])
|
||||
{
|
||||
size_t i;
|
||||
u32 carry = 0;
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
u64 prod = p256_u32_muladd64(x, y[i], z[i], carry);
|
||||
|
||||
z[i] = (u32) prod;
|
||||
carry = (u32)(prod >> 32);
|
||||
}
|
||||
|
||||
{
|
||||
u64 sum = (u64) z[P256_WORDS] + carry;
|
||||
z[P256_WORDS] = (u32) sum;
|
||||
carry = (u32)(sum >> 32);
|
||||
}
|
||||
|
||||
return carry;
|
||||
}
|
||||
|
||||
static inline void p256_u288_rshift32(u32 z[P256_WORDS + 1], u32 c)
|
||||
{
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
z[i] = z[i + 1];
|
||||
}
|
||||
z[P256_WORDS] = c;
|
||||
}
|
||||
|
||||
/*
|
||||
* CIOS Montgomery multiplication for secp256r1.
|
||||
*
|
||||
* The Montgomery constant mu = -p^{-1} mod 2^{32} equals 1 for this prime
|
||||
* because p[0] = 0xFFFFFFFF, i.e. p ≡ -1 (mod 2^{32}). That simplifies
|
||||
* the reduction factor to u = new_a[0] * 1 = new_a[0], which we compute
|
||||
* early as a[0] + x[i]*y[0] (the low word of the partial accumulator after
|
||||
* the multiply step) to break the data dependency.
|
||||
*/
|
||||
static inline void p256_mont_mul(u32 z[P256_WORDS],
|
||||
const u32 x[P256_WORDS],
|
||||
const u32 y[P256_WORDS])
|
||||
{
|
||||
u32 a[P256_WORDS + 1] = {0};
|
||||
u32 reduced[P256_WORDS];
|
||||
size_t i;
|
||||
|
||||
for (i = 0; i < P256_WORDS; i++) {
|
||||
u32 u = a[0] + x[i] * y[0];
|
||||
u32 c = p256_u288_muladd(a, x[i], y);
|
||||
c += p256_u288_muladd(a, u, p256_p_le);
|
||||
p256_u288_rshift32(a, c);
|
||||
}
|
||||
|
||||
{
|
||||
u32 carry_add = a[P256_WORDS];
|
||||
u32 carry_sub = p256_words_sub_borrow(reduced, a, p256_p_le);
|
||||
u32 use_sub = carry_add | (1U - carry_sub);
|
||||
|
||||
os_memcpy(z, a, sizeof(u32) * P256_WORDS);
|
||||
p256_words_cmov(z, reduced, use_sub);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user