#include <libecc/lib_ecc_config.h>
#if defined(WITH_SIG_EDDSA25519) || defined(WITH_SIG_EDDSA448)
#if defined(USE_SMALL_STACK)
#error "Error: EDDSA25519 and EDDSA448 are incompatible with USE_SMALL_STACK (devices low on memory)"
#endif
#if defined(WITH_SIG_EDDSA25519)
#if !defined(WITH_HASH_SHA512) || !defined(WITH_CURVE_WEI25519)
#error "Error: EDDSA25519 needs SHA-512 and WEI25519 to be defined! Please define them in libecc config file"
#endif
#endif
#if defined(WITH_SIG_EDDSA448)
#if !defined(WITH_HASH_SHAKE256) || !defined(WITH_CURVE_WEI448)
#error "Error: EDDSA25519 needs SHAKE256 and WEI448 to be defined! Please define them in libecc config file"
#endif
#endif
#include <libecc/nn/nn_rand.h>
#include <libecc/nn/nn_mul_public.h>
#include <libecc/nn/nn_logical.h>
#include <libecc/fp/fp.h>
#include <libecc/fp/fp_sqrt.h>
#include "../nn/nn_div.h"
#include <libecc/sig/sig_algs_internal.h>
#include <libecc/sig/sig_algs.h>
#include <libecc/sig/ec_key.h>
#include <libecc/utils/utils.h>
#ifdef VERBOSE_INNER_VALUES
#define EC_SIG_ALG "EDDSA"
#endif
#include <libecc/utils/dbg_sig.h>
ATTRIBUTE_WARN_UNUSED_RET static inline int dom(u16 x, const u8 *y, u16 olen_y, const hash_mapping *h,
hash_context *h_ctx, u8 dom_type){
u8 tmp[2];
int ret;
MUST_HAVE((h != NULL) && (h_ctx != NULL), ret, err);
MUST_HAVE((x <= 255) && (olen_y <= 255), ret, err);
if(dom_type == 2){
ret = h->hfunc_update(h_ctx, (const u8*)"SigEd25519 no Ed25519 collisions", 32); EG(ret, err);
}
else if(dom_type == 4){
ret = h->hfunc_update(h_ctx, (const u8*)"SigEd448", 8); EG(ret, err);
}
else{
ret = -1;
goto err;
}
tmp[0] = (u8)x;
tmp[1] = (u8)olen_y;
ret = h->hfunc_update(h_ctx, tmp, 2); EG(ret, err);
if(y != NULL){
ret = h->hfunc_update(h_ctx, y, olen_y); EG(ret, err);
}
err:
return ret;
}
#if defined(WITH_SIG_EDDSA25519)
ATTRIBUTE_WARN_UNUSED_RET static inline int dom2(u16 x, const u8 *y, u16 olen_y, const hash_mapping *h,
hash_context *h_ctx){
return dom(x, y, olen_y, h, h_ctx, 2);
}
#endif
#if defined(WITH_SIG_EDDSA448)
ATTRIBUTE_WARN_UNUSED_RET static inline int dom4(u16 x, const u8 *y, u16 olen_y, const hash_mapping *h,
hash_context *h_ctx){
return dom(x, y, olen_y, h, h_ctx, 4);
}
#endif
ATTRIBUTE_WARN_UNUSED_RET static inline hash_alg_type get_eddsa_hash_type(ec_alg_type sig_type){
hash_alg_type hash_type = UNKNOWN_HASH_ALG;
switch (sig_type) {
#if defined(WITH_SIG_EDDSA25519)
case EDDSA25519:
case EDDSA25519PH:
case EDDSA25519CTX:{
hash_type = SHA512;
break;
}
#endif
#if defined(WITH_SIG_EDDSA448)
case EDDSA448:
case EDDSA448PH:{
hash_type = SHAKE256;
break;
}
#endif
default:{
hash_type = UNKNOWN_HASH_ALG;
break;
}
}
return hash_type;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_key_type_check_curve(ec_alg_type key_type,
ec_curve_type curve_type)
{
int ret;
switch (key_type) {
#if defined(WITH_SIG_EDDSA25519)
case EDDSA25519:
case EDDSA25519PH:
case EDDSA25519CTX:{
ret = (curve_type == WEI25519) ? 0 : -1;
break;
}
#endif
#if defined(WITH_SIG_EDDSA448)
case EDDSA448:
case EDDSA448PH:{
ret = (curve_type == WEI448) ? 0 : -1;
break;
}
#endif
default:{
ret = -1;
break;
}
}
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_priv_key_sanity_check(const ec_priv_key *in_priv)
{
int ret;
ret = priv_key_check_initialized(in_priv); EG(ret, err);
ret = eddsa_key_type_check_curve(in_priv->key_type,
in_priv->params->curve_type);
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_pub_key_sanity_check(const ec_pub_key *in_pub)
{
int ret;
ret = pub_key_check_initialized(in_pub); EG(ret, err);
ret = eddsa_key_type_check_curve(in_pub->key_type,
in_pub->params->curve_type);
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_key_pair_sanity_check(const ec_key_pair *key_pair)
{
int ret;
MUST_HAVE((key_pair != NULL), ret, err);
ret = eddsa_priv_key_sanity_check(&(key_pair->priv_key)); EG(ret, err);
ret = eddsa_pub_key_sanity_check(&(key_pair->pub_key)); EG(ret, err);
MUST_HAVE((key_pair->priv_key.key_type == key_pair->pub_key.key_type), ret, err);
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_decode_integer(nn_t nn_out, const u8 *buf, u16 buf_size)
{
u16 i;
u8 buf_little_endian[MAX_DIGEST_SIZE];
int ret;
MUST_HAVE((buf != NULL), ret, err);
MUST_HAVE((sizeof(buf_little_endian) >= buf_size), ret, err);
ret = nn_init(nn_out, 0); EG(ret, err);
ret = local_memset(buf_little_endian, 0, sizeof(buf_little_endian)); EG(ret, err);
if(buf_size > 1){
for(i = 0; i < buf_size; i++){
buf_little_endian[i] = buf[buf_size - 1 - i];
}
}
ret = nn_init_from_buf(nn_out, buf_little_endian, buf_size);
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_encode_integer(nn_src_t nn_in, u8 *buf, u16 buf_size)
{
u16 i;
u8 tmp;
int ret;
bitcnt_t blen;
MUST_HAVE((buf != NULL), ret, err);
ret = nn_check_initialized(nn_in); EG(ret, err);
ret = nn_bitlen(nn_in, &blen); EG(ret, err);
MUST_HAVE((((u32)blen) <= (8 * (u32)buf_size)), ret, err);
ret = nn_export_to_buf(buf, buf_size, nn_in); EG(ret, err);
if(buf_size > 1){
for(i = 0; i < (buf_size / 2); i++){
tmp = buf[i];
buf[i] = buf[buf_size - 1 - i];
buf[buf_size - 1 - i] = tmp;
}
}
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_compute_s(nn_t s, const u8 *digest, u16 digest_size)
{
int ret;
MUST_HAVE((digest != NULL), ret, err);
MUST_HAVE(((digest_size % 2) == 0), ret, err);
ret = eddsa_decode_integer(s, digest, (digest_size / 2)); EG(ret, err);
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_get_digest_from_priv_key(u8 *digest, u8 *digest_size, const ec_priv_key *in_priv)
{
int ret;
hash_alg_type hash_type;
const hash_mapping *hash;
MUST_HAVE(((digest != NULL) && (digest_size != NULL)), ret, err);
ret = eddsa_priv_key_sanity_check(in_priv); EG(ret, err);
MUST_HAVE(((hash_type = get_eddsa_hash_type(in_priv->key_type)) != UNKNOWN_HASH_ALG), ret, err);
ret = get_hash_by_type(hash_type, &hash); EG(ret, err);
MUST_HAVE((hash != NULL), ret, err);
MUST_HAVE(((*digest_size) >= hash->digest_size), ret, err);
(*digest_size) = hash->digest_size;
ret = nn_export_to_buf(digest, *digest_size, &(in_priv->x));
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_encode_point(aff_pt_edwards_src_t in,
fp_src_t alpha_edwards,
u8 *buf, u16 buflen,
ec_alg_type sig_alg)
{
nn out_reduced;
u8 lsb = 0;
int ret;
out_reduced.magic = WORD(0);
MUST_HAVE((buf != NULL), ret, err);
ret = aff_pt_edwards_check_initialized(in); EG(ret, err);
ret = fp_check_initialized(alpha_edwards); EG(ret, err);
ret = local_memset(buf, 0, buflen); EG(ret, err);
ret = nn_init(&out_reduced, 0); EG(ret, err);
#if defined(WITH_SIG_EDDSA448)
if((sig_alg == EDDSA448) || (sig_alg == EDDSA448PH)){
fp tmp_x, tmp_y, y1;
tmp_x.magic = tmp_y.magic = y1.magic = WORD(0);
ret = fp_init(&y1, in->y.ctx); EG(ret, err1);
ret = fp_copy(&tmp_x, &(in->x)); EG(ret, err1);
ret = fp_sqr(&tmp_x, &tmp_x); EG(ret, err1);
ret = fp_copy(&tmp_y, &(in->y)); EG(ret, err1);
ret = fp_sqr(&tmp_y, &tmp_y); EG(ret, err1);
ret = fp_sub(&tmp_y, &tmp_y, &tmp_x); EG(ret, err1);
ret = fp_inv(&tmp_y, &tmp_y); EG(ret, err1);
ret = fp_set_word_value(&tmp_x, WORD(4)); EG(ret, err1);
ret = fp_mul(&tmp_x, &tmp_x, &(in->x)); EG(ret, err1);
ret = fp_mul(&tmp_x, &tmp_x, &(in->y)); EG(ret, err1);
ret = fp_mul(&tmp_x, &tmp_x, &tmp_y); EG(ret, err1);
ret = fp_inv(&tmp_y, alpha_edwards); EG(ret, err1);
ret = fp_mul(&tmp_x, &tmp_x, &tmp_y); EG(ret, err1);
ret = nn_getbit(&(tmp_x.fp_val), 0, &lsb); EG(ret, err1);
ret = fp_copy(&tmp_x, &(in->x)); EG(ret, err1);
ret = fp_sqr(&tmp_x, &tmp_x); EG(ret, err1);
ret = fp_copy(&tmp_y, &(in->y)); EG(ret, err1);
ret = fp_sqr(&tmp_y, &tmp_y); EG(ret, err1);
ret = fp_set_word_value(&y1, WORD(2)); EG(ret, err1);
ret = fp_sub(&y1, &y1, &tmp_x); EG(ret, err1);
ret = fp_sub(&y1, &y1, &tmp_y); EG(ret, err1);
ret = fp_add(&tmp_x, &tmp_x, &tmp_y); EG(ret, err1);
ret = fp_inv(&tmp_x, &tmp_x); EG(ret, err1);
ret = fp_mul(&y1, &y1, &tmp_x); EG(ret, err1);
ret = eddsa_encode_integer(&(y1.fp_val), buf, buflen);
err1:
fp_uninit(&tmp_x);
fp_uninit(&tmp_y);
fp_uninit(&y1);
EG(ret, err);
}
else
#endif
{
FORCE_USED_VAR(sig_alg);
ret = nn_getbit(&(in->x.fp_val), 0, &lsb); EG(ret, err);
ret = eddsa_encode_integer(&(in->y.fp_val), buf, buflen); EG(ret, err);
}
MUST_HAVE((buflen > 1), ret, err);
buf[buflen - 1] |= (u8)(lsb << 7);
err:
nn_uninit(&out_reduced);
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_decode_point(aff_pt_edwards_t out, ec_edwards_crv_src_t edwards_curve,
fp_src_t alpha_edwards, const u8 *buf, u16 buflen,
ec_alg_type sig_type)
{
fp x, y;
fp sqrt1, sqrt2;
u8 x_0, lsb;
u8 buf_little_endian[MAX_DIGEST_SIZE];
u16 i;
int ret, iszero;
#if defined(WITH_SIG_EDDSA448)
fp tmp;
tmp.magic = WORD(0);
#endif
x.magic = y.magic = sqrt1.magic = sqrt2.magic = WORD(0);
MUST_HAVE((buf != NULL), ret, err);
ret = ec_edwards_crv_check_initialized(edwards_curve); EG(ret, err);
ret = fp_check_initialized(alpha_edwards); EG(ret, err);
x_0 = ((buf[buflen - 1] & 0x80) >> 7);
MUST_HAVE((sizeof(buf_little_endian) >= buflen), ret, err);
MUST_HAVE((buflen > 1), ret, err);
for(i = 0; i < buflen; i++){
buf_little_endian[i] = buf[buflen - 1 - i];
if(i == 0){
buf_little_endian[i] &= 0x7f;
}
}
ret = fp_init_from_buf(&y, edwards_curve->a.ctx, buf_little_endian, buflen); EG(ret, err);
ret = fp_init(&sqrt1, edwards_curve->a.ctx); EG(ret, err);
ret = fp_init(&sqrt2, edwards_curve->a.ctx); EG(ret, err);
ret = fp_init(&x, edwards_curve->a.ctx); EG(ret, err);
#if defined(WITH_SIG_EDDSA448)
if((sig_type == EDDSA448) || (sig_type == EDDSA448PH)){
const u8 d_edwards448_buff[] = {
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0x67, 0x56
};
ec_edwards_crv edwards_curve_edwards448;
ret = fp_init(&tmp, edwards_curve->a.ctx); EG(ret, err);
ret = fp_init_from_buf(&tmp, edwards_curve->a.ctx,
(const u8*)d_edwards448_buff, sizeof(d_edwards448_buff)); EG(ret, err);
ret = ec_edwards_crv_init(&edwards_curve_edwards448, &(edwards_curve->a), &tmp, &(edwards_curve->order)); EG(ret, err);
ret = aff_pt_edwards_x_from_y(&sqrt1, &sqrt2, &y, &edwards_curve_edwards448); EG(ret, err);
ec_edwards_crv_uninit(&edwards_curve_edwards448);
}
else
#endif
{
ret = aff_pt_edwards_x_from_y(&sqrt1, &sqrt2, &y, edwards_curve); EG(ret, err);
}
ret = nn_getbit(&(sqrt1.fp_val), 0, &lsb); EG(ret, err);
if(lsb == x_0){
ret = fp_copy(&x, &sqrt1); EG(ret, err);
}
else{
ret = fp_copy(&x, &sqrt2); EG(ret, err);
}
ret = fp_iszero(&x, &iszero); EG(ret, err);
MUST_HAVE(!(iszero && (x_0 == 1)), ret, err);
#if defined(WITH_SIG_EDDSA448)
if((sig_type == EDDSA448) || (sig_type == EDDSA448PH)){
ret = fp_copy(&sqrt1, &x); EG(ret, err);
ret = fp_copy(&sqrt2, &y); EG(ret, err);
ret = fp_set_word_value(&x, WORD(2)); EG(ret, err);
ret = fp_sqr(&tmp, &sqrt1); EG(ret, err);
ret = fp_sub(&x, &x, &tmp); EG(ret, err);
ret = fp_sqr(&tmp, &sqrt2); EG(ret, err);
ret = fp_sub(&x, &x, &tmp); EG(ret, err);
ret = fp_inv(&x, &x); EG(ret, err);
ret = fp_mul(&x, &x, &sqrt1); EG(ret, err);
ret = fp_mul(&x, &x, &sqrt2); EG(ret, err);
ret = fp_mul(&x, &x, alpha_edwards); EG(ret, err);
ret = fp_sqr(&sqrt1, &sqrt1); EG(ret, err);
ret = fp_sqr(&sqrt2, &sqrt2); EG(ret, err);
ret = fp_sub(&y, &sqrt2, &sqrt1); EG(ret, err);
ret = fp_inv(&y, &y); EG(ret, err);
ret = fp_add(&sqrt1, &sqrt1, &sqrt2); EG(ret, err);
ret = fp_mul(&y, &y, &sqrt1); EG(ret, err);
}
#endif
ret = aff_pt_edwards_init_from_coords(out, edwards_curve, &x, &y);
err:
fp_uninit(&sqrt1);
fp_uninit(&sqrt2);
fp_uninit(&x);
fp_uninit(&y);
#if defined(WITH_SIG_EDDSA448)
fp_uninit(&tmp);
#endif
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_derive_priv_key_hash(const ec_priv_key *in_priv,
u8 *buf, u16 buflen)
{
hash_alg_type hash_type = UNKNOWN_HASH_ALG;
const hash_mapping *hash;
u8 x_buf[EC_PRIV_KEY_MAX_SIZE];
int ret;
const u8 *in[2];
u32 in_len[2];
MUST_HAVE((buf != NULL), ret, err);
ret = eddsa_priv_key_sanity_check(in_priv); EG(ret, err);
MUST_HAVE(((hash_type = get_eddsa_hash_type(in_priv->key_type)) != UNKNOWN_HASH_ALG), ret, err);
ret = get_hash_by_type(hash_type, &hash); EG(ret, err);
MUST_HAVE((hash != NULL), ret, err);
ret = local_memset(x_buf, 0, sizeof(x_buf)); EG(ret, err);
MUST_HAVE((sizeof(x_buf) >= (hash->digest_size / 2)), ret, err);
ret = ec_priv_key_export_to_buf(in_priv, x_buf, (hash->digest_size / 2)); EG(ret, err);
ret = hash_mapping_callbacks_sanity_check(hash); EG(ret, err);
MUST_HAVE((buflen >= hash->digest_size), ret, err);
in[0] = x_buf; in[1] = NULL;
in_len[0] = (hash->digest_size / 2); in_len[1] = 0;
ret = hash->hfunc_scattered(in, in_len, buf);
err:
PTR_NULLIFY(hash);
return ret;
}
int eddsa_derive_priv_key(ec_priv_key *priv_key)
{
int ret, cmp;
u8 digest_size;
u8 digest[MAX_DIGEST_SIZE];
hash_alg_type hash_type = UNKNOWN_HASH_ALG;
word_t cofactor = WORD(0);
ret = eddsa_priv_key_sanity_check(priv_key); EG(ret, err);
MUST_HAVE(((hash_type = get_eddsa_hash_type(priv_key->key_type)) != UNKNOWN_HASH_ALG), ret, err);
digest_size = 0;
ret = get_hash_sizes(hash_type, &digest_size, NULL); EG(ret, err);
MUST_HAVE(((2 * priv_key->params->ec_fp.p_bitlen) < (8 * (bitcnt_t)digest_size)), ret, err);
MUST_HAVE(((digest_size % 2) == 0), ret, err);
MUST_HAVE((digest_size <= sizeof(digest)), ret, err);
ret = eddsa_derive_priv_key_hash(priv_key, digest, digest_size); EG(ret, err);
cofactor = priv_key->params->ec_gen_cofactor.val[0];
ret = nn_cmp_word(&(priv_key->params->ec_gen_cofactor), cofactor, &cmp); EG(ret, err);
MUST_HAVE((cmp == 0), ret, err);
MUST_HAVE((cofactor == (0x1 << 2)) || (cofactor == (0x1 << 3)), ret, err);
digest[0] &= (u8)(~(cofactor - 1));
#if defined(WITH_SIG_EDDSA25519)
if ((priv_key->key_type == EDDSA25519) ||
(priv_key->key_type == EDDSA25519CTX) ||
(priv_key->key_type == EDDSA25519PH)){
digest[(digest_size / 2) - 1] &= 0x7f;
digest[(digest_size / 2) - 1] |= 0x40;
}
#endif
#if defined(WITH_SIG_EDDSA448)
if ((priv_key->key_type == EDDSA448) || (priv_key->key_type == EDDSA448PH)) {
MUST_HAVE((digest_size / 2) >= 2, ret, err);
digest[(digest_size / 2) - 1] = 0;
digest[(digest_size / 2) - 2] |= 0x80;
}
#endif
#if !defined(WITH_SIG_EDDSA25519) && !defined(WITH_SIG_EDDSA448)
ret = -1;
goto err;
#endif
ret = nn_init_from_buf(&(priv_key->x), digest, digest_size);
err:
VAR_ZEROIFY(digest_size);
return ret;
}
int eddsa_gen_priv_key(ec_priv_key *priv_key)
{
int ret;
u8 digest_size;
hash_alg_type hash_type = UNKNOWN_HASH_ALG;
ret = eddsa_priv_key_sanity_check(priv_key); EG(ret, err);
MUST_HAVE(((hash_type = get_eddsa_hash_type(priv_key->key_type)) != UNKNOWN_HASH_ALG), ret, err);
digest_size = 0;
ret = get_hash_sizes(hash_type, &digest_size, NULL); EG(ret, err);
MUST_HAVE(((2 * priv_key->params->ec_fp.p_bitlen) < (8 * (bitcnt_t)digest_size)), ret, err);
MUST_HAVE(((digest_size % 2) == 0), ret, err);
ret = nn_get_random_len(&(priv_key->x), (digest_size / 2)); EG(ret, err);
ret = eddsa_derive_priv_key(priv_key);
err:
VAR_ZEROIFY(digest_size);
return ret;
}
int eddsa_import_priv_key(ec_priv_key *priv_key, const u8 *buf, u16 buflen,
const ec_params *shortw_curve_params,
ec_alg_type sig_type)
{
int ret;
hash_alg_type hash_type = UNKNOWN_HASH_ALG;
u8 digest_size;
bitcnt_t blen;
MUST_HAVE((priv_key != NULL) && (buf != NULL) && (shortw_curve_params != NULL), ret, err);
ret = nn_init_from_buf(&(priv_key->x), buf, buflen); EG(ret, err);
hash_type = get_eddsa_hash_type(sig_type);
MUST_HAVE((hash_type != UNKNOWN_HASH_ALG), ret, err);
digest_size = 0;
ret = get_hash_sizes(hash_type, &digest_size, NULL); EG(ret, err);
ret = nn_bitlen(&(priv_key->x), &blen); EG(ret, err);
MUST_HAVE((blen <= (8 * ((bitcnt_t)digest_size / 2))), ret, err);
priv_key->key_type = sig_type;
priv_key->params = shortw_curve_params;
priv_key->magic = PRIV_KEY_MAGIC;
ret = eddsa_derive_priv_key(priv_key);
err:
if((priv_key != NULL) && ret){
IGNORE_RET_VAL(local_memset(priv_key, 0, sizeof(ec_priv_key)));
}
VAR_ZEROIFY(digest_size);
VAR_ZEROIFY(blen);
return ret;
}
int eddsa_init_pub_key(ec_pub_key *out_pub, const ec_priv_key *in_priv)
{
prj_pt_src_t G;
u8 digest_size;
u8 digest[MAX_DIGEST_SIZE];
nn s;
hash_alg_type hash_type;
u8 digest_size_;
int ret;
s.magic = WORD(0);
MUST_HAVE(out_pub != NULL, ret, err);
ret = eddsa_priv_key_sanity_check(in_priv); EG(ret, err);
ret = nn_init(&s, 0); EG(ret, err);
ret = local_memset(out_pub, 0, sizeof(ec_pub_key)); EG(ret, err);
G = &(in_priv->params->ec_gen);
MUST_HAVE(((hash_type = get_eddsa_hash_type(in_priv->key_type)) != UNKNOWN_HASH_ALG), ret, err);
digest_size_ = 0;
ret = get_hash_sizes(hash_type, &digest_size_, NULL); EG(ret, err);
digest_size = sizeof(digest);
ret = eddsa_get_digest_from_priv_key(digest, &digest_size, in_priv); EG(ret, err);
MUST_HAVE((digest_size == digest_size_), ret, err);
ret = eddsa_compute_s(&s, digest, digest_size); EG(ret, err);
#if defined(WITH_SIG_EDDSA448)
if((in_priv->key_type == EDDSA448) || (in_priv->key_type == EDDSA448PH)){
ret = nn_rshift(&s, &s, 2); EG(ret, err);
}
#endif
ret = prj_pt_mul_blind(&(out_pub->y), &s, G); EG(ret, err);
out_pub->key_type = in_priv->key_type;
out_pub->params = in_priv->params;
out_pub->magic = PUB_KEY_MAGIC;
err:
PTR_NULLIFY(G);
VAR_ZEROIFY(digest_size);
nn_uninit(&s);
return ret;
}
int eddsa_import_pub_key(ec_pub_key *pub_key, const u8 *buf, u16 buflen,
const ec_params *shortw_curve_params,
ec_alg_type sig_type)
{
aff_pt_edwards _Tmp;
ec_edwards_crv edwards_curve;
int ret;
ec_shortw_crv_src_t shortw_curve;
fp_src_t alpha_montgomery;
fp_src_t gamma_montgomery;
fp_src_t alpha_edwards;
prj_pt_t pub_key_y;
_Tmp.magic = edwards_curve.magic = WORD(0);
#if defined(WITH_SIG_EDDSA25519) && defined(WITH_SIG_EDDSA448)
if((sig_type != EDDSA25519) && (sig_type != EDDSA25519CTX) && (sig_type != EDDSA25519PH) && \
(sig_type != EDDSA448) && (sig_type != EDDSA448PH)){
#endif
#if defined(WITH_SIG_EDDSA25519) && !defined(WITH_SIG_EDDSA448)
if((sig_type != EDDSA25519) && (sig_type != EDDSA25519CTX) && (sig_type != EDDSA25519PH)){
#endif
#if !defined(WITH_SIG_EDDSA25519) && defined(WITH_SIG_EDDSA448)
if((sig_type != EDDSA448) && (sig_type != EDDSA448PH)){
#endif
ret = -1;
goto err;
}
MUST_HAVE((pub_key != NULL) && (shortw_curve_params != NULL) && (buf != NULL), ret, err);
#if defined(WITH_SIG_EDDSA25519)
if((sig_type == EDDSA25519) || (sig_type == EDDSA25519CTX) || (sig_type == EDDSA25519PH)){
MUST_HAVE((buflen == EDDSA25519_PUB_KEY_ENCODED_LEN), ret, err);
}
#endif
#if defined(WITH_SIG_EDDSA448)
if((sig_type == EDDSA448) || (sig_type == EDDSA448PH)){
MUST_HAVE((buflen == EDDSA448_PUB_KEY_ENCODED_LEN), ret, err);
}
#endif
shortw_curve = &(shortw_curve_params->ec_curve);
alpha_montgomery = &(shortw_curve_params->ec_alpha_montgomery);
gamma_montgomery = &(shortw_curve_params->ec_gamma_montgomery);
alpha_edwards = &(shortw_curve_params->ec_alpha_edwards);
pub_key_y = &(pub_key->y);
ret = curve_shortw_to_edwards(shortw_curve, &edwards_curve, alpha_montgomery,
gamma_montgomery, alpha_edwards); EG(ret, err);
ret = eddsa_decode_point(&_Tmp, &edwards_curve, alpha_edwards, buf, buflen,
sig_type); EG(ret, err);
ret = aff_pt_edwards_to_prj_pt_shortw(&_Tmp, shortw_curve, pub_key_y,
alpha_edwards); EG(ret, err);
#if defined(WITH_SIG_EDDSA448)
if((sig_type == EDDSA448) || (sig_type == EDDSA448PH)){
nn_src_t gen_order = &(shortw_curve_params->ec_gen_order);
nn tmp;
tmp.magic = WORD(0);
ret = nn_init(&tmp, 0); EG(ret, err1);
ret = nn_modinv_word(&tmp, WORD(4), gen_order); EG(ret, err1);
ret = prj_pt_mul(&(pub_key->y), &tmp, pub_key_y); EG(ret, err1);
err1:
nn_uninit(&tmp);
PTR_NULLIFY(gen_order);
EG(ret, err);
}
#endif
pub_key->key_type = sig_type;
pub_key->params = shortw_curve_params;
pub_key->magic = PUB_KEY_MAGIC;
ret = eddsa_pub_key_sanity_check(pub_key);
err:
if((pub_key != NULL) && ret){
IGNORE_RET_VAL(local_memset(pub_key, 0, sizeof(ec_pub_key)));
}
PTR_NULLIFY(shortw_curve);
PTR_NULLIFY(alpha_montgomery);
PTR_NULLIFY(gamma_montgomery);
PTR_NULLIFY(alpha_edwards);
PTR_NULLIFY(pub_key_y);
aff_pt_edwards_uninit(&_Tmp);
ec_edwards_crv_uninit(&edwards_curve);
return ret;
}
int eddsa_export_pub_key(const ec_pub_key *in_pub, u8 *buf, u16 buflen)
{
aff_pt_edwards _Tmp;
ec_edwards_crv edwards_curve;
ec_alg_type sig_type;
int ret;
ec_shortw_crv_src_t shortw_curve;
fp_src_t alpha_montgomery;
fp_src_t gamma_montgomery;
fp_src_t alpha_edwards;
prj_pt_src_t pub_key_y;
_Tmp.magic = edwards_curve.magic = WORD(0);
ret = pub_key_check_initialized(in_pub); EG(ret, err);
MUST_HAVE((buf != NULL), ret, err);
shortw_curve = &(in_pub->params->ec_curve);
alpha_montgomery = &(in_pub->params->ec_alpha_montgomery);
gamma_montgomery = &(in_pub->params->ec_gamma_montgomery);
alpha_edwards = &(in_pub->params->ec_alpha_edwards);
pub_key_y = &(in_pub->y);
sig_type = in_pub->key_type;
#if defined(WITH_SIG_EDDSA25519)
if((sig_type == EDDSA25519) || (sig_type == EDDSA25519CTX) || (sig_type == EDDSA25519PH)){
MUST_HAVE((buflen == EDDSA25519_PUB_KEY_ENCODED_LEN), ret, err);
}
#endif
#if defined(WITH_SIG_EDDSA448)
if((sig_type == EDDSA448) || (sig_type == EDDSA448PH)){
MUST_HAVE((buflen == EDDSA448_PUB_KEY_ENCODED_LEN), ret, err);
}
#endif
ret = curve_shortw_to_edwards(shortw_curve, &edwards_curve, alpha_montgomery,
gamma_montgomery, alpha_edwards); EG(ret, err);
ret = prj_pt_shortw_to_aff_pt_edwards(pub_key_y, &edwards_curve, &_Tmp,
alpha_edwards); EG(ret, err);
ret = eddsa_encode_point(&_Tmp, alpha_edwards, buf,
buflen, in_pub->key_type);
err:
PTR_NULLIFY(shortw_curve);
PTR_NULLIFY(alpha_montgomery);
PTR_NULLIFY(gamma_montgomery);
PTR_NULLIFY(alpha_edwards);
PTR_NULLIFY(pub_key_y);
aff_pt_edwards_uninit(&_Tmp);
ec_edwards_crv_uninit(&edwards_curve);
return ret;
}
int eddsa_import_key_pair_from_priv_key_buf(ec_key_pair *kp,
const u8 *buf, u16 buflen,
const ec_params *shortw_curve_params,
ec_alg_type sig_type)
{
int ret;
MUST_HAVE((kp != NULL), ret, err);
ret = eddsa_import_priv_key(&(kp->priv_key), buf, buflen,
shortw_curve_params, sig_type); EG(ret, err);
ret = eddsa_init_pub_key(&(kp->pub_key), &(kp->priv_key));
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int eddsa_compute_pre_hash(const u8 *message, u32 message_size,
u8 *digest, u8 *digest_size,
ec_alg_type sig_type)
{
hash_alg_type hash_type;
const hash_mapping *hash;
hash_context hash_ctx;
int ret;
MUST_HAVE((message != NULL) && (digest != NULL) && (digest_size != NULL), ret, err);
MUST_HAVE(((hash_type = get_eddsa_hash_type(sig_type)) != UNKNOWN_HASH_ALG), ret, err);
ret = get_hash_by_type(hash_type, &hash); EG(ret, err);
MUST_HAVE((hash != NULL), ret, err);
MUST_HAVE(((*digest_size) >= hash->digest_size), ret, err);
(*digest_size) = hash->digest_size;
ret = hash_mapping_callbacks_sanity_check(hash); EG(ret, err);
ret = hash->hfunc_init(&hash_ctx); EG(ret, err);
ret = hash->hfunc_update(&hash_ctx, message, message_size); EG(ret, err);
ret = hash->hfunc_finalize(&hash_ctx, digest); EG(ret, err);
err:
return ret;
}
int eddsa_siglen(u16 p_bit_len, u16 q_bit_len, u8 hsize, u8 blocksize, u8 *siglen)
{
int ret;
MUST_HAVE((siglen != NULL), ret, err);
MUST_HAVE((p_bit_len <= CURVES_MAX_P_BIT_LEN) &&
(q_bit_len <= CURVES_MAX_Q_BIT_LEN) &&
(hsize <= MAX_DIGEST_SIZE) && (blocksize <= MAX_BLOCK_SIZE), ret, err);
(*siglen) = (u8)EDDSA_SIGLEN(hsize);
ret = 0;
err:
return ret;
}
#define EDDSA_SIGN_MAGIC ((word_t)(0x7632542bf630972bULL))
#define EDDSA_SIGN_CHECK_INITIALIZED(A, ret, err) \
MUST_HAVE((((void *)(A)) != NULL) && ((A)->magic == EDDSA_SIGN_MAGIC), ret, err)
int _eddsa_sign_init_pre_hash(struct ec_sign_context *ctx)
{
int ret;
bitcnt_t blen;
u8 use_message_pre_hash = 0;
ec_alg_type key_type = UNKNOWN_ALG;
const ec_key_pair *key_pair;
const hash_mapping *h;
ret = sig_sign_check_initialized(ctx); EG(ret, err);
key_pair = ctx->key_pair;
h = ctx->h;
key_type = ctx->key_pair->priv_key.key_type;
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519PH){
use_message_pre_hash = 1;
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448PH){
use_message_pre_hash = 1;
}
#endif
MUST_HAVE((use_message_pre_hash == 1), ret, err);
ret = eddsa_key_pair_sanity_check(key_pair); EG(ret, err);
MUST_HAVE((h != NULL) && (h->digest_size <= MAX_DIGEST_SIZE) && (h->block_size <= MAX_BLOCK_SIZE), ret, err);
MUST_HAVE((key_type == key_pair->pub_key.key_type) && (h->type == get_eddsa_hash_type(key_type)), ret, err);
ret = nn_bitlen(&(key_pair->priv_key.x), &blen); EG(ret, err);
MUST_HAVE(blen <= (8 * h->digest_size), ret, err);
ret = hash_mapping_callbacks_sanity_check(h); EG(ret, err);
ret = h->hfunc_init(&(ctx->sign_data.eddsa.h_ctx)); EG(ret, err);
ctx->sign_data.eddsa.magic = EDDSA_SIGN_MAGIC;
err:
PTR_NULLIFY(key_pair);
PTR_NULLIFY(h);
VAR_ZEROIFY(use_message_pre_hash);
return ret;
}
int _eddsa_sign_update_pre_hash(struct ec_sign_context *ctx,
const u8 *chunk, u32 chunklen)
{
int ret;
ec_alg_type key_type = UNKNOWN_ALG;
u8 use_message_pre_hash = 0;
ret = sig_sign_check_initialized(ctx); EG(ret, err);
EDDSA_SIGN_CHECK_INITIALIZED(&(ctx->sign_data.eddsa), ret, err);
MUST_HAVE((chunk != NULL), ret, err);
key_type = ctx->key_pair->priv_key.key_type;
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519PH){
use_message_pre_hash = 1;
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448PH){
use_message_pre_hash = 1;
}
#endif
MUST_HAVE(use_message_pre_hash == 1, ret, err);
MUST_HAVE((ctx->h->type == get_eddsa_hash_type(key_type)), ret, err);
ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err);
ret = ctx->h->hfunc_update(&(ctx->sign_data.eddsa.h_ctx), chunk, chunklen);
err:
VAR_ZEROIFY(use_message_pre_hash);
return ret;
}
int _eddsa_sign_finalize_pre_hash(struct ec_sign_context *ctx, u8 *sig, u8 siglen)
{
const ec_priv_key *priv_key;
const ec_pub_key *pub_key;
prj_pt_src_t G;
u8 hash[MAX_DIGEST_SIZE];
u8 ph_hash[MAX_DIGEST_SIZE];
prj_pt R;
ec_edwards_crv crv_edwards;
aff_pt_edwards Tmp_edwards;
nn_src_t q;
u8 hsize, hash_size;
int ret;
ec_shortw_crv_src_t shortw_curve;
fp_src_t alpha_montgomery;
fp_src_t gamma_montgomery;
fp_src_t alpha_edwards;
prj_pt_src_t pub_key_y;
u8 use_message_pre_hash = 0;
u16 use_message_pre_hash_hsize = 0;
ec_alg_type key_type = UNKNOWN_ALG;
u8 r_len, s_len;
const hash_mapping *h;
nn r, s, S;
#ifdef USE_SIG_BLINDING
nn b, binv;
b.magic = binv.magic = WORD(0);
#endif
r.magic = s.magic = S.magic = WORD(0);
R.magic = crv_edwards.magic = Tmp_edwards.magic = WORD(0);
ret = sig_sign_check_initialized(ctx); EG(ret, err);
EDDSA_SIGN_CHECK_INITIALIZED(&(ctx->sign_data.eddsa), ret, err);
MUST_HAVE((sig != NULL), ret, err);
ret = local_memset(&R, 0, sizeof(prj_pt)); EG(ret, err);
ret = local_memset(&Tmp_edwards, 0, sizeof(aff_pt_edwards)); EG(ret, err);
ret = local_memset(&crv_edwards, 0, sizeof(ec_edwards_crv)); EG(ret, err);
ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);
ret = local_memset(ph_hash, 0, sizeof(ph_hash)); EG(ret, err);
key_type = ctx->key_pair->priv_key.key_type;
MUST_HAVE((key_type == ctx->key_pair->pub_key.key_type) && (ctx->h->type == get_eddsa_hash_type(key_type)), ret, err);
priv_key = &(ctx->key_pair->priv_key);
pub_key = &(ctx->key_pair->pub_key);
q = &(priv_key->params->ec_gen_order);
G = &(priv_key->params->ec_gen);
h = ctx->h;
hsize = h->digest_size;
r_len = EDDSA_R_LEN(hsize);
s_len = EDDSA_S_LEN(hsize);
shortw_curve = &(priv_key->params->ec_curve);
alpha_montgomery = &(priv_key->params->ec_alpha_montgomery);
gamma_montgomery = &(priv_key->params->ec_gamma_montgomery);
alpha_edwards = &(priv_key->params->ec_alpha_edwards);
pub_key_y = &(pub_key->y);
dbg_nn_print("p", &(priv_key->params->ec_fp.p));
dbg_nn_print("q", &(priv_key->params->ec_gen_order));
dbg_priv_key_print("x", priv_key);
dbg_ec_point_print("G", &(priv_key->params->ec_gen));
dbg_pub_key_print("Y", &(ctx->key_pair->pub_key));
MUST_HAVE((siglen == EDDSA_SIGLEN(hsize)) && (siglen == (r_len + s_len)), ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519PH){
use_message_pre_hash = 1;
use_message_pre_hash_hsize = hsize;
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448PH){
use_message_pre_hash = 1;
use_message_pre_hash_hsize = 64;
}
#endif
MUST_HAVE((use_message_pre_hash == 1), ret, err);
ret = hash_mapping_callbacks_sanity_check(h); EG(ret, err);
ret = h->hfunc_finalize(&(ctx->sign_data.eddsa.h_ctx), ph_hash); EG(ret, err);
hash_size = sizeof(hash);
ret = eddsa_get_digest_from_priv_key(hash, &hash_size, priv_key); EG(ret, err);
MUST_HAVE((hash_size == hsize), ret, err);
ret = h->hfunc_init(&(ctx->sign_data.eddsa.h_ctx)); EG(ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519PH){
ret = dom2(1, ctx->adata, ctx->adata_len, h,
&(ctx->sign_data.eddsa.h_ctx)); EG(ret, err);
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448PH){
ret = dom4(1, ctx->adata, ctx->adata_len, h,
&(ctx->sign_data.eddsa.h_ctx)); EG(ret, err);
}
#endif
ret = h->hfunc_update(&(ctx->sign_data.eddsa.h_ctx), &hash[hsize / 2], hsize / 2); EG(ret, err);
MUST_HAVE((use_message_pre_hash_hsize <= hsize), ret, err);
ret = h->hfunc_update(&(ctx->sign_data.eddsa.h_ctx), ph_hash,
use_message_pre_hash_hsize); EG(ret, err);
ret = h->hfunc_finalize(&(ctx->sign_data.eddsa.h_ctx), hash); EG(ret, err);
dbg_buf_print("h(h || m)", hash, hsize);
ret = eddsa_decode_integer(&r, hash, hsize); EG(ret, err);
#ifdef USE_SIG_BLINDING
ret = nn_get_random_mod(&b, q); EG(ret, err);
dbg_nn_print("b", &b);
ret = nn_modinv_fermat(&binv, &b, q); EG(ret, err);
ret = nn_mul(&r, &r, &b); EG(ret, err);
#endif
ret = nn_mod_notrim(&r, &r, q); EG(ret, err);
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448PH){
nn r_tmp;
r_tmp.magic = WORD(0);
ret = nn_init(&r_tmp, 0); EG(ret, err1);
ret = nn_modinv_word(&r_tmp, WORD(4), q); EG(ret, err1);
ret = nn_mod_mul(&r_tmp, &r_tmp, &r, q); EG(ret, err1);
#ifdef USE_SIG_BLINDING
ret = nn_mod_mul(&r_tmp, &r_tmp, &binv, q); EG(ret, err1);
ret = prj_pt_mul_blind(&R, &r_tmp, G);
#else
ret = prj_pt_mul(&R, &r_tmp, G);
#endif
err1:
nn_uninit(&r_tmp);
EG(ret, err);
}
else
#endif
{
#ifdef USE_SIG_BLINDING
nn r_tmp;
r_tmp.magic = WORD(0);
ret = nn_init(&r_tmp, 0); EG(ret, err2);
ret = nn_copy(&r_tmp, &r); EG(ret, err2);
ret = nn_mod_mul(&r_tmp, &r_tmp, &binv, q); EG(ret, err2);
ret = prj_pt_mul_blind(&R, &r_tmp, G); EG(ret, err2);
err2:
nn_uninit(&r_tmp);
EG(ret, err);
#else
ret = prj_pt_mul(&R, &r, G); EG(ret, err);
#endif
}
ret = h->hfunc_init(&(ctx->sign_data.eddsa.h_ctx)); EG(ret, err);
ret = curve_shortw_to_edwards(shortw_curve, &crv_edwards, alpha_montgomery,
gamma_montgomery, alpha_edwards); EG(ret, err);
ret = prj_pt_shortw_to_aff_pt_edwards(&R, &crv_edwards, &Tmp_edwards,
alpha_edwards); EG(ret, err);
dbg_ec_edwards_point_print("R", &Tmp_edwards);
MUST_HAVE((r_len <= siglen), ret, err);
ret = eddsa_encode_point(&Tmp_edwards, alpha_edwards, &sig[0],
r_len, key_type); EG(ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519PH){
ret = dom2(1, ctx->adata, ctx->adata_len, h,
&(ctx->sign_data.eddsa.h_ctx)); EG(ret, err);
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448PH){
ret = dom4(1, ctx->adata, ctx->adata_len, h,
&(ctx->sign_data.eddsa.h_ctx)); EG(ret, err);
}
#endif
ret = h->hfunc_update(&(ctx->sign_data.eddsa.h_ctx), &sig[0], r_len); EG(ret, err);
ret = prj_pt_shortw_to_aff_pt_edwards(pub_key_y, &crv_edwards,
&Tmp_edwards, alpha_edwards); EG(ret, err);
dbg_ec_edwards_point_print("A", &Tmp_edwards);
MUST_HAVE(r_len <= sizeof(hash), ret, err);
ret = eddsa_encode_point(&Tmp_edwards, alpha_edwards, hash,
r_len, key_type); EG(ret, err);
ret = h->hfunc_update(&(ctx->sign_data.eddsa.h_ctx), hash, r_len); EG(ret, err);
ret = h->hfunc_update(&(ctx->sign_data.eddsa.h_ctx), ph_hash,
use_message_pre_hash_hsize); EG(ret, err);
ret = h->hfunc_finalize(&(ctx->sign_data.eddsa.h_ctx), hash); EG(ret, err);
dbg_buf_print("h(R || PubKey || PH(m))", hash, hsize);
ret = eddsa_decode_integer(&S, hash, hsize); EG(ret, err);
ret = nn_mod(&S, &S, q); EG(ret, err);
hsize = sizeof(hash);
ret = eddsa_get_digest_from_priv_key(hash, &hsize, priv_key); EG(ret, err);
ret = eddsa_compute_s(&s, hash, hsize); EG(ret, err);
ret = nn_mod(&s, &s, q); EG(ret, err);
#ifdef USE_SIG_BLINDING
ret = nn_mod_mul(&S, &S, &b, q); EG(ret, err);
#endif
ret = nn_mod_mul(&S, &S, &s, q); EG(ret, err);
nn_uninit(&s);
ret = nn_mod_add(&S, &S, &r, q); EG(ret, err);
#ifdef USE_SIG_BLINDING
ret = nn_mod_mul(&S, &S, &binv, q); EG(ret, err);
#endif
MUST_HAVE((s_len <= (siglen - r_len)), ret, err);
ret = eddsa_encode_integer(&S, &sig[r_len], s_len);
err:
PTR_NULLIFY(h);
PTR_NULLIFY(priv_key);
PTR_NULLIFY(pub_key);
PTR_NULLIFY(G);
PTR_NULLIFY(q);
PTR_NULLIFY(shortw_curve);
PTR_NULLIFY(alpha_montgomery);
PTR_NULLIFY(gamma_montgomery);
PTR_NULLIFY(alpha_edwards);
PTR_NULLIFY(pub_key_y);
VAR_ZEROIFY(hsize);
VAR_ZEROIFY(hash_size);
VAR_ZEROIFY(use_message_pre_hash);
VAR_ZEROIFY(use_message_pre_hash_hsize);
VAR_ZEROIFY(r_len);
VAR_ZEROIFY(s_len);
prj_pt_uninit(&R);
ec_edwards_crv_uninit(&crv_edwards);
aff_pt_edwards_uninit(&Tmp_edwards);
nn_uninit(&s);
nn_uninit(&r);
nn_uninit(&S);
#ifdef USE_SIG_BLINDING
nn_uninit(&b);
nn_uninit(&binv);
#endif
if(ctx != NULL){
IGNORE_RET_VAL(local_memset(&(ctx->sign_data.eddsa), 0, sizeof(eddsa_sign_data)));
}
IGNORE_RET_VAL(local_memset(ph_hash, 0, sizeof(ph_hash)));
return ret;
}
int _eddsa_sign(u8 *sig, u8 siglen, const ec_key_pair *key_pair,
const u8 *m, u32 mlen, int (*rand) (nn_t out, nn_src_t q),
ec_alg_type sig_type, hash_alg_type hash_type,
const u8 *adata, u16 adata_len)
{
int ret;
ec_alg_type key_type = UNKNOWN_ALG;
ec_shortw_crv_src_t shortw_curve;
fp_src_t alpha_montgomery;
fp_src_t gamma_montgomery;
fp_src_t alpha_edwards;
prj_pt_src_t pub_key_y;
u8 use_message_pre_hash = 0;
u16 use_message_pre_hash_hsize = 0;
prj_pt_src_t G;
prj_pt R;
aff_pt_edwards Tmp_edwards;
ec_edwards_crv crv_edwards;
u8 hash[MAX_DIGEST_SIZE];
u8 ph_hash[MAX_DIGEST_SIZE];
const ec_priv_key *priv_key;
const ec_pub_key *pub_key;
nn_src_t q;
u8 hsize, hash_size;
hash_context h_ctx;
u8 r_len, s_len;
bitcnt_t blen;
const hash_mapping *h;
nn r, s, S;
#ifdef USE_SIG_BLINDING
nn b, binv;
b.magic = binv.magic = WORD(0);
#endif
r.magic = s.magic = S.magic = WORD(0);
R.magic = Tmp_edwards.magic = crv_edwards.magic = WORD(0);
MUST_HAVE((rand == NULL), ret, err);
ret = local_memset(&R, 0, sizeof(prj_pt)); EG(ret, err);
ret = local_memset(&Tmp_edwards, 0, sizeof(aff_pt_edwards)); EG(ret, err);
ret = local_memset(&crv_edwards, 0, sizeof(ec_edwards_crv)); EG(ret, err);
ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);
ret = local_memset(ph_hash, 0, sizeof(ph_hash)); EG(ret, err);
ret = eddsa_key_pair_sanity_check(key_pair); EG(ret, err);
ret = get_hash_by_type(hash_type, &h); EG(ret, err);
key_type = key_pair->priv_key.key_type;
MUST_HAVE((h != NULL), ret, err);
MUST_HAVE((get_eddsa_hash_type(sig_type) == hash_type), ret, err);
MUST_HAVE(key_type == sig_type, ret, err);
MUST_HAVE((h != NULL) && (h->digest_size <= MAX_DIGEST_SIZE) && (h->block_size <= MAX_BLOCK_SIZE), ret, err);
ret = nn_bitlen(&(key_pair->priv_key.x), &blen); EG(ret, err);
MUST_HAVE((blen <= (8 * h->digest_size)), ret, err);
priv_key = &(key_pair->priv_key);
pub_key = &(key_pair->pub_key);
q = &(priv_key->params->ec_gen_order);
G = &(priv_key->params->ec_gen);
hsize = h->digest_size;
r_len = EDDSA_R_LEN(hsize);
s_len = EDDSA_S_LEN(hsize);
shortw_curve = &(priv_key->params->ec_curve);
alpha_montgomery = &(priv_key->params->ec_alpha_montgomery);
gamma_montgomery = &(priv_key->params->ec_gamma_montgomery);
alpha_edwards = &(priv_key->params->ec_alpha_edwards);
pub_key_y = &(pub_key->y);
dbg_nn_print("p", &(priv_key->params->ec_fp.p));
dbg_nn_print("q", &(priv_key->params->ec_gen_order));
dbg_priv_key_print("x", priv_key);
dbg_ec_point_print("G", &(priv_key->params->ec_gen));
dbg_pub_key_print("Y", pub_key);
MUST_HAVE((siglen == EDDSA_SIGLEN(hsize)) && (siglen == (r_len + s_len)), ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519PH){
use_message_pre_hash = 1;
use_message_pre_hash_hsize = hsize;
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448PH){
use_message_pre_hash = 1;
use_message_pre_hash_hsize = 64;
}
#endif
if(use_message_pre_hash){
hash_size = sizeof(ph_hash);
ret = eddsa_compute_pre_hash(m, mlen, ph_hash, &hash_size, sig_type); EG(ret, err);
MUST_HAVE(use_message_pre_hash_hsize <= hash_size, ret, err);
}
hash_size = sizeof(hash);
ret = eddsa_get_digest_from_priv_key(hash, &hash_size, &(key_pair->priv_key)); EG(ret, err);
MUST_HAVE((hash_size == hsize), ret, err);
ret = hash_mapping_callbacks_sanity_check(h); EG(ret, err);
ret = h->hfunc_init(&h_ctx); EG(ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519CTX){
MUST_HAVE(adata != NULL, ret, err);
ret = dom2(0, adata, adata_len, h, &h_ctx); EG(ret, err);
}
if(key_type == EDDSA25519PH){
ret = dom2(1, adata, adata_len, h, &h_ctx); EG(ret, err);
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448){
ret = dom4(0, adata, adata_len, h, &h_ctx); EG(ret, err);
}
if(key_type == EDDSA448PH){
ret = dom4(1, adata, adata_len, h, &h_ctx); EG(ret, err);
}
#endif
ret = h->hfunc_update(&h_ctx, &hash[hsize / 2], hsize / 2); EG(ret, err);
if(use_message_pre_hash){
ret = h->hfunc_update(&h_ctx, ph_hash, use_message_pre_hash_hsize); EG(ret, err);
}
else{
ret = h->hfunc_update(&h_ctx, m, mlen); EG(ret, err);
}
ret = h->hfunc_finalize(&h_ctx, hash); EG(ret, err);
dbg_buf_print("h(h || PH(m))", hash, hsize);
ret = eddsa_decode_integer(&r, hash, hsize); EG(ret, err);
#ifdef USE_SIG_BLINDING
ret = nn_get_random_mod(&b, q); EG(ret, err);
dbg_nn_print("b", &b);
ret = nn_modinv_fermat(&binv, &b, q); EG(ret, err);
ret = nn_mul(&r, &r, &b); EG(ret, err);
#endif
ret = nn_mod_notrim(&r, &r, q); EG(ret, err);
#if defined(WITH_SIG_EDDSA448)
if((key_type == EDDSA448) || (key_type == EDDSA448PH)){
nn r_tmp;
r_tmp.magic = WORD(0);
ret = nn_init(&r_tmp, 0); EG(ret, err1);
ret = nn_modinv_word(&r_tmp, WORD(4), q); EG(ret, err1);
ret = nn_mod_mul(&r_tmp, &r_tmp, &r, q); EG(ret, err1);
#ifdef USE_SIG_BLINDING
ret = nn_mod_mul(&r_tmp, &r_tmp, &binv, q); EG(ret, err1);
ret = prj_pt_mul_blind(&R, &r_tmp, G);
#else
ret = prj_pt_mul(&R, &r_tmp, G);
#endif
err1:
nn_uninit(&r_tmp);
EG(ret, err);
}
else
#endif
{
#ifdef USE_SIG_BLINDING
nn r_tmp;
r_tmp.magic = WORD(0);
ret = nn_init(&r_tmp, 0); EG(ret, err2);
ret = nn_copy(&r_tmp, &r); EG(ret, err2);
ret = nn_mod_mul(&r_tmp, &r_tmp, &binv, q); EG(ret, err2);
ret = prj_pt_mul_blind(&R, &r_tmp, G); EG(ret, err2);
err2:
nn_uninit(&r_tmp);
EG(ret, err);
#else
ret = prj_pt_mul(&R, &r, G); EG(ret, err);
#endif
}
ret = hash_mapping_callbacks_sanity_check(h); EG(ret, err);
ret = h->hfunc_init(&h_ctx); EG(ret, err);
ret = curve_shortw_to_edwards(shortw_curve, &crv_edwards, alpha_montgomery,
gamma_montgomery, alpha_edwards); EG(ret, err);
ret = prj_pt_shortw_to_aff_pt_edwards(&R, &crv_edwards, &Tmp_edwards,
alpha_edwards); EG(ret, err);
dbg_ec_edwards_point_print("R", &Tmp_edwards);
MUST_HAVE((r_len <= siglen), ret, err);
ret = eddsa_encode_point(&Tmp_edwards, alpha_edwards, &sig[0],
r_len, key_type); EG(ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519CTX){
MUST_HAVE((adata != NULL), ret, err);
ret = dom2(0, adata, adata_len, h, &h_ctx); EG(ret, err);
}
if(key_type == EDDSA25519PH){
ret = dom2(1, adata, adata_len, h, &h_ctx); EG(ret, err);
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448){
ret = dom4(0, adata, adata_len, h, &h_ctx); EG(ret, err);
}
if(key_type == EDDSA448PH){
ret = dom4(1, adata, adata_len, h, &h_ctx); EG(ret, err);
}
#endif
ret = h->hfunc_update(&h_ctx, &sig[0], r_len); EG(ret, err);
ret = prj_pt_shortw_to_aff_pt_edwards(pub_key_y, &crv_edwards, &Tmp_edwards,
alpha_edwards); EG(ret, err);
dbg_ec_edwards_point_print("A", &Tmp_edwards);
MUST_HAVE((r_len <= sizeof(hash)), ret, err);
ret = eddsa_encode_point(&Tmp_edwards, alpha_edwards,
hash, r_len, key_type); EG(ret, err);
ret = h->hfunc_update(&h_ctx, hash, r_len); EG(ret, err);
if(use_message_pre_hash){
ret = h->hfunc_update(&h_ctx, ph_hash, use_message_pre_hash_hsize); EG(ret, err);
}
else{
ret = h->hfunc_update(&h_ctx, m, mlen); EG(ret, err);
}
ret = h->hfunc_finalize(&h_ctx, hash); EG(ret, err);
dbg_buf_print("h(R || PubKey || PH(m))", hash, hsize);
ret = eddsa_decode_integer(&S, hash, hsize); EG(ret, err);
ret = nn_mod(&S, &S, q); EG(ret, err);
hsize = sizeof(hash);
ret = eddsa_get_digest_from_priv_key(hash, &hsize, priv_key); EG(ret, err);
ret = eddsa_compute_s(&s, hash, hsize); EG(ret, err);
ret = nn_mod(&s, &s, q); EG(ret, err);
#ifdef USE_SIG_BLINDING
ret = nn_mod_mul(&S, &S, &b, q); EG(ret, err);
#endif
ret = nn_mod_mul(&S, &S, &s, q); EG(ret, err);
nn_uninit(&s);
ret = nn_mod_add(&S, &S, &r, q); EG(ret, err);
#ifdef USE_SIG_BLINDING
ret = nn_mod_mul(&S, &S, &binv, q); EG(ret, err);
#endif
MUST_HAVE((s_len <= (siglen - r_len)), ret, err);
ret = eddsa_encode_integer(&S, &sig[r_len], s_len);
err:
PTR_NULLIFY(priv_key);
PTR_NULLIFY(pub_key);
PTR_NULLIFY(G);
PTR_NULLIFY(q);
PTR_NULLIFY(shortw_curve);
PTR_NULLIFY(alpha_montgomery);
PTR_NULLIFY(gamma_montgomery);
PTR_NULLIFY(alpha_edwards);
PTR_NULLIFY(pub_key_y);
PTR_NULLIFY(h);
VAR_ZEROIFY(hsize);
VAR_ZEROIFY(hash_size);
VAR_ZEROIFY(use_message_pre_hash);
VAR_ZEROIFY(use_message_pre_hash_hsize);
VAR_ZEROIFY(r_len);
VAR_ZEROIFY(s_len);
VAR_ZEROIFY(blen);
IGNORE_RET_VAL(local_memset(&h_ctx, 0, sizeof(h_ctx)));
IGNORE_RET_VAL(local_memset(hash, 0, sizeof(hash)));
IGNORE_RET_VAL(local_memset(ph_hash, 0, sizeof(ph_hash)));
prj_pt_uninit(&R);
ec_edwards_crv_uninit(&crv_edwards);
aff_pt_edwards_uninit(&Tmp_edwards);
nn_uninit(&s);
nn_uninit(&r);
nn_uninit(&S);
#ifdef USE_SIG_BLINDING
nn_uninit(&b);
nn_uninit(&binv);
#endif
return ret;
}
#define EDDSA_VERIFY_MAGIC ((word_t)(0x3298fe87e77151beULL))
#define EDDSA_VERIFY_CHECK_INITIALIZED(A, ret, err) \
MUST_HAVE((((void *)(A)) != NULL) && ((A)->magic == EDDSA_VERIFY_MAGIC), ret, err)
int _eddsa_verify_init(struct ec_verify_context *ctx, const u8 *sig, u8 siglen)
{
nn_src_t q;
ec_edwards_crv crv_edwards;
aff_pt_edwards R;
prj_pt _Tmp;
prj_pt_t _R;
aff_pt_edwards A;
nn *S;
u8 buff[MAX_DIGEST_SIZE];
int ret, iszero, cmp;
u16 hsize;
const ec_pub_key *pub_key;
ec_shortw_crv_src_t shortw_curve;
fp_src_t alpha_montgomery;
fp_src_t gamma_montgomery;
fp_src_t alpha_edwards;
nn_src_t gen_cofactor;
prj_pt_src_t pub_key_y;
hash_context *h_ctx;
hash_context *h_ctx_pre_hash;
ec_alg_type key_type = UNKNOWN_ALG;
R.magic = crv_edwards.magic = _Tmp.magic = A.magic = WORD(0);
ret = sig_verify_check_initialized(ctx); EG(ret, err);
MUST_HAVE((sig != NULL), ret, err);
ret = local_memset(&A, 0, sizeof(aff_pt_edwards)); EG(ret, err);
ret = local_memset(&crv_edwards, 0, sizeof(ec_edwards_crv)); EG(ret, err);
ret = local_memset(buff, 0, sizeof(buff)); EG(ret, err);
ret = local_memset(&R, 0, sizeof(R)); EG(ret, err);
ret = local_memset(&_Tmp, 0, sizeof(_Tmp)); EG(ret, err);
ret = eddsa_pub_key_sanity_check(ctx->pub_key); EG(ret, err);
MUST_HAVE((ctx->h != NULL) && (ctx->h->digest_size <= MAX_DIGEST_SIZE) && (ctx->h->block_size <= MAX_BLOCK_SIZE), ret, err);
q = &(ctx->pub_key->params->ec_gen_order);
_R = &(ctx->verify_data.eddsa._R);
S = &(ctx->verify_data.eddsa.S);
hsize = ctx->h->digest_size;
pub_key = ctx->pub_key;
shortw_curve = &(pub_key->params->ec_curve);
alpha_montgomery = &(pub_key->params->ec_alpha_montgomery);
gamma_montgomery = &(pub_key->params->ec_gamma_montgomery);
alpha_edwards = &(pub_key->params->ec_alpha_edwards);
gen_cofactor = &(pub_key->params->ec_gen_cofactor);
pub_key_y = &(pub_key->y);
key_type = pub_key->key_type;
h_ctx = &(ctx->verify_data.eddsa.h_ctx);
h_ctx_pre_hash = &(ctx->verify_data.eddsa.h_ctx_pre_hash);
MUST_HAVE((ctx->h->type == get_eddsa_hash_type(key_type)), ret, err);
MUST_HAVE((siglen == EDDSA_SIGLEN(hsize)), ret, err);
MUST_HAVE((siglen == (EDDSA_R_LEN(hsize) + EDDSA_S_LEN(hsize))), ret, err);
ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err);
ret = ctx->h->hfunc_init(h_ctx); EG(ret, err);
ret = ctx->h->hfunc_init(h_ctx_pre_hash); EG(ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519CTX){
MUST_HAVE((ctx->adata != NULL), ret, err);
ret = dom2(0, ctx->adata, ctx->adata_len, ctx->h, h_ctx); EG(ret, err);
}
if(key_type == EDDSA25519PH){
ret = dom2(1, ctx->adata, ctx->adata_len, ctx->h, h_ctx); EG(ret, err);
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448){
ret = dom4(0, ctx->adata, ctx->adata_len, ctx->h, h_ctx); EG(ret, err);
}
if(key_type == EDDSA448PH){
ret = dom4(1, ctx->adata, ctx->adata_len, ctx->h, h_ctx); EG(ret, err);
}
#endif
ret = curve_shortw_to_edwards(shortw_curve, &crv_edwards, alpha_montgomery,
gamma_montgomery, alpha_edwards); EG(ret, err);
ret = eddsa_decode_point(&R, &crv_edwards, alpha_edwards, &sig[0],
EDDSA_R_LEN(hsize), key_type); EG(ret, err);
dbg_ec_edwards_point_print("R", &R);
ret = aff_pt_edwards_to_prj_pt_shortw(&R, shortw_curve, _R, alpha_edwards); EG(ret, err);
ret = ctx->h->hfunc_update(h_ctx, &sig[0], EDDSA_R_LEN(hsize)); EG(ret, err);
ret = eddsa_decode_integer(S, &sig[EDDSA_R_LEN(hsize)], EDDSA_S_LEN(hsize)); EG(ret, err);
ret = nn_cmp(S, q, &cmp); EG(ret, err);
MUST_HAVE((cmp < 0), ret, err);
dbg_nn_print("S", S);
ret = _prj_pt_unprotected_mult(&_Tmp, gen_cofactor, pub_key_y); EG(ret, err);
ret = prj_pt_iszero(&_Tmp, &iszero); EG(ret, err);
MUST_HAVE((!iszero), ret, err);
ret = prj_pt_shortw_to_aff_pt_edwards(pub_key_y, &crv_edwards, &A, alpha_edwards); EG(ret, err);
dbg_ec_edwards_point_print("A", &A);
MUST_HAVE((EDDSA_R_LEN(hsize) <= sizeof(buff)), ret, err);
ret = eddsa_encode_point(&A, alpha_edwards, buff, EDDSA_R_LEN(hsize), key_type); EG(ret, err);
ret = ctx->h->hfunc_update(h_ctx, buff, EDDSA_R_LEN(hsize)); EG(ret, err);
ctx->verify_data.eddsa.magic = EDDSA_VERIFY_MAGIC;
err:
PTR_NULLIFY(q);
PTR_NULLIFY(_R);
PTR_NULLIFY(S);
PTR_NULLIFY(pub_key);
PTR_NULLIFY(shortw_curve);
PTR_NULLIFY(alpha_montgomery);
PTR_NULLIFY(gamma_montgomery);
PTR_NULLIFY(alpha_edwards);
PTR_NULLIFY(gen_cofactor);
PTR_NULLIFY(pub_key_y);
ec_edwards_crv_uninit(&crv_edwards);
aff_pt_edwards_uninit(&A);
aff_pt_edwards_uninit(&R);
prj_pt_uninit(&_Tmp);
return ret;
}
int _eddsa_verify_update(struct ec_verify_context *ctx,
const u8 *chunk, u32 chunklen)
{
int ret;
ec_alg_type key_type = UNKNOWN_ALG;
u8 use_message_pre_hash = 0;
hash_context *h_ctx;
hash_context *h_ctx_pre_hash;
ret = sig_verify_check_initialized(ctx); EG(ret, err);
EDDSA_VERIFY_CHECK_INITIALIZED(&(ctx->verify_data.eddsa), ret, err);
key_type = ctx->pub_key->key_type;
h_ctx = &(ctx->verify_data.eddsa.h_ctx);
h_ctx_pre_hash = &(ctx->verify_data.eddsa.h_ctx_pre_hash);
MUST_HAVE(ctx->h->type == get_eddsa_hash_type(key_type), ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519PH){
use_message_pre_hash = 1;
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448PH){
use_message_pre_hash = 1;
}
#endif
ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err);
if(use_message_pre_hash == 1){
ret = ctx->h->hfunc_update(h_ctx_pre_hash,
chunk, chunklen); EG(ret, err);
}
else{
ret = ctx->h->hfunc_update(h_ctx, chunk, chunklen); EG(ret, err);
}
err:
VAR_ZEROIFY(use_message_pre_hash);
return ret;
}
int _eddsa_verify_finalize(struct ec_verify_context *ctx)
{
prj_pt_src_t G, _R, A;
prj_pt _Tmp1, _Tmp2;
nn_src_t q, S;
nn h;
u16 hsize;
u8 hash[MAX_DIGEST_SIZE];
nn_src_t gen_cofactor;
int ret, iszero, cmp;
ec_alg_type key_type = UNKNOWN_ALG;
u8 use_message_pre_hash = 0;
u16 use_message_pre_hash_hsize = 0;
hash_context *h_ctx;
hash_context *h_ctx_pre_hash;
_Tmp1.magic = _Tmp2.magic = h.magic = WORD(0);
ret = sig_verify_check_initialized(ctx); EG(ret, err);
EDDSA_VERIFY_CHECK_INITIALIZED(&(ctx->verify_data.eddsa), ret, err);
ret = local_memset(&_Tmp1, 0, sizeof(prj_pt)); EG(ret, err);
ret = local_memset(&_Tmp2, 0, sizeof(prj_pt)); EG(ret, err);
ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);
G = &(ctx->pub_key->params->ec_gen);
A = &(ctx->pub_key->y);
q = &(ctx->pub_key->params->ec_gen_order);
hsize = ctx->h->digest_size;
S = &(ctx->verify_data.eddsa.S);
_R = &(ctx->verify_data.eddsa._R);
gen_cofactor = &(ctx->pub_key->params->ec_gen_cofactor);
key_type = ctx->pub_key->key_type;
h_ctx = &(ctx->verify_data.eddsa.h_ctx);
h_ctx_pre_hash = &(ctx->verify_data.eddsa.h_ctx_pre_hash);
MUST_HAVE((ctx->h->type == get_eddsa_hash_type(key_type)), ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519PH){
use_message_pre_hash = 1;
use_message_pre_hash_hsize = hsize;
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448PH){
use_message_pre_hash = 1;
use_message_pre_hash_hsize = 64;
}
#endif
ret = nn_cmp(S, q, &cmp); EG(ret, err);
MUST_HAVE((cmp < 0), ret, err);
MUST_HAVE((hsize <= sizeof(hash)), ret, err);
ret = hash_mapping_callbacks_sanity_check(ctx->h); EG(ret, err);
if(use_message_pre_hash == 1){
ret = ctx->h->hfunc_finalize(h_ctx_pre_hash, hash); EG(ret, err);
MUST_HAVE((use_message_pre_hash_hsize <= hsize), ret, err);
ret = ctx->h->hfunc_update(h_ctx, hash, use_message_pre_hash_hsize); EG(ret, err);
}
ret = ctx->h->hfunc_finalize(h_ctx, hash); EG(ret, err);
dbg_buf_print("hash = H(R || A || PH(M))", hash, hsize);
ret = eddsa_decode_integer(&h, hash, hsize); EG(ret, err);
ret = nn_mod(&h, &h, q); EG(ret, err);
dbg_nn_print("h = ", &h);
#if defined(WITH_SIG_EDDSA448)
if((key_type == EDDSA448) || (key_type == EDDSA448PH)){
ret = nn_lshift(&h, &h, 2); EG(ret, err);
ret = nn_mod(&h, &h, q); EG(ret, err);
}
#endif
ret = prj_pt_mul(&_Tmp1, S, G); EG(ret, err);
ret = prj_pt_neg(&_Tmp2, _R); EG(ret, err);
ret = prj_pt_add(&_Tmp1, &_Tmp1, &_Tmp2); EG(ret, err);
ret = prj_pt_mul(&_Tmp2, &h, A); EG(ret, err);
ret = prj_pt_neg(&_Tmp2, &_Tmp2); EG(ret, err);
ret = prj_pt_add(&_Tmp1, &_Tmp1, &_Tmp2); EG(ret, err);
ret = _prj_pt_unprotected_mult(&_Tmp2, gen_cofactor, &_Tmp1); EG(ret, err);
ret = prj_pt_iszero(&_Tmp2, &iszero); EG(ret, err);
ret = iszero ? 0 : -1;
err:
if(ctx != NULL){
IGNORE_RET_VAL(local_memset(&(ctx->verify_data.eddsa), 0, sizeof(eddsa_verify_data)));
}
PTR_NULLIFY(G);
PTR_NULLIFY(A);
PTR_NULLIFY(q);
PTR_NULLIFY(S);
PTR_NULLIFY(_R);
PTR_NULLIFY(gen_cofactor);
VAR_ZEROIFY(hsize);
VAR_ZEROIFY(use_message_pre_hash);
VAR_ZEROIFY(use_message_pre_hash_hsize);
nn_uninit(&h);
prj_pt_uninit(&_Tmp1);
prj_pt_uninit(&_Tmp2);
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int _eddsa_verify_batch_no_memory(const u8 **s, const u8 *s_len, const ec_pub_key **pub_keys,
const u8 **m, const u32 *m_len, u32 num, ec_alg_type sig_type,
hash_alg_type hash_type, const u8 **adata, const u16 *adata_len)
{
nn_src_t q = NULL;
ec_edwards_crv crv_edwards;
aff_pt_edwards R, A;
prj_pt_src_t G = NULL;
prj_pt _Tmp, _R_sum, _A_sum;
nn S, S_sum, z, h;
u8 hash[MAX_DIGEST_SIZE];
int ret, iszero, cmp;
u16 hsize;
const ec_pub_key *pub_key, *pub_key0;
ec_shortw_crv_src_t shortw_curve;
fp_src_t alpha_montgomery;
fp_src_t gamma_montgomery;
fp_src_t alpha_edwards;
nn_src_t gen_cofactor = NULL;
prj_pt_src_t pub_key_y;
hash_context h_ctx;
hash_context h_ctx_pre_hash;
u8 use_message_pre_hash = 0;
u16 use_message_pre_hash_hsize = 0;
const hash_mapping *hm;
ec_alg_type key_type = UNKNOWN_ALG;
u32 i;
R.magic = S.magic = S_sum.magic = crv_edwards.magic = WORD(0);
_Tmp.magic = _R_sum.magic = _A_sum.magic = WORD(0);
z.magic = h.magic = WORD(0);
MUST_HAVE((s != NULL) && (pub_keys != NULL) && (m != NULL) && (adata != NULL), ret, err);
MUST_HAVE((num > 0), ret, err);
ret = local_memset(&crv_edwards, 0, sizeof(ec_edwards_crv)); EG(ret, err);
ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);
ret = local_memset(&A, 0, sizeof(aff_pt_edwards)); EG(ret, err);
ret = local_memset(&R, 0, sizeof(aff_pt_edwards)); EG(ret, err);
ret = local_memset(&_R_sum, 0, sizeof(prj_pt)); EG(ret, err);
ret = local_memset(&_A_sum, 0, sizeof(prj_pt)); EG(ret, err);
ret = local_memset(&_Tmp, 0, sizeof(prj_pt)); EG(ret, err);
pub_key0 = pub_keys[0];
MUST_HAVE((pub_key0 != NULL), ret, err);
ret = get_hash_by_type(hash_type, &hm); EG(ret, err);
hsize = hm->digest_size;
MUST_HAVE((hm != NULL), ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(sig_type == EDDSA25519PH){
use_message_pre_hash = 1;
use_message_pre_hash_hsize = hsize;
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(sig_type == EDDSA448PH){
use_message_pre_hash = 1;
use_message_pre_hash_hsize = 64;
}
#endif
for(i = 0; i < num; i++){
u8 siglen;
const u8 *sig = NULL;
ret = eddsa_pub_key_sanity_check(pub_keys[i]); EG(ret, err);
pub_key = pub_keys[i];
MUST_HAVE((pub_key->params) == (pub_key0->params), ret, err);
q = &(pub_key->params->ec_gen_order);
shortw_curve = &(pub_key->params->ec_curve);
alpha_montgomery = &(pub_key->params->ec_alpha_montgomery);
gamma_montgomery = &(pub_key->params->ec_gamma_montgomery);
alpha_edwards = &(pub_key->params->ec_alpha_edwards);
gen_cofactor = &(pub_key->params->ec_gen_cofactor);
pub_key_y = &(pub_key->y);
key_type = pub_key->key_type;
G = &(pub_key->params->ec_gen);
MUST_HAVE((key_type == sig_type), ret, err);
if(i == 0){
ret = nn_init(&S_sum, 0); EG(ret, err);
ret = prj_pt_init(&_R_sum, shortw_curve); EG(ret, err);
ret = prj_pt_zero(&_R_sum); EG(ret, err);
ret = prj_pt_init(&_A_sum, shortw_curve); EG(ret, err);
ret = prj_pt_zero(&_A_sum); EG(ret, err);
ret = nn_init(&z, 0); EG(ret, err);
ret = nn_init(&h, 0); EG(ret, err);
}
gen_z_again:
ret = nn_get_random_len(&z, (hsize / 4)); EG(ret, err);
ret = nn_iszero(&z, &iszero); EG(ret, err);
if(iszero){
goto gen_z_again;
}
MUST_HAVE((hash_type == get_eddsa_hash_type(key_type)), ret, err);
siglen = s_len[i];
sig = s[i];
MUST_HAVE((siglen == EDDSA_SIGLEN(hsize)), ret, err);
MUST_HAVE((siglen == (EDDSA_R_LEN(hsize) + EDDSA_S_LEN(hsize))), ret, err);
ret = hash_mapping_callbacks_sanity_check(hm); EG(ret, err);
ret = hm->hfunc_init(&h_ctx); EG(ret, err);
ret = hm->hfunc_init(&h_ctx_pre_hash); EG(ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519CTX){
MUST_HAVE((adata[i] != NULL), ret, err);
ret = dom2(0, adata[i], adata_len[i], hm, &h_ctx); EG(ret, err);
}
if(key_type == EDDSA25519PH){
ret = dom2(1, adata[i], adata_len[i], hm, &h_ctx); EG(ret, err);
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448){
ret = dom4(0, adata[i], adata_len[i], hm, &h_ctx); EG(ret, err);
}
if(key_type == EDDSA448PH){
ret = dom4(1, adata[i], adata_len[i], hm, &h_ctx); EG(ret, err);
}
#endif
ret = curve_shortw_to_edwards(shortw_curve, &crv_edwards, alpha_montgomery,
gamma_montgomery, alpha_edwards); EG(ret, err);
ret = eddsa_decode_point(&R, &crv_edwards, alpha_edwards, &sig[0],
EDDSA_R_LEN(hsize), key_type); EG(ret, err);
dbg_ec_edwards_point_print("R", &R);
ret = aff_pt_edwards_to_prj_pt_shortw(&R, shortw_curve, &_Tmp, alpha_edwards); EG(ret, err);
ret = hm->hfunc_update(&h_ctx, &sig[0], EDDSA_R_LEN(hsize)); EG(ret, err);
ret = _prj_pt_unprotected_mult(&_Tmp, &z, &_Tmp); EG(ret, err);
ret = prj_pt_add(&_R_sum, &_R_sum, &_Tmp); EG(ret, err);
ret = eddsa_decode_integer(&S, &sig[EDDSA_R_LEN(hsize)], EDDSA_S_LEN(hsize)); EG(ret, err);
ret = nn_cmp(&S, q, &cmp); EG(ret, err);
MUST_HAVE((cmp < 0), ret, err);
dbg_nn_print("S", &S);
ret = nn_mul(&S, &S, &z); EG(ret, err);
ret = nn_mod(&S, &S, q); EG(ret, err);
ret = nn_mod_add(&S_sum, &S_sum, &S, q); EG(ret, err);
ret = _prj_pt_unprotected_mult(&_Tmp, gen_cofactor, pub_key_y); EG(ret, err);
ret = prj_pt_iszero(&_Tmp, &iszero); EG(ret, err);
MUST_HAVE((!iszero), ret, err);
ret = prj_pt_shortw_to_aff_pt_edwards(pub_key_y, &crv_edwards, &A, alpha_edwards); EG(ret, err);
dbg_ec_edwards_point_print("A", &A);
MUST_HAVE((EDDSA_R_LEN(hsize) <= sizeof(hash)), ret, err);
ret = eddsa_encode_point(&A, alpha_edwards, hash, EDDSA_R_LEN(hsize), key_type); EG(ret, err);
ret = hm->hfunc_update(&h_ctx, hash, EDDSA_R_LEN(hsize)); EG(ret, err);
if(use_message_pre_hash == 1){
ret = hm->hfunc_update(&h_ctx_pre_hash, m[i], m_len[i]); EG(ret, err);
ret = hm->hfunc_finalize(&h_ctx_pre_hash, hash); EG(ret, err);
MUST_HAVE((use_message_pre_hash_hsize <= hsize), ret, err);
ret = hm->hfunc_update(&h_ctx, hash, use_message_pre_hash_hsize); EG(ret, err);
}
else{
ret = hm->hfunc_update(&h_ctx, m[i], m_len[i]); EG(ret, err);
}
ret = hm->hfunc_finalize(&h_ctx, hash); EG(ret, err);
dbg_buf_print("hash = H(R || A || PH(M))", hash, hsize);
ret = eddsa_decode_integer(&h, hash, hsize); EG(ret, err);
ret = nn_mod(&h, &h, q); EG(ret, err);
dbg_nn_print("h = ", &h);
#if defined(WITH_SIG_EDDSA448)
if((key_type == EDDSA448) || (key_type == EDDSA448PH)){
ret = nn_lshift(&h, &h, 2); EG(ret, err);
ret = nn_mod(&h, &h, q); EG(ret, err);
}
#endif
ret = nn_mul(&z, &z, &h); EG(ret, err);
ret = nn_mod(&z, &z, q); EG(ret, err);
ret = _prj_pt_unprotected_mult(&_Tmp, &z, &_Tmp); EG(ret, err);
ret = prj_pt_add(&_A_sum, &_A_sum, &_Tmp); EG(ret, err);
}
MUST_HAVE((gen_cofactor != NULL) && (q != NULL) && (G != NULL), ret, err);
ret = nn_mul(&S_sum, &S_sum, gen_cofactor); EG(ret, err);
ret = nn_mod(&S_sum, &S_sum, q); EG(ret, err);
ret = nn_mod_neg(&S_sum, &S_sum, q); EG(ret, err);
ret = _prj_pt_unprotected_mult(&_Tmp, &S_sum, G); EG(ret, err);
ret = _prj_pt_unprotected_mult(&_R_sum, gen_cofactor, &_R_sum); EG(ret, err);
ret = prj_pt_add(&_Tmp, &_Tmp, &_A_sum);
ret = prj_pt_add(&_Tmp, &_Tmp, &_R_sum);
ret = prj_pt_iszero(&_Tmp, &iszero); EG(ret, err);
ret = iszero ? 0 : -1;
err:
PTR_NULLIFY(q);
PTR_NULLIFY(pub_key);
PTR_NULLIFY(pub_key0);
PTR_NULLIFY(shortw_curve);
PTR_NULLIFY(alpha_montgomery);
PTR_NULLIFY(gamma_montgomery);
PTR_NULLIFY(alpha_edwards);
PTR_NULLIFY(gen_cofactor);
PTR_NULLIFY(pub_key_y);
PTR_NULLIFY(G);
ec_edwards_crv_uninit(&crv_edwards);
aff_pt_edwards_uninit(&A);
aff_pt_edwards_uninit(&R);
prj_pt_uninit(&_R_sum);
prj_pt_uninit(&_A_sum);
prj_pt_uninit(&_Tmp);
nn_uninit(&S);
nn_uninit(&S_sum);
nn_uninit(&z);
nn_uninit(&h);
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int _eddsa_verify_batch(const u8 **s, const u8 *s_len, const ec_pub_key **pub_keys,
const u8 **m, const u32 *m_len, u32 num, ec_alg_type sig_type,
hash_alg_type hash_type, const u8 **adata, const u16 *adata_len,
verify_batch_scratch_pad *scratch_pad_area, u32 *scratch_pad_area_len)
{
nn_src_t q = NULL;
ec_edwards_crv crv_edwards;
aff_pt_edwards R, A;
prj_pt_src_t G = NULL;
nn S, z;
u8 hash[MAX_DIGEST_SIZE];
int ret, iszero, cmp;
u16 hsize;
const ec_pub_key *pub_key, *pub_key0;
ec_shortw_crv_src_t shortw_curve;
fp_src_t alpha_montgomery;
fp_src_t gamma_montgomery;
fp_src_t alpha_edwards;
nn_src_t gen_cofactor = NULL;
prj_pt_src_t pub_key_y;
hash_context h_ctx;
hash_context h_ctx_pre_hash;
u8 use_message_pre_hash = 0;
u16 use_message_pre_hash_hsize = 0;
const hash_mapping *hm;
ec_alg_type key_type = UNKNOWN_ALG;
verify_batch_scratch_pad *elements = scratch_pad_area;
u32 i;
u64 expected_len;
bitcnt_t q_bit_len = 0;
S.magic = z.magic = crv_edwards.magic = WORD(0);
MUST_HAVE((s != NULL) && (pub_keys != NULL) && (m != NULL) && (adata != NULL), ret, err);
MUST_HAVE((scratch_pad_area_len != NULL), ret, err);
MUST_HAVE(((2 * num) >= num), ret, err);
MUST_HAVE(((2 * num) + 1) >= num, ret, err);
if(num <= 1){
if(scratch_pad_area == NULL){
(*scratch_pad_area_len) = 0;
ret = 0;
goto err;
}
else{
ret = _eddsa_verify_batch_no_memory(s, s_len, pub_keys, m, m_len, num, sig_type,
hash_type, adata, adata_len);
goto err;
}
}
expected_len = ((2 * num) + 1) * sizeof(verify_batch_scratch_pad);
MUST_HAVE((expected_len < 0xffffffff), ret, err);
if(scratch_pad_area == NULL){
(*scratch_pad_area_len) = (u32)expected_len;
ret = 0;
goto err;
}
else{
MUST_HAVE((*scratch_pad_area_len) >= expected_len, ret, err);
}
ret = local_memset(&crv_edwards, 0, sizeof(ec_edwards_crv)); EG(ret, err);
ret = local_memset(hash, 0, sizeof(hash)); EG(ret, err);
ret = local_memset(&A, 0, sizeof(aff_pt_edwards)); EG(ret, err);
ret = local_memset(&R, 0, sizeof(aff_pt_edwards)); EG(ret, err);
pub_key0 = pub_keys[0];
MUST_HAVE((pub_key0 != NULL), ret, err);
ret = get_hash_by_type(hash_type, &hm); EG(ret, err);
hsize = hm->digest_size;
MUST_HAVE((hm != NULL), ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(sig_type == EDDSA25519PH){
use_message_pre_hash = 1;
use_message_pre_hash_hsize = hsize;
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(sig_type == EDDSA448PH){
use_message_pre_hash = 1;
use_message_pre_hash_hsize = 64;
}
#endif
MUST_HAVE((num >= 1), ret, err);
for(i = 0; i < num; i++){
u8 siglen;
const u8 *sig = NULL;
ret = eddsa_pub_key_sanity_check(pub_keys[i]); EG(ret, err);
pub_key = pub_keys[i];
MUST_HAVE((pub_key->params) == (pub_key0->params), ret, err);
q = &(pub_key->params->ec_gen_order);
shortw_curve = &(pub_key->params->ec_curve);
alpha_montgomery = &(pub_key->params->ec_alpha_montgomery);
gamma_montgomery = &(pub_key->params->ec_gamma_montgomery);
alpha_edwards = &(pub_key->params->ec_alpha_edwards);
gen_cofactor = &(pub_key->params->ec_gen_cofactor);
pub_key_y = &(pub_key->y);
key_type = pub_key->key_type;
G = &(pub_key->params->ec_gen);
q_bit_len = pub_key->params->ec_gen_order_bitlen;
MUST_HAVE((key_type == sig_type), ret, err);
if(i == 0){
ret = nn_init(&z, 0); EG(ret, err);
ret = nn_init(&S, 0); EG(ret, err);
ret = nn_init(&elements[(2 * num)].number, 0); EG(ret, err);
ret = _prj_pt_unprotected_mult(&elements[(2 * num)].point, gen_cofactor, G); EG(ret, err);
}
gen_z_again:
ret = nn_get_random_len(&z, (hsize / 4)); EG(ret, err);
ret = nn_iszero(&z, &iszero); EG(ret, err);
if(iszero){
goto gen_z_again;
}
MUST_HAVE((hash_type == get_eddsa_hash_type(key_type)), ret, err);
siglen = s_len[i];
sig = s[i];
MUST_HAVE((siglen == EDDSA_SIGLEN(hsize)), ret, err);
MUST_HAVE((siglen == (EDDSA_R_LEN(hsize) + EDDSA_S_LEN(hsize))), ret, err);
ret = hash_mapping_callbacks_sanity_check(hm); EG(ret, err);
ret = hm->hfunc_init(&h_ctx); EG(ret, err);
ret = hm->hfunc_init(&h_ctx_pre_hash); EG(ret, err);
#if defined(WITH_SIG_EDDSA25519)
if(key_type == EDDSA25519CTX){
MUST_HAVE((adata[i] != NULL), ret, err);
ret = dom2(0, adata[i], adata_len[i], hm, &h_ctx); EG(ret, err);
}
if(key_type == EDDSA25519PH){
ret = dom2(1, adata[i], adata_len[i], hm, &h_ctx); EG(ret, err);
}
#endif
#if defined(WITH_SIG_EDDSA448)
if(key_type == EDDSA448){
ret = dom4(0, adata[i], adata_len[i], hm, &h_ctx); EG(ret, err);
}
if(key_type == EDDSA448PH){
ret = dom4(1, adata[i], adata_len[i], hm, &h_ctx); EG(ret, err);
}
#endif
ret = curve_shortw_to_edwards(shortw_curve, &crv_edwards, alpha_montgomery,
gamma_montgomery, alpha_edwards); EG(ret, err);
ret = eddsa_decode_point(&R, &crv_edwards, alpha_edwards, &sig[0],
EDDSA_R_LEN(hsize), key_type); EG(ret, err);
dbg_ec_edwards_point_print("R", &R);
ret = aff_pt_edwards_to_prj_pt_shortw(&R, shortw_curve, &elements[i].point, alpha_edwards); EG(ret, err);
ret = hm->hfunc_update(&h_ctx, &sig[0], EDDSA_R_LEN(hsize)); EG(ret, err);
ret = nn_init(&elements[i].number, 0); EG(ret, err);
ret = nn_mul(&elements[i].number, gen_cofactor, &z); EG(ret, err);
ret = nn_mod(&elements[i].number, &elements[i].number, q); EG(ret, err);
ret = eddsa_decode_integer(&S, &sig[EDDSA_R_LEN(hsize)], EDDSA_S_LEN(hsize)); EG(ret, err);
ret = nn_cmp(&S, q, &cmp); EG(ret, err);
MUST_HAVE((cmp < 0), ret, err);
dbg_nn_print("S", &S);
ret = nn_mul(&S, &S, &z); EG(ret, err);
ret = nn_mod(&S, &S, q); EG(ret, err);
ret = nn_mod_neg(&S, &S, q); EG(ret, err);
ret = nn_mod_add(&elements[(2 * num)].number, &elements[(2 * num)].number, &S, q); EG(ret, err);
ret = _prj_pt_unprotected_mult(&elements[num + i].point, gen_cofactor, pub_key_y); EG(ret, err);
ret = prj_pt_iszero(&elements[num + i].point, &iszero); EG(ret, err);
MUST_HAVE((!iszero), ret, err);
ret = prj_pt_shortw_to_aff_pt_edwards(pub_key_y, &crv_edwards, &A, alpha_edwards); EG(ret, err);
dbg_ec_edwards_point_print("A", &A);
MUST_HAVE((EDDSA_R_LEN(hsize) <= sizeof(hash)), ret, err);
ret = eddsa_encode_point(&A, alpha_edwards, hash, EDDSA_R_LEN(hsize), key_type); EG(ret, err);
ret = hm->hfunc_update(&h_ctx, hash, EDDSA_R_LEN(hsize)); EG(ret, err);
if(use_message_pre_hash == 1){
ret = hm->hfunc_update(&h_ctx_pre_hash, m[i], m_len[i]); EG(ret, err);
ret = hm->hfunc_finalize(&h_ctx_pre_hash, hash); EG(ret, err);
MUST_HAVE((use_message_pre_hash_hsize <= hsize), ret, err);
ret = hm->hfunc_update(&h_ctx, hash, use_message_pre_hash_hsize); EG(ret, err);
}
else{
ret = hm->hfunc_update(&h_ctx, m[i], m_len[i]); EG(ret, err);
}
ret = hm->hfunc_finalize(&h_ctx, hash); EG(ret, err);
dbg_buf_print("hash = H(R || A || PH(M))", hash, hsize);
ret = eddsa_decode_integer(&elements[num + i].number, hash, hsize); EG(ret, err);
ret = nn_mod(&elements[num + i].number, &elements[num + i].number, q); EG(ret, err);
dbg_nn_print("h = ", &elements[num + i].number);
#if defined(WITH_SIG_EDDSA448)
if((key_type == EDDSA448) || (key_type == EDDSA448PH)){
ret = nn_lshift(&elements[num + i].number, &elements[num + i].number, 2); EG(ret, err);
ret = nn_mod(&elements[num + i].number, &elements[num + i].number, q); EG(ret, err);
}
#endif
ret = nn_mul(&elements[num + i].number, &elements[num + i].number, &z); EG(ret, err);
ret = nn_mod(&elements[num + i].number, &elements[num + i].number, q); EG(ret, err);
}
MUST_HAVE((gen_cofactor != NULL) && (q != NULL) && (G != NULL) && (q_bit_len != 0), ret, err);
ret = ec_verify_bos_coster(elements, (2 * num) + 1, q_bit_len);
if(ret){
if(ret == -2){
ret = _eddsa_verify_batch_no_memory(s, s_len, pub_keys, m, m_len, num, sig_type,
hash_type, adata, adata_len); EG(ret, err);
}
goto err;
}
ret = prj_pt_iszero(&elements[elements[0].index].point, &iszero); EG(ret, err);
ret = iszero ? 0 : -1;
err:
PTR_NULLIFY(q);
PTR_NULLIFY(pub_key);
PTR_NULLIFY(pub_key0);
PTR_NULLIFY(shortw_curve);
PTR_NULLIFY(alpha_montgomery);
PTR_NULLIFY(gamma_montgomery);
PTR_NULLIFY(alpha_edwards);
PTR_NULLIFY(gen_cofactor);
PTR_NULLIFY(pub_key_y);
PTR_NULLIFY(G);
PTR_NULLIFY(elements);
if((scratch_pad_area != NULL) && (scratch_pad_area_len != NULL)){
IGNORE_RET_VAL(local_memset((u8*)scratch_pad_area, 0, (*scratch_pad_area_len)));
}
ec_edwards_crv_uninit(&crv_edwards);
aff_pt_edwards_uninit(&A);
aff_pt_edwards_uninit(&R);
nn_uninit(&S);
nn_uninit(&z);
return ret;
}
int eddsa_verify_batch(const u8 **s, const u8 *s_len, const ec_pub_key **pub_keys,
const u8 **m, const u32 *m_len, u32 num, ec_alg_type sig_type,
hash_alg_type hash_type, const u8 **adata, const u16 *adata_len,
verify_batch_scratch_pad *scratch_pad_area, u32 *scratch_pad_area_len)
{
int ret;
if(scratch_pad_area != NULL){
MUST_HAVE((scratch_pad_area_len != NULL), ret, err);
ret = _eddsa_verify_batch(s, s_len, pub_keys, m, m_len, num, sig_type,
hash_type, adata, adata_len,
scratch_pad_area, scratch_pad_area_len); EG(ret, err);
}
else{
ret = _eddsa_verify_batch_no_memory(s, s_len, pub_keys, m, m_len, num, sig_type,
hash_type, adata, adata_len); EG(ret, err);
}
err:
return ret;
}
#else
typedef int dummy;
#endif