[API BREAK] Use a nonce-generation function instead of a nonce
This commit is contained in:
parent
cf0c48bea5
commit
c6e7f4e8d8
@ -77,40 +77,64 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
|
|||||||
int pubkeylen
|
int pubkeylen
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
/** A pointer to a function to deterministically generate a nonce.
|
||||||
|
* Returns: 1 if a nonce was succesfully generated. 0 will cause signing to fail.
|
||||||
|
* 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)
|
||||||
|
* attempt: how many iterations we have tried to find a nonce.
|
||||||
|
* This will almost always be 0, but different attempt values
|
||||||
|
* are required to result in a different nonce.
|
||||||
|
* data: Arbitrary data pointer that is passed through.
|
||||||
|
* Out: nonce32: pointer to a 32-byte array to be filled by the function.
|
||||||
|
* Except for test cases, this function should compute some cryptographic hash of
|
||||||
|
* the message, the key and the attempt. It is advised to use RFC6979.
|
||||||
|
*/
|
||||||
|
typedef int (*secp256k1_nonce_function_t)(
|
||||||
|
unsigned char *nonce32,
|
||||||
|
const unsigned char *msg32,
|
||||||
|
const unsigned char *key32,
|
||||||
|
unsigned int attempt,
|
||||||
|
const void *data
|
||||||
|
);
|
||||||
|
|
||||||
/** Create an ECDSA signature.
|
/** Create an ECDSA signature.
|
||||||
* Returns: 1: signature created
|
* Returns: 1: signature created
|
||||||
* 0: nonce invalid, try another one
|
* 0: the nonce generation function failed
|
||||||
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
|
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
|
||||||
* seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid)
|
* seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid)
|
||||||
* nonce: pointer to a 32-byte nonce (cannot be NULL, generated with a cryptographic PRNG)
|
* noncefp:pointer to a nonce generation function (cannot be NULL)
|
||||||
|
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
|
||||||
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
|
* Out: sig: pointer to an array where the signature will be placed (cannot be NULL)
|
||||||
* In/Out: siglen: pointer to an int with the length of sig, which will be updated
|
* In/Out: siglen: pointer to an int with the length of sig, which will be updated
|
||||||
* to contain the actual signature length (<=72).
|
* to contain the actual signature length (<=72).
|
||||||
* Requires starting using SECP256K1_START_SIGN.
|
* Requires starting using SECP256K1_START_SIGN.
|
||||||
*/
|
*/
|
||||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_sign(
|
int secp256k1_ecdsa_sign(
|
||||||
const unsigned char *msg32,
|
const unsigned char *msg32,
|
||||||
unsigned char *sig,
|
unsigned char *sig,
|
||||||
int *siglen,
|
int *siglen,
|
||||||
const unsigned char *seckey,
|
const unsigned char *seckey,
|
||||||
const unsigned char *nonce
|
secp256k1_nonce_function_t noncefp,
|
||||||
|
const void *ndata
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
|
||||||
|
|
||||||
/** Create a compact ECDSA signature (64 byte + recovery id).
|
/** Create a compact ECDSA signature (64 byte + recovery id).
|
||||||
* Returns: 1: signature created
|
* Returns: 1: signature created
|
||||||
* 0: nonce invalid, try another one
|
* 0: the nonce generation function failed
|
||||||
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
|
* In: msg32: the 32-byte message hash being signed (cannot be NULL)
|
||||||
* seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid)
|
* seckey: pointer to a 32-byte secret key (cannot be NULL, assumed to be valid)
|
||||||
* nonce: pointer to a 32-byte nonce (cannot be NULL, generated with a cryptographic PRNG)
|
* noncefp:pointer to a nonce generation function (cannot be NULL)
|
||||||
|
* ndata: pointer to arbitrary data used by the nonce generation function (can be NULL)
|
||||||
* Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL)
|
* Out: sig: pointer to a 64-byte array where the signature will be placed (cannot be NULL)
|
||||||
* recid: pointer to an int, which will be updated to contain the recovery id (can be NULL)
|
* recid: pointer to an int, which will be updated to contain the recovery id (can be NULL)
|
||||||
* Requires starting using SECP256K1_START_SIGN.
|
* Requires starting using SECP256K1_START_SIGN.
|
||||||
*/
|
*/
|
||||||
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_sign_compact(
|
int secp256k1_ecdsa_sign_compact(
|
||||||
const unsigned char *msg32,
|
const unsigned char *msg32,
|
||||||
unsigned char *sig64,
|
unsigned char *sig64,
|
||||||
const unsigned char *seckey,
|
const unsigned char *seckey,
|
||||||
const unsigned char *nonce,
|
secp256k1_nonce_function_t noncefp,
|
||||||
|
const void *ndata,
|
||||||
int *recid
|
int *recid
|
||||||
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
|
||||||
|
|
||||||
|
@ -10,15 +10,22 @@
|
|||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char msg[32];
|
unsigned char msg[32];
|
||||||
unsigned char nonce[32];
|
|
||||||
unsigned char key[32];
|
unsigned char key[32];
|
||||||
} bench_sign_t;
|
} bench_sign_t;
|
||||||
|
|
||||||
|
/** Very fast but insecure nonce generation function. Do not use for production code. */
|
||||||
|
static int insecure_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int count, const void *data) {
|
||||||
|
(void)data;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
((uint32_t*)nonce32)[i] = ((uint32_t*)msg32)[i] + ((uint32_t*)key32)[i] + count;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void bench_sign_setup(void* arg) {
|
static void bench_sign_setup(void* arg) {
|
||||||
bench_sign_t *data = (bench_sign_t*)arg;
|
bench_sign_t *data = (bench_sign_t*)arg;
|
||||||
|
|
||||||
for (int i = 0; i < 32; i++) data->msg[i] = i + 1;
|
for (int i = 0; i < 32; i++) data->msg[i] = i + 1;
|
||||||
for (int i = 0; i < 32; i++) data->nonce[i] = i + 33;
|
|
||||||
for (int i = 0; i < 32; i++) data->key[i] = i + 65;
|
for (int i = 0; i < 32; i++) data->key[i] = i + 65;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -28,9 +35,8 @@ static void bench_sign(void* arg) {
|
|||||||
unsigned char sig[64];
|
unsigned char sig[64];
|
||||||
for (int i=0; i<20000; i++) {
|
for (int i=0; i<20000; i++) {
|
||||||
int recid = 0;
|
int recid = 0;
|
||||||
CHECK(secp256k1_ecdsa_sign_compact(data->msg, sig, data->key, data->nonce, &recid));
|
secp256k1_ecdsa_sign_compact(data->msg, sig, data->key, insecure_nonce_function, NULL, &recid);
|
||||||
for (int j = 0; j < 32; j++) {
|
for (int j = 0; j < 32; j++) {
|
||||||
data->nonce[j] = data->key[j]; /* Move former key to nonce */
|
|
||||||
data->msg[j] = sig[j]; /* Move former R to message. */
|
data->msg[j] = sig[j]; /* Move former R to message. */
|
||||||
data->key[j] = sig[j + 32]; /* Move former S to key. */
|
data->key[j] = sig[j + 32]; /* Move former S to key. */
|
||||||
}
|
}
|
||||||
|
@ -14,13 +14,21 @@
|
|||||||
typedef struct {
|
typedef struct {
|
||||||
unsigned char msg[32];
|
unsigned char msg[32];
|
||||||
unsigned char key[32];
|
unsigned char key[32];
|
||||||
unsigned char nonce[32];
|
|
||||||
unsigned char sig[72];
|
unsigned char sig[72];
|
||||||
int siglen;
|
int siglen;
|
||||||
unsigned char pubkey[33];
|
unsigned char pubkey[33];
|
||||||
int pubkeylen;
|
int pubkeylen;
|
||||||
} benchmark_verify_t;
|
} benchmark_verify_t;
|
||||||
|
|
||||||
|
/** Very fast but insecure nonce generation function. Do not use for production code. */
|
||||||
|
static int insecure_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int count, const void *data) {
|
||||||
|
(void)data;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
((uint32_t*)nonce32)[i] = ((uint32_t*)msg32)[i] + ((uint32_t*)key32)[i] + count;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
static void benchmark_verify(void* arg) {
|
static void benchmark_verify(void* arg) {
|
||||||
benchmark_verify_t* data = (benchmark_verify_t*)arg;
|
benchmark_verify_t* data = (benchmark_verify_t*)arg;
|
||||||
|
|
||||||
@ -42,9 +50,8 @@ int main(void) {
|
|||||||
|
|
||||||
for (int i = 0; i < 32; i++) data.msg[i] = 1 + i;
|
for (int i = 0; i < 32; i++) data.msg[i] = 1 + i;
|
||||||
for (int i = 0; i < 32; i++) data.key[i] = 33 + i;
|
for (int i = 0; i < 32; i++) data.key[i] = 33 + i;
|
||||||
for (int i = 0; i < 32; i++) data.nonce[i] = 65 + i;
|
|
||||||
data.siglen = 72;
|
data.siglen = 72;
|
||||||
CHECK(secp256k1_ecdsa_sign(data.msg, data.sig, &data.siglen, data.key, data.nonce));
|
secp256k1_ecdsa_sign(data.msg, data.sig, &data.siglen, data.key, insecure_nonce_function, NULL);
|
||||||
data.pubkeylen = 33;
|
data.pubkeylen = 33;
|
||||||
CHECK(secp256k1_ec_pubkey_create(data.pubkey, &data.pubkeylen, data.key, 1));
|
CHECK(secp256k1_ec_pubkey_create(data.pubkey, &data.pubkeylen, data.key, 1));
|
||||||
|
|
||||||
|
@ -69,23 +69,35 @@ end:
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, const unsigned char *nonce) {
|
int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) {
|
||||||
DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL);
|
DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL);
|
||||||
DEBUG_CHECK(msg32 != NULL);
|
DEBUG_CHECK(msg32 != NULL);
|
||||||
DEBUG_CHECK(signature != NULL);
|
DEBUG_CHECK(signature != NULL);
|
||||||
DEBUG_CHECK(signaturelen != NULL);
|
DEBUG_CHECK(signaturelen != NULL);
|
||||||
DEBUG_CHECK(seckey != NULL);
|
DEBUG_CHECK(seckey != NULL);
|
||||||
DEBUG_CHECK(nonce != NULL);
|
DEBUG_CHECK(noncefp != NULL);
|
||||||
|
|
||||||
secp256k1_scalar_t sec, non, msg;
|
secp256k1_scalar_t sec, non, msg;
|
||||||
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
||||||
int overflow = 0;
|
|
||||||
secp256k1_scalar_set_b32(&non, nonce, &overflow);
|
|
||||||
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||||
int ret = !secp256k1_scalar_is_zero(&non) && !overflow;
|
int overflow = 0;
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int count = 0;
|
||||||
secp256k1_ecdsa_sig_t sig;
|
secp256k1_ecdsa_sig_t sig;
|
||||||
if (ret) {
|
while (1) {
|
||||||
ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, NULL);
|
unsigned char nonce32[32];
|
||||||
|
ret = noncefp(nonce32, msg32, seckey, count, noncedata);
|
||||||
|
if (!ret) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
|
||||||
|
memset(nonce32, 0, 32);
|
||||||
|
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
|
||||||
|
if (secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, NULL)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
|
ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
|
||||||
@ -96,22 +108,34 @@ int secp256k1_ecdsa_sign(const unsigned char *msg32, unsigned char *signature, i
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, const unsigned char *nonce, int *recid) {
|
int secp256k1_ecdsa_sign_compact(const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) {
|
||||||
DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL);
|
DEBUG_CHECK(secp256k1_ecmult_gen_consts != NULL);
|
||||||
DEBUG_CHECK(msg32 != NULL);
|
DEBUG_CHECK(msg32 != NULL);
|
||||||
DEBUG_CHECK(sig64 != NULL);
|
DEBUG_CHECK(sig64 != NULL);
|
||||||
DEBUG_CHECK(seckey != NULL);
|
DEBUG_CHECK(seckey != NULL);
|
||||||
DEBUG_CHECK(nonce != NULL);
|
DEBUG_CHECK(noncefp != NULL);
|
||||||
|
|
||||||
secp256k1_scalar_t sec, non, msg;
|
secp256k1_scalar_t sec, non, msg;
|
||||||
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
secp256k1_scalar_set_b32(&sec, seckey, NULL);
|
||||||
int overflow = 0;
|
|
||||||
secp256k1_scalar_set_b32(&non, nonce, &overflow);
|
|
||||||
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
secp256k1_scalar_set_b32(&msg, msg32, NULL);
|
||||||
int ret = !secp256k1_scalar_is_zero(&non) && !overflow;
|
int overflow = 0;
|
||||||
|
int ret = 0;
|
||||||
|
unsigned int count = 0;
|
||||||
secp256k1_ecdsa_sig_t sig;
|
secp256k1_ecdsa_sig_t sig;
|
||||||
if (ret) {
|
while (1) {
|
||||||
ret = secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid);
|
unsigned char nonce32[32];
|
||||||
|
ret = noncefp(nonce32, msg32, seckey, count, noncedata);
|
||||||
|
if (!ret) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
secp256k1_scalar_set_b32(&non, nonce32, &overflow);
|
||||||
|
memset(nonce32, 0, 32);
|
||||||
|
if (!secp256k1_scalar_is_zero(&non) && !overflow) {
|
||||||
|
if (secp256k1_ecdsa_sig_sign(&sig, &sec, &msg, &non, recid)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
count++;
|
||||||
}
|
}
|
||||||
if (ret) {
|
if (ret) {
|
||||||
secp256k1_scalar_get_b32(sig64, &sig.r);
|
secp256k1_scalar_get_b32(sig64, &sig.r);
|
||||||
|
39
src/tests.c
39
src/tests.c
@ -949,6 +949,23 @@ void run_ecdsa_sign_verify(void) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** Very fast but insecure nonce generation function. Do not use for production code. */
|
||||||
|
static int insecure_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) {
|
||||||
|
(void)data;
|
||||||
|
for (int i = 0; i < 8; i++) {
|
||||||
|
((uint32_t*)nonce32)[i] = ((uint32_t*)msg32)[i] + ((uint32_t*)key32)[i] + counter;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Dummy nonce generation function that just uses a precomputed nonce, and fails if it is not accepted. Use only for testing. */
|
||||||
|
static int precomputed_nonce_function(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) {
|
||||||
|
(void)msg32;
|
||||||
|
(void)key32;
|
||||||
|
memcpy(nonce32, data, 32);
|
||||||
|
return (counter == 0);
|
||||||
|
}
|
||||||
|
|
||||||
void test_ecdsa_end_to_end(void) {
|
void test_ecdsa_end_to_end(void) {
|
||||||
unsigned char privkey[32];
|
unsigned char privkey[32];
|
||||||
unsigned char message[32];
|
unsigned char message[32];
|
||||||
@ -1006,13 +1023,7 @@ void test_ecdsa_end_to_end(void) {
|
|||||||
|
|
||||||
/* Sign. */
|
/* Sign. */
|
||||||
unsigned char signature[72]; int signaturelen = 72;
|
unsigned char signature[72]; int signaturelen = 72;
|
||||||
while(1) {
|
CHECK(secp256k1_ecdsa_sign(message, signature, &signaturelen, privkey, insecure_nonce_function, NULL) == 1);
|
||||||
unsigned char rnd[32];
|
|
||||||
secp256k1_rand256_test(rnd);
|
|
||||||
if (secp256k1_ecdsa_sign(message, signature, &signaturelen, privkey, rnd) == 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Verify. */
|
/* Verify. */
|
||||||
CHECK(secp256k1_ecdsa_verify(message, signature, signaturelen, pubkey, pubkeylen) == 1);
|
CHECK(secp256k1_ecdsa_verify(message, signature, signaturelen, pubkey, pubkeylen) == 1);
|
||||||
/* Destroy signature and verify again. */
|
/* Destroy signature and verify again. */
|
||||||
@ -1021,13 +1032,7 @@ void test_ecdsa_end_to_end(void) {
|
|||||||
|
|
||||||
/* Compact sign. */
|
/* Compact sign. */
|
||||||
unsigned char csignature[64]; int recid = 0;
|
unsigned char csignature[64]; int recid = 0;
|
||||||
while(1) {
|
CHECK(secp256k1_ecdsa_sign_compact(message, csignature, privkey, insecure_nonce_function, NULL, &recid) == 1);
|
||||||
unsigned char rnd[32];
|
|
||||||
secp256k1_rand256_test(rnd);
|
|
||||||
if (secp256k1_ecdsa_sign_compact(message, csignature, privkey, rnd, &recid) == 1) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
/* Recover. */
|
/* Recover. */
|
||||||
unsigned char recpubkey[65]; int recpubkeylen = 0;
|
unsigned char recpubkey[65]; int recpubkeylen = 0;
|
||||||
CHECK(secp256k1_ecdsa_recover_compact(message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1);
|
CHECK(secp256k1_ecdsa_recover_compact(message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1);
|
||||||
@ -1294,12 +1299,12 @@ void test_ecdsa_edge_cases(void) {
|
|||||||
};
|
};
|
||||||
unsigned char sig[72];
|
unsigned char sig[72];
|
||||||
int siglen = 72;
|
int siglen = 72;
|
||||||
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce) == 0);
|
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0);
|
||||||
msg[31] = 0xaa;
|
msg[31] = 0xaa;
|
||||||
siglen = 72;
|
siglen = 72;
|
||||||
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce) == 1);
|
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1);
|
||||||
siglen = 10;
|
siglen = 10;
|
||||||
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, nonce) != 1);
|
CHECK(secp256k1_ecdsa_sign(msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Privkey export where pubkey is the point at infinity. */
|
/* Privkey export where pubkey is the point at infinity. */
|
||||||
|
Loading…
x
Reference in New Issue
Block a user