Merge bitcoin-core/secp256k1#1725: tests: refactor tagged hash verification

5153cf1c91 tests: refactor tagged hash tests (josibake)

Pull request description:

  Opened in response to https://github.com/bitcoin-core/secp256k1/pull/1698#discussion_r2269449070

  ---

  We use tagged hashes in `modules/musig`, `modules/schnorrsig`, `modules/ellswift`, and the proposed `modules/silentpayments`. In looking for inspiration on how to add tagged hash midstate verification for https://github.com/bitcoin-core/secp256k1/pull/1698, it seemed like a good opportunity to DRY up the code across all of the modules.

  I chose the convention used in the ellswift module as this seems the most idiomatic C. Since the tags are normally specified as strings in the BIPs, I also added a comment above each char array for convenience.

  If its deemed too invasive to refactor the existing modules in this PR, I'm happy to drop the refactor commits for the ellswift and schnorrsig modules. All I need for https://github.com/bitcoin-core/secp256k1/pull/1698 is the first commit which moves the utility function out of the musig module to make it available to use in the silent payments module.

ACKs for top commit:
  real-or-random:
    utACK 5153cf1c91 assuming CI passes
  theStack:
    Code-review ACK 5153cf1c91

Tree-SHA512: 335ec3ee6a265e13cc379968f8fa1624534bef2389e4e21b85e6a9572ce1bd9dee4eabd2cb6d187ac974db3ab8246c2626d309ccfbee5744c30cf7560d1e261c
This commit is contained in:
merge-script
2025-08-21 09:56:22 +02:00
4 changed files with 36 additions and 30 deletions

View File

@@ -405,31 +405,31 @@ void run_ellswift_tests(void) {
/* Test hash initializers. */
{
secp256k1_sha256 sha, sha_optimized;
secp256k1_sha256 sha_optimized;
/* "secp256k1_ellswift_encode" */
static const unsigned char encode_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'e', 'n', 'c', 'o', 'd', 'e'};
/* "secp256k1_ellswift_create" */
static const unsigned char create_tag[] = {'s', 'e', 'c', 'p', '2', '5', '6', 'k', '1', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'c', 'r', 'e', 'a', 't', 'e'};
/* "bip324_ellswift_xonly_ecdh" */
static const unsigned char bip324_tag[] = {'b', 'i', 'p', '3', '2', '4', '_', 'e', 'l', 'l', 's', 'w', 'i', 'f', 't', '_', 'x', 'o', 'n', 'l', 'y', '_', 'e', 'c', 'd', 'h'};
/* Check that hash initialized by
* secp256k1_ellswift_sha256_init_encode has the expected
* state. */
secp256k1_sha256_initialize_tagged(&sha, encode_tag, sizeof(encode_tag));
secp256k1_ellswift_sha256_init_encode(&sha_optimized);
test_sha256_eq(&sha, &sha_optimized);
test_sha256_tag_midstate(&sha_optimized, encode_tag, sizeof(encode_tag));
/* Check that hash initialized by
* secp256k1_ellswift_sha256_init_create has the expected
* state. */
secp256k1_sha256_initialize_tagged(&sha, create_tag, sizeof(create_tag));
secp256k1_ellswift_sha256_init_create(&sha_optimized);
test_sha256_eq(&sha, &sha_optimized);
test_sha256_tag_midstate(&sha_optimized, create_tag, sizeof(create_tag));
/* Check that hash initialized by
* secp256k1_ellswift_sha256_init_bip324 has the expected
* state. */
secp256k1_sha256_initialize_tagged(&sha, bip324_tag, sizeof(bip324_tag));
secp256k1_ellswift_sha256_init_bip324(&sha_optimized);
test_sha256_eq(&sha, &sha_optimized);
test_sha256_tag_midstate(&sha_optimized, bip324_tag, sizeof(bip324_tag));
}
}

View File

