Skip to content

Commit

Permalink
ecdsa_adaptor: add nonce function and tags
Browse files Browse the repository at this point in the history
This commit adds a nonce function that will be used by default
for ECDSA adaptor signatures.

This nonce function is similar to secp256k1_nonce_function_hardened
except it uses the compressed 33-byte encoding for the pubkey argument.
We need 33 bytes instead of 32 because, unlike with BIP-340, an ECDSA
X-coordinate alone is not sufficient to disambiguate the Y-coordinate.
  • Loading branch information
jesseposner committed Mar 16, 2021
1 parent 654cd63 commit d8f3365
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 0 deletions.
34 changes: 34 additions & 0 deletions include/secp256k1_ecdsa_adaptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions src/modules/ecdsa_adaptor/Makefile.am.include
Original file line number Diff line number Diff line change
@@ -1 +1,2 @@
include_HEADERS += include/secp256k1_ecdsa_adaptor.h
noinst_HEADERS += src/modules/ecdsa_adaptor/main_impl.h
78 changes: 78 additions & 0 deletions src/modules/ecdsa_adaptor/main_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -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

0 comments on commit d8f3365

Please sign in to comment.