#include <wolfssl/wolfcrypt/libwolfssl_sources.h>
#ifdef NO_INLINE
#include <wolfssl/wolfcrypt/misc.h>
#else
#define WOLFSSL_MISC_INCLUDED
#include <wolfcrypt/src/misc.c>
#endif
#ifdef WOLFCRYPT_HAVE_ECCSI
#include <wolfssl/wolfcrypt/eccsi.h>
#include <wolfssl/wolfcrypt/asn_public.h>
#ifdef WOLFSSL_HAVE_SP_ECC
#include <wolfssl/wolfcrypt/sp.h>
#endif
#if defined(WOLFSSL_USE_SAVE_VECTOR_REGISTERS) && !defined(WOLFSSL_SP_ASM)
#undef SAVE_VECTOR_REGISTERS
#define SAVE_VECTOR_REGISTERS(fail_clause) SAVE_NO_VECTOR_REGISTERS(fail_clause)
#undef RESTORE_VECTOR_REGISTERS
#define RESTORE_VECTOR_REGISTERS() RESTORE_NO_VECTOR_REGISTERS()
#endif
#ifndef WOLFSSL_HAVE_ECC_KEY_GET_PRIV
#define wc_ecc_key_get_priv(key) (&((key)->k))
#define WOLFSSL_HAVE_ECC_KEY_GET_PRIV
#endif
int wc_InitEccsiKey_ex(EccsiKey* key, int keySz, int curveId, void* heap,
int devId)
{
int err = 0;
EccsiKeyParams* params = NULL;
if (key == NULL) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
XMEMSET(key, 0, sizeof(*key));
key->heap = heap;
params = &key->params;
err = wc_ecc_init_ex(&key->ecc, heap, devId);
}
if (err == 0) {
err = wc_ecc_init_ex(&key->pubkey, heap, devId);
}
if (err == 0) {
key->pvt = wc_ecc_new_point_h(heap);
if (key->pvt == NULL) {
err = MEMORY_E;
}
}
if (err == 0) {
err = mp_init_multi(¶ms->order,
#ifdef WOLFCRYPT_ECCSI_CLIENT
¶ms->a, ¶ms->b, ¶ms->prime, &key->tmp, &key->ssk
#else
NULL, NULL, NULL, NULL, NULL
#endif
);
}
if (err == 0) {
err = wc_ecc_set_curve(&key->ecc, keySz, curveId);
}
if (err == 0) {
err = wc_ecc_set_curve(&key->pubkey, keySz, curveId);
}
if (err != 0) {
wc_FreeEccsiKey(key);
}
return err;
}
int wc_InitEccsiKey(EccsiKey* key, void* heap, int devId)
{
return wc_InitEccsiKey_ex(key, 32, ECC_SECP256R1, heap, devId);
}
void wc_FreeEccsiKey(EccsiKey* key)
{
if (key != NULL) {
EccsiKeyParams* params = &key->params;
wc_ecc_del_point_h(params->base, key->heap);
#ifdef WOLFCRYPT_ECCSI_CLIENT
mp_free(&key->ssk);
mp_free(&key->tmp);
mp_free(¶ms->prime);
mp_free(¶ms->b);
mp_free(¶ms->a);
#endif
mp_free(¶ms->order);
wc_ecc_del_point_h(key->pvt, key->heap);
wc_ecc_free(&key->pubkey);
wc_ecc_free(&key->ecc);
XMEMSET(key, 0, sizeof(*key));
}
}
static int eccsi_load_order(EccsiKey* key)
{
int err = 0;
if (!key->params.haveOrder) {
err = mp_read_radix(&key->params.order, key->ecc.dp->order,
MP_RADIX_HEX);
if (err == 0) {
key->params.haveOrder = 1;
}
}
return err;
}
#ifdef WOLFCRYPT_ECCSI_CLIENT
static int eccsi_load_ecc_params(EccsiKey* key)
{
int err = 0;
EccsiKeyParams* params = &key->params;
err = eccsi_load_order(key);
if ((err == 0) && (!params->haveA)) {
err = mp_read_radix(¶ms->a, key->ecc.dp->Af, MP_RADIX_HEX);
if (err == 0) {
params->haveA = 1;
}
}
if ((err == 0) && (!params->haveB)) {
err = mp_read_radix(¶ms->b, key->ecc.dp->Bf, MP_RADIX_HEX);
if (err == 0) {
params->haveB = 1;
}
}
if ((err == 0) && (!params->havePrime)) {
err = mp_read_radix(¶ms->prime, key->ecc.dp->prime, MP_RADIX_HEX);
if (err == 0) {
params->havePrime = 1;
}
}
return err;
}
#endif
static int eccsi_load_base(EccsiKey* key)
{
int err = 0;
EccsiKeyParams* params = &key->params;
if (!params->haveBase) {
if (params->base == NULL) {
params->base = wc_ecc_new_point_h(key->heap);
if (params->base == NULL) {
err = MEMORY_E;
}
}
if (err == 0) {
err = mp_read_radix(params->base->x, key->ecc.dp->Gx, MP_RADIX_HEX);
}
if (err == 0) {
err = mp_read_radix(params->base->y, key->ecc.dp->Gy, MP_RADIX_HEX);
}
if (err == 0) {
err = mp_set(params->base->z, 1);
}
if (err == 0) {
params->haveBase = 1;
}
}
return err;
}
static int eccsi_encode_base(EccsiKey* key, byte* data, word32* dataSz)
{
int err;
int idx = wc_ecc_get_curve_idx(key->ecc.dp->id);
err = eccsi_load_base(key);
if (err == 0) {
err = wc_ecc_export_point_der(idx, key->params.base, data, dataSz);
}
return err;
}
#ifndef WOLFSSL_HAVE_SP_ECC
static int eccsi_kpak_to_mont(EccsiKey* key)
{
int err = 0;
ecc_point* kpak = &key->ecc.pubkey;
mp_int* mu = &key->tmp;
mp_int* prime = &key->params.prime;
if (!key->kpakMont) {
err = mp_montgomery_calc_normalization(mu, prime);
if (err == 0) {
err = mp_mulmod(kpak->x, mu, prime, kpak->x);
}
if (err == 0) {
err = mp_mulmod(kpak->y, mu, prime, kpak->y);
}
if (err == 0) {
err = mp_mulmod(kpak->z, mu, prime, kpak->z);
}
if (err == 0) {
key->kpakMont = 1;
}
}
return err;
}
#endif
static int eccsi_kpak_from_mont(EccsiKey* key)
{
int err = 0;
ecc_point* kpak = &key->ecc.pubkey;
mp_digit mp;
mp_int* prime = &key->params.prime;
if (key->kpakMont) {
err = mp_montgomery_setup(prime, &mp);
if (err == 0) {
err = mp_montgomery_reduce(kpak->x, prime, mp);
}
if (err == 0) {
err = mp_montgomery_reduce(kpak->y, prime, mp);
}
if (err == 0) {
err = mp_montgomery_reduce(kpak->z, prime, mp);
}
if (err == 0) {
key->kpakMont = 0;
}
}
return err;
}
static int eccsi_compute_hs(EccsiKey* key, enum wc_HashType hashType,
const byte* id, word32 idSz, ecc_point* pvt, byte* hash, byte* hashSz)
{
int err;
word32 dataSz = 0;
int idx = wc_ecc_get_curve_idx(key->ecc.dp->id);
ecc_point* kpak = &key->ecc.pubkey;
int hash_inited = 0;
err = wc_HashInit_ex(&key->hash, hashType, key->heap, INVALID_DEVID);
if (err == 0) {
hash_inited = 1;
dataSz = sizeof(key->data);
err = eccsi_encode_base(key, key->data, &dataSz);
}
if (err == 0) {
err = wc_HashUpdate(&key->hash, hashType, key->data, dataSz);
}
if (err == 0) {
err = eccsi_kpak_from_mont(key);
}
if (err == 0) {
dataSz = sizeof(key->data);
err = wc_ecc_export_point_der(idx, kpak, key->data, &dataSz);
}
if (err == 0) {
err = wc_HashUpdate(&key->hash, hashType, key->data, dataSz);
}
if (err == 0) {
err = wc_HashUpdate(&key->hash, hashType, id, idSz);
}
if (err == 0) {
dataSz = sizeof(key->data);
err = wc_ecc_export_point_der(idx, pvt, key->data, &dataSz);
}
if (err == 0) {
err = wc_HashUpdate(&key->hash, hashType, key->data, dataSz);
}
if (err == 0) {
err = wc_HashFinal(&key->hash, hashType, hash);
}
if (err == 0) {
*hashSz = (byte)wc_HashGetDigestSize(hashType);
}
if (hash_inited) {
(void)wc_HashFree(&key->hash, hashType);
}
return err;
}
#ifdef WOLFCRYPT_ECCSI_KMS
int wc_MakeEccsiKey(EccsiKey* key, WC_RNG* rng)
{
int err = 0;
if ((key == NULL) || (rng == NULL)) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
err = wc_ecc_make_key_ex(rng, key->ecc.dp->size, &key->ecc,
key->ecc.dp->id);
}
return err;
}
static int eccsi_encode_point(ecc_point* point, word32 size, byte* data,
word32* sz, int raw)
{
int err = 0;
if (data == NULL) {
*sz = size * 2 + !raw;
err = WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
if ((err == 0) && (*sz < size * 2 + !raw)) {
err = BUFFER_E;
}
if (err == 0) {
if (!raw) {
data[0] = 0x04;
data++;
}
err = mp_to_unsigned_bin_len(point->x, data, (int)size);
}
if (err == 0) {
data += size;
err = mp_to_unsigned_bin_len(point->y, data, (int)size);
}
if (err == 0) {
*sz = size * 2 + !raw;
}
return err;
}
static int eccsi_decode_point(ecc_point* point, word32 size, const byte* data,
word32 sz)
{
int err = 0;
if ((sz != size * 2) && (sz != size * 2 + 1)) {
err = BUFFER_E;
}
if ((err == 0) && (sz & 1)) {
if (data[0] != 0x04) {
err = ASN_PARSE_E;
}
data++;
}
if (err == 0) {
err = mp_read_unsigned_bin(point->x, data, size);
}
if (err == 0) {
data += size;
err = mp_read_unsigned_bin(point->y, data, size);
}
if (err == 0) {
err = mp_set(point->z, 1);
}
return err;
}
static int eccsi_encode_key(EccsiKey* key, byte* data)
{
int err;
word32 sz = (word32)key->ecc.dp->size * 2;
err = mp_to_unsigned_bin_len(wc_ecc_key_get_priv(&key->ecc), data,
key->ecc.dp->size);
if (err == 0) {
data += key->ecc.dp->size;
err = eccsi_encode_point(&key->ecc.pubkey, (word32)key->ecc.dp->size,
data, &sz, 1);
}
return err;
}
int wc_ExportEccsiKey(EccsiKey* key, byte* data, word32* sz)
{
int err = 0;
if ((key == NULL) || (sz == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY)) {
err = BAD_STATE_E;
}
if (err == 0) {
if (data == NULL) {
*sz = (word32)(key->ecc.dp->size * 3);
err = WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
else if (*sz < (word32)key->ecc.dp->size * 3) {
err = BUFFER_E;
}
else {
*sz = (word32)(key->ecc.dp->size * 3);
}
}
if (err == 0) {
err = eccsi_kpak_from_mont(key);
}
if (err == 0) {
err = eccsi_encode_key(key, data);
}
return err;
}
static int eccsi_decode_key(EccsiKey* key, const byte* data)
{
int err;
err = mp_read_unsigned_bin(wc_ecc_key_get_priv(&key->ecc), data,
(word32)key->ecc.dp->size);
if (err == 0) {
data += key->ecc.dp->size;
err = eccsi_decode_point(&key->ecc.pubkey, (word32)key->ecc.dp->size,
data, (word32)(key->ecc.dp->size * 2));
}
return err;
}
int wc_ImportEccsiKey(EccsiKey* key, const byte* data, word32 sz)
{
int err = 0;
if ((key == NULL) || (data == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (sz != (word32)key->ecc.dp->size * 3)) {
err = BUFFER_E;
}
if (err == 0) {
key->kpakMont = 0;
err = eccsi_decode_key(key, data);
}
if (err == 0) {
key->ecc.type = ECC_PRIVATEKEY;
}
return err;
}
int wc_ExportEccsiPrivateKey(EccsiKey* key, byte* data, word32* sz)
{
int err = 0;
if ((key == NULL) || (sz == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY)) {
err = BAD_STATE_E;
}
if (err == 0) {
if (data == NULL) {
*sz = (word32)key->ecc.dp->size;
err = WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
else if (*sz < (word32)key->ecc.dp->size) {
err = BUFFER_E;
}
else {
*sz = (word32)key->ecc.dp->size;
}
}
if (err == 0) {
err = mp_to_unsigned_bin_len(wc_ecc_key_get_priv(&key->ecc), data,
key->ecc.dp->size);
}
return err;
}
int wc_ImportEccsiPrivateKey(EccsiKey* key, const byte* data, word32 sz)
{
int err = 0;
if ((key == NULL) || (data == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (sz != (word32)key->ecc.dp->size)) {
err = BUFFER_E;
}
if (err == 0) {
err = mp_read_unsigned_bin(wc_ecc_key_get_priv(&key->ecc), data,
(word32)key->ecc.dp->size);
}
return err;
}
int wc_ExportEccsiPublicKey(EccsiKey* key, byte* data, word32* sz, int raw)
{
int err = 0;
if ((key == NULL) || (sz == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY) &&
(key->ecc.type != ECC_PUBLICKEY)) {
err = BAD_STATE_E;
}
if ((err == 0) && (data != NULL)) {
err = eccsi_kpak_from_mont(key);
}
if (err == 0) {
err = eccsi_encode_point(&key->ecc.pubkey, (word32)key->ecc.dp->size,
data, sz, raw);
}
return err;
}
static int eccsi_make_pair(EccsiKey* key, WC_RNG* rng,
enum wc_HashType hashType, const byte* id, word32 idSz, mp_int* ssk,
ecc_point* pvt)
{
int err = 0;
byte hashSz = 0;
int genTryCnt = 0;
do {
if ((++genTryCnt) > ECCSI_MAX_GEN_COUNT) {
err = RNG_FAILURE_E;
}
if (err == 0) {
wc_ecc_free(&key->pubkey);
err = wc_ecc_make_key_ex(rng, key->ecc.dp->size, &key->pubkey,
key->ecc.dp->id);
}
if (err == 0) {
err = wc_ecc_copy_point(&key->pubkey.pubkey, pvt);
}
if (err == 0) {
hashSz = (byte)sizeof(key->data);
err = eccsi_compute_hs(key, hashType, id, idSz, pvt, key->data,
&hashSz);
}
if (err == 0) {
err = mp_read_unsigned_bin(ssk, key->data, hashSz);
}
if (err == 0) {
err = mp_mulmod(ssk, wc_ecc_key_get_priv(&key->pubkey),
&key->params.order, ssk);
}
if (err == 0) {
err = mp_addmod(ssk, wc_ecc_key_get_priv(&key->ecc),
&key->params.order, ssk);
}
}
while ((err == 0) && (mp_iszero(ssk) ||
(mp_cmp(ssk, wc_ecc_key_get_priv(&key->ecc)) == MP_EQ)));
mp_forcezero(wc_ecc_key_get_priv(&key->pubkey));
return err;
}
int wc_MakeEccsiPair(EccsiKey* key, WC_RNG* rng, enum wc_HashType hashType,
const byte* id, word32 idSz, mp_int* ssk, ecc_point* pvt)
{
int err = 0;
if ((key == NULL) || (rng == NULL) || (id == NULL) || (ssk == NULL) ||
(pvt == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY)) {
err = BAD_STATE_E;
}
if (err == 0) {
err = eccsi_load_order(key);
}
if (err == 0) {
err = eccsi_make_pair(key, rng, hashType, id, idSz, ssk, pvt);
}
return err;
}
int wc_EncodeEccsiPair(const EccsiKey* key, mp_int* ssk, ecc_point* pvt,
byte* data, word32* sz)
{
int err = 0;
if ((key == NULL) || (ssk == NULL) || (pvt == NULL) || (sz == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (data == NULL)) {
*sz = (word32)(key->ecc.dp->size * 3);
err = WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
if ((err == 0) && (*sz < (word32)(key->ecc.dp->size * 3))) {
err = BUFFER_E;
}
if (err == 0) {
err = mp_to_unsigned_bin_len(ssk, data, key->ecc.dp->size);
}
if (err == 0) {
data += key->ecc.dp->size;
err = mp_to_unsigned_bin_len(pvt->x, data, key->ecc.dp->size);
}
if (err == 0) {
data += key->ecc.dp->size;
err = mp_to_unsigned_bin_len(pvt->y, data, key->ecc.dp->size);
}
if (err == 0) {
*sz = (word32)(key->ecc.dp->size * 3);
}
return err;
}
int wc_EncodeEccsiSsk(const EccsiKey* key, mp_int* ssk, byte* data, word32* sz)
{
int err = 0;
if ((key == NULL) || (ssk == NULL) || (sz == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY)) {
err = BAD_STATE_E;
}
if (err == 0) {
if (data == NULL) {
*sz = (word32)key->ecc.dp->size;
err = WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
else if (*sz < (word32)key->ecc.dp->size) {
err = BUFFER_E;
}
else {
*sz = (word32)key->ecc.dp->size;
}
}
if (err == 0) {
err = mp_to_unsigned_bin_len(ssk, data, key->ecc.dp->size);
}
return err;
}
int wc_DecodeEccsiSsk(const EccsiKey* key, const byte* data, word32 sz,
mp_int* ssk)
{
int err = 0;
if ((key == NULL) || (data == NULL) || (ssk == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (sz != (word32)key->ecc.dp->size)) {
err = BUFFER_E;
}
if (err == 0) {
err = mp_read_unsigned_bin(ssk, data, (word32)key->ecc.dp->size);
}
return err;
}
int wc_EncodeEccsiPvt(const EccsiKey* key, ecc_point* pvt, byte* data,
word32* sz, int raw)
{
int err = 0;
if ((key == NULL) || (pvt == NULL) || (sz == NULL)) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
err = eccsi_encode_point(pvt, (word32)key->ecc.dp->size, data, sz, raw);
}
return err;
}
#endif
#ifdef WOLFCRYPT_ECCSI_CLIENT
int wc_DecodeEccsiPair(const EccsiKey* key, const byte* data, word32 sz,
mp_int* ssk, ecc_point* pvt)
{
int err = 0;
if ((key == NULL) || (data == NULL) || (ssk == NULL) || (pvt == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (sz != (word32)(key->ecc.dp->size * 3))) {
err = BUFFER_E;
}
if (err == 0) {
err = mp_read_unsigned_bin(ssk, data, (word32)key->ecc.dp->size);
}
if (err == 0) {
data += key->ecc.dp->size;
err = mp_read_unsigned_bin(pvt->x, data, (word32)key->ecc.dp->size);
}
if (err == 0) {
data += key->ecc.dp->size;
err = mp_read_unsigned_bin(pvt->y, data, (word32)key->ecc.dp->size);
}
if (err == 0) {
err = mp_set(pvt->z, 1);
}
return err;
}
int wc_DecodeEccsiPvt(const EccsiKey* key, const byte* data, word32 sz,
ecc_point* pvt)
{
int err = 0;
if ((key == NULL) || (data == NULL) || (pvt == NULL)) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
err = eccsi_decode_point(pvt, (word32)key->ecc.dp->size, data, sz);
}
return err;
}
int wc_DecodeEccsiPvtFromSig(const EccsiKey* key, const byte* sig, word32 sz,
ecc_point* pvt)
{
int err = 0;
if ((key == NULL) || (sig == NULL) || (pvt == NULL)) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
word32 rSz = (word32)(key->ecc.dp->size * 2);
err = eccsi_decode_point(pvt, (word32)key->ecc.dp->size, sig + rSz,
sz - rSz);
}
return err;
}
int wc_ImportEccsiPublicKey(EccsiKey* key, const byte* data, word32 sz,
int trusted)
{
int err = 0;
if ((key == NULL) || (data == NULL)) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
key->kpakMont = 0;
err = eccsi_decode_point(&key->ecc.pubkey, (word32)key->ecc.dp->size,
data, sz);
}
if (err == 0) {
key->ecc.type = ECC_PUBLICKEY;
}
if ((err == 0) && (!trusted)) {
err = wc_ecc_check_key(&key->ecc);
}
return err;
}
static int eccsi_mulmod_base_add(EccsiKey* key, const mp_int* n,
ecc_point* a, ecc_point* res, mp_digit mp, int map)
{
int err = 0;
#if defined(WOLFSSL_HAVE_SP_ECC) && !defined(WOLFSSL_SP_NO_256)
if ((key->ecc.idx != ECC_CUSTOM_IDX) &&
(ecc_sets[key->ecc.idx].id == ECC_SECP256R1)) {
err = sp_ecc_mulmod_base_add_256(n, a, 1, res, map, key->heap);
}
else
#endif
#ifndef WOLFSSL_SP_MATH
{
EccsiKeyParams* params = &key->params;
err = wc_ecc_mulmod(n, params->base, params->base, ¶ms->a,
¶ms->prime, 0);
key->params.haveBase = 0;
if (err == 0) {
err = ecc_projective_add_point(params->base, a, res, ¶ms->a,
¶ms->prime, mp);
}
if ((err == 0) && map) {
err = ecc_map(res, ¶ms->prime, mp);
}
}
#else
{
err = NOT_COMPILED_IN;
}
(void)key;
(void)n;
(void)a;
(void)res;
(void)mp;
(void)map;
#endif
return err;
}
static int eccsi_mulmod_point(EccsiKey* key, const mp_int* n, ecc_point* point,
ecc_point* res, int map)
{
int err;
#if defined(WOLFSSL_HAVE_SP_ECC) && !defined(WOLFSSL_SP_NO_256)
if ((key->ecc.idx != ECC_CUSTOM_IDX) &&
(ecc_sets[key->ecc.idx].id == ECC_SECP256R1)) {
err = sp_ecc_mulmod_256(n, point, res, map, key->heap);
}
else
#endif
{
EccsiKeyParams* params = &key->params;
err = wc_ecc_mulmod(n, point, res, ¶ms->a, ¶ms->prime, map);
}
return err;
}
static int eccsi_mulmod_point_add(EccsiKey* key, const mp_int* n,
ecc_point* point, ecc_point* a, ecc_point* res, mp_digit mp, int map)
{
#if defined(WOLFSSL_HAVE_SP_ECC) && !defined(WOLFSSL_SP_NO_256)
int err = WC_NO_ERR_TRACE(NOT_COMPILED_IN);
if ((key->ecc.idx != ECC_CUSTOM_IDX) &&
(ecc_sets[key->ecc.idx].id == ECC_SECP256R1)) {
err = sp_ecc_mulmod_add_256(n, point, a, 0, res, map, key->heap);
}
(void)mp;
return err;
#else
int err;
EccsiKeyParams* params = &key->params;
err = wc_ecc_mulmod(n, point, res, ¶ms->a, ¶ms->prime, 0);
if (err == 0) {
err = ecc_projective_add_point(res, a, res, &key->params.a,
¶ms->prime, mp);
}
if ((err == 0) && map) {
err = ecc_map(res, ¶ms->prime, mp);
}
return err;
#endif
}
int wc_ValidateEccsiPair(EccsiKey* key, enum wc_HashType hashType,
const byte* id, word32 idSz, const mp_int* ssk, ecc_point* pvt,
int* valid)
{
int err = 0;
ecc_point* res = NULL;
mp_int* hs = NULL;
mp_digit mp = 0;
byte hashSz = 0;
EccsiKeyParams* params = NULL;
if ((key == NULL) || (id == NULL) || (ssk == NULL) || (pvt == NULL) ||
(valid == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY) &&
(key->ecc.type != ECC_PUBLICKEY)) {
err = BAD_STATE_E;
}
if (err != 0)
return err;
SAVE_VECTOR_REGISTERS(return _svr_ret;);
params = &key->params;
hs = &key->tmp;
res = &key->pubkey.pubkey;
err = eccsi_load_base(key);
if (err == 0) {
err = eccsi_load_ecc_params(key);
}
if (err == 0) {
err = mp_montgomery_setup(¶ms->prime, &mp);
}
if (err == 0) {
err = wc_ecc_is_point(pvt, ¶ms->a, ¶ms->b, ¶ms->prime);
if (err == -1) {
err = IS_POINT_E;
}
}
if (err == 0) {
hashSz = (byte)sizeof(key->data);
err = eccsi_compute_hs(key, hashType, id, idSz, pvt, key->data,
&hashSz);
}
if (err == 0) {
err = mp_read_unsigned_bin(hs, key->data, hashSz);
}
if (err == 0) {
err = eccsi_mulmod_point(key, hs, pvt, res, 0);
}
if (err == 0) {
err = mp_sub(¶ms->prime, res->y, res->y);
}
if (err == 0) {
err = eccsi_mulmod_base_add(key, ssk, res, res, mp, 1);
}
if (valid != NULL) {
*valid = (err == 0);
if (err == 0) {
ecc_point* kpak = &key->ecc.pubkey;
*valid = (wc_ecc_cmp_point(res, kpak) == MP_EQ);
}
}
RESTORE_VECTOR_REGISTERS();
return err;
}
int wc_ValidateEccsiPvt(EccsiKey* key, const ecc_point* pvt, int* valid)
{
int err = 0;
if ((key == NULL)| (pvt == NULL) || (valid == NULL)) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
err = wc_ecc_set_curve(&key->pubkey, key->ecc.dp->size,
key->ecc.dp->id);
}
if (err == 0) {
err = wc_ecc_copy_point(pvt, &key->pubkey.pubkey);
}
if (err == 0) {
*valid = (wc_ecc_check_key(&key->pubkey) == 0);
}
return err;
}
int wc_HashEccsiId(EccsiKey* key, enum wc_HashType hashType, const byte* id,
word32 idSz, ecc_point* pvt, byte* hash, byte* hashSz)
{
int err = 0;
int dgstSz = -1;
int curveSz = -1;
if ((key == NULL) || (id == NULL) || (pvt == NULL) || (hash == NULL) ||
(hashSz == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY) &&
(key->ecc.type != ECC_PUBLICKEY)) {
err = BAD_STATE_E;
}
if (err == 0) {
dgstSz = wc_HashGetDigestSize(hashType);
if (dgstSz < 0) {
err = dgstSz;
}
}
if (err == 0) {
curveSz = wc_ecc_get_curve_size_from_id(key->ecc.dp->id);
if (curveSz < 0) {
err = curveSz;
}
}
if ((err == 0) && (dgstSz != curveSz)) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
err = eccsi_load_ecc_params(key);
}
if (err == 0) {
err = eccsi_compute_hs(key, hashType, id, idSz, pvt, hash, hashSz);
}
if (err == 0) {
XMEMCPY(key->idHash, hash, *hashSz);
key->idHashSz = *hashSz;
}
return err;
}
int wc_SetEccsiHash(EccsiKey* key, const byte* hash, byte hashSz)
{
int err = 0;
if ((key == NULL) || (hash == NULL) || (hashSz > WC_MAX_DIGEST_SIZE)) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
XMEMCPY(key->idHash, hash, hashSz);
key->idHashSz = hashSz;
}
return err;
}
int wc_SetEccsiPair(EccsiKey* key, const mp_int* ssk, const ecc_point* pvt)
{
int err = 0;
if ((key == NULL) || (ssk == NULL) || (pvt == NULL)) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
err = mp_copy(ssk, &key->ssk);
}
if (err == 0) {
err = wc_ecc_copy_point(pvt, key->pvt);
}
return err;
}
#ifdef ECCSI_ORDER_MORE_BITS_THAN_PRIME
static int eccsi_fit_to_octets(const mp_int* a, mp_int* order, int m,
mp_int* r)
{
int err;
if (mp_count_bits(a) > m * 8) {
err = mp_sub(order, (mp_int*)a, r);
}
else
{
err = mp_copy(a, r);
}
return err;
}
#else
static int eccsi_fit_to_octets(const mp_int* a, const mp_int* order, int m,
mp_int* r)
{
(void)order;
(void)m;
return mp_copy(a, r);
}
#endif
static int eccsi_compute_he(EccsiKey* key, enum wc_HashType hashType,
mp_int* r, const byte* msg, word32 msgSz, byte* he, word32* heSz)
{
int err = 0;
word32 dataSz = (word32)key->ecc.dp->size;
int hash_inited = 0;
err = wc_HashInit_ex(&key->hash, hashType, key->heap, INVALID_DEVID);
if (err == 0) {
hash_inited = 1;
err = wc_HashUpdate(&key->hash, hashType, key->idHash, key->idHashSz);
}
if (err == 0) {
err = mp_to_unsigned_bin_len(r, key->data, (int)dataSz);
}
if (err == 0) {
err = wc_HashUpdate(&key->hash, hashType, key->data, dataSz);
}
if (err == 0) {
err = wc_HashUpdate(&key->hash, hashType, msg, msgSz);
}
if (err == 0) {
err = wc_HashFinal(&key->hash, hashType, he);
}
if (err == 0) {
*heSz = (word32)wc_HashGetDigestSize(hashType);
}
if (hash_inited) {
(void)wc_HashFree(&key->hash, hashType);
}
return err;
}
static int eccsi_encode_sig(const EccsiKey* key, mp_int* r, mp_int* s,
byte* sig, word32* sigSz)
{
int err;
word32 sz = (word32)key->ecc.dp->size;
err = mp_to_unsigned_bin_len(r, sig, (int)sz);
if (err == 0) {
err = mp_to_unsigned_bin_len(s, sig + sz, (int)sz);
}
if (err == 0) {
*sigSz = (word32)(key->ecc.dp->size * 2 + 1);
err = wc_ecc_export_point_der(wc_ecc_get_curve_idx(key->ecc.dp->id),
key->pvt, sig + sz * 2, sigSz);
}
if (err == 0) {
*sigSz = sz * 4 + 1;
}
return err;
}
static int eccsi_gen_sig(EccsiKey* key, WC_RNG* rng, enum wc_HashType hashType,
const byte* msg, word32 msgSz, mp_int* r, mp_int* s)
{
int err = 0;
int sz = key->ecc.dp->size;
word32 heSz = 0;
const mp_int* jx = NULL;
mp_int* he = &key->tmp;
int genTryCnt = 0;
do {
if ((++genTryCnt) > ECCSI_MAX_GEN_COUNT) {
err = RNG_FAILURE_E;
}
if (err == 0) {
wc_ecc_free(&key->pubkey);
err = wc_ecc_make_key_ex(rng, sz, &key->pubkey, key->ecc.dp->id);
}
if (err == 0) {
jx = key->pubkey.pubkey.x;
err = eccsi_fit_to_octets(jx, &key->params.order, sz, r);
}
if (err == 0) {
err = eccsi_compute_he(key, hashType, r, msg, msgSz, key->data,
&heSz);
}
if (err == 0) {
err = mp_read_unsigned_bin(he, key->data, heSz);
}
if (err == 0) {
err = mp_mulmod(r, &key->ssk, &key->params.order, s);
}
if (err == 0) {
err = mp_addmod(he, s, &key->params.order, s);
}
}
while ((err == 0) && (mp_iszero(s) || (mp_cmp(s, he) == MP_EQ)));
return err;
}
int wc_SignEccsiHash(EccsiKey* key, WC_RNG* rng, enum wc_HashType hashType,
const byte* msg, word32 msgSz, byte* sig, word32* sigSz)
{
int err = 0;
mp_int* r = NULL;
mp_int* s = NULL;
mp_int* j = NULL;
word32 sz = 0;
if ((key == NULL) || (rng == NULL) || (msg == NULL) || (sigSz == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (key->ecc.type != ECC_PUBLICKEY) &&
(key->ecc.type != ECC_PRIVATEKEY)) {
err = BAD_STATE_E;
}
if ((err == 0) && (sig != NULL) && (key->idHashSz == 0)) {
err = BAD_STATE_E;
}
if (err == 0) {
sz = (word32)key->ecc.dp->size;
if (sig == NULL) {
*sigSz = sz * 4 + 1;
err = WC_NO_ERR_TRACE(LENGTH_ONLY_E);
}
}
if ((err == 0) && (*sigSz < sz * 4 + 1)) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
r = key->pubkey.pubkey.y;
s = key->pubkey.pubkey.z;
err = eccsi_load_order(key);
}
if (err == 0) {
err = eccsi_gen_sig(key, rng, hashType, msg, msgSz, r, s);
}
if (err == 0) {
err = mp_invmod(s, &key->params.order, s);
}
if (err == 0) {
j = wc_ecc_key_get_priv(&key->pubkey);
err = mp_mulmod(s, j, &key->params.order, s);
}
if (err == 0) {
mp_forcezero(j);
err = eccsi_fit_to_octets(s, &key->params.order, (int)sz, s);
}
if (err == 0) {
err = eccsi_encode_sig(key, r, s, sig, sigSz);
}
return err;
}
static int eccsi_decode_sig_s(const EccsiKey* key, const byte* sig,
word32 sigSz, mp_int* s)
{
int err = 0;
word32 sz = (word32)key->ecc.dp->size;
if (sigSz != sz * 4 + 1) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
err = mp_read_unsigned_bin(s, sig + sz, sz);
}
return err;
}
static int eccsi_decode_sig_r_pvt(const EccsiKey* key, const byte* sig,
word32 sigSz, mp_int* r, ecc_point* pvt)
{
int err = 0;
word32 sz = (word32)key->ecc.dp->size;
if (sigSz != sz * 4 + 1) {
err = BAD_FUNC_ARG;
}
if (err == 0) {
err = mp_read_unsigned_bin(r, sig, sz);
}
if (err == 0) {
mp_clear(pvt->x);
mp_clear(pvt->y);
mp_clear(pvt->z);
err = wc_ecc_import_point_der(sig + sz * 2, sz * 2 + 1,
wc_ecc_get_curve_idx(key->ecc.dp->id), pvt);
}
return err;
}
static int eccsi_calc_y(EccsiKey* key, ecc_point* pvt, mp_digit mp,
ecc_point* y)
{
int err;
mp_int* hs = &key->ssk;
err = mp_read_unsigned_bin(hs, key->idHash, key->idHashSz);
#ifndef WOLFSSL_HAVE_SP_ECC
if (err == 0) {
err = eccsi_kpak_to_mont(key);
}
#endif
if (err == 0) {
ecc_point* kpak = &key->ecc.pubkey;
err = eccsi_mulmod_point_add(key, hs, pvt, kpak, y, mp, 1);
}
return err;
}
static int eccsi_calc_j(EccsiKey* key, const mp_int* hem, const byte* sig,
word32 sigSz, ecc_point* y, mp_digit mp, ecc_point* j)
{
int err;
mp_int* s = &key->tmp;
err = eccsi_mulmod_base_add(key, hem, y, j, mp, 1);
if (err == 0) {
err = eccsi_decode_sig_s(key, sig, sigSz, s);
}
if (err == 0) {
if (mp_iszero(s)) {
err = MP_ZERO_E;
}
else if (mp_cmp(s, &key->params.order) != MP_LT) {
err = ECC_OUT_OF_RANGE_E;
}
}
if (err == 0) {
err = eccsi_mulmod_point(key, s, j, j, 1);
}
return err;
}
int wc_VerifyEccsiHash(EccsiKey* key, enum wc_HashType hashType,
const byte* msg, word32 msgSz, const byte* sig, word32 sigSz,
int* verified)
{
int err = 0;
byte* he = NULL;
word32 heSz = 0;
mp_int* r = NULL;
mp_int* jx = NULL;
mp_int* hem = NULL;
ecc_point* pvt = NULL;
ecc_point* y = NULL;
ecc_point* j = NULL;
mp_digit mp = 0;
EccsiKeyParams* params = NULL;
if ((key == NULL) || (msg == NULL) || (sig == NULL) || (verified == NULL)) {
err = BAD_FUNC_ARG;
}
if ((err == 0) && (key->ecc.type != ECC_PRIVATEKEY) &&
(key->ecc.type != ECC_PUBLICKEY)) {
err = BAD_STATE_E;
}
if ((err == 0) && (key->idHashSz == 0)) {
err = BAD_STATE_E;
}
if (err != 0)
return err;
SAVE_VECTOR_REGISTERS(return _svr_ret;);
r = wc_ecc_key_get_priv(&key->pubkey);
pvt = &key->pubkey.pubkey;
err = eccsi_decode_sig_r_pvt(key, sig, sigSz, r, pvt);
if (err == 0) {
err = eccsi_load_base(key);
}
if (err == 0) {
err = eccsi_load_ecc_params(key);
}
if (err == 0) {
params = &key->params;
err = mp_montgomery_setup(¶ms->prime, &mp);
}
if (err == 0) {
if (mp_iszero(r)) {
err = MP_ZERO_E;
}
else if (mp_cmp(r, ¶ms->order) != MP_LT) {
err = ECC_OUT_OF_RANGE_E;
}
}
if (err == 0) {
err = wc_ecc_is_point(pvt, ¶ms->a, ¶ms->b, ¶ms->prime);
}
if (err == 0) {
he = key->data;
err = eccsi_compute_he(key, hashType, r, msg, msgSz, he, &heSz);
}
if (err == 0) {
y = pvt;
err = eccsi_calc_y(key, pvt, mp, y);
}
if (err == 0) {
hem = &key->tmp;
err = mp_read_unsigned_bin(hem, he, heSz);
}
if (err == 0) {
err = eccsi_mulmod_point(key, r, y, y, 0);
}
if (err == 0) {
j = params->base;
err = eccsi_calc_j(key, hem, sig, sigSz, y, mp, j);
key->params.haveBase = 0;
}
if (err == 0) {
if (wc_ecc_point_is_at_infinity(j)) {
err = ECC_INF_E;
}
}
if (err == 0) {
jx = &key->tmp;
err = eccsi_fit_to_octets(j->x, ¶ms->order, key->ecc.dp->size, jx);
}
if (verified != NULL) {
*verified = ((err == 0) && (mp_cmp(jx, r) == MP_EQ));
}
RESTORE_VECTOR_REGISTERS();
return err;
}
#endif
#endif