#include <libecc/sig/sig_algs.h>
int generic_gen_priv_key(ec_priv_key *priv_key)
{
nn_src_t q;
int ret;
ret = priv_key_check_initialized(priv_key); EG(ret, err);
q = &(priv_key->params->ec_gen_order);
ret = nn_get_random_mod(&(priv_key->x), q);
err:
return ret;
}
int gen_priv_key(ec_priv_key *priv_key)
{
const ec_sig_mapping *sm;
int ret;
u8 i;
ret = priv_key_check_initialized(priv_key); EG(ret, err);
ret = -1;
for (i = 0, sm = &ec_sig_maps[i];
sm->type != UNKNOWN_ALG; sm = &ec_sig_maps[++i]) {
if (sm->type == priv_key->key_type) {
MUST_HAVE((sm->gen_priv_key != NULL), ret, err);
ret = sm->gen_priv_key(priv_key);
break;
}
}
err:
return ret;
}
int init_pubkey_from_privkey(ec_pub_key *pub_key, ec_priv_key *priv_key)
{
const ec_sig_mapping *sm;
int ret;
u8 i;
ret = priv_key_check_initialized(priv_key); EG(ret, err);
ret = -1;
for (i = 0, sm = &ec_sig_maps[i];
sm->type != UNKNOWN_ALG; sm = &ec_sig_maps[++i]) {
if (sm->type == priv_key->key_type) {
MUST_HAVE((sm->init_pub_key != NULL), ret, err);
ret = sm->init_pub_key(pub_key, priv_key);
break;
}
}
err:
return ret;
}
int get_sig_by_name(const char *ec_sig_name, const ec_sig_mapping **sig_mapping)
{
const ec_sig_mapping *sm;
int ret, check;
u8 i;
MUST_HAVE((ec_sig_name != NULL), ret, err);
MUST_HAVE((sig_mapping != NULL), ret, err);
ret = -1;
for (i = 0, sm = &ec_sig_maps[i];
sm->type != UNKNOWN_ALG; sm = &ec_sig_maps[++i]) {
if((!are_str_equal(ec_sig_name, sm->name, &check)) && check){
(*sig_mapping) = sm;
ret = 0;
break;
}
}
err:
return ret;
}
int get_sig_by_type(ec_alg_type sig_type, const ec_sig_mapping **sig_mapping)
{
const ec_sig_mapping *sm;
int ret;
u8 i;
MUST_HAVE((sig_mapping != NULL), ret, err);
ret = -1;
for (i = 0, sm = &ec_sig_maps[i];
sm->type != UNKNOWN_ALG; sm = &ec_sig_maps[++i]) {
if (sm->type == sig_type) {
(*sig_mapping) = sm;
ret = 0;
break;
}
}
err:
return ret;
}
int ec_sig_mapping_callbacks_sanity_check(const ec_sig_mapping *sig)
{
const ec_sig_mapping *sm;
int ret = -1, check;
u8 i;
MUST_HAVE((sig != NULL), ret, err);
for (i = 0, sm = &ec_sig_maps[i];
sm->type != UNKNOWN_ALG; sm = &ec_sig_maps[++i]) {
if (sm->type == sig->type){
if ((!are_str_equal_nlen(sm->name, sig->name, MAX_SIG_ALG_NAME_LEN, &check)) && (!check)){
goto err;
} else if (sm->siglen != sig->siglen){
goto err;
} else if (sm->gen_priv_key != sig->gen_priv_key){
goto err;
} else if (sm->init_pub_key != sig->init_pub_key){
goto err;
} else if (sm->sign_init != sig->sign_init){
goto err;
} else if (sm->sign_update != sig->sign_update){
goto err;
} else if (sm->sign_finalize != sig->sign_finalize){
goto err;
} else if (sm->sign != sig->sign){
goto err;
} else if (sm->verify_init != sig->verify_init){
goto err;
} else if (sm->verify_update != sig->verify_update){
goto err;
} else if (sm->verify_finalize != sig->verify_finalize){
goto err;
} else if (sm->verify != sig->verify){
goto err;
} else{
ret = 0;
}
}
}
err:
return ret;
}
int ec_sig_ctx_callbacks_sanity_check(const struct ec_sign_context *sig_ctx)
{
int ret;
MUST_HAVE((sig_ctx != NULL) && (sig_ctx->ctx_magic == SIG_SIGN_MAGIC), ret, err);
ret = hash_mapping_callbacks_sanity_check(sig_ctx->h); EG(ret, err);
ret = ec_sig_mapping_callbacks_sanity_check(sig_ctx->sig);
err:
return ret;
}
int ec_verify_ctx_callbacks_sanity_check(const struct ec_verify_context *verify_ctx)
{
int ret;
MUST_HAVE((verify_ctx != NULL) && (verify_ctx->ctx_magic == SIG_VERIFY_MAGIC), ret, err);
ret = hash_mapping_callbacks_sanity_check(verify_ctx->h); EG(ret, err);
ret = ec_sig_mapping_callbacks_sanity_check(verify_ctx->sig);
err:
return ret;
}
int ec_get_sig_len(const ec_params *params, ec_alg_type sig_type,
hash_alg_type hash_type, u8 *siglen)
{
const ec_sig_mapping *sm;
u8 digest_size = 0;
u8 block_size = 0;
int ret;
u8 i;
MUST_HAVE(((params != NULL) && (siglen != NULL)), ret, err);
ret = get_hash_sizes(hash_type, &digest_size, &block_size); EG(ret, err);
ret = -1;
for (i = 0, sm = &ec_sig_maps[i];
sm->type != UNKNOWN_ALG; sm = &ec_sig_maps[++i]) {
if (sm->type == sig_type) {
MUST_HAVE((sm->siglen != NULL), ret, err);
ret = sm->siglen(params->ec_fp.p_bitlen,
params->ec_gen_order_bitlen,
digest_size, block_size, siglen);
break;
}
}
err:
return ret;
}
int _ec_sign_init(struct ec_sign_context *ctx,
const ec_key_pair *key_pair,
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)
{
const ec_sig_mapping *sm;
const hash_mapping *hm;
int ret;
u8 i;
MUST_HAVE((ctx != NULL), ret, err);
ret = key_pair_check_initialized_and_type(key_pair, sig_type); EG(ret, err);
ret = -1;
for (i = 0, hm = &hash_maps[i];
hm->type != UNKNOWN_HASH_ALG; hm = &hash_maps[++i]) {
if (hm->type == hash_type) {
ret = 0;
break;
}
}
if (ret) {
goto err;
}
ret = -1;
for (i = 0, sm = &ec_sig_maps[i];
sm->type != UNKNOWN_ALG; sm = &ec_sig_maps[++i]) {
if ((sm->type == sig_type) && (sm->sign_init != NULL)) {
ret = 0;
break;
}
}
if (ret) {
goto err;
}
#ifdef NO_KNOWN_VECTORS
if (rand) {
MUST_HAVE((rand == nn_get_random_mod), ret, err);
}
rand = nn_get_random_mod;
#else
if (!rand) {
rand = nn_get_random_mod;
}
#endif
ret = hash_mapping_sanity_check(hm); EG(ret, err);
ret = sig_mapping_sanity_check(sm); EG(ret, err);
ret = local_memset(ctx, 0, sizeof(struct ec_sign_context)); EG(ret, err);
ctx->key_pair = key_pair;
ctx->rand = rand;
ctx->h = hm;
ctx->sig = sm;
ctx->adata = adata;
ctx->adata_len = adata_len;
ctx->ctx_magic = SIG_SIGN_MAGIC;
ret = sm->sign_init(ctx);
err:
if (ret && (ctx != NULL)) {
IGNORE_RET_VAL(local_memset(ctx, 0, sizeof(struct ec_sign_context)));
}
return ret;
}
int ec_sign_init(struct ec_sign_context *ctx, const ec_key_pair *key_pair,
ec_alg_type sig_type, hash_alg_type hash_type,
const u8 *adata, u16 adata_len)
{
return _ec_sign_init(ctx, key_pair, NULL, sig_type, hash_type,
adata, adata_len);
}
int ec_sign_update(struct ec_sign_context *ctx, const u8 *chunk, u32 chunklen)
{
int ret;
ret = sig_sign_check_initialized(ctx); EG(ret, err);
ret = sig_mapping_sanity_check(ctx->sig); EG(ret, err);
ret = hash_mapping_sanity_check(ctx->h); EG(ret, err);
ret = ec_sig_ctx_callbacks_sanity_check(ctx); EG(ret, err);
ret = ctx->sig->sign_update(ctx, chunk, chunklen);
err:
if (ret && (ctx != NULL)) {
IGNORE_RET_VAL(local_memset(ctx, 0, sizeof(struct ec_sign_context)));
}
return ret;
}
int ec_sign_finalize(struct ec_sign_context *ctx, u8 *sig, u8 siglen)
{
int ret;
ret = sig_sign_check_initialized(ctx); EG(ret, err);
ret = sig_mapping_sanity_check(ctx->sig); EG(ret, err);
ret = hash_mapping_sanity_check(ctx->h); EG(ret, err);
ret = ec_sig_ctx_callbacks_sanity_check(ctx); EG(ret, err);
ret = ctx->sig->sign_finalize(ctx, sig, siglen);
err:
if (ctx != NULL) {
IGNORE_RET_VAL(local_memset(ctx, 0, sizeof(struct ec_sign_context)));
}
return ret;
}
int generic_ec_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)
{
struct ec_sign_context ctx;
int ret;
ret = _ec_sign_init(&ctx, key_pair, rand, sig_type,
hash_type, adata, adata_len); EG(ret, err);
ret = ec_sign_update(&ctx, m, mlen); EG(ret, err);
ret = ec_sign_finalize(&ctx, sig, siglen);
err:
return ret;
}
int _ec_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)
{
const ec_sig_mapping *sm;
int ret;
ret = get_sig_by_type(sig_type, &sm); EG(ret, err);
MUST_HAVE(((sm != NULL) && (sm->sign != NULL)), ret, err);
ret = sm->sign(sig, siglen, key_pair, m, mlen, rand,
sig_type, hash_type, adata, adata_len);
err:
return ret;
}
int ec_sign(u8 *sig, u8 siglen, const ec_key_pair *key_pair,
const u8 *m, u32 mlen,
ec_alg_type sig_type, hash_alg_type hash_type,
const u8 *adata, u16 adata_len)
{
return _ec_sign(sig, siglen, key_pair, m, mlen,
NULL, sig_type, hash_type, adata, adata_len);
}
int ec_verify_init(struct ec_verify_context *ctx, const ec_pub_key *pub_key,
const u8 *sig, u8 siglen,
ec_alg_type sig_type, hash_alg_type hash_type,
const u8 *adata, u16 adata_len)
{
const ec_sig_mapping *sm;
const hash_mapping *hm;
u8 i;
int ret;
MUST_HAVE((ctx != NULL), ret, err);
ret = pub_key_check_initialized_and_type(pub_key, sig_type); EG(ret, err);
ret = -1;
for (i = 0, hm = &hash_maps[i];
hm->type != UNKNOWN_HASH_ALG; hm = &hash_maps[++i]) {
if (hm->type == hash_type) {
ret = 0;
break;
}
}
if (ret) {
goto err;
}
ret = -1;
for (i = 0, sm = &ec_sig_maps[i];
sm->type != UNKNOWN_ALG; sm = &ec_sig_maps[++i]) {
if ((sm->type == sig_type) && (sm->verify_init != NULL)) {
ret = 0;
break;
}
}
if (ret) {
goto err;
}
ret = hash_mapping_sanity_check(hm); EG(ret, err);
ret = sig_mapping_sanity_check(sm); EG(ret, err);
ret = local_memset(ctx, 0, sizeof(struct ec_verify_context)); EG(ret, err);
ctx->pub_key = pub_key;
ctx->h = hm;
ctx->sig = sm;
ctx->adata = adata;
ctx->adata_len = adata_len;
ctx->ctx_magic = SIG_VERIFY_MAGIC;
ret = sm->verify_init(ctx, sig, siglen);
err:
if (ret && (ctx != NULL)) {
IGNORE_RET_VAL(local_memset(ctx, 0, sizeof(struct ec_verify_context)));
}
return ret;
}
int ec_verify_update(struct ec_verify_context *ctx,
const u8 *chunk, u32 chunklen)
{
int ret;
ret = sig_verify_check_initialized(ctx); EG(ret, err);
ret = sig_mapping_sanity_check(ctx->sig); EG(ret, err);
ret = hash_mapping_sanity_check(ctx->h); EG(ret, err);
ret = ec_verify_ctx_callbacks_sanity_check(ctx); EG(ret, err);
ret = ctx->sig->verify_update(ctx, chunk, chunklen);
err:
if (ret && (ctx != NULL)) {
IGNORE_RET_VAL(local_memset(ctx, 0, sizeof(struct ec_verify_context)));
}
return ret;
}
int ec_verify_finalize(struct ec_verify_context *ctx)
{
int ret;
ret = sig_verify_check_initialized(ctx); EG(ret, err);
ret = sig_mapping_sanity_check(ctx->sig); EG(ret, err);
ret = hash_mapping_sanity_check(ctx->h); EG(ret, err);
ret = ec_verify_ctx_callbacks_sanity_check(ctx); EG(ret, err);
ret = ctx->sig->verify_finalize(ctx);
err:
if (ret && (ctx != NULL)) {
IGNORE_RET_VAL(local_memset(ctx, 0, sizeof(struct ec_verify_context)));
}
return ret;
}
int generic_ec_verify(const u8 *sig, u8 siglen, const ec_pub_key *pub_key,
const u8 *m, u32 mlen,
ec_alg_type sig_type, hash_alg_type hash_type,
const u8 *adata, u16 adata_len)
{
struct ec_verify_context ctx;
int ret;
ret = ec_verify_init(&ctx, pub_key, sig, siglen, sig_type,
hash_type, adata, adata_len); EG(ret, err);
ret = ec_verify_update(&ctx, m, mlen); EG(ret, err);
ret = ec_verify_finalize(&ctx);
err:
return ret;
}
int ec_verify(const u8 *sig, u8 siglen, const ec_pub_key *pub_key,
const u8 *m, u32 mlen,
ec_alg_type sig_type, hash_alg_type hash_type,
const u8 *adata, u16 adata_len)
{
const ec_sig_mapping *sm;
int ret;
ret = get_sig_by_type(sig_type, &sm); EG(ret, err);
MUST_HAVE((sm != NULL) && (sm->verify != NULL), ret, err);
ret = sm->verify(sig, siglen, pub_key, m, mlen, sig_type,
hash_type, adata, adata_len);
err:
return ret;
}
int ec_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)
{
const ec_sig_mapping *sm;
int ret;
ret = get_sig_by_type(sig_type, &sm); EG(ret, err);
MUST_HAVE((sm != NULL) && (sm->verify_batch != NULL), ret, err);
ret = sm->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);
err:
return ret;
}
int ec_structured_sig_import_from_buf(u8 *sig, u32 siglen,
const u8 *out_buf, u32 outlen,
ec_alg_type * sig_type,
hash_alg_type * hash_type,
u8 curve_name[MAX_CURVE_NAME_LEN])
{
u32 metadata_len = (3 * sizeof(u8));
int ret;
MUST_HAVE((out_buf != NULL) && (sig_type != NULL) &&
(hash_type != NULL) && (curve_name != NULL), ret, err);
MUST_HAVE((siglen <= EC_MAX_SIGLEN) && (sig != NULL), ret, err);
MUST_HAVE((outlen <= (siglen + metadata_len)), ret, err);
*sig_type = (ec_alg_type)out_buf[0];
*hash_type = (hash_alg_type)out_buf[1];
ret = ec_get_curve_name_by_type((ec_curve_type) out_buf[2],
curve_name, MAX_CURVE_NAME_LEN); EG(ret, err);
ret = local_memcpy(sig, out_buf + metadata_len, siglen);
err:
return ret;
}
int ec_structured_sig_export_to_buf(const u8 *sig, u32 siglen,
u8 *out_buf, u32 outlen,
ec_alg_type sig_type,
hash_alg_type hash_type,
const u8
curve_name[MAX_CURVE_NAME_LEN])
{
u32 metadata_len = (3 * sizeof(u8));
u32 len;
u8 curve_name_len;
ec_curve_type curve_type;
int ret;
MUST_HAVE((out_buf != NULL) && (curve_name != NULL), ret, err);
MUST_HAVE((siglen <= EC_MAX_SIGLEN) && (sig != NULL), ret, err);
MUST_HAVE(outlen >= (siglen + metadata_len), ret, err);
out_buf[0] = (u8)sig_type;
out_buf[1] = (u8)hash_type;
ret = local_strlen((const char *)curve_name, &len); EG(ret, err);
len += 1;
MUST_HAVE((len < 256), ret, err);
curve_name_len = (u8)len;
ret = ec_get_curve_type_by_name(curve_name, curve_name_len, &curve_type); EG(ret, err);
out_buf[2] = (u8)curve_type;
MUST_HAVE((out_buf[2] != UNKNOWN_CURVE), ret, err);
ret = local_memcpy(out_buf + metadata_len, sig, siglen);
err:
return ret;
}
int unsupported_sign_init(struct ec_sign_context * ctx)
{
FORCE_USED_VAR(ctx);
return -1;
}
int unsupported_sign_update(struct ec_sign_context * ctx,
const u8 *chunk, u32 chunklen)
{
FORCE_USED_VAR(ctx);
FORCE_USED_VAR(chunk);
FORCE_USED_VAR(chunklen);
return -1;
}
int unsupported_sign_finalize(struct ec_sign_context *ctx, u8 *sig, u8 siglen)
{
FORCE_USED_VAR(ctx);
FORCE_USED_VAR(sig);
FORCE_USED_VAR(siglen);
return -1;
}
int unsupported_verify_init(struct ec_verify_context * ctx,
const u8 *sig, u8 siglen)
{
FORCE_USED_VAR(ctx);
FORCE_USED_VAR(sig);
FORCE_USED_VAR(siglen);
return -1;
}
int unsupported_verify_update(struct ec_verify_context * ctx,
const u8 *chunk, u32 chunklen)
{
FORCE_USED_VAR(ctx);
FORCE_USED_VAR(chunk);
FORCE_USED_VAR(chunklen);
return -1;
}
int unsupported_verify_finalize(struct ec_verify_context * ctx)
{
FORCE_USED_VAR(ctx);
return -1;
}
int unsupported_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)
{
FORCE_USED_VAR(s);
FORCE_USED_VAR(pub_keys);
FORCE_USED_VAR(m);
FORCE_USED_VAR(num);
FORCE_USED_VAR(sig_type);
FORCE_USED_VAR(hash_type);
FORCE_USED_VAR(adata);
FORCE_USED_VAR(s_len);
FORCE_USED_VAR(m_len);
FORCE_USED_VAR(adata_len);
FORCE_USED_VAR(scratch_pad_area);
FORCE_USED_VAR(scratch_pad_area_len);
return -1;
}
int is_sign_streaming_mode_supported(ec_alg_type sig_type, int *check)
{
int ret;
const ec_sig_mapping *sig;
MUST_HAVE((check != NULL), ret, err);
ret = get_sig_by_type(sig_type, &sig); EG(ret, err);
MUST_HAVE((sig != NULL), ret, err);
if ((sig->sign_init == unsupported_sign_init) ||
(sig->sign_update == unsupported_sign_update) ||
(sig->sign_finalize == unsupported_sign_finalize)) {
(*check) = 0;
}
else{
(*check) = 1;
}
err:
return ret;
}
int is_verify_streaming_mode_supported(ec_alg_type sig_type, int *check)
{
int ret;
const ec_sig_mapping *sig;
MUST_HAVE((check != NULL), ret, err);
ret = get_sig_by_type(sig_type, &sig); EG(ret, err);
MUST_HAVE((sig != NULL), ret, err);
if ((sig->verify_init == unsupported_verify_init) ||
(sig->verify_update == unsupported_verify_update) ||
(sig->verify_finalize == unsupported_verify_finalize)) {
(*check) = 0;
}
else{
(*check) = 1;
}
err:
return ret;
}
int is_verify_batch_mode_supported(ec_alg_type sig_type, int *check)
{
int ret;
const ec_sig_mapping *sig;
MUST_HAVE((check != NULL), ret, err);
ret = get_sig_by_type(sig_type, &sig); EG(ret, err);
MUST_HAVE((sig != NULL), ret, err);
if (sig->verify_batch == unsupported_verify_batch) {
(*check) = 0;
}
else{
(*check) = 1;
}
err:
return ret;
}
int is_sign_deterministic(ec_alg_type sig_type, int *check)
{
int ret;
const ec_sig_mapping *sig;
MUST_HAVE((check != NULL), ret, err);
ret = get_sig_by_type(sig_type, &sig); EG(ret, err);
MUST_HAVE((sig != NULL), ret, err);
switch(sig_type) {
#if defined(WITH_SIG_EDDSA25519)
case EDDSA25519:
case EDDSA25519CTX:
case EDDSA25519PH:
(*check) = 1;
break;
#endif
#if defined(WITH_SIG_EDDSA448)
case EDDSA448:
case EDDSA448PH:
(*check) = 1;
break;
#endif
#if defined(WITH_SIG_DECDSA)
case DECDSA:
(*check) = 1;
break;
#endif
default:
(*check) = 0;
break;
}
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int _bubble_sort(verify_batch_scratch_pad *elements, u32 num)
{
u32 i, j;
int ret, swapped;
MUST_HAVE((elements != NULL), ret, err);
MUST_HAVE((num >= 1), ret, err);
for(i = 0; i < (num - 1); i++){
swapped = 0;
for(j = 0; j < (num - i - 1); j++){
int check;
u32 indexj, indexj_next;
indexj = elements[j].index;
indexj_next = elements[j + 1].index;
ret = nn_cmp(&elements[indexj].number, &elements[indexj_next].number, &check); EG(ret, err);
if(check < 0){
elements[j].index = indexj_next;
elements[j + 1].index = indexj;
swapped = 1;
}
}
if(!swapped){
break;
}
}
ret = 0;
err:
return ret;
}
int ec_verify_bos_coster(verify_batch_scratch_pad *elements, u32 num, bitcnt_t bits)
{
int ret, check;
u32 i, index0, index1, max_bos_coster_iterations;
MUST_HAVE((elements != NULL), ret, err);
MUST_HAVE((num > 1), ret, err);
MUST_HAVE((num * bits) >= num, ret, err);
MUST_HAVE((num * bits) >= bits, ret, err);
max_bos_coster_iterations = (num * bits);
for(i = 0; i < num; i++){
elements[i].index = i;
}
i = 0;
do {
ret = _bubble_sort(elements, num); EG(ret, err);
index0 = elements[0].index;
index1 = elements[1].index;
ret = prj_pt_add(&elements[index1].point, &elements[index0].point,
&elements[index1].point); EG(ret, err);
ret = nn_cmp(&elements[index0].number, &elements[index1].number, &check);
ret = nn_sub(&elements[index0].number, &elements[index0].number,
&elements[index1].number); EG(ret, err);
i++;
if(i > max_bos_coster_iterations){
ret = -2;
goto err;
}
} while(check > 0);
index0 = elements[0].index;
ret = _prj_pt_unprotected_mult(&elements[index0].point, &elements[index0].number, &elements[index0].point);
err:
return ret;
}