Skip to content

Commit

Permalink
Add algolen argument to nonce function
Browse files Browse the repository at this point in the history
This commit is based on code changes proposed in
bitcoin-core/secp256k1#844.

Responds to comment:
BlockstreamResearch#117 (comment)
  • Loading branch information
jesseposner committed Feb 19, 2021
1 parent 7810e7c commit 6404189
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 57 deletions.
11 changes: 6 additions & 5 deletions include/secp256k1_ecdsa_adaptor.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ extern "C" {
* 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
* algo16: pointer to a 16-byte array describing the signature
* algorithm
* 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
Expand All @@ -40,13 +40,14 @@ typedef int (*secp256k1_nonce_function_hardened_ecdsa_adaptor)(
const unsigned char *msg32,
const unsigned char *key32,
const unsigned char *pk33,
const unsigned char *algo16,
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 algo16 after removing all terminating null bytes.
* 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;

Expand Down Expand Up @@ -90,7 +91,7 @@ SECP256K1_API int secp256k1_ecdsa_adaptor_encrypt(
* In: adaptor_sig162: pointer to 162-byte signature to verify
* pubkey: pointer to the public key corresponding to the secret key
* used for signing
* msg32: pointer to the 32-byte message hash
* msg32: pointer to the 32-byte message hash being verified
* enckey: pointer to the adaptor encryption public key
*/
SECP256K1_API int secp256k1_ecdsa_adaptor_verify(
Expand Down
12 changes: 6 additions & 6 deletions src/modules/ecdsa_adaptor/dleq_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ static void secp256k1_nonce_function_dleq_sha256_tagged(secp256k1_sha256 *sha) {
sha->bytes = 64;
}

/* algo16 argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */
static const unsigned char dleq_algo16[16] = "DLEQ\0\0\0\0\0\0\0\0\0\0\0\0";
/* algo argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */
static const unsigned char dleq_algo[4] = "DLEQ";

static int secp256k1_dleq_hash_point(secp256k1_sha256 *sha, secp256k1_ge *p) {
unsigned char buf[33];
Expand All @@ -32,7 +32,7 @@ static int secp256k1_dleq_hash_point(secp256k1_sha256 *sha, secp256k1_ge *p) {
return 1;
}

static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *algo16, const secp256k1_scalar *sk, secp256k1_ge *gen2, secp256k1_ge *p1, secp256k1_ge *p2, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *algo, const secp256k1_scalar *sk, secp256k1_ge *gen2, secp256k1_ge *p1, secp256k1_ge *p2, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
secp256k1_sha256 sha;
unsigned char buf[32];
unsigned char key[32];
Expand All @@ -57,7 +57,7 @@ static int secp256k1_dleq_nonce(secp256k1_scalar *k, const unsigned char *algo16
return 0;
}

if (!noncefp(nonce, buf, key, pk, algo16, ndata)) {
if (!noncefp(nonce, buf, key, pk, algo, sizeof(algo), ndata)) {
return 0;
}
secp256k1_scalar_set_b32(k, nonce, NULL);
Expand Down Expand Up @@ -97,12 +97,12 @@ static void secp256k1_dleq_pair(const secp256k1_ecmult_gen_context *ecmult_gen_c

/* Generates a proof that the discrete logarithm of P1 to the secp256k1 base G is the
* same as the discrete logarithm of P2 to the base Y */
static int secp256k1_dleq_prove(const secp256k1_context* ctx, secp256k1_scalar *s, secp256k1_scalar *e, const unsigned char *algo16, const secp256k1_scalar *sk, secp256k1_ge *gen2, secp256k1_ge *p1, secp256k1_ge *p2, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
static int secp256k1_dleq_prove(const secp256k1_context* ctx, secp256k1_scalar *s, secp256k1_scalar *e, const unsigned char *algo, const secp256k1_scalar *sk, secp256k1_ge *gen2, secp256k1_ge *p1, secp256k1_ge *p2, secp256k1_nonce_function_hardened_ecdsa_adaptor noncefp, void *ndata) {
secp256k1_ge r1, r2;
secp256k1_scalar k = { 0 };
int ret = 1;

ret &= secp256k1_dleq_nonce(&k, algo16, sk, gen2, p1, p2, noncefp, ndata);
ret &= secp256k1_dleq_nonce(&k, algo, sk, gen2, p1, p2, noncefp, ndata);
/* R1 = k*G, R2 = k*Y */
secp256k1_dleq_pair(&ctx->ecmult_gen_ctx, &r1, &r2, &k, gen2);
/* We declassify the non-secret values r1 and r2 to allow using them as
Expand Down
27 changes: 12 additions & 15 deletions src/modules/ecdsa_adaptor/main_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -97,16 +97,16 @@ static void secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged_aux(secp256k1_s
sha->bytes = 64;
}

/* algo16 argument for nonce_function_ecdsa_adaptor to derive the nonce using a tagged hash function. */
static const unsigned char ecdsa_adaptor_algo16[16] = "ECDSAadaptor/non";
/* 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 *algo16, void *data) {
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 (algo16 == NULL) {
if (algo == NULL) {
return 0;
}

Expand All @@ -119,20 +119,17 @@ static int nonce_function_ecdsa_adaptor(unsigned char *nonce32, const unsigned c
}
}

/* 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
* algorithims. An optimized tagging implementation is used if the default
* tag is provided. */
if (secp256k1_memcmp_var(algo16, ecdsa_adaptor_algo16, 16) == 0) {
if (algolen == sizeof(ecdsa_adaptor_algo)
&& secp256k1_memcmp_var(algo, ecdsa_adaptor_algo, algolen) == 0) {
secp256k1_nonce_function_ecdsa_adaptor_sha256_tagged(&sha);
} else if (secp256k1_memcmp_var(algo16, dleq_algo16, 16) == 0) {
} else if (algolen == sizeof(dleq_algo)
&& secp256k1_memcmp_var(algo, dleq_algo, algolen) == 0) {
secp256k1_nonce_function_dleq_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 BIP-340 */
Expand Down Expand Up @@ -179,7 +176,7 @@ int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char

ret &= secp256k1_pubkey_load(ctx, &enckey_ge, enckey);
secp256k1_eckey_pubkey_serialize(&enckey_ge, buf33, &size, 1);
ret &= !!noncefp(nonce32, msg32, seckey32, buf33, ecdsa_adaptor_algo16, ndata);
ret &= !!noncefp(nonce32, msg32, seckey32, buf33, ecdsa_adaptor_algo, sizeof(ecdsa_adaptor_algo), ndata);
secp256k1_scalar_set_b32(&k, nonce32, NULL);
ret &= !secp256k1_scalar_is_zero(&k);
secp256k1_scalar_cmov(&k, &secp256k1_scalar_one, !ret);
Expand All @@ -196,7 +193,7 @@ int secp256k1_ecdsa_adaptor_encrypt(const secp256k1_context* ctx, unsigned char
secp256k1_declassify(ctx, &r, sizeof(r));

/* dleq_proof = DLEQ_prove(k, (R', Y, R)) */
ret &= secp256k1_dleq_prove(ctx, &dleq_proof_s, &dleq_proof_e, dleq_algo16, &k, &enckey_ge, &rp, &r, noncefp, ndata);
ret &= secp256k1_dleq_prove(ctx, &dleq_proof_s, &dleq_proof_e, dleq_algo, &k, &enckey_ge, &rp, &r, noncefp, ndata);

ret &= secp256k1_scalar_set_b32_seckey(&sk, seckey32);
secp256k1_scalar_cmov(&sk, &secp256k1_scalar_one, !ret);
Expand Down
73 changes: 42 additions & 31 deletions src/modules/ecdsa_adaptor/tests_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -616,34 +616,37 @@ void test_ecdsa_adaptor_spec_vectors(void) {
}

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

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

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

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

memset(nonce32, 0xFF, 32);
Expand All @@ -653,11 +656,11 @@ static int ecdsa_adaptor_nonce_function_overflowing(unsigned char *nonce32, cons
/* Checks that a bit flip in the n_flip-th argument (that has n_bytes many
* bytes) changes the hash function
*/
void nonce_function_ecdsa_adaptor_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes) {
void nonce_function_ecdsa_adaptor_bitflip(unsigned char **args, size_t n_flip, size_t n_bytes, size_t algolen) {
unsigned char nonces[2][32];
CHECK(nonce_function_ecdsa_adaptor(nonces[0], args[0], args[1], args[2], args[3], args[4]) == 1);
CHECK(nonce_function_ecdsa_adaptor(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_ecdsa_adaptor(nonces[1], args[0], args[1], args[2], args[3], args[4]) == 1);
CHECK(nonce_function_ecdsa_adaptor(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 @@ -675,7 +678,8 @@ void ecdsa_adaptor_test_sha256_eq(const secp256k1_sha256 *sha1, const secp256k1_
void run_nonce_function_ecdsa_adaptor_tests(void) {
unsigned char tag[16] = "ECDSAadaptor/non";
unsigned char aux_tag[16] = "ECDSAadaptor/aux";
unsigned char algo16[16] = "ECDSAadaptor/non";
unsigned char algo[16] = "ECDSAadaptor/non";
size_t algolen = sizeof(algo);
unsigned char dleq_tag[4] = "DLEQ";
secp256k1_sha256 sha;
secp256k1_sha256 sha_optimized;
Expand Down Expand Up @@ -717,33 +721,40 @@ void run_nonce_function_ecdsa_adaptor_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_ecdsa_adaptor_bitflip(args, 0, 32);
nonce_function_ecdsa_adaptor_bitflip(args, 1, 32);
nonce_function_ecdsa_adaptor_bitflip(args, 2, 32);
/* Flip algo16 special case "ECDSAadaptor/non" */
nonce_function_ecdsa_adaptor_bitflip(args, 3, 16);
/* Flip algo16 again */
nonce_function_ecdsa_adaptor_bitflip(args, 3, 16);
nonce_function_ecdsa_adaptor_bitflip(args, 4, 32);
nonce_function_ecdsa_adaptor_bitflip(args, 0, 32, algolen);
nonce_function_ecdsa_adaptor_bitflip(args, 1, 32, algolen);
nonce_function_ecdsa_adaptor_bitflip(args, 2, 32, algolen);
/* Flip algo special case "ECDSAadaptor/non" */
nonce_function_ecdsa_adaptor_bitflip(args, 3, 16, algolen);
/* Flip algo again */
nonce_function_ecdsa_adaptor_bitflip(args, 3, 16, algolen);
nonce_function_ecdsa_adaptor_bitflip(args, 4, 32, algolen);
}

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

/* Different algolen gives different nonce */
for (i = 0; i < count; i++) {
unsigned char nonce2[32];
uint32_t offset = secp256k1_testrand_int(algolen - 1);
size_t algolen_tmp = (algolen + offset) % algolen;

CHECK(nonce_function_ecdsa_adaptor(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_ecdsa_adaptor(nonce, msg, key, pk, algo16, NULL) == 1);
CHECK(nonce_function_ecdsa_adaptor(nonce, msg, key, pk, algo, algolen, NULL) == 1);
}

void test_ecdsa_adaptor_api(void) {
Expand Down

0 comments on commit 6404189

Please sign in to comment.