Skip to content

Commit 0283a11

Browse files
committed
Merge #1866: musig: Add hash context tests
fac66a1 musig: add hash context tests (mllwchrry) Pull request description: Adds missing hash context tests for the musig module, covering the`pubkey_agg`, `nonce_gen`, and `nonce_process` functions. Follows the same pattern as the hash context tests for other modules added in #1777. ACKs for top commit: theStack: ACK fac66a1 furszy: utACK fac66a1 Tree-SHA512: 917327a63e62d7e78887092ff02ab2f2691ab84e4a46b513f9471202d1d1b8920f5f7cd90fd6801bea9a09b5499eec50b263dcbe2ae17dad7caa66e1d9752460
2 parents 31716e4 + fac66a1 commit 0283a11

1 file changed

Lines changed: 92 additions & 0 deletions

File tree

‎src/modules/musig/tests_impl.h‎

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "../../group.h"
2121
#include "../../hash.h"
2222
#include "../../util.h"
23+
#include "../../testutil.h"
2324
#include "../../unit_test.h"
2425

2526
#include "vectors.h"
@@ -608,6 +609,96 @@ static void sha256_tag_test(void) {
608609
}
609610
}
610611

612+
DEFINE_SHA256_TRANSFORM_PROBE(sha256_musig_pubkey_agg)
613+
DEFINE_SHA256_TRANSFORM_PROBE(sha256_musig_nonce_gen)
614+
DEFINE_SHA256_TRANSFORM_PROBE(sha256_musig_nonce_gen_counter)
615+
DEFINE_SHA256_TRANSFORM_PROBE(sha256_musig_nonce_process)
616+
DEFINE_SHA256_TRANSFORM_PROBE(sha256_musig_partial_sign)
617+
DEFINE_SHA256_TRANSFORM_PROBE(sha256_musig_partial_sig_verify)
618+
/* Check that a ctx-provided SHA256 compression override takes effect in every musig
619+
* API function that uses the hash context. These functions share the same signing
620+
* session, so the setup is built only once with the default compression, then each
621+
* function is re-run with its own override enabled. */
622+
static void musig_ctx_sha256(void) {
623+
secp256k1_context *ctx = secp256k1_context_clone(CTX);
624+
secp256k1_musig_keyagg_cache keyagg_cache, keyagg_cache_custom;
625+
secp256k1_musig_secnonce secnonce, secnonce_tmp, secnonce_unused;
626+
secp256k1_musig_pubnonce pubnonce, pubnonce_custom;
627+
secp256k1_musig_pubnonce pubnonce_counter, pubnonce_counter_custom;
628+
const secp256k1_musig_pubnonce *pubnonce_ptr[1];
629+
secp256k1_musig_aggnonce aggnonce;
630+
secp256k1_musig_session session, session_custom;
631+
secp256k1_musig_partial_sig partial_sig, partial_sig_custom;
632+
const unsigned char sk[32] = {1};
633+
const unsigned char msg32[32] = {1};
634+
unsigned char secrand[32] = {1};
635+
secp256k1_keypair keypair;
636+
secp256k1_pubkey pk;
637+
const secp256k1_pubkey *pks[1];
638+
639+
CHECK(secp256k1_keypair_create(ctx, &keypair, sk) == 1);
640+
CHECK(secp256k1_keypair_pub(ctx, &pk, &keypair) == 1);
641+
pks[0] = &pk;
642+
pubnonce_ptr[0] = &pubnonce;
643+
644+
/* Run a full signing session with the default compression. */
645+
CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &keyagg_cache, pks, 1) == 1);
646+
CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce, &pubnonce, secrand, sk, &pk, NULL, NULL, NULL) == 1);
647+
CHECK(secp256k1_musig_nonce_agg(ctx, &aggnonce, pubnonce_ptr, 1) == 1);
648+
CHECK(secp256k1_musig_nonce_process(ctx, &session, &aggnonce, msg32, &keyagg_cache) == 1);
649+
/* partial_sign zeroes the secnonce to prevent reuse, so keep a copy for the override run */
650+
memcpy(&secnonce_tmp, &secnonce, sizeof(secnonce_tmp));
651+
CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig, &secnonce, &keypair, &keyagg_cache, &session) == 1);
652+
CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig, &pubnonce, &pk, &keyagg_cache, &session) == 1);
653+
/* nonce_gen_counter is an alternative to nonce_gen and not part of the session above,
654+
* so run it separately with the default compression. */
655+
CHECK(secp256k1_musig_nonce_gen_counter(ctx, &secnonce_unused, &pubnonce_counter, 0, &keypair, NULL, NULL, NULL) == 1);
656+
CHECK(!sha256_musig_pubkey_agg_called);
657+
CHECK(!sha256_musig_nonce_gen_called);
658+
CHECK(!sha256_musig_nonce_gen_counter_called);
659+
CHECK(!sha256_musig_nonce_process_called);
660+
CHECK(!sha256_musig_partial_sign_called);
661+
CHECK(!sha256_musig_partial_sig_verify_called);
662+
663+
/* Re-run each function with its SHA256 compression override, set directly to bypass
664+
* the ctx setter sanity checks. Each override must change the output relative to the
665+
* default run above. The override runs reuse the default inputs from above, so each
666+
* function is exercised in isolation. */
667+
ctx->hash_ctx.fn_sha256_compression = sha256_musig_pubkey_agg;
668+
CHECK(secp256k1_musig_pubkey_agg(ctx, NULL, &keyagg_cache_custom, pks, 1) == 1);
669+
CHECK(sha256_musig_pubkey_agg_called);
670+
CHECK(secp256k1_memcmp_var(keyagg_cache.data, keyagg_cache_custom.data, sizeof(keyagg_cache.data)) != 0);
671+
672+
/* Restore secrand (nonce_gen zeroed it). */
673+
secrand[0] = 1;
674+
ctx->hash_ctx.fn_sha256_compression = sha256_musig_nonce_gen;
675+
CHECK(secp256k1_musig_nonce_gen(ctx, &secnonce_unused, &pubnonce_custom, secrand, sk, &pk, NULL, NULL, NULL) == 1);
676+
CHECK(sha256_musig_nonce_gen_called);
677+
CHECK(secp256k1_memcmp_var(pubnonce.data, pubnonce_custom.data, sizeof(pubnonce.data)) != 0);
678+
679+
ctx->hash_ctx.fn_sha256_compression = sha256_musig_nonce_process;
680+
CHECK(secp256k1_musig_nonce_process(ctx, &session_custom, &aggnonce, msg32, &keyagg_cache) == 1);
681+
CHECK(sha256_musig_nonce_process_called);
682+
CHECK(secp256k1_memcmp_var(session.data, session_custom.data, sizeof(session.data)) != 0);
683+
684+
ctx->hash_ctx.fn_sha256_compression = sha256_musig_partial_sign;
685+
CHECK(secp256k1_musig_partial_sign(ctx, &partial_sig_custom, &secnonce_tmp, &keypair, &keyagg_cache, &session) == 1);
686+
CHECK(sha256_musig_partial_sign_called);
687+
CHECK(secp256k1_memcmp_var(partial_sig.data, partial_sig_custom.data, sizeof(partial_sig.data)) != 0);
688+
689+
/* The default partial sig no longer verifies once the override changes the KeyAgg coefficient. */
690+
ctx->hash_ctx.fn_sha256_compression = sha256_musig_partial_sig_verify;
691+
CHECK(secp256k1_musig_partial_sig_verify(ctx, &partial_sig, &pubnonce, &pk, &keyagg_cache, &session) == 0);
692+
CHECK(sha256_musig_partial_sig_verify_called);
693+
694+
ctx->hash_ctx.fn_sha256_compression = sha256_musig_nonce_gen_counter;
695+
CHECK(secp256k1_musig_nonce_gen_counter(ctx, &secnonce_unused, &pubnonce_counter_custom, 0, &keypair, NULL, NULL, NULL) == 1);
696+
CHECK(sha256_musig_nonce_gen_counter_called);
697+
CHECK(secp256k1_memcmp_var(pubnonce_counter.data, pubnonce_counter_custom.data, sizeof(pubnonce_counter.data)) != 0);
698+
699+
secp256k1_context_destroy(ctx);
700+
}
701+
611702
/* Attempts to create a signature for the aggregate public key using given secret
612703
* keys and keyagg_cache. */
613704
static void musig_tweak_test_helper(const secp256k1_xonly_pubkey* agg_pk, const unsigned char *sk0, const unsigned char *sk1, secp256k1_musig_keyagg_cache *keyagg_cache) {
@@ -1172,6 +1263,7 @@ static const struct tf_test_entry tests_musig[] = {
11721263
CASE1(musig_nonce_test),
11731264
CASE1(musig_tweak_test),
11741265
CASE1(sha256_tag_test),
1266+
CASE1(musig_ctx_sha256),
11751267
CASE1(musig_test_vectors_keyagg),
11761268
CASE1(musig_test_vectors_noncegen),
11771269
CASE1(musig_test_vectors_nonceagg),

0 commit comments

Comments
 (0)