@@ -548,40 +548,39 @@ static void musig_nonce_test(void) {
}
}
static void sha256_tag_test_internal(secp256k1_sha256 *sha_tagged, unsigned char *tag, size_t taglen) {
secp256k1_sha256 sha;
secp256k1_sha256_initialize_tagged(&sha, tag, taglen);
test_sha256_eq(&sha, sha_tagged);
}
/* Checks that the initialized tagged hashes have the expected
* state. */
static void sha256_tag_test(void) {
secp256k1_sha256 sha;
{
char tag[] = "KeyAgg list";
/* "KeyAgg list" */
static const unsigned char tag[] = {'K', 'e', 'y', 'A', 'g', 'g', ' ', 'l', 'i', 's', 't'};
secp256k1_musig_keyagglist_sha256(&sha);
sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1);
test_sha256_tag_midstate(&sha, tag, sizeof(tag));
}
{
char tag[] = "KeyAgg coefficient";
/* "KeyAgg coefficient" */
static const unsigned char tag[] = {'K', 'e', 'y', 'A', 'g', 'g', ' ', 'c', 'o', 'e', 'f', 'f', 'i', 'c', 'i', 'e', 'n', 't'};
secp256k1_musig_keyaggcoef_sha256(&sha);
sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1);
test_sha256_tag_midstate(&sha, tag, sizeof(tag));
}
{
unsigned char tag[] = "MuSig/aux";
/* "MuSig/aux" */
static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'a', 'u', 'x' };
secp256k1_nonce_function_musig_sha256_tagged_aux(&sha);
sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1);
test_sha256_tag_midstate(&sha, tag, sizeof(tag));
}
{
unsigned char tag[] = "MuSig/nonce";
/* "MuSig/nonce" */
static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'n', 'o', 'n', 'c', 'e' };
secp256k1_nonce_function_musig_sha256_tagged(&sha);
sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1);
test_sha256_tag_midstate(&sha, tag, sizeof(tag));
}
{
unsigned char tag[] = "MuSig/noncecoef";
/* "MuSig/noncecoef" */
static const unsigned char tag[] = { 'M', 'u', 'S', 'i', 'g', '/', 'n', 'o', 'n', 'c', 'e', 'c', 'o', 'e', 'f' };
secp256k1_musig_compute_noncehash_sha256_tagged(&sha);
sha256_tag_test_internal(&sha, (unsigned char*)tag, sizeof(tag) - 1);
test_sha256_tag_midstate(&sha, tag, sizeof(tag));
}
}

View File

@@ -21,11 +21,12 @@ static void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, s
}
static void run_nonce_function_bip340_tests(void) {
unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'};
unsigned char aux_tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'a', 'u', 'x'};
/* "BIP0340/nonce" */
static const unsigned char tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'};
/* "BIP0340/aux" */
static const unsigned char aux_tag[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'a', 'u', 'x'};
unsigned char algo[] = {'B', 'I', 'P', '0', '3', '4', '0', '/', 'n', 'o', 'n', 'c', 'e'};
size_t algolen = sizeof(algo);
secp256k1_sha256 sha;
secp256k1_sha256 sha_optimized;
unsigned char nonce[32], nonce_z[32];
unsigned char msg[32];
@@ -39,16 +40,15 @@ static void run_nonce_function_bip340_tests(void) {
/* Check that hash initialized by
* secp256k1_nonce_function_bip340_sha256_tagged has the expected
* state. */
secp256k1_sha256_initialize_tagged(&sha, tag, sizeof(tag));
secp256k1_nonce_function_bip340_sha256_tagged(&sha_optimized);
test_sha256_eq(&sha, &sha_optimized);
test_sha256_tag_midstate(&sha_optimized, tag, sizeof(tag));
/* Check that hash initialized by
* secp256k1_nonce_function_bip340_sha256_tagged_aux has the expected
* state. */
secp256k1_sha256_initialize_tagged(&sha, aux_tag, sizeof(aux_tag));
secp256k1_nonce_function_bip340_sha256_tagged_aux(&sha_optimized);
test_sha256_eq(&sha, &sha_optimized);
test_sha256_tag_midstate(&sha_optimized, aux_tag, sizeof(aux_tag));
testrand256(msg);
testrand256(key);

View File

@@ -609,6 +609,13 @@ static void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256
CHECK(sha1->bytes == sha2->bytes);
CHECK(secp256k1_memcmp_var(sha1->s, sha2->s, sizeof(sha1->s)) == 0);
}
/* Convenience function for using test_sha256_eq to verify the correctness of a
* tagged hash midstate. This function is used by some module tests. */
static void test_sha256_tag_midstate(secp256k1_sha256 *sha_tagged, const unsigned char *tag, size_t taglen) {
secp256k1_sha256 sha;
secp256k1_sha256_initialize_tagged(&sha, tag, taglen);
test_sha256_eq(&sha, sha_tagged);
}
static void run_hmac_sha256_tests(void) {
static const char *keys[6] = {