/*********************************************************************** * Copyright (c) 2020 Gregory Maxwell * * Distributed under the MIT software license, see the accompanying * * file COPYING or https://www.opensource.org/licenses/mit-license.php.* ***********************************************************************/ #include #include #include #include "../include/secp256k1.h" #include "assumptions.h" #include "checkmem.h" #if !SECP256K1_CHECKMEM_ENABLED # error "This tool cannot be compiled without memory-checking interface (valgrind or msan)" #endif #ifdef ENABLE_MODULE_ECDH # include "../include/secp256k1_ecdh.h" #endif #ifdef ENABLE_MODULE_RECOVERY # include "../include/secp256k1_recovery.h" #endif #ifdef ENABLE_MODULE_EXTRAKEYS # include "../include/secp256k1_extrakeys.h" #endif #ifdef ENABLE_MODULE_SCHNORRSIG #include "../include/secp256k1_schnorrsig.h" #endif #ifdef ENABLE_MODULE_MUSIG #include "../include/secp256k1_musig.h" #endif #ifdef ENABLE_MODULE_ELLSWIFT #include "../include/secp256k1_ellswift.h" #endif #ifdef ENABLE_MODULE_ECDSA_S2C #include "../include/secp256k1_ecdsa_s2c.h" #endif #ifdef ENABLE_MODULE_ECDSA_ADAPTOR #include "../include/secp256k1_ecdsa_adaptor.h" #endif #if defined(__GNUC__) # pragma GCC diagnostic push # pragma GCC diagnostic warning "-Wunused-function" #endif #ifdef ENABLE_MODULE_FROST #include "../include/secp256k1_frost.h" #endif #ifdef ENABLE_MODULE_CHILLDKG #include "../include/secp256k1_chilldkg.h" #endif #ifdef ENABLE_MODULE_PREFRACTAL #include "../include/secp256k1_prefractal.h" #endif #ifdef ENABLE_MODULE_FROST_ENROLLMENT #include "../include/secp256k1_frost_enrollment.h" #endif #ifdef ENABLE_MODULE_ICEBERG #include "../include/secp256k1_iceberg.h" #include "../include/secp256k1_iceberg_dealer.h" #endif static void run_tests(secp256k1_context *ctx, unsigned char *key); int main(void) { secp256k1_context* ctx; unsigned char key[32]; int ret, i; if (!SECP256K1_CHECKMEM_RUNNING()) { fprintf(stderr, "This test can only usefully be run inside valgrind because it was not compiled under msan.\n"); fprintf(stderr, "Usage: valgrind ./ctime_tests (or with Autotools: libtool --mode=execute valgrind ./ctime_tests)\n"); return EXIT_FAILURE; } ctx = secp256k1_context_create(SECP256K1_CONTEXT_DECLASSIFY); /** In theory, testing with a single secret input should be sufficient: * If control flow depended on secrets the tool would generate an error. */ for (i = 0; i < 32; i++) { key[i] = i + 65; } run_tests(ctx, key); /* Test context randomisation. Do this last because it leaves the context * tainted. */ SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_context_randomize(ctx, key); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret); secp256k1_context_destroy(ctx); return EXIT_SUCCESS; } static void run_tests(secp256k1_context *ctx, unsigned char *key) { secp256k1_ecdsa_signature signature; secp256k1_pubkey pubkey; size_t siglen = 74; size_t outputlen = 33; int i; int ret; unsigned char msg[32]; unsigned char sig[74]; unsigned char spubkey[33]; #ifdef ENABLE_MODULE_RECOVERY secp256k1_ecdsa_recoverable_signature recoverable_signature; int recid; #endif #ifdef ENABLE_MODULE_EXTRAKEYS secp256k1_keypair keypair; #endif #ifdef ENABLE_MODULE_ELLSWIFT unsigned char ellswift[64]; static const unsigned char prefix[64] = {'t', 'e', 's', 't'}; #endif for (i = 0; i < 32; i++) { msg[i] = i + 1; } /* Test keygen. */ SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ec_pubkey_create(ctx, &pubkey, key); SECP256K1_CHECKMEM_DEFINE(&pubkey, sizeof(secp256k1_pubkey)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret); CHECK(secp256k1_ec_pubkey_serialize(ctx, spubkey, &outputlen, &pubkey, SECP256K1_EC_COMPRESSED) == 1); /* Test signing. */ SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ecdsa_sign(ctx, &signature, msg, key, NULL, NULL); SECP256K1_CHECKMEM_DEFINE(&signature, sizeof(secp256k1_ecdsa_signature)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret); CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature)); #ifdef ENABLE_MODULE_ECDH /* Test ECDH. */ SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ecdh(ctx, msg, &pubkey, key, NULL, NULL); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); #endif #ifdef ENABLE_MODULE_RECOVERY /* Test signing a recoverable signature. */ SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ecdsa_sign_recoverable(ctx, &recoverable_signature, msg, key, NULL, NULL); SECP256K1_CHECKMEM_DEFINE(&recoverable_signature, sizeof(recoverable_signature)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret); CHECK(secp256k1_ecdsa_recoverable_signature_serialize_compact(ctx, sig, &recid, &recoverable_signature)); CHECK(recid >= 0 && recid <= 3); #endif SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ec_seckey_verify(ctx, key); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ec_seckey_negate(ctx, key); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(key, 32); SECP256K1_CHECKMEM_UNDEFINE(msg, 32); ret = secp256k1_ec_seckey_tweak_add(ctx, key, msg); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(key, 32); SECP256K1_CHECKMEM_UNDEFINE(msg, 32); ret = secp256k1_ec_seckey_tweak_mul(ctx, key, msg); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); /* Test keypair_create and keypair_xonly_tweak_add. */ #ifdef ENABLE_MODULE_EXTRAKEYS SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_keypair_create(ctx, &keypair, key); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); /* The tweak is not treated as a secret in keypair_tweak_add */ SECP256K1_CHECKMEM_DEFINE(msg, 32); ret = secp256k1_keypair_xonly_tweak_add(ctx, &keypair, msg); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(key, 32); SECP256K1_CHECKMEM_UNDEFINE(&keypair, sizeof(keypair)); ret = secp256k1_keypair_sec(ctx, key, &keypair); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); #endif #ifdef ENABLE_MODULE_SCHNORRSIG SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_keypair_create(ctx, &keypair, key); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); ret = secp256k1_schnorrsig_sign32(ctx, sig, msg, &keypair, NULL); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); #endif #ifdef ENABLE_MODULE_MUSIG { secp256k1_pubkey pk; const secp256k1_pubkey *pk_ptr[1]; secp256k1_xonly_pubkey agg_pk; unsigned char session_secrand[32]; uint64_t nonrepeating_cnt = 0; secp256k1_musig_secnonce secnonce; secp256k1_musig_pubnonce pubnonce; const secp256k1_musig_pubnonce *pubnonce_ptr[1]; secp256k1_musig_aggnonce aggnonce; secp256k1_musig_keyagg_cache cache; secp256k1_musig_session session; secp256k1_musig_partial_sig partial_sig; const secp256k1_musig_partial_sig *partial_sig_ptr[1]; unsigned char extra_input[32]; unsigned char sec_adaptor[32]; secp256k1_pubkey adaptor; unsigned char pre_sig[64]; int nonce_parity; pk_ptr[0] = &pk; pubnonce_ptr[0] = &pubnonce; SECP256K1_CHECKMEM_DEFINE(key, 32); memcpy(session_secrand, key, sizeof(session_secrand)); session_secrand[0] = session_secrand[0] + 1; memcpy(extra_input, key, sizeof(extra_input)); extra_input[0] = extra_input[0] + 2; memcpy(sec_adaptor, key, sizeof(sec_adaptor)); sec_adaptor[0] = extra_input[0] + 3; partial_sig_ptr[0] = &partial_sig; CHECK(secp256k1_keypair_create(ctx, &keypair, key)); CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair)); CHECK(secp256k1_musig_pubkey_agg(ctx, &agg_pk, &cache, pk_ptr, 1)); CHECK(secp256k1_ec_pubkey_create(ctx, &adaptor, sec_adaptor)); SECP256K1_CHECKMEM_UNDEFINE(key, 32); SECP256K1_CHECKMEM_UNDEFINE(session_secrand, sizeof(session_secrand)); SECP256K1_CHECKMEM_UNDEFINE(extra_input, sizeof(extra_input)); SECP256K1_CHECKMEM_UNDEFINE(sec_adaptor, sizeof(sec_adaptor)); ret = secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, session_secrand, key, &pk, msg, &cache, extra_input); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); ret = secp256k1_musig_nonce_gen_counter(ctx, &secnonce, &pubnonce, nonrepeating_cnt, &keypair, msg, &cache, extra_input); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1)); /* Make sure that previous tests don't undefine msg. It's not used as a secret here. */ SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg)); CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg, &cache, &adaptor) == 1); ret = secp256k1_keypair_create(ctx, &keypair, key); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); ret = secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &cache, &session); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&partial_sig, sizeof(partial_sig)); CHECK(secp256k1_musig_partial_sig_agg(ctx, pre_sig, &session, partial_sig_ptr, 1)); SECP256K1_CHECKMEM_DEFINE(pre_sig, sizeof(pre_sig)); CHECK(secp256k1_musig_nonce_parity(ctx, &nonce_parity, &session)); ret = secp256k1_musig_adapt(ctx, sig, pre_sig, sec_adaptor, nonce_parity); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); ret = secp256k1_musig_extract_adaptor(ctx, sec_adaptor, sig, pre_sig, nonce_parity); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); } #endif #ifdef ENABLE_MODULE_ELLSWIFT SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ellswift_create(ctx, ellswift, key, NULL); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ellswift_create(ctx, ellswift, key, ellswift); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); for (i = 0; i < 2; i++) { SECP256K1_CHECKMEM_UNDEFINE(key, 32); SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_bip324, NULL); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(key, 32); SECP256K1_CHECKMEM_DEFINE(&ellswift, sizeof(ellswift)); ret = secp256k1_ellswift_xdh(ctx, msg, ellswift, ellswift, key, i, secp256k1_ellswift_xdh_hash_function_prefix, (void *)prefix); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); } #endif #ifdef ENABLE_MODULE_ECDSA_S2C { unsigned char s2c_data[32] = {0}; unsigned char s2c_data_comm[32] = {0}; secp256k1_ecdsa_s2c_opening s2c_opening; SECP256K1_CHECKMEM_UNDEFINE(key, 32); SECP256K1_CHECKMEM_UNDEFINE(s2c_data, 32); ret = secp256k1_ecdsa_s2c_sign(ctx, &signature, &s2c_opening, msg, key, s2c_data); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(s2c_data, 32); ret = secp256k1_ecdsa_anti_exfil_host_commit(ctx, s2c_data_comm, s2c_data); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(key, 32); SECP256K1_CHECKMEM_UNDEFINE(s2c_data, 32); ret = secp256k1_ecdsa_anti_exfil_signer_commit(ctx, &s2c_opening, msg, key, s2c_data); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); } #endif #ifdef ENABLE_MODULE_ECDSA_ADAPTOR { unsigned char adaptor_sig[162]; unsigned char deckey[32]; unsigned char expected_deckey[32]; secp256k1_pubkey enckey; for (i = 0; i < 32; i++) { deckey[i] = i + 2; } ret = secp256k1_ec_pubkey_create(ctx, &enckey, deckey); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_ecdsa_adaptor_encrypt(ctx, adaptor_sig, key, &enckey, msg, NULL, NULL); SECP256K1_CHECKMEM_DEFINE(adaptor_sig, sizeof(adaptor_sig)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(deckey, 32); ret = secp256k1_ecdsa_adaptor_decrypt(ctx, &signature, deckey, adaptor_sig); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_UNDEFINE(&signature, 32); ret = secp256k1_ecdsa_adaptor_recover(ctx, expected_deckey, &signature, adaptor_sig, &enckey); SECP256K1_CHECKMEM_DEFINE(expected_deckey, sizeof(expected_deckey)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(deckey, sizeof(deckey)); ret = secp256k1_memcmp_var(deckey, expected_deckey, sizeof(expected_deckey)); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 0); } #endif #ifdef ENABLE_MODULE_FROST { unsigned char thresh_seckey[32]; unsigned char secshares[2 * 32]; secp256k1_pubkey thresh_pk; secp256k1_pubkey pubshares[2]; uint32_t frost_ids[2] = { 0, 1 }; secp256k1_frost_tweak_cache cache; secp256k1_frost_secnonce secnonce[2]; secp256k1_frost_pubnonce pubnonce[2]; const secp256k1_frost_pubnonce *pubnonce_ptrs[2]; secp256k1_frost_aggnonce aggnonce; secp256k1_frost_session session; secp256k1_frost_partial_sig partial_sig[2]; const secp256k1_frost_partial_sig *partial_sig_ptrs[2]; unsigned char session_secrand[2][32]; pubnonce_ptrs[0] = &pubnonce[0]; pubnonce_ptrs[1] = &pubnonce[1]; partial_sig_ptrs[0] = &partial_sig[0]; partial_sig_ptrs[1] = &partial_sig[1]; /* All public inputs are derived from defined memory. key is reused as * the base of the (secret) threshold key and session randomness. */ SECP256K1_CHECKMEM_DEFINE(key, 32); memcpy(thresh_seckey, key, sizeof(thresh_seckey)); thresh_seckey[0] = thresh_seckey[0] + 1; memcpy(session_secrand[0], key, 32); session_secrand[0][0] = session_secrand[0][0] + 2; memcpy(session_secrand[1], key, 32); session_secrand[1][0] = session_secrand[1][0] + 3; /* Test frost_trusted_dealer_keygen. The threshold secret key and the * resulting secret shares are secret; the threshold public key and * the public shares are public. */ SECP256K1_CHECKMEM_UNDEFINE(thresh_seckey, sizeof(thresh_seckey)); ret = secp256k1_frost_trusted_dealer_keygen(ctx, secshares, &thresh_pk, pubshares, 2, 2, thresh_seckey); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&thresh_pk, sizeof(thresh_pk)); SECP256K1_CHECKMEM_DEFINE(pubshares, sizeof(pubshares)); /* The session setup uses only public inputs. */ CHECK(secp256k1_frost_tweak_cache_init(ctx, &cache, &thresh_pk) == 1); /* Make sure that previous tests don't undefine msg. It's not used as a secret here. */ SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg)); /* Test frost_nonce_gen. The session randomness and the secret share * are secret; the pubnonce is public. The secnonce stays secret. */ for (i = 0; i < 2; i++) { SECP256K1_CHECKMEM_UNDEFINE(session_secrand[i], 32); SECP256K1_CHECKMEM_UNDEFINE(&secshares[32 * i], 32); ret = secp256k1_frost_nonce_gen(ctx, &secnonce[i], &pubnonce[i], session_secrand[i], &secshares[32 * i], &pubshares[i], NULL, msg, 32, NULL, 0); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&pubnonce[i], sizeof(pubnonce[i])); } CHECK(secp256k1_frost_nonce_agg(ctx, &aggnonce, NULL, pubnonce_ptrs, 2) == 1); CHECK(secp256k1_frost_session_init(ctx, &session, &aggnonce, frost_ids, pubshares, 2, 2, 2, &cache, msg, 32) == 1); /* Test frost_sign. The secret share is secret (the secnonce is * tainted through the tainted session randomness; its magic bytes * must remain defined for the validity check). The partial signature * is public. */ for (i = 0; i < 2; i++) { SECP256K1_CHECKMEM_UNDEFINE(&secshares[32 * i], 32); ret = secp256k1_frost_sign(ctx, &partial_sig[i], &secnonce[i], &secshares[32 * i], &session, frost_ids, pubshares, 2, frost_ids[i]); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&partial_sig[i], sizeof(partial_sig[i])); } CHECK(secp256k1_frost_partial_sig_agg(ctx, sig, NULL, &session, partial_sig_ptrs, 2) == 1); /* Test frost_deterministic_sign. The secret share is secret; the * pubnonce and the partial signature are public. */ for (i = 0; i < 2; i++) { secp256k1_frost_pubnonce det_pubnonce; secp256k1_frost_partial_sig det_partial_sig; SECP256K1_CHECKMEM_UNDEFINE(&secshares[32 * i], 32); ret = secp256k1_frost_deterministic_sign(ctx, &det_partial_sig, &det_pubnonce, &secshares[32 * i], frost_ids[i], &aggnonce, frost_ids, pubshares, 2, 2, 2, &cache, msg, 32, NULL); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&det_pubnonce, sizeof(det_pubnonce)); SECP256K1_CHECKMEM_DEFINE(&det_partial_sig, sizeof(det_partial_sig)); } } #endif #ifdef ENABLE_MODULE_CHILLDKG { /* Full ChillDKG session with n = 2, t = 2 (pmsg1: 227 bytes, cmsg1: * 357 bytes, cert: 128 bytes, recovery data: 394 bytes). */ unsigned char hostseckeys[2][32]; unsigned char hostpubkeys[2 * 33]; unsigned char dkg_random[2][32]; unsigned char aux_rands[2][32]; secp256k1_chilldkg_participant_state1 state1[2]; secp256k1_chilldkg_participant_state2 state2[2]; secp256k1_chilldkg_coordinator_state cstate; unsigned char pmsgs1[2][227]; const unsigned char *pmsgs1_ptrs[2]; unsigned char cmsg1[357]; unsigned char pmsgs2[2][64]; const unsigned char *pmsgs2_ptrs[2]; unsigned char cmsg2[128]; unsigned char secshare32[32]; unsigned char thresh_pk33[33]; unsigned char pubshares33[2 * 33]; unsigned char recovery[394]; unsigned char rec_secshare32[32]; unsigned char rec_thresh_pk33[33]; unsigned char rec_pubshares33[33 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS]; unsigned char rec_hostpubkeys33[33 * SECP256K1_CHILLDKG_MAX_PARTICIPANTS]; unsigned char ack_sig[64]; size_t rec_n; uint32_t rec_t; uint32_t fault_index; secp256k1_chilldkg_fault fault; pmsgs1_ptrs[0] = pmsgs1[0]; pmsgs1_ptrs[1] = pmsgs1[1]; pmsgs2_ptrs[0] = pmsgs2[0]; pmsgs2_ptrs[1] = pmsgs2[1]; /* All public inputs are derived from defined memory. key is reused as * the base of the (secret) host keys, session randomness and * auxiliary randomness. */ SECP256K1_CHECKMEM_DEFINE(key, 32); for (i = 0; i < 2; i++) { memcpy(hostseckeys[i], key, 32); hostseckeys[i][0] = hostseckeys[i][0] + 4 + i; memcpy(dkg_random[i], key, 32); dkg_random[i][0] = dkg_random[i][0] + 6 + i; memcpy(aux_rands[i], key, 32); aux_rands[i][0] = aux_rands[i][0] + 8 + i; } /* Test chilldkg_hostpubkey_gen. The host secret keys are secret; the * host public keys are public. */ for (i = 0; i < 2; i++) { SECP256K1_CHECKMEM_UNDEFINE(hostseckeys[i], 32); ret = secp256k1_chilldkg_hostpubkey_gen(ctx, &hostpubkeys[33 * i], hostseckeys[i]); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&hostpubkeys[33 * i], 33); } /* Test chilldkg_participant_step1. The host secret key and the * session randomness are secret; pmsg1 and the state1 object (which * contains no secrets) are public. */ for (i = 0; i < 2; i++) { SECP256K1_CHECKMEM_UNDEFINE(hostseckeys[i], 32); SECP256K1_CHECKMEM_UNDEFINE(dkg_random[i], 32); ret = secp256k1_chilldkg_participant_step1(ctx, &state1[i], pmsgs1[i], hostseckeys[i], hostpubkeys, 2, 2, dkg_random[i]); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(pmsgs1[i], sizeof(pmsgs1[i])); SECP256K1_CHECKMEM_DEFINE(&state1[i], sizeof(state1[i])); } /* The coordinator's steps use only public inputs. */ fault = secp256k1_chilldkg_coordinator_step1(ctx, &cstate, cmsg1, &fault_index, pmsgs1_ptrs, hostpubkeys, 2, 2); SECP256K1_CHECKMEM_DEFINE(&fault, sizeof(fault)); CHECK(fault == SECP256K1_CHILLDKG_OK); /* Test chilldkg_participant_step2. The host secret key and the aux * randomness are secret; the CertEq signature is public. The state2 * object contains the secret share and stays secret. */ for (i = 0; i < 2; i++) { SECP256K1_CHECKMEM_UNDEFINE(hostseckeys[i], 32); SECP256K1_CHECKMEM_UNDEFINE(aux_rands[i], 32); fault = secp256k1_chilldkg_participant_step2(ctx, &state2[i], pmsgs2[i], &fault_index, NULL, &state1[i], hostseckeys[i], cmsg1, aux_rands[i]); SECP256K1_CHECKMEM_DEFINE(&fault, sizeof(fault)); CHECK(fault == SECP256K1_CHILLDKG_OK); SECP256K1_CHECKMEM_DEFINE(pmsgs2[i], sizeof(pmsgs2[i])); } fault = secp256k1_chilldkg_coordinator_finalize(ctx, cmsg2, thresh_pk33, pubshares33, recovery, &fault_index, &cstate, pmsgs2_ptrs); SECP256K1_CHECKMEM_DEFINE(&fault, sizeof(fault)); CHECK(fault == SECP256K1_CHILLDKG_OK); /* Test chilldkg_participant_finalize. The state2 input and the * secshare output are secret; the threshold public key, the public * shares and the recovery data are public. */ fault = secp256k1_chilldkg_participant_finalize(ctx, secshare32, thresh_pk33, pubshares33, recovery, &fault_index, &state2[0], cmsg2); SECP256K1_CHECKMEM_DEFINE(&fault, sizeof(fault)); CHECK(fault == SECP256K1_CHILLDKG_OK); SECP256K1_CHECKMEM_DEFINE(thresh_pk33, sizeof(thresh_pk33)); SECP256K1_CHECKMEM_DEFINE(pubshares33, sizeof(pubshares33)); SECP256K1_CHECKMEM_DEFINE(recovery, sizeof(recovery)); /* Test chilldkg_participant_recover. The host secret key and the * recovered secret share are secret; the recovery data and the * remaining outputs are public. */ SECP256K1_CHECKMEM_UNDEFINE(hostseckeys[0], 32); fault = secp256k1_chilldkg_participant_recover(ctx, rec_secshare32, rec_thresh_pk33, rec_pubshares33, rec_hostpubkeys33, &rec_n, &rec_t, &fault_index, hostseckeys[0], recovery, sizeof(recovery)); SECP256K1_CHECKMEM_DEFINE(&fault, sizeof(fault)); CHECK(fault == SECP256K1_CHILLDKG_OK); SECP256K1_CHECKMEM_DEFINE(rec_thresh_pk33, sizeof(rec_thresh_pk33)); SECP256K1_CHECKMEM_DEFINE(rec_pubshares33, 2 * 33); SECP256K1_CHECKMEM_DEFINE(rec_hostpubkeys33, 2 * 33); SECP256K1_CHECKMEM_DEFINE(&rec_n, sizeof(rec_n)); SECP256K1_CHECKMEM_DEFINE(&rec_t, sizeof(rec_t)); CHECK(rec_n == 2 && rec_t == 2); /* Test chilldkg_recovery_ack_sign. The host secret key and the aux * randomness are secret; the acknowledgment signature is public. */ SECP256K1_CHECKMEM_UNDEFINE(hostseckeys[0], 32); SECP256K1_CHECKMEM_UNDEFINE(aux_rands[0], 32); ret = secp256k1_chilldkg_recovery_ack_sign(ctx, ack_sig, hostseckeys[0], hostpubkeys, 2, 2, recovery, sizeof(recovery), aux_rands[0]); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(ack_sig, sizeof(ack_sig)); } #endif #ifdef ENABLE_MODULE_PREFRACTAL { /* A 2-of-2 nested group with one stock musig cosigner, taken as far as * one signature share. Secret here is the threshold key, the secret * shares derived from it, and the session randomness the nonces come * from. Not secret: the identifiers, the public shares, the threshold * public key, both aggregate nonces, the outer keyagg cache, b_frost, * and the resulting partial signature. */ unsigned char thresh_seckey[32]; unsigned char secshares[2 * 32]; unsigned char session_secrand[2][32]; unsigned char cosigner_seckey[32]; secp256k1_pubkey thresh_pk, pubshares[2], cosigner_pk; const secp256k1_pubkey *outer_pubkeys[2]; uint32_t pf_ids[2] = { 0, 1 }; secp256k1_frost_tweak_cache pf_cache; secp256k1_frost_secnonce pf_secnonce[2]; secp256k1_frost_pubnonce pf_pubnonce[2]; const secp256k1_frost_pubnonce *pf_pubnonce_ptrs[2]; secp256k1_frost_aggnonce pf_aggnonce; secp256k1_frost_partial_sig pf_partial_sig; secp256k1_xonly_pubkey outer_xonly; secp256k1_musig_keyagg_cache outer_cache; secp256k1_musig_pubnonce group_pubnonce, cosigner_pubnonce; const secp256k1_musig_pubnonce *just_cosigner[1]; secp256k1_musig_secnonce cosigner_secnonce; secp256k1_musig_aggnonce cosigner_aggnonce; unsigned char cosigner_secrand[32]; pf_pubnonce_ptrs[0] = &pf_pubnonce[0]; pf_pubnonce_ptrs[1] = &pf_pubnonce[1]; SECP256K1_CHECKMEM_DEFINE(key, 32); memcpy(thresh_seckey, key, sizeof(thresh_seckey)); thresh_seckey[0] = thresh_seckey[0] + 4; memcpy(cosigner_seckey, key, sizeof(cosigner_seckey)); cosigner_seckey[0] = cosigner_seckey[0] + 5; memcpy(session_secrand[0], key, 32); session_secrand[0][0] = session_secrand[0][0] + 6; memcpy(session_secrand[1], key, 32); session_secrand[1][0] = session_secrand[1][0] + 7; memcpy(cosigner_secrand, key, 32); cosigner_secrand[0] = cosigner_secrand[0] + 8; SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg)); SECP256K1_CHECKMEM_UNDEFINE(thresh_seckey, sizeof(thresh_seckey)); ret = secp256k1_frost_trusted_dealer_keygen(ctx, secshares, &thresh_pk, pubshares, 2, 2, thresh_seckey); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&thresh_pk, sizeof(thresh_pk)); SECP256K1_CHECKMEM_DEFINE(pubshares, sizeof(pubshares)); CHECK(secp256k1_frost_tweak_cache_init(ctx, &pf_cache, &thresh_pk) == 1); /* The outer aggregation and the cosigner's round one are entirely * public as far as this module is concerned. */ SECP256K1_CHECKMEM_UNDEFINE(cosigner_seckey, sizeof(cosigner_seckey)); ret = secp256k1_ec_pubkey_create(ctx, &cosigner_pk, cosigner_seckey); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&cosigner_pk, sizeof(cosigner_pk)); outer_pubkeys[0] = &thresh_pk; outer_pubkeys[1] = &cosigner_pk; CHECK(secp256k1_musig_pubkey_agg(ctx, &outer_xonly, &outer_cache, outer_pubkeys, 2) == 1); SECP256K1_CHECKMEM_UNDEFINE(cosigner_secrand, sizeof(cosigner_secrand)); ret = secp256k1_musig_nonce_gen(ctx, &cosigner_secnonce, &cosigner_pubnonce, cosigner_secrand, cosigner_seckey, &cosigner_pk, msg, &outer_cache, NULL); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&cosigner_pubnonce, sizeof(cosigner_pubnonce)); just_cosigner[0] = &cosigner_pubnonce; CHECK(secp256k1_musig_nonce_agg(ctx, &cosigner_aggnonce, just_cosigner, 1) == 1); /* Group round one. msg is NULL: the wire nonce is published before the * message is known. */ for (i = 0; i < 2; i++) { SECP256K1_CHECKMEM_UNDEFINE(session_secrand[i], 32); SECP256K1_CHECKMEM_UNDEFINE(&secshares[32 * i], 32); ret = secp256k1_frost_nonce_gen(ctx, &pf_secnonce[i], &pf_pubnonce[i], session_secrand[i], &secshares[32 * i], &pubshares[i], NULL, NULL, 0, NULL, 0); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&pf_pubnonce[i], sizeof(pf_pubnonce[i])); } /* Aggregation is over published nonces only, so it is public. */ CHECK(secp256k1_prefractal_nonce_agg(ctx, &group_pubnonce, &pf_aggnonce, pf_pubnonce_ptrs, pf_ids, 2, &thresh_pk) == 1); /* The share and the secnonce are secret; the partial signature is the * public output. */ ret = secp256k1_prefractal_sign(ctx, &pf_partial_sig, &pf_secnonce[0], &secshares[0], pf_ids[0], pf_ids, pubshares, 2, &pf_aggnonce, &thresh_pk, &pf_cache, &outer_cache, &cosigner_aggnonce, msg); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&pf_partial_sig, sizeof(pf_partial_sig)); } #endif #ifdef ENABLE_MODULE_FROST_ENROLLMENT { /* A 2-of-3 group enrolling a fourth participant, taken through all * three rounds. Secret here is the threshold key, the secret shares * derived from it, the session randomness the split comes from, and * every delta and sigma value on the wire -- those are additive shares * of real secret shares. Not secret: the identifiers, the public * shares, the threshold public key, the parameters hashes, and the * public share derived for the new participant. */ unsigned char thresh_seckey[32]; unsigned char secshares[3 * 32]; unsigned char session_secrand[2][32]; unsigned char shares[2][2 * 32]; unsigned char all_shares[2 * 32]; unsigned char received_hashes[2 * 32]; unsigned char params_hashes[2][32]; unsigned char sigmas[2 * 32]; unsigned char new_secshare[32]; unsigned char direct_hash[32]; secp256k1_pubkey thresh_pk, pubshares[3], new_pubshare; uint32_t fe_ids[2] = { 0, 1 }; uint32_t mismatch_id; int j; SECP256K1_CHECKMEM_DEFINE(key, 32); memcpy(thresh_seckey, key, sizeof(thresh_seckey)); thresh_seckey[0] = thresh_seckey[0] + 9; memcpy(session_secrand[0], key, 32); session_secrand[0][0] = session_secrand[0][0] + 10; memcpy(session_secrand[1], key, 32); session_secrand[1][0] = session_secrand[1][0] + 11; SECP256K1_CHECKMEM_UNDEFINE(thresh_seckey, sizeof(thresh_seckey)); ret = secp256k1_frost_trusted_dealer_keygen(ctx, secshares, &thresh_pk, pubshares, 3, 2, thresh_seckey); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&thresh_pk, sizeof(thresh_pk)); SECP256K1_CHECKMEM_DEFINE(pubshares, sizeof(pubshares)); /* The parameters hash and the public share at the target identifier * are functions of public data alone, so these calls take no secret * input. Their outputs are not compared against anything here: this * is a constant-time harness, and correctness is tests_impl.h's job. */ CHECK(secp256k1_frost_enrollment_params_hash(ctx, direct_hash, &thresh_pk, fe_ids, 2, 3, 3, 2) == 1); CHECK(secp256k1_frost_enrollment_pubshare_derive(ctx, &new_pubshare, pubshares, fe_ids, 2, 3, 3, 2) == 1); /* Round 1.1. The seed and the secret share are secret; the parameters * hash is public and is marked so, while the delta values stay * secret and are carried into round 1.2 undefined. */ for (i = 0; i < 2; i++) { SECP256K1_CHECKMEM_UNDEFINE(session_secrand[i], 32); SECP256K1_CHECKMEM_UNDEFINE(&secshares[32 * i], 32); ret = secp256k1_frost_enrollment_shares_gen(ctx, shares[i], params_hashes[i], session_secrand[i], &secshares[32 * i], &thresh_pk, fe_ids, 2, fe_ids[i], 3, 3, 2); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(params_hashes[i], 32); } /* Round 1.2, for both helpers. The delta values stay secret through * the sum; only the return value is examined. */ for (j = 0; j < 2; j++) { memset(received_hashes, 0, sizeof(received_hashes)); for (i = 0; i < 2; i++) { memcpy(&all_shares[32 * i], &shares[i][32 * j], 32); if (i != j) { memcpy(&received_hashes[32 * i], params_hashes[i], 32); } } ret = secp256k1_frost_enrollment_share_agg(ctx, &sigmas[32 * j], &mismatch_id, all_shares, received_hashes, &thresh_pk, fe_ids, 2, fe_ids[j], 3, 3, 2); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); } /* Round 2, with both optional checks on. The resulting share is * secret; the verification against the expected public share is the * one place a secret-derived point is deliberately declassified. */ ret = secp256k1_frost_enrollment_secshare_gen(ctx, new_secshare, sigmas, &thresh_pk, fe_ids, 2, 3, 3, 2, params_hashes[0], &new_pubshare); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); } #endif #ifdef ENABLE_MODULE_ICEBERG { /* A 3-of-5 group, dealt from `key` and taken as far as one signature * share. Secret here is the dealer's root seed and everything the * module derives from it: the per-subset seeds, the key share, and the * two nonce shares. Not secret: participant indices, the group and * threshold, every Lagrange weight, the commitments, the session label, * and both nonce coefficients. */ enum { ICEBERG_N = 5, ICEBERG_T = 3, ICEBERG_MU = 2 * ICEBERG_T - 1 }; secp256k1_iceberg_share shares[ICEBERG_N]; secp256k1_iceberg_share *share_ptr[ICEBERG_N]; secp256k1_iceberg_share_cache share_cache; secp256k1_iceberg_pubshare pubshares[ICEBERG_N]; const secp256k1_iceberg_pubshare *pubshare_ptr[ICEBERG_N]; secp256k1_iceberg_pubnonce nonces[ICEBERG_N]; const secp256k1_iceberg_pubnonce *nonce_ptr[ICEBERG_N]; secp256k1_iceberg_aggnonce iceberg_aggnonce; secp256k1_iceberg_partial_sig iceberg_psig; secp256k1_musig_pubnonce group_pubnonce, cosigner_pubnonce; const secp256k1_musig_pubnonce *cosigner_ptr[1]; secp256k1_musig_secnonce cosigner_secnonce; secp256k1_musig_aggnonce cosigner_aggnonce; secp256k1_musig_keyagg_cache iceberg_cache; secp256k1_pubkey group_pk, cosigner_pk; const secp256k1_pubkey *iceberg_pk_ptr[2]; unsigned char share_bytes[SECP256K1_ICEBERG_SHARE_MAX_LEN]; unsigned char sid[32], cosigner_secrand[32]; size_t share_len; int party; for (party = 0; party < ICEBERG_N; party++) { share_ptr[party] = &shares[party]; pubshare_ptr[party] = &pubshares[party]; nonce_ptr[party] = &nonces[party]; } SECP256K1_CHECKMEM_DEFINE(key, 32); /* The cosigner needs randomness distinct from the dealer's root seed; * any perturbation of `key` will do. */ memcpy(cosigner_secrand, key, sizeof(cosigner_secrand)); cosigner_secrand[0] = cosigner_secrand[0] + 3; CHECK(secp256k1_keypair_create(ctx, &keypair, key)); CHECK(secp256k1_keypair_pub(ctx, &cosigner_pk, &keypair)); SECP256K1_CHECKMEM_UNDEFINE(key, 32); ret = secp256k1_iceberg_shares_gen(ctx, share_ptr, ICEBERG_N, ICEBERG_T, key); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); /* Storing and restoring a share moves seed material through a buffer, * which is where a length or an offset computed from it would show. */ share_len = sizeof(share_bytes); ret = secp256k1_iceberg_share_serialize(ctx, share_bytes, &share_len, &shares[0]); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); ret = secp256k1_iceberg_share_parse(ctx, &shares[0], share_bytes, share_len); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); ret = secp256k1_iceberg_share_cache_create(ctx, &share_cache, &shares[0]); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); /* The header says the cache holds no secret, and this is the line that * makes that a result rather than a claim. Every byte of it must be * defined: the weights come from the group size, the threshold and the * participant index, all of which are public, and none of them from a * seed. Declassifying is not the same test: it would say the value may be * published, where this says nothing secret reached it. */ SECP256K1_CHECKMEM_CHECK(&share_cache, sizeof(share_cache)); for (party = 0; party < ICEBERG_N; party++) { ret = secp256k1_iceberg_pubshare_gen(ctx, &pubshares[party], &shares[party], party == 0 ? &share_cache : NULL); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); } /* A commitment is public, and so is everything built from one. */ SECP256K1_CHECKMEM_DEFINE(pubshares, sizeof(pubshares)); CHECK(secp256k1_iceberg_pubkey_agg(ctx, &group_pk, pubshare_ptr, ICEBERG_MU, ICEBERG_N, ICEBERG_T) == 1); iceberg_pk_ptr[0] = &group_pk; iceberg_pk_ptr[1] = &cosigner_pk; CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &iceberg_cache, iceberg_pk_ptr, 2)); SECP256K1_CHECKMEM_DEFINE(msg, sizeof(msg)); SECP256K1_CHECKMEM_UNDEFINE(cosigner_secrand, sizeof(cosigner_secrand)); ret = secp256k1_musig_nonce_gen(ctx, &cosigner_secnonce, &cosigner_pubnonce, cosigner_secrand, NULL, &cosigner_pk, msg, &iceberg_cache, NULL); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); SECP256K1_CHECKMEM_DEFINE(&cosigner_pubnonce, sizeof(cosigner_pubnonce)); cosigner_ptr[0] = &cosigner_pubnonce; CHECK(secp256k1_musig_nonce_agg(ctx, &cosigner_aggnonce, cosigner_ptr, 1)); memset(sid, 0x7e, sizeof(sid)); /* public: the label is the caller's to choose */ for (party = 0; party < ICEBERG_MU; party++) { ret = secp256k1_iceberg_nonce_gen(ctx, &nonces[party], &shares[party], party == 0 ? &share_cache : NULL, sid); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); } SECP256K1_CHECKMEM_DEFINE(nonces, sizeof(nonces)); CHECK(secp256k1_iceberg_nonce_agg(ctx, &group_pubnonce, &iceberg_aggnonce, nonce_ptr, ICEBERG_MU, ICEBERG_N, ICEBERG_T, &group_pk) == 1); ret = secp256k1_iceberg_partial_sign(ctx, &iceberg_psig, &shares[0], &share_cache, sid, nonce_ptr, ICEBERG_MU, &group_pk, &iceberg_cache, msg, &cosigner_aggnonce); SECP256K1_CHECKMEM_DEFINE(&ret, sizeof(ret)); CHECK(ret == 1); } #endif } #if defined(__GNUC__) # pragma GCC diagnostic pop #endif