Skip to content

Commit 5a8e499

Browse files
committed
Add secp256k1_tagged_sha256 as defined in BIP-340
Gives users the ability to hash messages to 32 byte before they are signed while allowing efficient domain separation through the tag.
1 parent b6c0b72 commit 5a8e499

File tree

3 files changed

+71
-0
lines changed

3 files changed

+71
-0
lines changed

include/secp256k1.h

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -793,6 +793,31 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_combine(
793793
size_t n
794794
) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
795795

796+
/** Compute a tagged hash as defined in BIP-340.
797+
*
798+
* This is useful for creating a message hash and achieving domain separation
799+
* through an application-specific tag. This function returns
800+
* SHA256(SHA256(tag)||SHA256(tag)||msg). Therefore, tagged hash
801+
* implementations optimized for a specific tag can precompute the SHA256 state
802+
* after hashing the tag hashes.
803+
*
804+
* Returns 0 if the arguments are invalid and 1 otherwise.
805+
* Args: ctx: pointer to a context object
806+
* Out: hash32: pointer to a 32-byte array to store the resulting hash
807+
* In: tag: pointer to an array containing the tag
808+
* taglen: length of the tag array
809+
* msg: pointer to an array containing the message
810+
* msglen: length of the message array
811+
*/
812+
SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_tagged_sha256(
813+
const secp256k1_context* ctx,
814+
unsigned char *hash32,
815+
const unsigned char *tag,
816+
size_t taglen,
817+
const unsigned char *msg,
818+
size_t msglen
819+
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
820+
796821
#ifdef __cplusplus
797822
}
798823
#endif

src/secp256k1.c

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,19 @@ int secp256k1_ec_pubkey_combine(const secp256k1_context* ctx, secp256k1_pubkey *
790790
return 1;
791791
}
792792

793+
int secp256k1_tagged_sha256(const secp256k1_context* ctx, unsigned char *hash32, const unsigned char *tag, size_t taglen, const unsigned char *msg, size_t msglen) {
794+
secp256k1_sha256 sha;
795+
VERIFY_CHECK(ctx != NULL);
796+
ARG_CHECK(hash32 != NULL);
797+
ARG_CHECK(tag != NULL);
798+
ARG_CHECK(msg != NULL);
799+
800+
secp256k1_sha256_initialize_tagged(&sha, tag, taglen);
801+
secp256k1_sha256_write(&sha, msg, msglen);
802+
secp256k1_sha256_finalize(&sha, hash32);
803+
return 1;
804+
}
805+
793806
#ifdef ENABLE_MODULE_ECDH
794807
# include "modules/ecdh/main_impl.h"
795808
#endif

src/tests.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,38 @@ void run_rfc6979_hmac_sha256_tests(void) {
564564
secp256k1_rfc6979_hmac_sha256_finalize(&rng);
565565
}
566566

567+
void run_tagged_sha256_tests(void) {
568+
int ecount = 0;
569+
secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
570+
unsigned char tag[32] = { 0 };
571+
unsigned char msg[32] = { 0 };
572+
unsigned char hash32[32];
573+
unsigned char hash_expected[32] = {
574+
0x04, 0x7A, 0x5E, 0x17, 0xB5, 0x86, 0x47, 0xC1,
575+
0x3C, 0xC6, 0xEB, 0xC0, 0xAA, 0x58, 0x3B, 0x62,
576+
0xFB, 0x16, 0x43, 0x32, 0x68, 0x77, 0x40, 0x6C,
577+
0xE2, 0x76, 0x55, 0x9A, 0x3B, 0xDE, 0x55, 0xB3
578+
};
579+
580+
secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount);
581+
582+
/* API test */
583+
CHECK(secp256k1_tagged_sha256(none, hash32, tag, sizeof(tag), msg, sizeof(msg)) == 1);
584+
CHECK(secp256k1_tagged_sha256(none, NULL, tag, sizeof(tag), msg, sizeof(msg)) == 0);
585+
CHECK(ecount == 1);
586+
CHECK(secp256k1_tagged_sha256(none, hash32, NULL, 0, msg, sizeof(msg)) == 0);
587+
CHECK(ecount == 2);
588+
CHECK(secp256k1_tagged_sha256(none, hash32, tag, sizeof(tag), NULL, 0) == 0);
589+
CHECK(ecount == 3);
590+
591+
/* Static test vector */
592+
memcpy(tag, "tag", 3);
593+
memcpy(msg, "msg", 3);
594+
CHECK(secp256k1_tagged_sha256(none, hash32, tag, 3, msg, 3) == 1);
595+
CHECK(secp256k1_memcmp_var(hash32, hash_expected, sizeof(hash32)) == 0);
596+
secp256k1_context_destroy(none);
597+
}
598+
567599
/***** RANDOM TESTS *****/
568600

569601
void test_rand_bits(int rand32, int bits) {
@@ -6505,6 +6537,7 @@ int main(int argc, char **argv) {
65056537
run_sha256_tests();
65066538
run_hmac_sha256_tests();
65076539
run_rfc6979_hmac_sha256_tests();
6540+
run_tagged_sha256_tests();
65086541

65096542
/* scalar tests */
65106543
run_scalar_tests();

0 commit comments

Comments
 (0)