diff --git a/include/secp256k1_ecdsa_adaptor.h b/include/secp256k1_ecdsa_adaptor.h index 60da16a4..7bc43277 100644 --- a/include/secp256k1_ecdsa_adaptor.h +++ b/include/secp256k1_ecdsa_adaptor.h @@ -12,6 +12,40 @@ extern "C" { * and https://github.com/LLFourn/one-time-VES/blob/master/main.pdf). */ +/** A pointer to a function to deterministically generate a nonce. + * + * Same as secp256k1_nonce_function_hardened with the exception of using the + * compressed 33-byte encoding for the pubkey argument. + * + * Returns: 1 if a nonce was successfully generated. 0 will cause signing to + * return an error. + * Out: nonce32: pointer to a 32-byte array to be filled by the function + * In: msg32: the 32-byte message hash being verified + * key32: pointer to a 32-byte secret key + * pk33: the 33-byte serialized pubkey corresponding to key32 + * algo: pointer to an array describing the signature algorithm + * algolen: the length of the algo array + * data: arbitrary data pointer that is passed through + * + * Except for test cases, this function should compute some cryptographic hash of + * the message, the key, the pubkey, the algorithm description, and data. + */ +typedef int (*secp256k1_nonce_function_hardened_ecdsa_adaptor)( + unsigned char *nonce32, + const unsigned char *msg32, + const unsigned char *key32, + const unsigned char *pk33, + const unsigned char *algo, + size_t algolen, + void *data +); + +/** A modified BIP-340 nonce generation function. If a data pointer is passed, it is + * assumed to be a pointer to 32 bytes of auxiliary random data as defined in BIP-340. + * The hash will be tagged with algo after removing all terminating null bytes. + */ +SECP256K1_API extern const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor; + #ifdef __cplusplus } #endif diff --git a/src/modules/ecdsa_adaptor/Makefile.am.include b/src/modules/ecdsa_adaptor/Makefile.am.include index 17766fed..31c881a3 100644 --- a/src/modules/ecdsa_adaptor/Makefile.am.include +++ b/src/modules/ecdsa_adaptor/Makefile.am.include @@ -1 +1,2 @@ include_HEADERS += include/secp256k1_ecdsa_adaptor.h +noinst_HEADERS += src/modules/ecdsa_adaptor/main_impl.h diff --git a/src/modules/ecdsa_adaptor/main_impl.h b/src/modules/ecdsa_adaptor/main_impl.h index 79b98fee..e7426f59 100644 --- a/src/modules/ecdsa_adaptor/main_impl.h +++ b/src/modules/ecdsa_adaptor/main_impl.h @@ -9,4 +9,82 @@ #include "include/secp256k1_ecdsa_adaptor.h" +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("ECDSAadaptor/non")||SHA256("ECDSAadaptor/non"). */ +static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0x791dae43ul; + sha->s[1] = 0xe52d3b44ul; + sha->s[2] = 0x37f9edeaul; + sha->s[3] = 0x9bfd2ab1ul; + sha->s[4] = 0xcfb0f44dul; + sha->s[5] = 0xccf1d880ul; + sha->s[6] = 0xd18f2c13ul; + sha->s[7] = 0xa37b9024ul; + + sha->bytes = 64; +} + +/* Initializes SHA256 with fixed midstate. This midstate was computed by applying + * SHA256 to SHA256("ECDSAadaptor/aux")||SHA256("ECDSAadaptor/aux"). */ +static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux(secp256k1_sha256 *sha) { + secp256k1_sha256_initialize(sha); + sha->s[0] = 0xd14c7bd9ul; + sha->s[1] = 0x095d35e6ul; + sha->s[2] = 0xb8490a88ul; + sha->s[3] = 0xfb00ef74ul; + sha->s[4] = 0x0baa488ful; + sha->s[5] = 0x69366693ul; + sha->s[6] = 0x1c81c5baul; + sha->s[7] = 0xc33b296aul; + + sha->bytes = 64; +} + +/* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */ +static const unsigned char ecdsa_adaptor_algo[16] = "ECDSAadaptor/non"; + +/* Modified BIP-340 nonce function */ +static int nonce_function_ecdsa_adaptor(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *pk33, const unsigned char *algo, size_t algolen, void *data) { + secp256k1_sha256 sha; + unsigned char masked_key[32]; + int i; + + if (algo == NULL) { + return 0; + } + + if (data != NULL) { + secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux(&sha); + secp256k1_sha256_write(&sha, data, 32); + secp256k1_sha256_finalize(&sha, masked_key); + for (i = 0; i < 32; i++) { + masked_key[i] ^= key32[i]; + } + } + + /* Tag the hash with algo which is important to avoid nonce reuse across + * algorithims. An optimized tagging implementation is used if the default + * tag is provided. */ + if (algolen == sizeof(ecdsa_adaptor_algo) + && secp256k1_memcmp_var(algo, ecdsa_adaptor_algo, algolen) == 0) { + secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(&sha); + } else { + secp256k1_sha256_initialize_tagged(&sha, algo, algolen); + } + + /* Hash (masked-)key||pk||msg using the tagged hash as per BIP-340 */ + if (data != NULL) { + secp256k1_sha256_write(&sha, masked_key, 32); + } else { + secp256k1_sha256_write(&sha, key32, 32); + } + secp256k1_sha256_write(&sha, pk33, 33); + secp256k1_sha256_write(&sha, msg32, 32); + secp256k1_sha256_finalize(&sha, nonce32); + return 1; +} + +const secp256k1_nonce_function_hardened_ecdsa_adaptor secp256k1_nonce_function_ecdsa_adaptor = nonce_function_ecdsa_adaptor; + #endif