#include <libecc/utils/utils.h>
#include <libecc/external_deps/rand.h>
#include <libecc/external_deps/time.h>
#include <libecc/external_deps/print.h>
#include "ec_self_tests_core.h"
#ifdef WITH_OPENMP_SELF_TESTS
#ifndef WITH_STDLIB
#error "Sorry: no possible self tests parallelization (OpenMP) without stdlib! Please use WITH_STDLIB"
#endif
#include <omp.h>
#include <stdlib.h>
static omp_lock_t global_lock;
static volatile u8 global_lock_initialized = 0;
#define OPENMP_LOCK() do { \
if(!global_lock_initialized){ \
omp_init_lock(&global_lock); \
global_lock_initialized = 1; \
} \
omp_set_lock(&global_lock); \
} while(0)
#define OPENMP_UNLOCK() do { \
omp_unset_lock(&global_lock); \
} while(0)
#define OPENMP_EG(ret, err) do { \
if(ret){ \
ext_printf("OpenMP abort following error ... %s:%d\n", __FILE__, __LINE__); \
exit(-1); \
} \
} while(0)
#else
#define OPENMP_LOCK()
#define OPENMP_UNLOCK()
#define OPENMP_EG(ret, err) do { \
EG(ret, err); \
} while(0)
#endif
ATTRIBUTE_WARN_UNUSED_RET static int ec_gen_import_export_kp(ec_key_pair *kp, const ec_params *params,
const ec_test_case *c)
{
u8 pub_key_buf[EC_STRUCTURED_PUB_KEY_MAX_EXPORT_SIZE];
u8 priv_key_buf[EC_STRUCTURED_PRIV_KEY_MAX_EXPORT_SIZE];
u8 pub_key_buf_len, priv_key_buf_len;
ec_key_pair imported_kp;
int ret;
MUST_HAVE(c != NULL, ret, err);
ret = local_memset(pub_key_buf, 0, sizeof(pub_key_buf)); EG(ret, err);
ret = local_memset(priv_key_buf, 0, sizeof(priv_key_buf)); EG(ret, err);
ret = local_memset(&imported_kp, 0, sizeof(imported_kp)); EG(ret, err);
ret = ec_key_pair_gen(kp, params, c->sig_type);
if (ret) {
ext_printf("Error generating key pair\n");
goto err;
}
pub_key_buf_len = EC_STRUCTURED_PUB_KEY_EXPORT_SIZE(&(kp->pub_key));
priv_key_buf_len = EC_STRUCTURED_PRIV_KEY_EXPORT_SIZE(&(kp->priv_key));
ret = ec_structured_pub_key_export_to_buf(&(kp->pub_key), pub_key_buf,
pub_key_buf_len);
if (ret) {
ext_printf("Error exporting public key\n");
goto err;
}
ret = ec_structured_priv_key_export_to_buf(&(kp->priv_key),
priv_key_buf,
priv_key_buf_len);
if (ret) {
ext_printf("Error exporting private key\n");
goto err;
}
ret = ec_structured_pub_key_import_from_buf(&(imported_kp.pub_key),
params,
pub_key_buf,
pub_key_buf_len,
c->sig_type);
if (ret) {
ext_printf("Error importing public key\n");
goto err;
}
ret = ec_structured_priv_key_import_from_buf(&(imported_kp.priv_key),
params, priv_key_buf,
priv_key_buf_len,
c->sig_type);
if (ret) {
ext_printf("Error importing private key\n");
goto err;
}
ret = 0;
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int random_split_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;
u32 consumed;
ret = local_memset(&ctx, 0, sizeof(ctx)); EG(ret, err);
MUST_HAVE(sig != NULL, ret, err);
MUST_HAVE(key_pair != NULL, ret, err);
MUST_HAVE(m != NULL, ret, err);
ret = _ec_sign_init(&ctx, key_pair, rand, sig_type, hash_type, adata, adata_len);
if (ret) {
goto err;
}
consumed = 0;
while(consumed < mlen){
u32 toconsume = 0;
ret = get_random((u8 *)&toconsume, sizeof(toconsume));
if (ret) {
ext_printf("Error when getting random\n");
goto err;
}
toconsume = (toconsume % (mlen - consumed));
if(((mlen - consumed) == 1) && (toconsume == 0)){
toconsume = 1;
}
ret = ec_sign_update(&ctx, &m[consumed], toconsume);
if (ret) {
goto err;
}
consumed += toconsume;
}
ret = ec_sign_finalize(&ctx, sig, siglen);
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int random_split_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)
{
int ret;
struct ec_verify_context ctx;
u32 consumed;
ret = local_memset(&ctx, 0, sizeof(ctx)); EG(ret, err);
ret = ec_verify_init(&ctx, pub_key, sig, siglen, sig_type, hash_type, adata, adata_len);
if (ret) {
goto err;
}
consumed = 0;
while(consumed < mlen){
u32 toconsume = 0;
ret = get_random((u8 *)&toconsume, sizeof(toconsume));
if (ret) {
ext_printf("Error when getting random\n");
goto err;
}
toconsume = (toconsume % (mlen - consumed));
if(((mlen - consumed) == 1) && (toconsume == 0)){
toconsume = 1;
}
ret = ec_verify_update(&ctx, &m[consumed], toconsume);
if (ret) {
goto err;
}
consumed += toconsume;
}
ret = ec_verify_finalize(&ctx);
err:
return ret;
}
#ifndef MAX_MSG_LEN
#if WORDSIZE == 16
#define MAX_MSG_LEN 1024
#else
#define MAX_MSG_LEN 8192
#endif
#endif
#ifndef MAX_BATCH_SIG_SIZE
#define MAX_BATCH_SIG_SIZE 20
#endif
ATTRIBUTE_WARN_UNUSED_RET static int ec_import_export_test(const ec_test_case *c)
{
ec_key_pair kp;
ec_params params;
int ret, check;
MUST_HAVE(c != NULL, ret, err);
ret = local_memset(&kp, 0, sizeof(kp)); EG(ret, err);
ret = local_memset(¶ms, 0, sizeof(params)); EG(ret, err);
ret = import_params(¶ms, c->ec_str_p);
if (ret) {
ext_printf("Error importing params\n");
goto err;
}
ret = ec_gen_import_export_kp(&kp, ¶ms, c);
if (ret) {
ext_printf("Error at key pair generation/import/export\n");
goto err;
}
{
u16 msglen;
u8 siglen;
u8 msg[MAX_MSG_LEN];
u8 sig[EC_MAX_SIGLEN];
u8 check_type = 0;
u8 sig_tmp1[EC_MAX_SIGLEN];
u8 sig_tmp2[EC_MAX_SIGLEN];
FORCE_USED_VAR(check_type);
ret = ec_get_sig_len(¶ms, c->sig_type, c->hash_type,
(u8 *)&siglen);
if (ret) {
ext_printf("Error computing effective sig size\n");
goto err;
}
ret = get_random((u8 *)&msglen, sizeof(msglen));
if (ret) {
ext_printf("Error when getting random\n");
goto err;
}
msglen = msglen % MAX_MSG_LEN;
ret = get_random(msg, msglen);
if (ret) {
ext_printf("Error when getting random\n");
goto err;
}
ret = _ec_sign(sig, siglen, &kp, msg, msglen,
c->nn_random, c->sig_type, c->hash_type, c->adata, c->adata_len);
if (ret) {
ext_printf("Error when signing\n");
goto err;
}
ret = local_memset(sig_tmp1, 0, sizeof(sig_tmp1)); EG(ret, err);
ret = local_memset(sig_tmp2, 0, sizeof(sig_tmp2)); EG(ret, err);
ret = is_sign_streaming_mode_supported(c->sig_type, &check); EG(ret, err);
if(check){
MUST_HAVE(siglen <= LOCAL_MAX(sizeof(sig_tmp1), sizeof(sig_tmp2)), ret, err);
ret = generic_ec_sign(sig_tmp1, siglen, &kp, msg, msglen,
c->nn_random, c->sig_type, c->hash_type, c->adata, c->adata_len);
if(ret){
ext_printf("Error when signing\n");
ret = -1;
goto err;
}
ret = random_split_ec_sign(sig_tmp2, siglen, &kp, msg, msglen,
c->nn_random, c->sig_type, c->hash_type, c->adata, c->adata_len);
if(ret){
ext_printf("Error when signing\n");
ret = -1;
goto err;
}
ret = is_sign_deterministic(c->sig_type, &check); EG(ret, err);
if(check){
ret = are_equal(sig, sig_tmp1, siglen, &check); EG(ret, err);
if(!check){
ext_printf("Error when signing: streaming and non streaming modes results differ "\
"for deterministic signature scheme!\n");
ret = -1;
goto err;
}
ret = are_equal(sig, sig_tmp2, siglen, &check); EG(ret, err);
if(!check){
ext_printf("Error when signing: streaming and non streaming modes results differ "\
"for deterministic signature scheme!\n");
ret = -1;
goto err;
}
}
}
ret = ec_verify(sig, siglen, &(kp.pub_key), msg, msglen,
c->sig_type, c->hash_type, c->adata, c->adata_len);
if (ret) {
ext_printf("Error when verifying signature\n");
goto err;
}
ret = is_verify_streaming_mode_supported(c->sig_type, &check); EG(ret, err);
if(check){
ret = is_sign_streaming_mode_supported(c->sig_type, &check); EG(ret, err);
if(check){
ret = ec_verify(sig_tmp2, siglen, &(kp.pub_key), msg, msglen,
c->sig_type, c->hash_type, c->adata, c->adata_len);
}
else{
ret = ec_verify(sig, siglen, &(kp.pub_key), msg, msglen,
c->sig_type, c->hash_type, c->adata, c->adata_len);
}
if (ret) {
ext_printf("Error when verifying signature ec_verify\n");
goto err;
}
ret = is_sign_streaming_mode_supported(c->sig_type, &check); EG(ret, err);
if(check){
ret = random_split_ec_verify(sig_tmp1, siglen, &(kp.pub_key), msg, msglen,
c->sig_type, c->hash_type, c->adata, c->adata_len);
}
else{
ret = random_split_ec_verify(sig, siglen, &(kp.pub_key), msg, msglen,
c->sig_type, c->hash_type, c->adata, c->adata_len);
}
if (ret) {
ext_printf("Error when verifying signature random_split_ec_verify\n");
goto err;
}
}
ret = is_verify_batch_mode_supported(c->sig_type, &check); EG(ret, err);
if(check){
const u8 *signatures[] = { sig };
const u8 signatures_len[] = { siglen };
const u8 *messages[] = { msg };
const u32 messages_len[] = { msglen };
const ec_pub_key *pub_keys[] = { &(kp.pub_key) };
const u8 *adatas[] = { c->adata };
const u16 adatas_len[] = { c->adata_len };
ret = ec_verify_batch(signatures, signatures_len, pub_keys, messages, messages_len,
1, c->sig_type, c->hash_type, adatas, adatas_len, NULL, NULL);
if(ret){
ext_printf("Error when verifying signature ec_verify_batch with batch 1\n");
goto err;
}
}
check_type = 0;
#if defined(WITH_SIG_ECDSA)
if(c->sig_type == ECDSA){
check_type = 1;
}
#endif
#if defined(WITH_SIG_DECDSA)
if(c->sig_type == DECDSA){
check_type = 1;
}
#endif
if(check_type){
struct ec_sign_context sig_ctx;
u8 digest[MAX_DIGEST_SIZE] = { 0 };
u8 digestlen;
ec_pub_key pub_key1;
ec_pub_key pub_key2;
nn_src_t cofactor = &(params.ec_gen_cofactor);
int cofactorisone;
const u8 *input[2] = { (const u8*)msg , NULL};
u32 ilens[2] = { msglen , 0 };
ret = ec_sign_init(&sig_ctx, &kp, c->sig_type, c->hash_type, c->adata, c->adata_len); EG(ret, err);
ret = hash_mapping_callbacks_sanity_check(sig_ctx.h); EG(ret, err);
ret = sig_ctx.h->hfunc_scattered(input, ilens, digest); EG(ret, err);
digestlen = sig_ctx.h->digest_size;
MUST_HAVE(digestlen <= sizeof(digest), ret, err);
ret = nn_isone(cofactor, &cofactorisone); EG(ret, err);
ret = __ecdsa_public_key_from_sig(&pub_key1, &pub_key2, ¶ms, sig, siglen, digest, digestlen, c->sig_type);
if(ret){
ret = 0;
check = -1;
goto pubkey_recovery_warning;
}
ret = prj_pt_cmp(&(pub_key1.y), &(kp.pub_key.y), &check); EG(ret, err);
if(check){
ret = prj_pt_cmp(&(pub_key2.y), &(kp.pub_key.y), &check); EG(ret, err);
}
pubkey_recovery_warning:
if(check && cofactorisone){
OPENMP_LOCK();
ext_printf("[~] Warning: ECDSA recovered public key differs from real one ...");
ext_printf("This can happen with very low probability. Please check the trace:\n");
pub_key_print("pub_key1", &pub_key1);
pub_key_print("pub_key2", &pub_key2);
pub_key_print("pub_key", &(kp.pub_key));
buf_print("digest", digest, digestlen);
buf_print("sig", sig, siglen);
OPENMP_UNLOCK();
}
}
#ifdef USE_CRYPTOFUZZ
check_type = 0;
#if defined(WITH_SIG_ECDSA)
if(c->sig_type == ECDSA){
check_type = 1;
}
#endif
#if defined(WITH_SIG_ECGDSA)
if(c->sig_type == ECGDSA){
check_type = 1;
}
#endif
#if defined(WITH_SIG_ECRDSA)
if(c->sig_type == ECRDSA){
check_type = 1;
}
#endif
if(check_type){
struct ec_sign_context sig_ctx;
struct ec_verify_context verif_ctx;
u8 digest[MAX_DIGEST_SIZE] = { 0 };
u8 digestlen;
const u8 *input[2] = { (const u8*)msg , NULL};
u32 ilens[2] = { msglen , 0 };
ret = ec_sign_init(&sig_ctx, &kp, c->sig_type, c->hash_type, c->adata, c->adata_len); EG(ret, err);
ret = hash_mapping_callbacks_sanity_check(sig_ctx.h); EG(ret, err);
ret = sig_ctx.h->hfunc_scattered(input, ilens, digest); EG(ret, err);
digestlen = sig_ctx.h->digest_size;
MUST_HAVE(digestlen <= sizeof(digest), ret, err);
#if defined(WITH_SIG_ECDSA)
if(c->sig_type == ECDSA){
ret = ecdsa_sign_raw(&sig_ctx, digest, digestlen, sig, siglen, NULL, 0); EG(ret, err);
}
#endif
#if defined(WITH_SIG_ECGDSA)
if(c->sig_type == ECGDSA){
ret = ecgdsa_sign_raw(&sig_ctx, digest, digestlen, sig, siglen, NULL, 0); EG(ret, err);
}
#endif
#if defined(WITH_SIG_ECRDSA)
if(c->sig_type == ECRDSA){
ret = ecrdsa_sign_raw(&sig_ctx, digest, digestlen, sig, siglen, NULL, 0); EG(ret, err);
}
#endif
ret = ec_verify_init(&verif_ctx, &(kp.pub_key), sig, siglen, c->sig_type, c->hash_type, c->adata, c->adata_len); EG(ret, err);
#if defined(WITH_SIG_ECDSA)
if(c->sig_type == ECDSA){
ret = ecdsa_verify_raw(&verif_ctx, digest, digestlen); EG(ret, err);
}
#endif
#if defined(WITH_SIG_ECGDSA)
if(c->sig_type == ECGDSA){
ret = ecgdsa_verify_raw(&verif_ctx, digest, digestlen); EG(ret, err);
}
#endif
#if defined(WITH_SIG_ECRDSA)
if(c->sig_type == ECRDSA){
ret = ecrdsa_verify_raw(&verif_ctx, digest, digestlen); EG(ret, err);
}
#endif
}
#endif
}
ret = is_verify_batch_mode_supported(c->sig_type, &check); EG(ret, err);
if(check){
u16 msglen;
u8 siglen;
ec_key_pair keypairs[MAX_BATCH_SIG_SIZE];
const ec_pub_key *pubkeys[MAX_BATCH_SIG_SIZE];
u8 msg[MAX_BATCH_SIG_SIZE * MAX_MSG_LEN];
const u8 *messages[MAX_BATCH_SIG_SIZE];
u32 messages_len[MAX_BATCH_SIG_SIZE];
u8 sig[MAX_BATCH_SIG_SIZE * EC_MAX_SIGLEN];
const u8 *signatures[MAX_BATCH_SIG_SIZE];
u8 signatures_len[MAX_BATCH_SIG_SIZE];
const u8 *adata[MAX_BATCH_SIG_SIZE];
u16 adata_len[MAX_BATCH_SIG_SIZE];
u8 check_type = 0;
u32 num_batch, i, current;
FORCE_USED_VAR(check_type);
gen_num_batch:
ret = get_random((u8 *)&num_batch, sizeof(num_batch));
if(ret){
ext_printf("Error when getting random\n");
goto err;
}
num_batch = (num_batch % MAX_BATCH_SIG_SIZE);
if(num_batch == 0){
goto gen_num_batch;
}
ret = ec_get_sig_len(¶ms, c->sig_type, c->hash_type,
(u8 *)&siglen);
if (ret) {
ext_printf("Error computing effective sig size\n");
goto err;
}
current = 0;
for(i = 0; i < num_batch; i++){
ret = ec_gen_import_export_kp(&keypairs[i], ¶ms, c);
pubkeys[i] = &(keypairs[i].pub_key);
if (ret) {
ext_printf("Error at key pair generation/import/export\n");
goto err;
}
ret = get_random((u8 *)&msglen, sizeof(msglen));
if (ret) {
ext_printf("Error when getting random\n");
goto err;
}
msglen = msglen % MAX_MSG_LEN;
messages_len[i] = msglen;
messages[i] = &msg[current];
ret = get_random(&msg[current], msglen);
if (ret) {
ext_printf("Error when getting random\n");
goto err;
}
current += msglen;
signatures[i] = &sig[i * siglen];
signatures_len[i] = siglen;
adata_len[i] = c->adata_len;
adata[i] = c->adata;
ret = _ec_sign(&sig[i * siglen], siglen, &keypairs[i], messages[i], messages_len[i],
c->nn_random, c->sig_type, c->hash_type, c->adata, c->adata_len);
if (ret) {
ext_printf("Error when signing\n");
goto err;
}
}
ret = ec_verify_batch(signatures, signatures_len, pubkeys, messages, messages_len,
num_batch, c->sig_type, c->hash_type, adata, adata_len, NULL, NULL);
if(ret){
ext_printf("Error when verifying signature ec_verify_batch no memory for batch size %" PRIu32 "\n", num_batch);
goto err;
}
{
u32 scratch_pad_area_len = 0;
verify_batch_scratch_pad scratch_pad_area[(2 * MAX_BATCH_SIG_SIZE) + 1];
ret = ec_verify_batch(signatures, signatures_len, pubkeys, messages, messages_len,
num_batch, c->sig_type, c->hash_type, adata, adata_len, NULL, &scratch_pad_area_len);
if(ret){
ext_printf("Error when getting scratch_pad_area length for ec_verify_batch optimized for batch size %" PRIu32 "\n", num_batch);
goto err;
}
MUST_HAVE((scratch_pad_area_len <= sizeof(scratch_pad_area)), ret, err);
scratch_pad_area_len = sizeof(scratch_pad_area);
ret = ec_verify_batch(signatures, signatures_len, pubkeys, messages, messages_len,
num_batch, c->sig_type, c->hash_type, adata, adata_len, scratch_pad_area, &scratch_pad_area_len);
if(ret){
ext_printf("Error when verifying signature ec_verify_batch optimized for batch size %" PRIu32 "\n", num_batch);
goto err;
}
}
}
ret = 0;
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int ec_test_sign(u8 *sig, u8 siglen, ec_key_pair *kp,
const ec_test_case *c)
{
int ret, check;
MUST_HAVE(sig != NULL, ret, err);
MUST_HAVE(c != NULL, ret, err);
ret = _ec_sign(sig, siglen, kp, (const u8 *)(c->msg), c->msglen,
c->nn_random, c->sig_type, c->hash_type, c->adata, c->adata_len); EG(ret, err);
ret = is_sign_streaming_mode_supported(c->sig_type, &check); EG(ret, err);
if(check){
u8 sig_tmp[EC_MAX_SIGLEN];
MUST_HAVE(siglen <= sizeof(sig_tmp), ret, err);
ret = generic_ec_sign(sig_tmp, siglen, kp, (const u8 *)(c->msg), c->msglen,
c->nn_random, c->sig_type, c->hash_type, c->adata, c->adata_len); EG(ret, err);
ret = are_equal(sig, sig_tmp, siglen, &check); EG(ret, err);
if(!check){
ret = -1;
goto err;
}
ret = random_split_ec_sign(sig_tmp, siglen, kp, (const u8 *)(c->msg), c->msglen,
c->nn_random, c->sig_type, c->hash_type, c->adata, c->adata_len); EG(ret, err);
ret = are_equal(sig, sig_tmp, siglen, &check); EG(ret, err);
if(!check){
ret = -1;
goto err;
}
}
ret = 0;
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int ec_test_verify(u8 *sig, u8 siglen, const ec_pub_key *pub_key,
const ec_test_case *c)
{
int ret, check;
MUST_HAVE(sig != NULL, ret, err);
MUST_HAVE(c != NULL, ret, err);
ret = ec_verify(sig, siglen, pub_key, (const u8 *)(c->msg), c->msglen,
c->sig_type, c->hash_type, c->adata, c->adata_len);
if(ret){
ret = -1;
goto err;
}
ret = is_verify_streaming_mode_supported(c->sig_type, &check); EG(ret, err);
if(check){
ret = ec_verify(sig, siglen, pub_key, (const u8 *)(c->msg), c->msglen,
c->sig_type, c->hash_type, c->adata, c->adata_len);
if(ret){
ret = -1;
goto err;
}
ret = random_split_ec_verify(sig, siglen, pub_key, (const u8 *)(c->msg), c->msglen,
c->sig_type, c->hash_type, c->adata, c->adata_len);
if(ret){
ret = -1;
goto err;
}
}
ret = is_verify_batch_mode_supported(c->sig_type, &check); EG(ret, err);
if(check){
const u8 *signatures[] = { sig };
const u8 signatures_len[] = { siglen };
const u8 *messages[] = { (const u8*)c->msg };
const u32 messages_len[] = { c->msglen };
const ec_pub_key *pub_keys[] = { pub_key };
const u8 *adatas[] = { c->adata };
const u16 adatas_len[] = { c->adata_len };
ret = ec_verify_batch(signatures, signatures_len, pub_keys, messages, messages_len,
1, c->sig_type, c->hash_type, adatas, adatas_len, NULL, NULL);
if(ret){
ret = -1;
goto err;
}
}
ret = 0;
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int ec_sig_known_vector_tests_one(const ec_test_case *c)
{
test_err_kind failed_test = TEST_KEY_IMPORT_ERROR;
u8 sig[EC_MAX_SIGLEN];
ec_params params;
ec_key_pair kp;
u8 siglen;
int ret;
int check = 0;
MUST_HAVE((c != NULL), ret, err);
ret = local_memset(&kp, 0, sizeof(kp)); EG(ret, err);
ret = local_memset(¶ms, 0, sizeof(params)); EG(ret, err);
ret = local_memset(sig, 0, sizeof(sig)); EG(ret, err);
ret = import_params(¶ms, c->ec_str_p);
if (ret) {
ext_printf("Error importing params\n");
goto err;
}
#if defined(WITH_SIG_EDDSA25519) || defined(WITH_SIG_EDDSA448)
#if defined(WITH_SIG_EDDSA25519) && defined(WITH_SIG_EDDSA448)
if((c->sig_type == EDDSA25519) || (c->sig_type == EDDSA25519CTX) || (c->sig_type == EDDSA25519PH) || \
(c->sig_type == EDDSA448) || (c->sig_type == EDDSA448PH)){
#endif
#if defined(WITH_SIG_EDDSA25519) && !defined(WITH_SIG_EDDSA448)
if((c->sig_type == EDDSA25519) || (c->sig_type == EDDSA25519CTX) || (c->sig_type == EDDSA25519PH)){
#endif
#if !defined(WITH_SIG_EDDSA25519) && defined(WITH_SIG_EDDSA448)
if((c->sig_type == EDDSA448) || (c->sig_type == EDDSA448PH)){
#endif
if(eddsa_import_key_pair_from_priv_key_buf(&kp, c->priv_key, c->priv_key_len, ¶ms, c->sig_type)){
ret = -1;
failed_test = TEST_KEY_IMPORT_ERROR;
goto err;
}
}
else
#endif
{
ret = ec_key_pair_import_from_priv_key_buf(&kp, ¶ms, c->priv_key,
c->priv_key_len,
c->sig_type);
if (ret) {
failed_test = TEST_KEY_IMPORT_ERROR;
goto err;
}
}
siglen = c->exp_siglen;
ret = ec_test_sign(sig, siglen, &kp, c);
if (ret) {
failed_test = TEST_SIG_ERROR;
goto err;
}
ret = are_equal(sig, c->exp_sig, siglen, &check); EG(ret, err);
if (!check) {
ret = -1;
failed_test = TEST_SIG_COMP_ERROR;
goto err;
}
ret = ec_test_verify(sig, siglen, &(kp.pub_key), c);
if (ret) {
failed_test = TEST_VERIF_ERROR;
goto err;
}
check = 0;
#if defined(WITH_SIG_ECDSA)
if(c->sig_type == ECDSA){
check = 1;
}
#endif
#if defined(WITH_SIG_DECDSA)
if(c->sig_type == DECDSA){
check = 1;
}
#endif
if(check){
struct ec_sign_context sig_ctx;
u8 digest[MAX_DIGEST_SIZE] = { 0 };
u8 digestlen;
ec_pub_key pub_key1;
ec_pub_key pub_key2;
nn_src_t cofactor = &(params.ec_gen_cofactor);
int cofactorisone;
const u8 *input[2] = { (const u8*)(c->msg) , NULL};
u32 ilens[2] = { c->msglen , 0 };
ret = ec_sign_init(&sig_ctx, &kp, c->sig_type, c->hash_type, c->adata, c->adata_len); EG(ret, err);
ret = hash_mapping_callbacks_sanity_check(sig_ctx.h); EG(ret, err);
ret = sig_ctx.h->hfunc_scattered(input, ilens, digest); EG(ret, err);
digestlen = sig_ctx.h->digest_size;
MUST_HAVE(digestlen <= sizeof(digest), ret, err);
ret = nn_isone(cofactor, &cofactorisone); EG(ret, err);
ret = __ecdsa_public_key_from_sig(&pub_key1, &pub_key2, ¶ms, sig, siglen, digest, digestlen, c->sig_type);
if(ret){
ret = 0;
check = -1;
goto pubkey_recovery_warning;
}
ret = prj_pt_cmp(&(pub_key1.y), &(kp.pub_key.y), &check); EG(ret, err);
if(check){
ret = prj_pt_cmp(&(pub_key2.y), &(kp.pub_key.y), &check); EG(ret, err);
}
pubkey_recovery_warning:
if(check && cofactorisone){
OPENMP_LOCK();
ext_printf("[~] Warning: ECDSA recovered public key differs from real one ...");
ext_printf("This can happen with very low probability. Please check the trace:\n");
pub_key_print("pub_key1", &pub_key1);
pub_key_print("pub_key2", &pub_key2);
pub_key_print("pub_key", &(kp.pub_key));
buf_print("digest", digest, digestlen);
buf_print("sig", sig, siglen);
OPENMP_UNLOCK();
}
}
#ifdef USE_CRYPTOFUZZ
check = 0;
#if defined(WITH_SIG_ECDSA)
if(c->sig_type == ECDSA){
check = 1;
}
#endif
#if defined(WITH_SIG_ECGDSA)
if(c->sig_type == ECGDSA){
check = 1;
}
#endif
#if defined(WITH_SIG_ECRDSA)
if(c->sig_type == ECRDSA){
check = 1;
}
#endif
if(check){
struct ec_sign_context sig_ctx;
struct ec_verify_context verif_ctx;
u8 digest[MAX_DIGEST_SIZE] = { 0 };
u8 digestlen;
const u8 *input[2] = { (const u8*)(c->msg) , NULL};
u32 ilens[2] = { c->msglen , 0 };
u8 nonce[LOCAL_MIN(255, BIT_LEN_WORDS(NN_MAX_BIT_LEN) * (WORDSIZE / 8))] = { 0 };
nn n_nonce;
bitcnt_t q_bit_len;
u8 noncelen;
if(ec_sign_init(&sig_ctx, &kp, c->sig_type, c->hash_type, c->adata, c->adata_len)){
ret = -1;
failed_test = TEST_SIG_ERROR;
goto err;
}
if(hash_mapping_callbacks_sanity_check(sig_ctx.h)){
ret = -1;
failed_test = TEST_SIG_ERROR;
goto err;
}
ret = sig_ctx.h->hfunc_scattered(input, ilens, digest); EG(ret, err);
digestlen = sig_ctx.h->digest_size;
MUST_HAVE(digestlen <= sizeof(digest), ret, err);
q_bit_len = kp.priv_key.params->ec_gen_order_bitlen;
if(c->nn_random(&n_nonce, &(kp.priv_key.params->ec_gen_order))){
ret = -1;
failed_test = TEST_SIG_ERROR;
goto err;
}
ret = nn_export_to_buf(nonce, (u16)BYTECEIL(q_bit_len), &n_nonce); EG(ret, err);
if((unsigned int)BYTECEIL(q_bit_len) > sizeof(nonce)){
ret = -1;
failed_test = TEST_SIG_ERROR;
goto err;
}
noncelen = (u8)(BYTECEIL(q_bit_len));
FORCE_USED_VAR(noncelen);
#if LOCAL_MIN(255, BIT_LEN_WORDS(NN_MAX_BIT_LEN) * (WORDSIZE / 8)) < 255
MUST_HAVE((u32)noncelen <= sizeof(nonce), ret, err);
#endif
#if defined(WITH_SIG_ECDSA)
if(c->sig_type == ECDSA){
if(ecdsa_sign_raw(&sig_ctx, digest, digestlen, sig, siglen, nonce, noncelen)){
ret = -1;
failed_test = TEST_SIG_ERROR;
goto err;
}
}
#endif
#if defined(WITH_SIG_ECGDSA)
if(c->sig_type == ECGDSA){
if(ecgdsa_sign_raw(&sig_ctx, digest, digestlen, sig, siglen, nonce, noncelen)){
ret = -1;
failed_test = TEST_SIG_ERROR;
goto err;
}
}
#endif
#if defined(WITH_SIG_ECRDSA)
if(c->sig_type == ECRDSA){
if(ecrdsa_sign_raw(&sig_ctx, digest, digestlen, sig, siglen, nonce, noncelen)){
ret = -1;
failed_test = TEST_SIG_ERROR;
goto err;
}
}
#endif
ret = are_equal(sig, c->exp_sig, siglen, &check); EG(ret, err);
if (!check) {
failed_test = TEST_SIG_COMP_ERROR;
ret = -1;
goto err;
}
if(ec_verify_init(&verif_ctx, &(kp.pub_key), sig, siglen, c->sig_type, c->hash_type, c->adata, c->adata_len)){
ret = -1;
failed_test = TEST_VERIF_ERROR;
goto err;
}
#if defined(WITH_SIG_ECDSA)
if(c->sig_type == ECDSA){
if(ecdsa_verify_raw(&verif_ctx, digest, digestlen)){
ret = -1;
failed_test = TEST_VERIF_ERROR;
goto err;
}
}
#endif
#if defined(WITH_SIG_ECGDSA)
if(c->sig_type == ECGDSA){
if(ecgdsa_verify_raw(&verif_ctx, digest, digestlen)){
ret = -1;
failed_test = TEST_VERIF_ERROR;
goto err;
}
}
#endif
#if defined(WITH_SIG_ECRDSA)
if(c->sig_type == ECRDSA){
if(ecrdsa_verify_raw(&verif_ctx, digest, digestlen)){
ret = -1;
failed_test = TEST_VERIF_ERROR;
goto err;
}
}
#endif
}
#endif
ret = 0;
err:
if (ret) {
u32 ret_;
ret = encode_error_value(c, failed_test, &ret_); EG(ret, err);
ret = (int)ret_;
}
return ret;
}
#if defined(WITH_ECCCDH) || defined(WITH_X25519) || defined(WITH_X448)
ATTRIBUTE_WARN_UNUSED_RET static int ecdh_known_vector_tests_one(const ecdh_test_case *c)
{
test_err_kind failed_test = TEST_KEY_IMPORT_ERROR;
ec_params params;
ec_key_pair kp;
int ret, check;
MUST_HAVE((c != NULL), ret, err);
ret = local_memset(&kp, 0, sizeof(kp)); EG(ret, err);
ret = local_memset(¶ms, 0, sizeof(params)); EG(ret, err);
ret = import_params(¶ms, c->ec_str_p);
if (ret) {
ext_printf("Error importing params\n");
goto err;
}
switch(c->ecdh_type){
#if defined(WITH_ECCCDH)
case ECCCDH:{
u8 serialized_pub_key[EC_PUB_KEY_MAX_SIZE];
u8 serialized_pub_key_len;
u8 shared_secret[EC_PUB_KEY_MAX_SIZE];
u8 shared_secret_len;
ret = local_memset(serialized_pub_key, 0, sizeof(serialized_pub_key)); EG(ret, err);
ret = local_memset(shared_secret, 0, sizeof(shared_secret)); EG(ret, err);
ret = ecccdh_import_key_pair_from_priv_key_buf(&kp, ¶ms, c->our_priv_key,
c->our_priv_key_len);
if (ret) {
failed_test = TEST_KEY_IMPORT_ERROR;
ret = -1;
goto err;
}
ret = ecccdh_serialized_pub_key_size(¶ms, &serialized_pub_key_len); EG(ret, err);
MUST_HAVE((sizeof(serialized_pub_key) >= serialized_pub_key_len), ret, err);
ret = ecccdh_serialize_pub_key(&(kp.pub_key), serialized_pub_key, serialized_pub_key_len);
if (ret) {
failed_test = TEST_ECDH_ERROR;
ret = -1;
goto err;
}
MUST_HAVE((serialized_pub_key_len == c->exp_our_pub_key_len), ret, err);
ret = are_equal(serialized_pub_key, c->exp_our_pub_key, serialized_pub_key_len, &check); EG(ret, err);
if (!check) {
failed_test = TEST_ECDH_COMP_ERROR;
ret = -1;
goto err;
}
ret = ecccdh_shared_secret_size(¶ms, &shared_secret_len); EG(ret, err);
MUST_HAVE((sizeof(shared_secret) >= shared_secret_len), ret, err);
ret = ecccdh_derive_secret(&(kp.priv_key), c->peer_pub_key, c->peer_pub_key_len, shared_secret, shared_secret_len);
if (ret) {
failed_test = TEST_ECDH_ERROR;
ret = -1;
goto err;
}
MUST_HAVE((shared_secret_len == c->exp_shared_secret_len), ret, err);
ret = are_equal(shared_secret, c->exp_shared_secret, shared_secret_len, &check); EG(ret, err);
if (!check) {
failed_test = TEST_ECDH_COMP_ERROR;
ret = -1;
goto err;
}
break;
}
#endif
#if defined(WITH_X25519)
case X25519:{
u8 pub_key[X25519_SIZE];
u8 shared_secret[X25519_SIZE];
ret = local_memset(pub_key, 0, sizeof(pub_key)); EG(ret, err);
ret = local_memset(shared_secret, 0, sizeof(shared_secret)); EG(ret, err);
MUST_HAVE((c->our_priv_key_len == X25519_SIZE), ret, err);
ret = x25519_init_pub_key(c->our_priv_key, pub_key);
if (ret) {
failed_test = TEST_KEY_IMPORT_ERROR;
ret = -1;
goto err;
}
MUST_HAVE((c->exp_our_pub_key_len == X25519_SIZE), ret, err);
ret = are_equal(pub_key, c->exp_our_pub_key, X25519_SIZE, &check); EG(ret, err);
if (!check) {
failed_test = TEST_ECDH_COMP_ERROR;
ret = -1;
goto err;
}
MUST_HAVE((c->peer_pub_key_len == X25519_SIZE), ret, err);
ret = x25519_derive_secret(c->our_priv_key, c->peer_pub_key, shared_secret);
if (ret) {
failed_test = TEST_ECDH_ERROR;
ret = -1;
goto err;
}
MUST_HAVE((c->exp_shared_secret_len == X25519_SIZE), ret, err);
ret = are_equal(shared_secret, c->exp_shared_secret, X25519_SIZE, &check); EG(ret, err);
if (!check) {
failed_test = TEST_ECDH_COMP_ERROR;
ret = -1;
goto err;
}
break;
}
#endif
#if defined(WITH_X448)
case X448:{
u8 pub_key[X448_SIZE];
u8 shared_secret[X448_SIZE];
ret = local_memset(pub_key, 0, sizeof(pub_key)); EG(ret, err);
ret = local_memset(shared_secret, 0, sizeof(shared_secret)); EG(ret, err);
MUST_HAVE((c->our_priv_key_len == X448_SIZE), ret, err);
ret = x448_init_pub_key(c->our_priv_key, pub_key);
if (ret) {
failed_test = TEST_KEY_IMPORT_ERROR;
ret = -1;
goto err;
}
MUST_HAVE((c->exp_our_pub_key_len == X448_SIZE), ret, err);
ret = are_equal(pub_key, c->exp_our_pub_key, X448_SIZE, &check); EG(ret, err);
if (!check) {
failed_test = TEST_ECDH_COMP_ERROR;
ret = -1;
goto err;
}
MUST_HAVE((c->peer_pub_key_len == X448_SIZE), ret, err);
ret = x448_derive_secret(c->our_priv_key, c->peer_pub_key, shared_secret);
if (ret) {
failed_test = TEST_ECDH_ERROR;
ret = -1;
goto err;
}
MUST_HAVE((c->exp_shared_secret_len == X448_SIZE), ret, err);
ret = are_equal(shared_secret, c->exp_shared_secret, X448_SIZE, &check); EG(ret, err);
if (!check) {
failed_test = TEST_ECDH_COMP_ERROR;
ret = -1;
goto err;
}
break;
}
#endif
default:{
ext_printf("Error: not an ECDH test\n");
ret = -1;
goto err;
}
}
err:
if (ret) {
u32 ret_;
ret = ecdh_encode_error_value(c, failed_test, &ret_); EG(ret, err);
ret = (int)ret_;
}
return ret;
}
#endif
ATTRIBUTE_WARN_UNUSED_RET int perform_known_test_vectors_test(const char *sig, const char *hash, const char *curve)
{
unsigned int i;
int ret = 0;
ext_printf("======= Known test vectors test =================\n");
#ifdef WITH_OPENMP_SELF_TESTS
#pragma omp parallel
#pragma omp for schedule(static, 1) nowait
#endif
for (i = 0; i < EC_FIXED_VECTOR_NUM_TESTS; i++) {
int check;
const ec_test_case *cur_test;
cur_test = ec_fixed_vector_tests[i];
if(cur_test == NULL){
continue;
}
if(cur_test->sig_type == UNKNOWN_ALG){
continue;
}
if(sig != NULL){
const ec_sig_mapping *sig_map;
ret = get_sig_by_type(cur_test->sig_type, &sig_map); OPENMP_EG(ret, err);
if(sig_map == NULL){
continue;
}
ret = are_str_equal(sig_map->name, sig, &check); OPENMP_EG(ret, err);
if(!check){
continue;
}
}
if(hash != NULL){
const hash_mapping *hash_map;
ret = get_hash_by_type(cur_test->hash_type, &hash_map); OPENMP_EG(ret, err);
if(hash_map == NULL){
continue;
}
ret = are_str_equal(hash_map->name, hash, &check); OPENMP_EG(ret, err);
if(!check){
continue;
}
}
if(curve != NULL){
if(cur_test->ec_str_p == NULL){
continue;
}
ret = are_str_equal((const char*)cur_test->ec_str_p->name->buf, curve, &check); OPENMP_EG(ret, err);
if(!check){
continue;
}
}
ret = ec_sig_known_vector_tests_one(cur_test);
OPENMP_LOCK();
ext_printf("[%s] %30s selftests: known test vectors "
"sig/verif %s\n", ret ? "-" : "+",
cur_test->name, ret ? "failed" : "ok");
check = 0;
#if defined(WITH_SIG_ECDSA)
if(cur_test->sig_type == ECDSA){
check = 1;
}
#endif
#if defined(WITH_SIG_DECDSA)
if(cur_test->sig_type == DECDSA){
check = 1;
}
#endif
if(check){
ext_printf("\t(ECDSA public key recovery also checked!)\n");
}
#ifdef USE_CRYPTOFUZZ
#if defined(WITH_SIG_ECDSA)
if(cur_test->sig_type == ECDSA){
ext_printf("\t(RAW ECDSA for CRYPTOFUZZ also checked!)\n");
}
#endif
#if defined(WITH_SIG_ECGDSA)
if(cur_test->sig_type == ECGDSA){
ext_printf("\t(RAW ECGDSA for CRYPTOFUZZ also checked!)\n");
}
#endif
#if defined(WITH_SIG_ECRDSA)
if(cur_test->sig_type == ECRDSA){
ext_printf("\t(RAW ECRDSA for CRYPTOFUZZ also checked!)\n");
}
#endif
#endif
OPENMP_UNLOCK();
OPENMP_EG(ret, err);
}
#if defined(WITH_ECCCDH) || defined(WITH_X25519) || defined(WITH_X448)
if((sig == NULL) && (hash == NULL)){
#ifdef WITH_OPENMP_SELF_TESTS
#pragma omp parallel
#pragma omp for schedule(static, 1) nowait
#endif
for (i = 0; i < ECDH_FIXED_VECTOR_NUM_TESTS; i++) {
int check;
const ecdh_test_case *ecdh_cur_test;
ecdh_cur_test = ecdh_fixed_vector_tests[i];
if(ecdh_cur_test == NULL){
continue;
}
if(ecdh_cur_test->ecdh_type == UNKNOWN_ALG){
continue;
}
if(curve != NULL){
if(ecdh_cur_test->ec_str_p == NULL){
continue;
}
ret = are_str_equal((const char*)ecdh_cur_test->ec_str_p->name->buf, curve, &check); OPENMP_EG(ret, err);
if(!check){
continue;
}
}
ret = ecdh_known_vector_tests_one(ecdh_cur_test);
OPENMP_LOCK();
ext_printf("[%s] %30s selftests: known test vectors "
"ecdh %s\n", ret ? "-" : "+",
ecdh_cur_test->name, ret ? "failed" : "ok");
OPENMP_EG(ret, err);
OPENMP_UNLOCK();
}
}
#endif
#ifndef WITH_OPENMP_SELF_TESTS
err:
#endif
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int rand_sig_verif_test_one(const ec_sig_mapping *sig,
const hash_mapping *hash,
const ec_mapping *ec)
{
char test_name[MAX_CURVE_NAME_LEN + MAX_HASH_ALG_NAME_LEN +
MAX_SIG_ALG_NAME_LEN + 2];
const unsigned int tn_size = sizeof(test_name) - 1;
const char *crv_name;
ec_test_case t;
int ret, check;
u32 len;
#if defined(WITH_SIG_EDDSA25519) || defined(WITH_SIG_SM2) || defined(WITH_SIG_BIGN) || defined(WITH_SIG_DBIGN)
u8 rand_adata[255];
ret = local_memset(rand_adata, 0, sizeof(rand_adata)); EG(ret, err);
#endif
ret = local_memset(test_name, 0, sizeof(test_name)); EG(ret, err);
MUST_HAVE((sig != NULL), ret, err);
MUST_HAVE((hash != NULL), ret, err);
MUST_HAVE((ec != NULL), ret, err);
crv_name = (const char *)PARAM_BUF_PTR((ec->params)->name);
ret = local_memset(test_name, 0, tn_size + 1); EG(ret, err);
ret = local_strncpy(test_name, sig->name, tn_size); EG(ret, err);
ret = local_strlen(test_name, &len); EG(ret, err);
ret = local_strncat(test_name, "-", tn_size - len); EG(ret, err);
ret = local_strlen(test_name, &len); EG(ret, err);
ret = local_strncat(test_name, hash->name, tn_size - len); EG(ret, err);
ret = local_strlen(test_name, &len); EG(ret, err);
ret = local_strncat(test_name, "/", tn_size - len); EG(ret, err);
ret = local_strlen(test_name, &len); EG(ret, err);
ret = local_strncat(test_name, crv_name, tn_size - len); EG(ret, err);
t.name = test_name;
t.ec_str_p = ec->params;
t.priv_key = NULL;
t.priv_key_len = 0;
t.nn_random = NULL;
t.hash_type = hash->type;
t.msg = NULL;
t.msglen = 0;
t.sig_type = sig->type;
t.exp_sig = NULL;
t.exp_siglen = 0;
#if defined(WITH_SIG_EDDSA25519) || defined(WITH_SIG_SM2)
#if defined(WITH_SIG_EDDSA25519) && !defined(WITH_SIG_SM2)
if(sig->type == EDDSA25519CTX)
#endif
#if !defined(WITH_SIG_EDDSA25519) && defined(WITH_SIG_SM2)
if(sig->type == SM2)
#endif
#if defined(WITH_SIG_EDDSA25519) && defined(WITH_SIG_SM2)
if((sig->type == EDDSA25519CTX) || (sig->type == SM2))
#endif
{
u8 rand_len = 0;
ret = get_random((u8 *)&rand_len, sizeof(rand_len)); EG(ret, err);
ret = get_random((u8 *)rand_adata, (u16)(rand_len % sizeof(rand_adata))); EG(ret, err);
t.adata = rand_adata;
t.adata_len = rand_len;
}
else
#endif
{
#if defined(WITH_SIG_BIGN) || defined(WITH_SIG_DBIGN)
#if defined(WITH_SIG_BIGN) && !defined(WITH_SIG_DBIGN)
if(sig->type == BIGN)
#endif
#if !defined(WITH_SIG_BIGN) && defined(WITH_SIG_DBIGN)
if(sig->type == DBIGN)
#endif
#if defined(WITH_SIG_BIGN) && defined(WITH_SIG_DBIGN)
if((sig->type == BIGN) || (sig->type == DBIGN))
#endif
{
u16 oid_len = 0;
u16 t_len = 0;
ret = get_random((u8 *)rand_adata, sizeof(rand_adata)); EG(ret, err);
ret = get_random((u8 *)&oid_len, sizeof(oid_len)); EG(ret, err);
ret = get_random((u8 *)&t_len, sizeof(oid_len)); EG(ret, err);
oid_len = (u8)(oid_len % (sizeof(rand_adata) - 4));
t_len = (u8)(t_len % (sizeof(rand_adata) - 4 - oid_len));
rand_adata[0] = (u8)(oid_len >> 8);
rand_adata[1] = (u8)(oid_len & 0xff);
rand_adata[2] = (u8)(t_len >> 8);
rand_adata[3] = (u8)(t_len & 0xff);
t.adata = rand_adata;
t.adata_len = (u8)(oid_len + t_len + 4);
}
else
#endif
{
t.adata = NULL;
t.adata_len = 0;
}
}
ret = ec_import_export_test(&t);
OPENMP_LOCK();
ext_printf("[%s] %34s randtests: random import/export "
"with sig/verif %s\n", ret ? "-" : "+", t.name,
ret ? "failed" : "ok");
check = 0;
#if defined(WITH_SIG_ECDSA)
if(t.sig_type == ECDSA){
check = 1;
}
#endif
#if defined(WITH_SIG_DECDSA)
if(t.sig_type == DECDSA){
check = 1;
}
#endif
if(check){
ext_printf("\t(ECDSA public key recovery also checked!)\n");
}
#ifdef USE_CRYPTOFUZZ
#if defined(WITH_SIG_ECDSA)
if(t.sig_type == ECDSA){
ext_printf("\t(RAW ECDSA for CRYPTOFUZZ also checked!)\n");
}
#endif
#if defined(WITH_SIG_ECGDSA)
if(t.sig_type == ECGDSA){
ext_printf("\t(RAW ECGDSA for CRYPTOFUZZ also checked!)\n");
}
#endif
#if defined(WITH_SIG_ECRDSA)
if(t.sig_type == ECRDSA){
ext_printf("\t(RAW ECRDSA for CRYPTOFUZZ also checked!)\n");
}
#endif
#endif
OPENMP_UNLOCK();
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET int perform_random_sig_verif_test(const char *sig, const char *hash, const char *curve)
{
unsigned int num_sig_maps, num_hash_maps;
int ret = 0;
for (num_sig_maps = 0; ec_sig_maps[num_sig_maps].type != UNKNOWN_ALG; num_sig_maps++) {}
for (num_hash_maps = 0; hash_maps[num_hash_maps].type != UNKNOWN_HASH_ALG; num_hash_maps++) {}
ext_printf("======= Random sig/verif test ===================\n");
for (unsigned int i = 0; i < num_sig_maps; i++) {
#ifdef WITH_OPENMP_SELF_TESTS
#pragma omp parallel for collapse(2)
#endif
for (unsigned int j = 0; j < num_hash_maps; j++) {
for (unsigned int k = 0; k < EC_CURVES_NUM; k++) {
int check;
if(sig != NULL){
ret = are_str_equal(ec_sig_maps[i].name, sig, &check); OPENMP_EG(ret, err);
if(!check){
continue;
}
}
if(hash != NULL){
ret = are_str_equal(hash_maps[j].name, hash, &check); OPENMP_EG(ret, err);
if(!check){
continue;
}
}
if(curve != NULL){
ret = are_str_equal((const char*)ec_maps[k].params->name->buf, curve, &check); OPENMP_EG(ret, err);
if(!check){
continue;
}
}
#ifdef WITH_SIG_EDDSA25519
if((ec_sig_maps[i].type == EDDSA25519) && ((hash_maps[j].type != SHA512) || (ec_maps[k].type != WEI25519))){
continue;
}
if((ec_sig_maps[i].type == EDDSA25519CTX) && ((hash_maps[j].type != SHA512) || (ec_maps[k].type != WEI25519))){
continue;
}
if((ec_sig_maps[i].type == EDDSA25519PH) && ((hash_maps[j].type != SHA512) || (ec_maps[k].type != WEI25519))){
continue;
}
#endif
#ifdef WITH_SIG_EDDSA448
if((ec_sig_maps[i].type == EDDSA448) && ((hash_maps[j].type != SHAKE256) || (ec_maps[k].type != WEI448))){
continue;
}
if((ec_sig_maps[i].type == EDDSA448PH) && ((hash_maps[j].type != SHAKE256) || (ec_maps[k].type != WEI448))){
continue;
}
#endif
ret = rand_sig_verif_test_one(&ec_sig_maps[i],
&hash_maps[j],
&ec_maps[k]);
OPENMP_EG(ret, err);
}
}
}
#ifndef WITH_OPENMP_SELF_TESTS
err:
#endif
return ret;
}
#define PERF_NUM_OP 300
#define PERF_BATCH_VERIFICATION 16
ATTRIBUTE_WARN_UNUSED_RET static int ec_performance_test(const ec_test_case *c,
unsigned int *n_perf_sign,
unsigned int *n_perf_verif,
unsigned int *n_perf_batch_verif,
unsigned char *batch_verify_ok)
{
ec_key_pair kp;
ec_params params;
int ret, check;
MUST_HAVE(c != NULL, ret, err);
MUST_HAVE(n_perf_sign != NULL, ret, err);
MUST_HAVE(n_perf_verif != NULL, ret, err);
MUST_HAVE((n_perf_batch_verif != NULL) && (batch_verify_ok != NULL), ret, err);
ret = local_memset(&kp, 0, sizeof(kp)); EG(ret, err);
ret = import_params(¶ms, c->ec_str_p);
if (ret) {
ext_printf("Error when importing parameters\n");
goto err;
}
ret = ec_gen_import_export_kp(&kp, ¶ms, c);
if (ret) {
ext_printf("Error at key pair generation/import/export\n");
goto err;
}
{
u8 sig[EC_MAX_SIGLEN];
u8 siglen;
u8 msg[MAX_BLOCK_SIZE];
u16 msglen;
u8 hash_digest_size, hash_block_size;
u64 time1, time2, cumulated_time_sign, cumulated_time_verify, cumulated_time_batch_verify;
unsigned int i;
ret = local_memset(sig, 0, sizeof(sig)); EG(ret, err);
ret = local_memset(msg, 0, sizeof(msg)); EG(ret, err);
ret = ec_get_sig_len(¶ms, c->sig_type, c->hash_type,
(u8 *)&siglen);
if (ret) {
ext_printf("Error computing effective sig size\n");
goto err;
}
ret = get_hash_sizes(c->hash_type, &hash_digest_size,
&hash_block_size);
if (ret) {
ext_printf("Error when getting hash size\n");
goto err;
}
cumulated_time_sign = cumulated_time_verify = cumulated_time_batch_verify = 0;
for (i = 0; i < PERF_NUM_OP; i++) {
ret = get_random((u8 *)&msglen, sizeof(msglen));
if (ret) {
ext_printf("Error when getting random\n");
goto err;
}
msglen = (u16)(msglen % hash_block_size);
ret = get_random(msg, msglen);
if (ret) {
ext_printf("Error when getting random\n");
goto err;
}
ret = get_ms_time(&time1);
if (ret) {
ext_printf("Error when getting time\n");
goto err;
}
ret = _ec_sign(sig, siglen, &kp, msg, msglen,
c->nn_random, c->sig_type, c->hash_type, c->adata, c->adata_len);
if (ret) {
ext_printf("Error when signing\n");
goto err;
}
ret = get_ms_time(&time2);
if (ret) {
ext_printf("Error when getting time\n");
goto err;
}
if (time2 < time1) {
ext_printf("Error: time error (t2 < t1)\n");
goto err;
}
cumulated_time_sign += (time2 - time1);
ret = get_ms_time(&time1);
if (ret) {
ext_printf("Error when getting time\n");
goto err;
}
ret = ec_verify(sig, siglen, &(kp.pub_key), msg, msglen,
c->sig_type, c->hash_type, c->adata, c->adata_len);
if (ret) {
ext_printf("Error when verifying signature\n");
goto err;
}
ret = get_ms_time(&time2);
if (ret) {
ext_printf("Error when getting time\n");
goto err;
}
if (time2 < time1) {
ext_printf("Error: time error (time2 < time1)\n");
goto err;
}
cumulated_time_verify += (time2 - time1);
ret = is_verify_batch_mode_supported(c->sig_type, &check); EG(ret, err);
if(check){
unsigned int j;
const u8 *signatures[PERF_BATCH_VERIFICATION];
u8 signatures_len[PERF_BATCH_VERIFICATION];
const u8 *messages[PERF_BATCH_VERIFICATION];
u32 messages_len[PERF_BATCH_VERIFICATION];
const ec_pub_key *pub_keys[PERF_BATCH_VERIFICATION];
const u8 *adatas[PERF_BATCH_VERIFICATION];
u16 adatas_len[PERF_BATCH_VERIFICATION];
verify_batch_scratch_pad scratch_pad_area[(2 * PERF_BATCH_VERIFICATION) + 1];
u32 scratch_pad_area_len = sizeof(scratch_pad_area);
for(j = 0; j < PERF_BATCH_VERIFICATION; j++){
signatures[j] = sig;
signatures_len[j] = siglen;
messages[j] = msg;
messages_len[j] = msglen;
pub_keys[j] = &(kp.pub_key);
adatas[j] = c->adata;
adatas_len[j] = c->adata_len;
}
ret = get_ms_time(&time1);
if (ret) {
ext_printf("Error when getting time\n");
goto err;
}
ret = ec_verify_batch(signatures, signatures_len, pub_keys, messages, messages_len,
PERF_BATCH_VERIFICATION, c->sig_type, c->hash_type, adatas, adatas_len, scratch_pad_area, &scratch_pad_area_len);
if(ret){
ext_printf("Error when verifying signature ec_verify_batch with batch %d\n", PERF_BATCH_VERIFICATION);
goto err;
}
ret = get_ms_time(&time2);
if (ret) {
ext_printf("Error when getting time\n");
goto err;
}
if (time2 < time1) {
ext_printf("Error: time error (time2 < time1)\n");
goto err;
}
cumulated_time_batch_verify += (time2 - time1);
(*batch_verify_ok) = 1;
}
else{
(*batch_verify_ok) = 0;
}
}
if (n_perf_sign != NULL) {
(*n_perf_sign) = (unsigned int)((PERF_NUM_OP * 1000ULL) / cumulated_time_sign);
}
if (n_perf_verif != NULL) {
(*n_perf_verif) = (unsigned int)((PERF_NUM_OP * 1000ULL) / cumulated_time_verify);
}
if (n_perf_batch_verif != NULL) {
if((*batch_verify_ok) == 1){
(*n_perf_batch_verif) = (unsigned int)((PERF_NUM_OP * PERF_BATCH_VERIFICATION * 1000ULL) / cumulated_time_batch_verify);
}
else{
(*n_perf_batch_verif) = 0;
}
}
}
ret = 0;
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET static int perf_test_one(const ec_sig_mapping *sig, const hash_mapping *hash,
const ec_mapping *ec)
{
char test_name[MAX_CURVE_NAME_LEN + MAX_HASH_ALG_NAME_LEN +
MAX_SIG_ALG_NAME_LEN + 2];
const unsigned int tn_size = sizeof(test_name) - 1;
unsigned int n_perf_sign = 0, n_perf_verif = 0, n_perf_batch_verif = 0;
unsigned char batch_verify_ok = 0;
const char *crv_name;
ec_test_case t;
int ret;
u32 len;
#if defined(WITH_SIG_EDDSA25519) || defined(WITH_SIG_SM2) || defined(WITH_SIG_BIGN) || defined(WITH_SIG_DBIGN)
u8 rand_adata[255];
ret = local_memset(rand_adata, 0, sizeof(rand_adata)); EG(ret, err);
#endif
MUST_HAVE((sig != NULL), ret, err);
MUST_HAVE((hash != NULL), ret, err);
MUST_HAVE((ec != NULL), ret, err);
ret = local_memset(test_name, 0, sizeof(test_name)); EG(ret, err);
crv_name = (const char *)PARAM_BUF_PTR((ec->params)->name);
ret = local_memset(test_name, 0, tn_size + 1); EG(ret, err);
ret = local_strncpy(test_name, sig->name, tn_size); EG(ret, err);
ret = local_strlen(test_name, &len); EG(ret, err);
ret = local_strncat(test_name, "-", tn_size - len); EG(ret, err);
ret = local_strlen(test_name, &len); EG(ret, err);
ret = local_strncat(test_name, hash->name, tn_size - len); EG(ret, err);
ret = local_strlen(test_name, &len); EG(ret, err);
ret = local_strncat(test_name, "/", tn_size - len); EG(ret, err);
ret = local_strlen(test_name, &len); EG(ret, err);
ret = local_strncat(test_name, crv_name, tn_size - len); EG(ret, err);
t.name = test_name;
t.ec_str_p = ec->params;
t.priv_key = NULL;
t.priv_key_len = 0;
t.nn_random = NULL;
t.hash_type = hash->type;
t.msg = NULL;
t.msglen = 0;
t.sig_type = sig->type;
t.exp_sig = NULL;
t.exp_siglen = 0;
#if defined(WITH_SIG_EDDSA25519) || defined(WITH_SIG_SM2)
#if defined(WITH_SIG_EDDSA25519) && !defined(WITH_SIG_SM2)
if(sig->type == EDDSA25519CTX)
#endif
#if !defined(WITH_SIG_EDDSA25519) && defined(WITH_SIG_SM2)
if(sig->type == SM2)
#endif
#if defined(WITH_SIG_EDDSA25519) && defined(WITH_SIG_SM2)
if((sig->type == EDDSA25519CTX) || (sig->type == SM2))
#endif
{
u8 rand_len = 0;
ret = get_random((u8 *)&rand_len, sizeof(rand_len)); EG(ret, err);
ret = get_random((u8 *)rand_adata, (u16)(rand_len % sizeof(rand_adata))); EG(ret, err);
t.adata = rand_adata;
t.adata_len = rand_len;
}
else
#endif
{
#if defined(WITH_SIG_BIGN) || defined(WITH_SIG_DBIGN)
#if defined(WITH_SIG_BIGN) && !defined(WITH_SIG_DBIGN)
if(sig->type == BIGN)
#endif
#if !defined(WITH_SIG_BIGN) && defined(WITH_SIG_DBIGN)
if(sig->type == DBIGN)
#endif
#if defined(WITH_SIG_BIGN) && defined(WITH_SIG_DBIGN)
if((sig->type == BIGN) || (sig->type == DBIGN))
#endif
{
u16 oid_len = 0;
u16 t_len = 0;
ret = get_random((u8 *)rand_adata, sizeof(rand_adata)); EG(ret, err);
ret = get_random((u8 *)&oid_len, sizeof(oid_len)); EG(ret, err);
ret = get_random((u8 *)&t_len, sizeof(oid_len)); EG(ret, err);
oid_len = (u8)(oid_len % (sizeof(rand_adata) - 4));
t_len = (u8)(t_len % (sizeof(rand_adata) - 4 - oid_len));
rand_adata[0] = (u8)(oid_len >> 8);
rand_adata[1] = (u8)(oid_len & 0xff);
rand_adata[2] = (u8)(t_len >> 8);
rand_adata[3] = (u8)(t_len & 0xff);
t.adata = rand_adata;
t.adata_len = (u8)(oid_len + t_len + 4);
}
else
#endif
{
t.adata = NULL;
t.adata_len = 0;
}
}
ret = ec_performance_test(&t, &n_perf_sign, &n_perf_verif, &n_perf_batch_verif, &batch_verify_ok);
OPENMP_LOCK();
if(batch_verify_ok == 1){
ext_printf("[%s] %30s perf: %u sign/s and %u verif/s, %u batch verif/s (for %u batch)\n",
ret ? "-" : "+", t.name, n_perf_sign, n_perf_verif, n_perf_batch_verif, (unsigned int)PERF_BATCH_VERIFICATION);
if ((n_perf_sign == 0) || (n_perf_verif == 0) || (n_perf_batch_verif == 0)) {
ext_printf("\t(0 is less than one sig/verif per sec)\n");
}
}
else{
ext_printf("[%s] %30s perf: %u sign/s and %u verif/s\n",
ret ? "-" : "+", t.name, n_perf_sign, n_perf_verif);
if ((n_perf_sign == 0) || (n_perf_verif == 0)) {
ext_printf("\t(0 is less than one sig/verif per sec)\n");
}
}
OPENMP_UNLOCK();
err:
return ret;
}
ATTRIBUTE_WARN_UNUSED_RET int perform_performance_test(const char *sig, const char *hash, const char *curve)
{
unsigned int i, j, k;
int ret, check;
ext_printf("======= Performance test ========================\n");
#ifdef WITH_OPENMP_SELF_TESTS
ext_printf("== NOTE: OpenMP parallelization is not applied to performance tests ...\n");
ext_printf("== (because of CPU/cores shared ressources such as caches, BPU, etc.)\n");
#endif
for (i = 0; ec_sig_maps[i].type != UNKNOWN_ALG; i++) {
for (j = 0; hash_maps[j].type != UNKNOWN_HASH_ALG; j++) {
for (k = 0; k < EC_CURVES_NUM; k++) {
if(sig != NULL){
ret = are_str_equal(ec_sig_maps[i].name, sig, &check); OPENMP_EG(ret, err);
if(!check){
continue;
}
}
if(hash != NULL){
ret = are_str_equal(hash_maps[j].name, hash, &check); OPENMP_EG(ret, err);
if(!check){
continue;
}
}
if(curve != NULL){
ret = are_str_equal((const char*)ec_maps[k].params->name->buf, curve, &check); OPENMP_EG(ret, err);
if(!check){
continue;
}
}
#ifdef WITH_SIG_EDDSA25519
if((ec_sig_maps[i].type == EDDSA25519) && ((hash_maps[j].type != SHA512) || (ec_maps[k].type != WEI25519))){
continue;
}
if((ec_sig_maps[i].type == EDDSA25519CTX) && ((hash_maps[j].type != SHA512) || (ec_maps[k].type != WEI25519))){
continue;
}
if((ec_sig_maps[i].type == EDDSA25519PH) && ((hash_maps[j].type != SHA512) || (ec_maps[k].type != WEI25519))){
continue;
}
#endif
#ifdef WITH_SIG_EDDSA448
if((ec_sig_maps[i].type == EDDSA448) && ((hash_maps[j].type != SHAKE256) || (ec_maps[k].type != WEI448))){
continue;
}
if((ec_sig_maps[i].type == EDDSA448PH) && ((hash_maps[j].type != SHAKE256) || (ec_maps[k].type != WEI448))){
continue;
}
#endif
ret = perf_test_one(&ec_sig_maps[i],
&hash_maps[j],
&ec_maps[k]);
if (ret) {
goto err;
}
}
}
}
return 0;
err:
return -1;
}