Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

schnorrsig API overhaul #844

Merged
merged 9 commits into from
Jul 3, 2021
28 changes: 15 additions & 13 deletions include/secp256k1_schnorrsig.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,14 +23,15 @@ extern "C" {
*
* 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 (will not be NULL)
* key32: pointer to a 32-byte secret key (will not be NULL)
* xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
* (will not be NULL)
* algo16: pointer to a 16-byte array describing the signature
* algorithm (will not be NULL).
* data: Arbitrary data pointer that is passed through.
* Out: nonce32: pointer to a 32-byte array to be filled by the function
* In: msg32: the 32-byte message hash being verified (will not be NULL)
* key32: pointer to a 32-byte secret key (will not be NULL)
* xonly_pk32: the 32-byte serialized xonly pubkey corresponding to key32
* (will not be NULL)
jonasnick marked this conversation as resolved.
Show resolved Hide resolved
* algo: pointer to an array describing the signature
* algorithm (will not be NULL)
* 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.
Expand All @@ -40,7 +41,8 @@ typedef int (*secp256k1_nonce_function_hardened)(
const unsigned char *msg32,
const unsigned char *key32,
const unsigned char *xonly_pk32,
const unsigned char *algo16,
const unsigned char *algo,
size_t algolen,
void *data
);

Expand All @@ -51,10 +53,10 @@ typedef int (*secp256k1_nonce_function_hardened)(
* 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. If the data pointer is NULL,
* the nonce derivation procedure follows BIP-340 by setting the auxiliary
* random data to zero. The algo16 argument must be non-NULL, otherwise the
* function will fail and return 0. The hash will be tagged with algo16 after
* removing all terminating null bytes. Therefore, to create BIP-340 compliant
* signatures, algo16 must be set to "BIP0340/nonce\0\0\0"
* random data to zero. The algo argument must be non-NULL, otherwise the
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I was about to suggest that maybe we could allow algo == NULL if algolen == 0 But I'm not sure. If don't think we want to encourage users to use empty strings...

* function will fail and return 0. The hash will be tagged with algo.
* Therefore, to create BIP-340 compliant signatures, algo must be set to
* "BIP0340/nonce" and algolen to 13.
*/
SECP256K1_API extern const secp256k1_nonce_function_hardened secp256k1_nonce_function_bip340;

Expand Down
22 changes: 9 additions & 13 deletions src/modules/schnorrsig/main_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,16 +43,16 @@ static void secp256k1_nonce_function_bip340_sha256_tagged_aux(secp256k1_sha256 *
sha->bytes = 64;
}

/* algo16 argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340
/* algo argument for nonce_function_bip340 to derive the nonce exactly as stated in BIP-340
* by using the correct tagged hash function. */
static const unsigned char bip340_algo16[16] = "BIP0340/nonce\0\0\0";
static const unsigned char bip340_algo[13] = "BIP0340/nonce";

static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
secp256k1_sha256 sha;
unsigned char masked_key[32];
int i;

if (algo16 == NULL) {
if (algo == NULL) {
return 0;
}

Expand All @@ -65,18 +65,14 @@ static int nonce_function_bip340(unsigned char *nonce32, const unsigned char *ms
}
}

/* Tag the hash with algo16 which is important to avoid nonce reuse across
/* Tag the hash with algo which is important to avoid nonce reuse across
* algorithms. If this nonce function is used in BIP-340 signing as defined
* in the spec, an optimized tagging implementation is used. */
if (secp256k1_memcmp_var(algo16, bip340_algo16, 16) == 0) {
if (algolen == sizeof(bip340_algo)
&& secp256k1_memcmp_var(algo, bip340_algo, algolen) == 0) {
secp256k1_nonce_function_bip340_sha256_tagged(&sha);
} else {
int algo16_len = 16;
/* Remove terminating null bytes */
while (algo16_len > 0 && !algo16[algo16_len - 1]) {
algo16_len--;
}
secp256k1_sha256_initialize_tagged(&sha, algo16, algo16_len);
secp256k1_sha256_initialize_tagged(&sha, algo, algolen);
}

/* Hash (masked-)key||pk||msg using the tagged hash as per the spec */
Expand Down Expand Up @@ -156,7 +152,7 @@ int secp256k1_schnorrsig_sign(const secp256k1_context* ctx, unsigned char *sig64

secp256k1_scalar_get_b32(seckey, &sk);
secp256k1_fe_get_b32(pk_buf, &pk.x);
ret &= !!noncefp(buf, msg32, seckey, pk_buf, bip340_algo16, ndata);
ret &= !!noncefp(buf, msg32, seckey, pk_buf, bip340_algo, sizeof(bip340_algo), ndata);
secp256k1_scalar_set_b32(&k, buf, NULL);
ret &= !secp256k1_scalar_is_zero(&k);
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
Expand Down
6 changes: 4 additions & 2 deletions src/modules/schnorrsig/tests_exhaustive_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,13 +60,15 @@ static const unsigned char invalid_pubkey_bytes[][32] = {

static int secp256k1_hardened_nonce_function_smallint(unsigned char *nonce32, const unsigned char *msg32,
const unsigned char *key32, const unsigned char *xonly_pk32,
const unsigned char *algo16, void* data) {
const unsigned char *algo, size_t algolen,
void* data) {
secp256k1_scalar s;
int *idata = data;
(void)msg32;
(void)key32;
(void)xonly_pk32;
(void)algo16;
(void)algo;
(void)algolen;
secp256k1_scalar_set_int(&s, *idata);
secp256k1_scalar_get_b32(nonce32, &s);
return 1;
Expand Down
70 changes: 39 additions & 31 deletions src/modules/schnorrsig/tests_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many
* bytes) changes the hash function
*/
void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) {
void nonce_function_bip340_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t algolen) {
unsigned char nonces[2][32];
CHECK(nonce_function_bip340(nonces[0], args[0], args[1], args[2], args[3], args[4]) == 1);
CHECK(nonce_function_bip340(nonces[0], args[0], args[1], args[2], args[3], algolen, args[4]) == 1);
secp256k1_testrand_flip(args[n_flip], n_bytes);
CHECK(nonce_function_bip340(nonces[1], args[0], args[1], args[2], args[3], args[4]) == 1);
CHECK(nonce_function_bip340(nonces[1], args[0], args[1], args[2], args[3], algolen, args[4]) == 1);
CHECK(secp256k1_memcmp_var(nonces[0], nonces[1], 32) != 0);
}

Expand All @@ -34,7 +34,8 @@ void test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_sha256 *sha2)
void run_nonce_function_bip340_tests(void) {
unsigned char tag[13] = "BIP0340/nonce";
unsigned char aux_tag[11] = "BIP0340/aux";
unsigned char algo16[16] = "BIP0340/nonce\0\0\0";
unsigned char algo[13] = "BIP0340/nonce";
size_t algolen = sizeof(algo);
secp256k1_sha256 sha;
secp256k1_sha256 sha_optimized;
unsigned char nonce[32];
Expand Down Expand Up @@ -68,33 +69,37 @@ void run_nonce_function_bip340_tests(void) {
args[0] = msg;
args[1] = key;
args[2] = pk;
args[3] = algo16;
args[3] = algo;
args[4] = aux_rand;
for (i = 0; i < count; i++) {
nonce_function_bip340_bitflip(args, 0, 32);
nonce_function_bip340_bitflip(args, 1, 32);
nonce_function_bip340_bitflip(args, 2, 32);
/* Flip algo16 special case "BIP0340/nonce" */
nonce_function_bip340_bitflip(args, 3, 16);
/* Flip algo16 again */
nonce_function_bip340_bitflip(args, 3, 16);
nonce_function_bip340_bitflip(args, 4, 32);
nonce_function_bip340_bitflip(args, 0, 32, algolen);
nonce_function_bip340_bitflip(args, 1, 32, algolen);
nonce_function_bip340_bitflip(args, 2, 32, algolen);
/* Flip algo special case "BIP0340/nonce" */
nonce_function_bip340_bitflip(args, 3, algolen, algolen);
/* Flip algo again */
nonce_function_bip340_bitflip(args, 3, algolen, algolen);
nonce_function_bip340_bitflip(args, 4, 32, algolen);
}

/* NULL algo16 is disallowed */
CHECK(nonce_function_bip340(nonce, msg, key, pk, NULL, NULL) == 0);
/* Empty algo16 is fine */
memset(algo16, 0x00, 16);
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
/* algo16 with terminating null bytes is fine */
algo16[1] = 65;
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
/* Other algo16 is fine */
memset(algo16, 0xFF, 16);
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
/* NULL algo is disallowed */
CHECK(nonce_function_bip340(nonce, msg, key, pk, NULL, 0, NULL) == 0);
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo, algolen, NULL) == 1);
/* Other algo is fine */
secp256k1_rfc6979_hmac_sha256_generate(&secp256k1_test_rng, algo, algolen);
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo, algolen, NULL) == 1);

for (i = 0; i < count; i++) {
unsigned char nonce2[32];
/* Different algolen gives different nonce */
uint32_t offset = secp256k1_testrand_int(algolen - 1);
size_t algolen_tmp = (algolen + offset) % algolen;
CHECK(nonce_function_bip340(nonce2, msg, key, pk, algo, algolen_tmp, NULL) == 1);
CHECK(secp256k1_memcmp_var(nonce, nonce2, 32) != 0);
}

/* NULL aux_rand argument is allowed. */
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo16, NULL) == 1);
CHECK(nonce_function_bip340(nonce, msg, key, pk, algo, algolen, NULL) == 1);
}

void test_schnorrsig_api(void) {
Expand Down Expand Up @@ -634,34 +639,37 @@ void test_schnorrsig_bip_vectors(void) {
}

/* Nonce function that returns constant 0 */
static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
static int nonce_function_failing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
(void) msg32;
(void) key32;
(void) xonly_pk32;
(void) algo16;
(void) algo;
(void) algolen;
(void) data;
(void) nonce32;
return 0;
}

/* Nonce function that sets nonce to 0 */
static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
static int nonce_function_0(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
(void) msg32;
(void) key32;
(void) xonly_pk32;
(void) algo16;
(void) algo;
(void) algolen;
(void) data;

memset(nonce32, 0, 32);
return 1;
}

/* Nonce function that sets nonce to 0xFF...0xFF */
static int nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo16, void *data) {
static int nonce_function_overflowing(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, const unsigned char *xonly_pk32, const unsigned char *algo, size_t algolen, void *data) {
(void) msg32;
(void) key32;
(void) xonly_pk32;
(void) algo16;
(void) algo;
(void) algolen;
(void) data;

memset(nonce32, 0xFF, 32);
Expand Down