Merge pull request #282

18c329c Remove the internal secp256k1_ecdsa_sig_t type (Pieter Wuille)
74a2acd Add a secp256k1_ecdsa_signature_t type (Pieter Wuille)
23cfa91 Introduce secp256k1_pubkey_t type (Pieter Wuille)
This commit is contained in:
Pieter Wuille
2015-07-26 17:41:48 +02:00
8 changed files with 574 additions and 518 deletions

View File

@ -74,26 +74,148 @@ void secp256k1_context_destroy(
secp256k1_context_t* ctx secp256k1_context_t* ctx
) SECP256K1_ARG_NONNULL(1); ) SECP256K1_ARG_NONNULL(1);
/** Data type to hold a parsed and valid public key.
This data type should be considered opaque to the user, and only created
through API functions. It is not guaranteed to be compatible between
different implementations. If you need to convert to a format suitable
for storage or transmission, use secp256k1_ec_pubkey_serialize and
secp256k1_ec_pubkey_parse.
*/
typedef struct {
unsigned char data[64];
} secp256k1_pubkey_t;
/** Parse a variable-length public key into the pubkey object.
* Returns: 1 if the public key was fully valid.
* 0 if the public key could not be parsed or is invalid.
* In: ctx: a secp256k1 context object.
* input: pointer to a serialized public key
* inputlen: length of the array pointed to by input
* Out: pubkey: pointer to a pubkey object. If 1 is returned, it is set to a
* parsed version of input. If not, its value is undefined.
* This function supports parsing compressed (33 bytes, header byte 0x02 or
* 0x03), uncompressed (65 bytes, header byte 0x04), or hybrid (65 bytes, header
* byte 0x06 or 0x07) format public keys.
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
const secp256k1_context_t* ctx,
secp256k1_pubkey_t* pubkey,
const unsigned char *input,
int inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize a pubkey object into a serialized byte sequence.
* Returns: 1 always.
* In: ctx: a secp256k1 context object.
* pubkey: a pointer to a secp256k1_pubkey_t containing an initialized
* public key.
* compressed: whether to serialize in compressed format.
* Out: output: a pointer to a 65-byte (if compressed==0) or 33-byte (if
* compressed==1) byte array to place the serialized key in.
* outputlen: a pointer to an integer which will contain the serialized
* size.
*/
int secp256k1_ec_pubkey_serialize(
const secp256k1_context_t* ctx,
unsigned char *output,
int *outputlen,
const secp256k1_pubkey_t* pubkey,
int compressed
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Data type to hold a parsed ECDSA signature, optionally supporting pubkey
* recovery.
This data type should be considered opaque to the user, and only created
through API functions. It is not guaranteed to be compatible between
different implementations. If you need to convert to a format suitable
for storage or transmission, use secp256k1_ecdsa_signature_serialize_* and
secp256k1_ecdsa_signature_parse_* functions. */
typedef struct {
unsigned char data[65];
} secp256k1_ecdsa_signature_t;
/** Parse a DER ECDSA signature.
* Returns: 1 when the signature could be parsed, 0 otherwise.
* In: ctx: a secp256k1 context object
* input: a pointer to the signature to be parsed
* inputlen: the length of the array pointed to be input
* Out: sig: a pointer to a signature object
*
* Note that this function also supports some violations of DER.
*
* The resulting signature object will not support pubkey recovery.
*/
int secp256k1_ecdsa_signature_parse_der(
const secp256k1_context_t* ctx,
secp256k1_ecdsa_signature_t* sig,
const unsigned char *input,
int inputlen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Parse a compact ECDSA signature (64 bytes + recovery id).
* Returns: 1 when the signature could be parsed, 0 otherwise
* In: ctx: a secp256k1 context object
* input64: a pointer to a 64-byte compact signature
* recid: the recovery id (0, 1, 2 or 3, or -1 for unknown)
* Out: sig: a pointer to a signature object
*
* If recid is not -1, the resulting signature object will support pubkey
* recovery.
*/
int secp256k1_ecdsa_signature_parse_compact(
const secp256k1_context_t* ctx,
secp256k1_ecdsa_signature_t* sig,
const unsigned char *input64,
int recid
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Serialize an ECDSA signature in DER format.
* Returns: 1 if enough space was available to serialize, 0 otherwise
* In: ctx: a secp256k1 context object
* sig: a pointer to an initialized signature object
* Out: output: a pointer to an array to store the DER serialization
* In/Out: outputlen: a pointer to a length integer. Initially, this integer
* should be set to the length of output. After the call
* it will be set to the length of the serialization (even
* if 0 was returned).
*/
int secp256k1_ecdsa_signature_serialize_der(
const secp256k1_context_t* ctx,
unsigned char *output,
int *outputlen,
const secp256k1_ecdsa_signature_t* sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Serialize an ECDSA signature in compact format (64 bytes + recovery id).
* Returns: 1
* In: ctx: a secp256k1 context object
* sig: a pointer to an initialized signature object (cannot be NULL)
* Out: output64: a pointer to a 64-byte array of the compact signature (cannot be NULL)
* recid: a pointer to an integer to hold the recovery id (can be NULL).
*
* If recid is not NULL, the signature must support pubkey recovery.
*/
int secp256k1_ecdsa_signature_serialize_compact(
const secp256k1_context_t* ctx,
unsigned char *output64,
int *recid,
const secp256k1_ecdsa_signature_t* sig
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4);
/** Verify an ECDSA signature. /** Verify an ECDSA signature.
* Returns: 1: correct signature * Returns: 1: correct signature
* 0: incorrect signature * 0: incorrect or unparseable signature
* -1: invalid public key
* -2: invalid signature
* In: ctx: a secp256k1 context object, initialized for verification. * In: ctx: a secp256k1 context object, initialized for verification.
* msg32: the 32-byte message hash being verified (cannot be NULL) * msg32: the 32-byte message hash being verified (cannot be NULL)
* sig: the signature being verified (cannot be NULL) * sig: the signature being verified (cannot be NULL)
* siglen: the length of the signature * pubkey: pointer to an initialized public key to verify with (cannot be NULL)
* pubkey: the public key to verify with (cannot be NULL)
* pubkeylen: the length of pubkey
*/ */
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify( SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_verify(
const secp256k1_context_t* ctx, const secp256k1_context_t* ctx,
const unsigned char *msg32, const unsigned char *msg32,
const unsigned char *sig, const secp256k1_ecdsa_signature_t *sig,
int siglen, const secp256k1_pubkey_t *pubkey
const unsigned char *pubkey, ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
int pubkeylen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5);
/** A pointer to a function to deterministically generate a nonce. /** A pointer to a function to deterministically generate a nonce.
* Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail. * Returns: 1 if a nonce was successfully generated. 0 will cause signing to fail.
@ -124,19 +246,17 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979;
/** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */ /** A default safe nonce generation function (currently equal to secp256k1_nonce_function_rfc6979). */
extern const secp256k1_nonce_function_t secp256k1_nonce_function_default; extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
/** Create an ECDSA signature. /** Create an ECDSA signature.
* Returns: 1: signature created * Returns: 1: signature created
* 0: the nonce generation function failed, the private key was invalid, or there is not * 0: the nonce generation function failed, or the private key was invalid.
* enough space in the signature (as indicated by siglen).
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL) * In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* msg32: the 32-byte message hash being signed (cannot be NULL) * msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL) * seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used * noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
* ndata: pointer to arbitrary data used by the nonce generation function (can 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 *
* to contain the actual signature length (<=72). * The resulting signature will support pubkey recovery.
* *
* The sig always has an s value in the lower half of the range (From 0x1 * The sig always has an s value in the lower half of the range (From 0x1
* to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0, * to 0x7FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF5D576E7357A4501DDFE92F46681B20A0,
@ -167,55 +287,26 @@ extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
int secp256k1_ecdsa_sign( int secp256k1_ecdsa_sign(
const secp256k1_context_t* ctx, const secp256k1_context_t* ctx,
const unsigned char *msg32, const unsigned char *msg32,
unsigned char *sig, secp256k1_ecdsa_signature_t *sig,
int *siglen,
const unsigned char *seckey, const unsigned char *seckey,
secp256k1_nonce_function_t noncefp, secp256k1_nonce_function_t noncefp,
const void *ndata const void *ndata
) 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).
* Returns: 1: signature created
* 0: the nonce generation function failed, or the secret key was invalid.
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* msg32: the 32-byte message hash being signed (cannot be NULL)
* seckey: pointer to a 32-byte secret key (cannot be NULL)
* noncefp:pointer to a nonce generation function. If NULL, secp256k1_nonce_function_default is used
* 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)
* In case 0 is returned, the returned signature length will be zero.
* recid: pointer to an int, which will be updated to contain the recovery id (can be NULL)
*/
int secp256k1_ecdsa_sign_compact(
const secp256k1_context_t* ctx,
const unsigned char *msg32,
unsigned char *sig64,
const unsigned char *seckey,
secp256k1_nonce_function_t noncefp,
const void *ndata,
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);
/** Recover an ECDSA public key from a compact signature. /** Recover an ECDSA public key from a signature.
* Returns: 1: public key successfully recovered (which guarantees a correct signature). * Returns: 1: public key successfully recovered (which guarantees a correct signature).
* 0: otherwise. * 0: otherwise.
* In: ctx: pointer to a context object, initialized for verification (cannot be NULL) * In: ctx: pointer to a context object, initialized for verification (cannot be NULL)
* msg32: the 32-byte message hash assumed to be signed (cannot be NULL) * msg32: the 32-byte message hash assumed to be signed (cannot be NULL)
* sig64: signature as 64 byte array (cannot be NULL) * sig64: pointer to initialized signature that supports pubkey recovery (cannot be NULL)
* compressed: whether to recover a compressed or uncompressed pubkey * Out: pubkey: pointer to the recoved public key (cannot be NULL)
* recid: the recovery id (0-3, as returned by ecdsa_sign_compact)
* Out: pubkey: pointer to a 33 or 65 byte array to put the pubkey (cannot be NULL)
* pubkeylen: pointer to an int that will contain the pubkey length (cannot be NULL)
*/ */
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover_compact( SECP256K1_WARN_UNUSED_RESULT int secp256k1_ecdsa_recover(
const secp256k1_context_t* ctx, const secp256k1_context_t* ctx,
const unsigned char *msg32, const unsigned char *msg32,
const unsigned char *sig64, const secp256k1_ecdsa_signature_t *sig,
unsigned char *pubkey, secp256k1_pubkey_t *pubkey
int *pubkeylen, ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
int compressed,
int recid
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(5);
/** Verify an ECDSA secret key. /** Verify an ECDSA secret key.
* Returns: 1: secret key is valid * Returns: 1: secret key is valid
@ -228,71 +319,18 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
const unsigned char *seckey const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Just validate a public key.
* Returns: 1: public key is valid
* 0: public key is invalid
* In: ctx: pointer to a context object (cannot be NULL)
* pubkey: pointer to a 33-byte or 65-byte public key (cannot be NULL).
* pubkeylen: length of pubkey
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_verify(
const secp256k1_context_t* ctx,
const unsigned char *pubkey,
int pubkeylen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2);
/** Compute the public key for a secret key. /** Compute the public key for a secret key.
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL) * In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
* compressed: whether the computed public key should be compressed
* seckey: pointer to a 32-byte private key (cannot be NULL) * seckey: pointer to a 32-byte private key (cannot be NULL)
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed) * Out: pubkey: pointer to the created public key (cannot be NULL)
* area to store the public key (cannot be NULL)
* pubkeylen: pointer to int that will be updated to contains the pubkey's
* length (cannot be NULL)
* Returns: 1: secret was valid, public key stores * Returns: 1: secret was valid, public key stores
* 0: secret was invalid, try again * 0: secret was invalid, try again
*/ */
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create( SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
const secp256k1_context_t* ctx, const secp256k1_context_t* ctx,
unsigned char *pubkey, secp256k1_pubkey_t *pubkey,
int *pubkeylen, const unsigned char *seckey
const unsigned char *seckey, ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
int compressed
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Compress a public key.
* In: ctx: pointer to a context object (cannot be NULL)
* pubkeyin: pointer to a 33-byte or 65-byte public key (cannot be NULL)
* Out: pubkeyout: pointer to a 33-byte array to put the compressed public key (cannot be NULL)
* May alias pubkeyin.
* pubkeylen: pointer to the size of the public key pointed to by pubkeyin (cannot be NULL)
* It will be updated to reflect the size of the public key in pubkeyout.
* Returns: 0: pubkeyin was invalid
* 1: pubkeyin was valid, and pubkeyout is its compressed version
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_compress(
const secp256k1_context_t* ctx,
const unsigned char *pubkeyin,
unsigned char *pubkeyout,
int *pubkeylen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Decompress a public key.
* In: ctx: pointer to a context object (cannot be NULL)
* pubkeyin: pointer to a 33-byte or 65-byte public key (cannot be NULL)
* Out: pubkeyout: pointer to a 65-byte array to put the decompressed public key (cannot be NULL)
* May alias pubkeyin.
* pubkeylen: pointer to the size of the public key pointed to by pubkeyin (cannot be NULL)
* It will be updated to reflect the size of the public key in pubkeyout.
* Returns: 0: pubkeyin was invalid
* 1: pubkeyin was valid, and pubkeyout is its decompressed version
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_decompress(
const secp256k1_context_t* ctx,
const unsigned char *pubkeyin,
unsigned char *pubkeyout,
int *pubkeylen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4);
/** Export a private key in DER format. /** Export a private key in DER format.
* In: ctx: pointer to a context object, initialized for signing (cannot be NULL) * In: ctx: pointer to a context object, initialized for signing (cannot be NULL)
@ -325,10 +363,9 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_add(
*/ */
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add( SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_add(
const secp256k1_context_t* ctx, const secp256k1_context_t* ctx,
unsigned char *pubkey, secp256k1_pubkey_t *pubkey,
int pubkeylen,
const unsigned char *tweak const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Tweak a private key by multiplying it with tweak. */ /** Tweak a private key by multiplying it with tweak. */
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul( SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
@ -342,10 +379,9 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_tweak_mul(
*/ */
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul( SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_tweak_mul(
const secp256k1_context_t* ctx, const secp256k1_context_t* ctx,
unsigned char *pubkey, secp256k1_pubkey_t *pubkey,
int pubkeylen,
const unsigned char *tweak const unsigned char *tweak
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(4); ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Updates the context randomization. /** Updates the context randomization.
* Returns: 1: randomization successfully updated * Returns: 1: randomization successfully updated

View File

@ -17,16 +17,20 @@ typedef struct {
void bench_recover(void* arg) { void bench_recover(void* arg) {
int i; int i;
bench_recover_t *data = (bench_recover_t*)arg; bench_recover_t *data = (bench_recover_t*)arg;
unsigned char pubkey[33]; secp256k1_pubkey_t pubkey;
unsigned char pubkeyc[33];
for (i = 0; i < 20000; i++) { for (i = 0; i < 20000; i++) {
int j; int j;
int pubkeylen = 33; int pubkeylen = 33;
CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, pubkey, &pubkeylen, 1, i % 2)); secp256k1_ecdsa_signature_t sig;
CHECK(secp256k1_ecdsa_signature_parse_compact(data->ctx, &sig, data->sig, i % 2));
CHECK(secp256k1_ecdsa_recover(data->ctx, data->msg, &sig, &pubkey));
CHECK(secp256k1_ec_pubkey_serialize(data->ctx, pubkeyc, &pubkeylen, &pubkey, 1));
for (j = 0; j < 32; j++) { for (j = 0; j < 32; j++) {
data->sig[j + 32] = data->msg[j]; /* Move former message to S. */ data->sig[j + 32] = data->msg[j]; /* Move former message to S. */
data->msg[j] = data->sig[j]; /* Move former R to message. */ data->msg[j] = data->sig[j]; /* Move former R to message. */
data->sig[j] = pubkey[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */ data->sig[j] = pubkeyc[j + 1]; /* Move recovered pubkey X coordinate to R (which must be a valid X coordinate). */
} }
} }
} }

View File

@ -30,7 +30,9 @@ static void bench_sign(void* arg) {
for (i = 0; i < 20000; i++) { for (i = 0; i < 20000; i++) {
int j; int j;
int recid = 0; int recid = 0;
CHECK(secp256k1_ecdsa_sign_compact(data->ctx, data->msg, sig, data->key, NULL, NULL, &recid)); secp256k1_ecdsa_signature_t signature;
CHECK(secp256k1_ecdsa_sign(data->ctx, data->msg, &signature, data->key, NULL, NULL));
CHECK(secp256k1_ecdsa_signature_serialize_compact(data->ctx, sig, &recid, &signature));
for (j = 0; j < 32; j++) { for (j = 0; j < 32; j++) {
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. */

View File

@ -26,10 +26,14 @@ static void benchmark_verify(void* arg) {
benchmark_verify_t* data = (benchmark_verify_t*)arg; benchmark_verify_t* data = (benchmark_verify_t*)arg;
for (i = 0; i < 20000; i++) { for (i = 0; i < 20000; i++) {
secp256k1_pubkey_t pubkey;
secp256k1_ecdsa_signature_t sig;
data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 1] ^= (i & 0xFF);
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, data->sig, data->siglen, data->pubkey, data->pubkeylen) == (i == 0)); CHECK(secp256k1_ec_pubkey_parse(data->ctx, &pubkey, data->pubkey, data->pubkeylen) == 1);
CHECK(secp256k1_ecdsa_signature_parse_der(data->ctx, &sig, data->sig, data->siglen) == 1);
CHECK(secp256k1_ecdsa_verify(data->ctx, data->msg, &sig, &pubkey) == (i == 0));
data->sig[data->siglen - 1] ^= (i & 0xFF); data->sig[data->siglen - 1] ^= (i & 0xFF);
data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF); data->sig[data->siglen - 2] ^= ((i >> 8) & 0xFF);
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF); data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
@ -38,6 +42,8 @@ static void benchmark_verify(void* arg) {
int main(void) { int main(void) {
int i; int i;
secp256k1_pubkey_t pubkey;
secp256k1_ecdsa_signature_t sig;
benchmark_verify_t data; benchmark_verify_t data;
data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); data.ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
@ -45,9 +51,10 @@ int main(void) {
for (i = 0; i < 32; i++) data.msg[i] = 1 + i; for (i = 0; i < 32; i++) data.msg[i] = 1 + i;
for (i = 0; i < 32; i++) data.key[i] = 33 + i; for (i = 0; i < 32; i++) data.key[i] = 33 + i;
data.siglen = 72; data.siglen = 72;
secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL); CHECK(secp256k1_ecdsa_sign(data.ctx, data.msg, &sig, data.key, NULL, NULL));
data.pubkeylen = 33; CHECK(secp256k1_ecdsa_signature_serialize_der(data.ctx, data.sig, &data.siglen, &sig));
CHECK(secp256k1_ec_pubkey_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1)); CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key));
CHECK(secp256k1_ec_pubkey_serialize(data.ctx, data.pubkey, &data.pubkeylen, &pubkey, 1) == 1);
run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000); run_benchmark("ecdsa_verify", benchmark_verify, NULL, NULL, &data, 10, 20000);

View File

@ -11,14 +11,10 @@
#include "group.h" #include "group.h"
#include "ecmult.h" #include "ecmult.h"
typedef struct { static int secp256k1_ecdsa_sig_parse(secp256k1_scalar_t *r, secp256k1_scalar_t *s, const unsigned char *sig, int size);
secp256k1_scalar_t r, s; static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_scalar_t *r, const secp256k1_scalar_t *s);
} secp256k1_ecdsa_sig_t; static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_scalar_t* r, const secp256k1_scalar_t* s, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message);
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_scalar_t* r, secp256k1_scalar_t* s, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid);
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size); static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_scalar_t* r, const secp256k1_scalar_t* s, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid);
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a);
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message);
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid);
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid);
#endif #endif

View File

@ -46,7 +46,7 @@ static const secp256k1_fe_t secp256k1_ecdsa_const_p_minus_order = SECP256K1_FE_C
0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL 0, 0, 0, 1, 0x45512319UL, 0x50B75FC4UL, 0x402DA172UL, 0x2FC9BAEEUL
); );
static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned char *sig, int size) { static int secp256k1_ecdsa_sig_parse(secp256k1_scalar_t *rr, secp256k1_scalar_t *rs, const unsigned char *sig, int size) {
unsigned char ra[32] = {0}, sa[32] = {0}; unsigned char ra[32] = {0}, sa[32] = {0};
const unsigned char *rp; const unsigned char *rp;
const unsigned char *sp; const unsigned char *sp;
@ -98,26 +98,27 @@ static int secp256k1_ecdsa_sig_parse(secp256k1_ecdsa_sig_t *r, const unsigned ch
memcpy(ra + 32 - lenr, rp, lenr); memcpy(ra + 32 - lenr, rp, lenr);
memcpy(sa + 32 - lens, sp, lens); memcpy(sa + 32 - lens, sp, lens);
overflow = 0; overflow = 0;
secp256k1_scalar_set_b32(&r->r, ra, &overflow); secp256k1_scalar_set_b32(rr, ra, &overflow);
if (overflow) { if (overflow) {
return 0; return 0;
} }
secp256k1_scalar_set_b32(&r->s, sa, &overflow); secp256k1_scalar_set_b32(rs, sa, &overflow);
if (overflow) { if (overflow) {
return 0; return 0;
} }
return 1; return 1;
} }
static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_ecdsa_sig_t *a) { static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const secp256k1_scalar_t* ar, const secp256k1_scalar_t* as) {
unsigned char r[33] = {0}, s[33] = {0}; unsigned char r[33] = {0}, s[33] = {0};
unsigned char *rp = r, *sp = s; unsigned char *rp = r, *sp = s;
int lenR = 33, lenS = 33; int lenR = 33, lenS = 33;
secp256k1_scalar_get_b32(&r[1], &a->r); secp256k1_scalar_get_b32(&r[1], ar);
secp256k1_scalar_get_b32(&s[1], &a->s); secp256k1_scalar_get_b32(&s[1], as);
while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; } while (lenR > 1 && rp[0] == 0 && rp[1] < 0x80) { lenR--; rp++; }
while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; } while (lenS > 1 && sp[0] == 0 && sp[1] < 0x80) { lenS--; sp++; }
if (*size < 6+lenS+lenR) { if (*size < 6+lenS+lenR) {
*size = 6 + lenS + lenR;
return 0; return 0;
} }
*size = 6 + lenS + lenR; *size = 6 + lenS + lenR;
@ -132,26 +133,26 @@ static int secp256k1_ecdsa_sig_serialize(unsigned char *sig, int *size, const se
return 1; return 1;
} }
static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) { static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, const secp256k1_scalar_t *sigr, const secp256k1_scalar_t *sigs, const secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message) {
unsigned char c[32]; unsigned char c[32];
secp256k1_scalar_t sn, u1, u2; secp256k1_scalar_t sn, u1, u2;
secp256k1_fe_t xr; secp256k1_fe_t xr;
secp256k1_gej_t pubkeyj; secp256k1_gej_t pubkeyj;
secp256k1_gej_t pr; secp256k1_gej_t pr;
if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
return 0; return 0;
} }
secp256k1_scalar_inverse_var(&sn, &sig->s); secp256k1_scalar_inverse_var(&sn, sigs);
secp256k1_scalar_mul(&u1, &sn, message); secp256k1_scalar_mul(&u1, &sn, message);
secp256k1_scalar_mul(&u2, &sn, &sig->r); secp256k1_scalar_mul(&u2, &sn, sigr);
secp256k1_gej_set_ge(&pubkeyj, pubkey); secp256k1_gej_set_ge(&pubkeyj, pubkey);
secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1); secp256k1_ecmult(ctx, &pr, &pubkeyj, &u2, &u1);
if (secp256k1_gej_is_infinity(&pr)) { if (secp256k1_gej_is_infinity(&pr)) {
return 0; return 0;
} }
secp256k1_scalar_get_b32(c, &sig->r); secp256k1_scalar_get_b32(c, sigr);
secp256k1_fe_set_b32(&xr, c); secp256k1_fe_set_b32(&xr, c);
/** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n) /** We now have the recomputed R point in pr, and its claimed x coordinate (modulo n)
@ -186,7 +187,7 @@ static int secp256k1_ecdsa_sig_verify(const secp256k1_ecmult_context_t *ctx, con
return 0; return 0;
} }
static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_ecdsa_sig_t *sig, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) { static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, const secp256k1_scalar_t *sigr, const secp256k1_scalar_t* sigs, secp256k1_ge_t *pubkey, const secp256k1_scalar_t *message, int recid) {
unsigned char brx[32]; unsigned char brx[32];
secp256k1_fe_t fx; secp256k1_fe_t fx;
secp256k1_ge_t x; secp256k1_ge_t x;
@ -194,11 +195,11 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, co
secp256k1_scalar_t rn, u1, u2; secp256k1_scalar_t rn, u1, u2;
secp256k1_gej_t qj; secp256k1_gej_t qj;
if (secp256k1_scalar_is_zero(&sig->r) || secp256k1_scalar_is_zero(&sig->s)) { if (secp256k1_scalar_is_zero(sigr) || secp256k1_scalar_is_zero(sigs)) {
return 0; return 0;
} }
secp256k1_scalar_get_b32(brx, &sig->r); secp256k1_scalar_get_b32(brx, sigr);
VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */ VERIFY_CHECK(secp256k1_fe_set_b32(&fx, brx)); /* brx comes from a scalar, so is less than the order; certainly less than p */
if (recid & 2) { if (recid & 2) {
if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) { if (secp256k1_fe_cmp_var(&fx, &secp256k1_ecdsa_const_p_minus_order) >= 0) {
@ -210,16 +211,16 @@ static int secp256k1_ecdsa_sig_recover(const secp256k1_ecmult_context_t *ctx, co
return 0; return 0;
} }
secp256k1_gej_set_ge(&xj, &x); secp256k1_gej_set_ge(&xj, &x);
secp256k1_scalar_inverse_var(&rn, &sig->r); secp256k1_scalar_inverse_var(&rn, sigr);
secp256k1_scalar_mul(&u1, &rn, message); secp256k1_scalar_mul(&u1, &rn, message);
secp256k1_scalar_negate(&u1, &u1); secp256k1_scalar_negate(&u1, &u1);
secp256k1_scalar_mul(&u2, &rn, &sig->s); secp256k1_scalar_mul(&u2, &rn, sigs);
secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1); secp256k1_ecmult(ctx, &qj, &xj, &u2, &u1);
secp256k1_ge_set_gej_var(pubkey, &qj); secp256k1_ge_set_gej_var(pubkey, &qj);
return !secp256k1_gej_is_infinity(&qj); return !secp256k1_gej_is_infinity(&qj);
} }
static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) { static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, secp256k1_scalar_t *sigr, secp256k1_scalar_t *sigs, const secp256k1_scalar_t *seckey, const secp256k1_scalar_t *message, const secp256k1_scalar_t *nonce, int *recid) {
unsigned char b[32]; unsigned char b[32];
secp256k1_gej_t rp; secp256k1_gej_t rp;
secp256k1_ge_t r; secp256k1_ge_t r;
@ -231,8 +232,8 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, s
secp256k1_fe_normalize(&r.x); secp256k1_fe_normalize(&r.x);
secp256k1_fe_normalize(&r.y); secp256k1_fe_normalize(&r.y);
secp256k1_fe_get_b32(b, &r.x); secp256k1_fe_get_b32(b, &r.x);
secp256k1_scalar_set_b32(&sig->r, b, &overflow); secp256k1_scalar_set_b32(sigr, b, &overflow);
if (secp256k1_scalar_is_zero(&sig->r)) { if (secp256k1_scalar_is_zero(sigr)) {
/* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */ /* P.x = order is on the curve, so technically sig->r could end up zero, which would be an invalid signature. */
secp256k1_gej_clear(&rp); secp256k1_gej_clear(&rp);
secp256k1_ge_clear(&r); secp256k1_ge_clear(&r);
@ -241,18 +242,18 @@ static int secp256k1_ecdsa_sig_sign(const secp256k1_ecmult_gen_context_t *ctx, s
if (recid) { if (recid) {
*recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0); *recid = (overflow ? 2 : 0) | (secp256k1_fe_is_odd(&r.y) ? 1 : 0);
} }
secp256k1_scalar_mul(&n, &sig->r, seckey); secp256k1_scalar_mul(&n, sigr, seckey);
secp256k1_scalar_add(&n, &n, message); secp256k1_scalar_add(&n, &n, message);
secp256k1_scalar_inverse(&sig->s, nonce); secp256k1_scalar_inverse(sigs, nonce);
secp256k1_scalar_mul(&sig->s, &sig->s, &n); secp256k1_scalar_mul(sigs, sigs, &n);
secp256k1_scalar_clear(&n); secp256k1_scalar_clear(&n);
secp256k1_gej_clear(&rp); secp256k1_gej_clear(&rp);
secp256k1_ge_clear(&r); secp256k1_ge_clear(&r);
if (secp256k1_scalar_is_zero(&sig->s)) { if (secp256k1_scalar_is_zero(sigs)) {
return 0; return 0;
} }
if (secp256k1_scalar_is_high(&sig->s)) { if (secp256k1_scalar_is_high(sigs)) {
secp256k1_scalar_negate(&sig->s, &sig->s); secp256k1_scalar_negate(sigs, sigs);
if (recid) { if (recid) {
*recid ^= 1; *recid ^= 1;
} }

View File

@ -54,11 +54,159 @@ void secp256k1_context_destroy(secp256k1_context_t* ctx) {
free(ctx); free(ctx);
} }
int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const unsigned char *pubkey, int pubkeylen) { static void secp256k1_pubkey_load(secp256k1_ge_t* ge, const secp256k1_pubkey_t* pubkey) {
if (sizeof(secp256k1_ge_storage_t) == 64) {
/* When the secp256k1_ge_storage_t type is exactly 64 byte, use its
* representation inside secp256k1_pubkey_t, as conversion is very fast.
* Note that secp256k1_pubkey_save must use the same representation. */
secp256k1_ge_storage_t s;
memcpy(&s, &pubkey->data[0], 64);
secp256k1_ge_from_storage(ge, &s);
DEBUG_CHECK(!secp256k1_fe_is_zero(&ge->x));
} else {
/* Otherwise, fall back to 32-byte big endian for X and Y. */
secp256k1_fe_t x, y;
secp256k1_fe_set_b32(&x, pubkey->data);
DEBUG_CHECK(!secp256k1_fe_is_zero(&x));
secp256k1_fe_set_b32(&y, pubkey->data + 32);
secp256k1_ge_set_xy(ge, &x, &y);
}
}
static void secp256k1_pubkey_save(secp256k1_pubkey_t* pubkey, secp256k1_ge_t* ge) {
if (sizeof(secp256k1_ge_storage_t) == 64) {
secp256k1_ge_storage_t s;
secp256k1_ge_to_storage(&s, ge);
memcpy(&pubkey->data[0], &s, 64);
} else {
VERIFY_CHECK(!secp256k1_ge_is_infinity(ge));
secp256k1_fe_normalize_var(&ge->x);
secp256k1_fe_normalize_var(&ge->y);
secp256k1_fe_get_b32(pubkey->data, &ge->x);
secp256k1_fe_get_b32(pubkey->data + 32, &ge->y);
}
}
int secp256k1_ec_pubkey_parse(const secp256k1_context_t* ctx, secp256k1_pubkey_t* pubkey, const unsigned char *input, int inputlen) {
secp256k1_ge_t Q;
(void)ctx;
if (!secp256k1_eckey_pubkey_parse(&Q, input, inputlen)) {
memset(pubkey, 0, sizeof(*pubkey));
return 0;
}
secp256k1_pubkey_save(pubkey, &Q);
secp256k1_ge_clear(&Q);
return 1;
}
int secp256k1_ec_pubkey_serialize(const secp256k1_context_t* ctx, unsigned char *output, int *outputlen, const secp256k1_pubkey_t* pubkey, int compressed) {
secp256k1_ge_t Q;
(void)ctx;
secp256k1_pubkey_load(&Q, pubkey);
return secp256k1_eckey_pubkey_serialize(&Q, output, outputlen, compressed);
}
static void secp256k1_ecdsa_signature_load(secp256k1_scalar_t* r, secp256k1_scalar_t* s, int* recid, const secp256k1_ecdsa_signature_t* sig) {
if (sizeof(secp256k1_scalar_t) == 32) {
/* When the secp256k1_scalar_t type is exactly 32 byte, use its
* representation inside secp256k1_ecdsa_signature_t, as conversion is very fast.
* Note that secp256k1_ecdsa_signature_save must use the same representation. */
memcpy(r, &sig->data[0], 32);
memcpy(s, &sig->data[32], 32);
} else {
secp256k1_scalar_set_b32(r, &sig->data[0], NULL);
secp256k1_scalar_set_b32(s, &sig->data[32], NULL);
}
if (recid) {
*recid = sig->data[64];
}
}
static void secp256k1_ecdsa_signature_save(secp256k1_ecdsa_signature_t* sig, const secp256k1_scalar_t* r, const secp256k1_scalar_t* s, int recid) {
if (sizeof(secp256k1_scalar_t) == 32) {
memcpy(&sig->data[0], r, 32);
memcpy(&sig->data[32], s, 32);
} else {
secp256k1_scalar_get_b32(&sig->data[0], r);
secp256k1_scalar_get_b32(&sig->data[32], s);
}
sig->data[64] = recid;
}
int secp256k1_ecdsa_signature_parse_der(const secp256k1_context_t* ctx, secp256k1_ecdsa_signature_t* sig, const unsigned char *input, int inputlen) {
secp256k1_scalar_t r, s;
(void)ctx;
DEBUG_CHECK(sig != NULL);
DEBUG_CHECK(input != NULL);
if (secp256k1_ecdsa_sig_parse(&r, &s, input, inputlen)) {
secp256k1_ecdsa_signature_save(sig, &r, &s, -1);
return 1;
} else {
memset(sig, 0, sizeof(*sig));
return 0;
}
}
int secp256k1_ecdsa_signature_parse_compact(const secp256k1_context_t* ctx, secp256k1_ecdsa_signature_t* sig, const unsigned char *input64, int recid) {
secp256k1_scalar_t r, s;
int ret = 1;
int overflow = 0;
(void)ctx;
DEBUG_CHECK(sig != NULL);
DEBUG_CHECK(input64 != NULL);
secp256k1_scalar_set_b32(&r, &input64[0], &overflow);
ret &= !overflow;
secp256k1_scalar_set_b32(&s, &input64[32], &overflow);
ret &= !overflow;
ret &= (recid == -1 || (recid >= 0 && recid < 4));
if (ret) {
secp256k1_ecdsa_signature_save(sig, &r, &s, recid);
} else {
memset(sig, 0, sizeof(*sig));
}
return ret;
}
int secp256k1_ecdsa_signature_serialize_der(const secp256k1_context_t* ctx, unsigned char *output, int *outputlen, const secp256k1_ecdsa_signature_t* sig) {
secp256k1_scalar_t r, s;
(void)ctx;
DEBUG_CHECK(output != NULL);
DEBUG_CHECK(outputlen != NULL);
DEBUG_CHECK(sig != NULL);
secp256k1_ecdsa_signature_load(&r, &s, NULL, sig);
return secp256k1_ecdsa_sig_serialize(output, outputlen, &r, &s);
}
int secp256k1_ecdsa_signature_serialize_compact(const secp256k1_context_t* ctx, unsigned char *output64, int *recid, const secp256k1_ecdsa_signature_t* sig) {
secp256k1_scalar_t r, s;
int rec;
(void)ctx;
DEBUG_CHECK(output64 != NULL);
DEBUG_CHECK(sig != NULL);
secp256k1_ecdsa_signature_load(&r, &s, &rec, sig);
secp256k1_scalar_get_b32(&output64[0], &r);
secp256k1_scalar_get_b32(&output64[32], &s);
if (recid) {
DEBUG_CHECK(rec >= 0 && rec < 4);
*recid = rec;
}
return 1;
}
int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const secp256k1_ecdsa_signature_t *sig, const secp256k1_pubkey_t *pubkey) {
secp256k1_ge_t q; secp256k1_ge_t q;
secp256k1_ecdsa_sig_t s; secp256k1_scalar_t r, s;
secp256k1_scalar_t m; secp256k1_scalar_t m;
int ret = -3;
DEBUG_CHECK(ctx != NULL); DEBUG_CHECK(ctx != NULL);
DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
DEBUG_CHECK(msg32 != NULL); DEBUG_CHECK(msg32 != NULL);
@ -66,23 +214,9 @@ int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *
DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(pubkey != NULL);
secp256k1_scalar_set_b32(&m, msg32, NULL); secp256k1_scalar_set_b32(&m, msg32, NULL);
secp256k1_pubkey_load(&q, pubkey);
if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { secp256k1_ecdsa_signature_load(&r, &s, NULL, sig);
if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) { return secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &r, &s, &q, &m);
if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) {
/* success is 1, all other values are fail */
ret = 1;
} else {
ret = 0;
}
} else {
ret = -2;
}
} else {
ret = -1;
}
return ret;
} }
static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) { static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *msg32, const unsigned char *key32, unsigned int counter, const void *data) {
@ -110,9 +244,10 @@ static int nonce_function_rfc6979(unsigned char *nonce32, const unsigned char *m
const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979; const secp256k1_nonce_function_t secp256k1_nonce_function_rfc6979 = nonce_function_rfc6979;
const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979; const secp256k1_nonce_function_t secp256k1_nonce_function_default = nonce_function_rfc6979;
int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *signature, int *signaturelen, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) { int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *msg32, secp256k1_ecdsa_signature_t *signature, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata) {
secp256k1_ecdsa_sig_t sig; secp256k1_scalar_t r, s;
secp256k1_scalar_t sec, non, msg; secp256k1_scalar_t sec, non, msg;
int recid;
int ret = 0; int ret = 0;
int overflow = 0; int overflow = 0;
unsigned int count = 0; unsigned int count = 0;
@ -120,7 +255,6 @@ int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *ms
DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
DEBUG_CHECK(msg32 != NULL); DEBUG_CHECK(msg32 != NULL);
DEBUG_CHECK(signature != NULL); DEBUG_CHECK(signature != NULL);
DEBUG_CHECK(signaturelen != NULL);
DEBUG_CHECK(seckey != NULL); DEBUG_CHECK(seckey != NULL);
if (noncefp == NULL) { if (noncefp == NULL) {
noncefp = secp256k1_nonce_function_default; noncefp = secp256k1_nonce_function_default;
@ -139,99 +273,45 @@ int secp256k1_ecdsa_sign(const secp256k1_context_t* ctx, const unsigned char *ms
secp256k1_scalar_set_b32(&non, nonce32, &overflow); secp256k1_scalar_set_b32(&non, nonce32, &overflow);
memset(nonce32, 0, 32); memset(nonce32, 0, 32);
if (!secp256k1_scalar_is_zero(&non) && !overflow) { if (!secp256k1_scalar_is_zero(&non) && !overflow) {
if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, NULL)) { if (secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, &r, &s, &sec, &msg, &non, &recid)) {
break; break;
} }
} }
count++; count++;
} }
if (ret) {
ret = secp256k1_ecdsa_sig_serialize(signature, signaturelen, &sig);
}
secp256k1_scalar_clear(&msg); secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non); secp256k1_scalar_clear(&non);
secp256k1_scalar_clear(&sec); secp256k1_scalar_clear(&sec);
} }
if (!ret) {
*signaturelen = 0;
}
return ret;
}
int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, unsigned char *sig64, const unsigned char *seckey, secp256k1_nonce_function_t noncefp, const void* noncedata, int *recid) {
secp256k1_ecdsa_sig_t sig;
secp256k1_scalar_t sec, non, msg;
int ret = 0;
int overflow = 0;
unsigned int count = 0;
DEBUG_CHECK(ctx != NULL);
DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
DEBUG_CHECK(msg32 != NULL);
DEBUG_CHECK(sig64 != NULL);
DEBUG_CHECK(seckey != NULL);
if (noncefp == NULL) {
noncefp = secp256k1_nonce_function_default;
}
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
/* Fail if the secret key is invalid. */
if (!overflow && !secp256k1_scalar_is_zero(&sec)) {
secp256k1_scalar_set_b32(&msg, msg32, NULL);
while (1) {
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(&ctx->ecmult_gen_ctx, &sig, &sec, &msg, &non, recid)) {
break;
}
}
count++;
}
if (ret) { if (ret) {
secp256k1_scalar_get_b32(sig64, &sig.r); secp256k1_ecdsa_signature_save(signature, &r, &s, recid);
secp256k1_scalar_get_b32(sig64 + 32, &sig.s); } else {
} memset(signature, 0, sizeof(*signature));
secp256k1_scalar_clear(&msg);
secp256k1_scalar_clear(&non);
secp256k1_scalar_clear(&sec);
}
if (!ret) {
memset(sig64, 0, 64);
} }
return ret; return ret;
} }
int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, unsigned char *pubkey, int *pubkeylen, int compressed, int recid) { int secp256k1_ecdsa_recover(const secp256k1_context_t* ctx, const unsigned char *msg32, const secp256k1_ecdsa_signature_t *signature, secp256k1_pubkey_t *pubkey) {
secp256k1_ge_t q; secp256k1_ge_t q;
secp256k1_ecdsa_sig_t sig; secp256k1_scalar_t r, s;
secp256k1_scalar_t m; secp256k1_scalar_t m;
int ret = 0; int recid;
int overflow = 0;
DEBUG_CHECK(ctx != NULL); DEBUG_CHECK(ctx != NULL);
DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
DEBUG_CHECK(msg32 != NULL); DEBUG_CHECK(msg32 != NULL);
DEBUG_CHECK(sig64 != NULL); DEBUG_CHECK(signature != NULL);
DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(pubkeylen != NULL);
DEBUG_CHECK(recid >= 0 && recid <= 3);
secp256k1_scalar_set_b32(&sig.r, sig64, &overflow); secp256k1_ecdsa_signature_load(&r, &s, &recid, signature);
if (!overflow) { DEBUG_CHECK(recid >= 0 && recid < 4);
secp256k1_scalar_set_b32(&sig.s, sig64 + 32, &overflow);
if (!overflow) {
secp256k1_scalar_set_b32(&m, msg32, NULL); secp256k1_scalar_set_b32(&m, msg32, NULL);
if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &r, &s, &q, &m, recid)) {
if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid)) { secp256k1_pubkey_save(pubkey, &q);
ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed); return 1;
} else {
memset(pubkey, 0, sizeof(*pubkey));
return 0;
} }
}
}
return ret;
} }
int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) { int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned char *seckey) {
@ -248,16 +328,7 @@ int secp256k1_ec_seckey_verify(const secp256k1_context_t* ctx, const unsigned ch
return ret; return ret;
} }
int secp256k1_ec_pubkey_verify(const secp256k1_context_t* ctx, const unsigned char *pubkey, int pubkeylen) { int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubkey, const unsigned char *seckey) {
secp256k1_ge_t q;
DEBUG_CHECK(ctx != NULL);
DEBUG_CHECK(pubkey != NULL);
(void)ctx;
return secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen);
}
int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pubkey, int *pubkeylen, const unsigned char *seckey, int compressed) {
secp256k1_gej_t pj; secp256k1_gej_t pj;
secp256k1_ge_t p; secp256k1_ge_t p;
secp256k1_scalar_t sec; secp256k1_scalar_t sec;
@ -266,51 +337,20 @@ int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, unsigned char *pu
DEBUG_CHECK(ctx != NULL); DEBUG_CHECK(ctx != NULL);
DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); DEBUG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(pubkeylen != NULL);
DEBUG_CHECK(seckey != NULL); DEBUG_CHECK(seckey != NULL);
secp256k1_scalar_set_b32(&sec, seckey, &overflow); secp256k1_scalar_set_b32(&sec, seckey, &overflow);
if (!overflow) { ret = !overflow & !secp256k1_scalar_is_zero(&sec);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
secp256k1_scalar_clear(&sec);
secp256k1_ge_set_gej(&p, &pj); secp256k1_ge_set_gej(&p, &pj);
ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed); secp256k1_pubkey_save(pubkey, &p);
} secp256k1_scalar_clear(&sec);
if (!ret) { if (!ret) {
*pubkeylen = 0; memset(pubkey, 0, sizeof(*pubkey));
} }
return ret; return ret;
} }
int secp256k1_ec_pubkey_decompress(const secp256k1_context_t* ctx, const unsigned char *pubkeyin, unsigned char *pubkeyout, int *pubkeylen) {
secp256k1_ge_t p;
int ret = 0;
DEBUG_CHECK(pubkeyin != NULL);
DEBUG_CHECK(pubkeyout != NULL);
DEBUG_CHECK(pubkeylen != NULL);
(void)ctx;
if (secp256k1_eckey_pubkey_parse(&p, pubkeyin, *pubkeylen)) {
ret = secp256k1_eckey_pubkey_serialize(&p, pubkeyout, pubkeylen, 0);
}
return ret;
}
int secp256k1_ec_pubkey_compress(const secp256k1_context_t* ctx, const unsigned char *pubkeyin, unsigned char *pubkeyout, int *pubkeylen) {
secp256k1_ge_t p;
int ret = 0;
DEBUG_CHECK(pubkeyin != NULL);
DEBUG_CHECK(pubkeyout != NULL);
DEBUG_CHECK(pubkeylen != NULL);
(void)ctx;
if (secp256k1_eckey_pubkey_parse(&p, pubkeyin, *pubkeylen)) {
ret = secp256k1_eckey_pubkey_serialize(&p, pubkeyout, pubkeylen, 1);
}
return ret;
}
int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) { int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *seckey, const unsigned char *tweak) {
secp256k1_scalar_t term; secp256k1_scalar_t term;
secp256k1_scalar_t sec; secp256k1_scalar_t sec;
@ -334,7 +374,7 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char
return ret; return ret;
} }
int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubkey, const unsigned char *tweak) {
secp256k1_ge_t p; secp256k1_ge_t p;
secp256k1_scalar_t term; secp256k1_scalar_t term;
int ret = 0; int ret = 0;
@ -345,15 +385,13 @@ int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char
DEBUG_CHECK(tweak != NULL); DEBUG_CHECK(tweak != NULL);
secp256k1_scalar_set_b32(&term, tweak, &overflow); secp256k1_scalar_set_b32(&term, tweak, &overflow);
secp256k1_pubkey_load(&p, pubkey);
if (!overflow) { if (!overflow) {
ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
if (ret) {
ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term); ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term);
}
if (ret) { if (ret) {
int oldlen = pubkeylen; secp256k1_pubkey_save(pubkey, &p);
ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); } else {
VERIFY_CHECK(pubkeylen == oldlen); memset(pubkey, 0, sizeof(*pubkey));
} }
} }
@ -382,7 +420,7 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char
return ret; return ret;
} }
int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char *pubkey, int pubkeylen, const unsigned char *tweak) { int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubkey, const unsigned char *tweak) {
secp256k1_ge_t p; secp256k1_ge_t p;
secp256k1_scalar_t factor; secp256k1_scalar_t factor;
int ret = 0; int ret = 0;
@ -393,15 +431,13 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char
DEBUG_CHECK(tweak != NULL); DEBUG_CHECK(tweak != NULL);
secp256k1_scalar_set_b32(&factor, tweak, &overflow); secp256k1_scalar_set_b32(&factor, tweak, &overflow);
secp256k1_pubkey_load(&p, pubkey);
if (!overflow) { if (!overflow) {
ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
if (ret) {
ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor); ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor);
}
if (ret) { if (ret) {
int oldlen = pubkeylen; secp256k1_pubkey_save(pubkey, &p);
ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33); } else {
VERIFY_CHECK(pubkeylen == oldlen); memset(pubkey, 0, sizeof(*pubkey));
} }
} }

View File

@ -13,6 +13,7 @@
#include <time.h> #include <time.h>
#include "include/secp256k1.h"
#include "secp256k1.c" #include "secp256k1.c"
#include "testrand_impl.h" #include "testrand_impl.h"
@ -110,7 +111,7 @@ void run_context_tests(void) {
secp256k1_gej_t pubj; secp256k1_gej_t pubj;
secp256k1_ge_t pub; secp256k1_ge_t pub;
secp256k1_scalar_t msg, key, nonce; secp256k1_scalar_t msg, key, nonce;
secp256k1_ecdsa_sig_t sig; secp256k1_scalar_t sigr, sigs;
/*** clone and destroy all of them to make sure cloning was complete ***/ /*** clone and destroy all of them to make sure cloning was complete ***/
{ {
@ -131,15 +132,15 @@ void run_context_tests(void) {
/* obtain a working nonce */ /* obtain a working nonce */
do { do {
random_scalar_order_test(&nonce); random_scalar_order_test(&nonce);
} while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
/* try signing */ /* try signing */
CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sigr, &sigs, &key, &msg, &nonce, NULL));
/* try verifying */ /* try verifying */
CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sig, &pub, &msg)); CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sigr, &sigs, &pub, &msg));
CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sig, &pub, &msg)); CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sigr, &sigs, &pub, &msg));
/* cleanup */ /* cleanup */
secp256k1_context_destroy(none); secp256k1_context_destroy(none);
@ -1487,11 +1488,11 @@ void run_ecmult_gen_blind(void) {
} }
void random_sign(secp256k1_ecdsa_sig_t *sig, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) { void random_sign(secp256k1_scalar_t *sigr, secp256k1_scalar_t *sigs, const secp256k1_scalar_t *key, const secp256k1_scalar_t *msg, int *recid) {
secp256k1_scalar_t nonce; secp256k1_scalar_t nonce;
do { do {
random_scalar_order_test(&nonce); random_scalar_order_test(&nonce);
} while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sig, key, msg, &nonce, recid)); } while(!secp256k1_ecdsa_sig_sign(&ctx->ecmult_gen_ctx, sigr, sigs, key, msg, &nonce, recid));
} }
void test_ecdsa_sign_verify(void) { void test_ecdsa_sign_verify(void) {
@ -1499,7 +1500,7 @@ void test_ecdsa_sign_verify(void) {
secp256k1_ge_t pub; secp256k1_ge_t pub;
secp256k1_scalar_t one; secp256k1_scalar_t one;
secp256k1_scalar_t msg, key; secp256k1_scalar_t msg, key;
secp256k1_ecdsa_sig_t sig; secp256k1_scalar_t sigr, sigs;
int recid; int recid;
int getrec; int getrec;
random_scalar_order_test(&msg); random_scalar_order_test(&msg);
@ -1507,14 +1508,14 @@ void test_ecdsa_sign_verify(void) {
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pubj, &key);
secp256k1_ge_set_gej(&pub, &pubj); secp256k1_ge_set_gej(&pub, &pubj);
getrec = secp256k1_rand32()&1; getrec = secp256k1_rand32()&1;
random_sign(&sig, &key, &msg, getrec?&recid:NULL); random_sign(&sigr, &sigs, &key, &msg, getrec?&recid:NULL);
if (getrec) { if (getrec) {
CHECK(recid >= 0 && recid < 4); CHECK(recid >= 0 && recid < 4);
} }
CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg));
secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_set_int(&one, 1);
secp256k1_scalar_add(&msg, &msg, &one); secp256k1_scalar_add(&msg, &msg, &one);
CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &pub, &msg)); CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &pub, &msg));
} }
void run_ecdsa_sign_verify(void) { void run_ecdsa_sign_verify(void) {
@ -1570,9 +1571,9 @@ static int nonce_function_test_retry(unsigned char *nonce32, const unsigned char
return nonce_function_rfc6979(nonce32, msg32, key32, counter - 5, data); return nonce_function_rfc6979(nonce32, msg32, key32, counter - 5, data);
} }
int is_empty_compact_signature(const unsigned char *sig64) { int is_empty_signature(const secp256k1_ecdsa_signature_t *sig) {
static const unsigned char res[64] = {0}; static const unsigned char res[sizeof(secp256k1_ecdsa_signature_t)] = {0};
return memcmp(sig64, res, 64) == 0; return memcmp(sig, res, sizeof(secp256k1_ecdsa_signature_t)) == 0;
} }
void test_ecdsa_end_to_end(void) { void test_ecdsa_end_to_end(void) {
@ -1580,21 +1581,15 @@ void test_ecdsa_end_to_end(void) {
unsigned char privkey[32]; unsigned char privkey[32];
unsigned char message[32]; unsigned char message[32];
unsigned char privkey2[32]; unsigned char privkey2[32];
unsigned char csignature[64]; secp256k1_ecdsa_signature_t signature[5];
unsigned char signature[72]; unsigned char sig[74];
unsigned char signature2[72]; int siglen = 74;
unsigned char signature3[72]; unsigned char pubkeyc[65];
unsigned char signature4[72]; int pubkeyclen = 65;
unsigned char pubkey[65]; secp256k1_pubkey_t pubkey;
unsigned char recpubkey[65]; secp256k1_pubkey_t recpubkey;
unsigned char seckey[300]; unsigned char seckey[300];
int signaturelen = 72;
int signaturelen2 = 72;
int signaturelen3 = 72;
int signaturelen4 = 72;
int recid = 0; int recid = 0;
int recpubkeylen = 0;
int pubkeylen = 65;
int seckeylen = 300; int seckeylen = 300;
/* Generate a random key and message. */ /* Generate a random key and message. */
@ -1608,31 +1603,12 @@ void test_ecdsa_end_to_end(void) {
/* Construct and verify corresponding public key. */ /* Construct and verify corresponding public key. */
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1); CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
if (secp256k1_rand32() & 1) {
unsigned char pubkey2[65] = {0};
unsigned char pubkey3RE[33] = {0};
int pubkey2len = pubkeylen, pubkey3len = pubkeylen;
/* Decompress into a new array */ /* Verify exporting and importing public key. */
CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, pubkey2, &pubkey2len)); CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand32() % 2) == 1);
memset(&pubkey, 0, sizeof(pubkey));
/* Compress into a new array */ CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
CHECK(secp256k1_ec_pubkey_compress(ctx, pubkey, pubkey3RE, &pubkey3len));
/* Check that the key was changed iff it was originally compressed */
if (pubkeylen == 65) {
CHECK(memcmp(pubkey, pubkey2, 65) == 0); /* Values should be the same */
CHECK(memcmp(pubkey3RE, pubkey, 33) != 0); /* Means it should have been compressed */
} else {
CHECK(memcmp(pubkey, pubkey2, 65) != 0); /* Should have been decompressed */
CHECK(memcmp(pubkey3RE, pubkey, 33) == 0); /* Therefore compressed key should equal initial pubkey */
}
/* Decompress in place */
CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, pubkey, &pubkeylen));
CHECK(memcmp(pubkey, pubkey2, 65) == 0);
}
CHECK(secp256k1_ec_pubkey_verify(ctx, pubkey, pubkeylen));
/* Verify private key import and export. */ /* Verify private key import and export. */
CHECK(secp256k1_ec_privkey_export(ctx, privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1); CHECK(secp256k1_ec_privkey_export(ctx, privkey, seckey, &seckeylen, secp256k1_rand32() % 2) == 1);
@ -1644,17 +1620,16 @@ void test_ecdsa_end_to_end(void) {
int ret1; int ret1;
int ret2; int ret2;
unsigned char rnd[32]; unsigned char rnd[32];
unsigned char pubkey2[65]; secp256k1_pubkey_t pubkey2;
int pubkeylen2 = 65;
secp256k1_rand256_test(rnd); secp256k1_rand256_test(rnd);
ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd); ret1 = secp256k1_ec_privkey_tweak_add(ctx, privkey, rnd);
ret2 = secp256k1_ec_pubkey_tweak_add(ctx, pubkey, pubkeylen, rnd); ret2 = secp256k1_ec_pubkey_tweak_add(ctx, &pubkey, rnd);
CHECK(ret1 == ret2); CHECK(ret1 == ret2);
if (ret1 == 0) { if (ret1 == 0) {
return; return;
} }
CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
} }
/* Optionally tweak the keys using multiplication. */ /* Optionally tweak the keys using multiplication. */
@ -1662,59 +1637,70 @@ void test_ecdsa_end_to_end(void) {
int ret1; int ret1;
int ret2; int ret2;
unsigned char rnd[32]; unsigned char rnd[32];
unsigned char pubkey2[65]; secp256k1_pubkey_t pubkey2;
int pubkeylen2 = 65;
secp256k1_rand256_test(rnd); secp256k1_rand256_test(rnd);
ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd); ret1 = secp256k1_ec_privkey_tweak_mul(ctx, privkey, rnd);
ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, pubkey, pubkeylen, rnd); ret2 = secp256k1_ec_pubkey_tweak_mul(ctx, &pubkey, rnd);
CHECK(ret1 == ret2); CHECK(ret1 == ret2);
if (ret1 == 0) { if (ret1 == 0) {
return; return;
} }
CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0); CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
} }
/* Sign. */ /* Sign. */
CHECK(secp256k1_ecdsa_sign(ctx, message, signature, &signaturelen, privkey, NULL, NULL) == 1); CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[0], privkey, NULL, NULL) == 1);
CHECK(signaturelen > 0); CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[4], privkey, NULL, NULL) == 1);
CHECK(secp256k1_ecdsa_sign(ctx, message, signature2, &signaturelen2, privkey, NULL, extra) == 1); CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[1], privkey, NULL, extra) == 1);
CHECK(signaturelen2 > 0);
extra[31] = 1; extra[31] = 1;
CHECK(secp256k1_ecdsa_sign(ctx, message, signature3, &signaturelen3, privkey, NULL, extra) == 1); CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[2], privkey, NULL, extra) == 1);
CHECK(signaturelen3 > 0);
extra[31] = 0; extra[31] = 0;
extra[0] = 1; extra[0] = 1;
CHECK(secp256k1_ecdsa_sign(ctx, message, signature4, &signaturelen4, privkey, NULL, extra) == 1); CHECK(secp256k1_ecdsa_sign(ctx, message, &signature[3], privkey, NULL, extra) == 1);
CHECK(signaturelen4 > 0); CHECK(memcmp(&signature[0], &signature[4], sizeof(signature[0])) == 0);
CHECK((signaturelen != signaturelen2) || (memcmp(signature, signature2, signaturelen) != 0)); CHECK(memcmp(&signature[0], &signature[1], sizeof(signature[0])) != 0);
CHECK((signaturelen != signaturelen3) || (memcmp(signature, signature3, signaturelen) != 0)); CHECK(memcmp(&signature[0], &signature[2], sizeof(signature[0])) != 0);
CHECK((signaturelen3 != signaturelen2) || (memcmp(signature3, signature2, signaturelen3) != 0)); CHECK(memcmp(&signature[0], &signature[3], sizeof(signature[0])) != 0);
CHECK((signaturelen4 != signaturelen3) || (memcmp(signature4, signature3, signaturelen4) != 0)); CHECK(memcmp(&signature[1], &signature[2], sizeof(signature[0])) != 0);
CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0)); CHECK(memcmp(&signature[1], &signature[3], sizeof(signature[0])) != 0);
CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0)); CHECK(memcmp(&signature[2], &signature[3], sizeof(signature[0])) != 0);
/* Verify. */ /* Verify. */
CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, pubkey, pubkeylen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[1], &pubkey) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, pubkey, pubkeylen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[2], &pubkey) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, pubkey, pubkeylen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[3], &pubkey) == 1);
/* Destroy signature and verify again. */
signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) != 1);
/* Compact sign. */ /* Serialize/parse DER and verify again */
CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1); CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);
CHECK(!is_empty_compact_signature(csignature)); memset(&signature[0], 0, sizeof(signature[0]));
/* Recover. */ CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 1);
CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 1);
CHECK(recpubkeylen == pubkeylen); /* Serialize/destroy/parse DER and verify again. */
CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0); CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, sig, &siglen, &signature[0]) == 1);
/* Destroy signature and verify again. */ sig[secp256k1_rand32() % siglen] += 1 + (secp256k1_rand32() % 255);
csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &signature[0], sig, siglen) == 0 ||
CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || secp256k1_ecdsa_verify(ctx, message, &signature[0], &pubkey) == 0);
memcmp(pubkey, recpubkey, pubkeylen) != 0);
CHECK(recpubkeylen == pubkeylen);
/* Serialize/parse compact (without recovery id) and verify again. */
CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sig, &recid, &signature[4]) == 1);
CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sig, NULL, &signature[4]) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[4], &pubkey) == 1);
memset(&signature[4], 0, sizeof(signature[4]));
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature[4], sig, -1) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[4], &pubkey) == 1);
/* Parse compact (with recovery id) and recover. */
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature[4], sig, recid) == 1);
CHECK(secp256k1_ecdsa_recover(ctx, message, &signature[4], &recpubkey) == 1);
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
/* Serialize/destroy/parse signature and verify again. */
CHECK(secp256k1_ecdsa_signature_serialize_compact(ctx, sig, &recid, &signature[4]) == 1);
sig[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255);
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &signature[4], sig, recid) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, &signature[4], &pubkey) == 0);
/* Recover again */
CHECK(secp256k1_ecdsa_recover(ctx, message, &signature[4], &recpubkey) == 0 ||
memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
} }
void test_random_pubkeys(void) { void test_random_pubkeys(void) {
@ -1816,9 +1802,8 @@ void test_ecdsa_edge_cases(void) {
0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86, 0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86,
0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57 0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
}; };
unsigned char pubkey[65]; secp256k1_pubkey_t pubkey;
int t; int t;
int pubkeylen = 65;
/* signature (r,s) = (4,4), which can be recovered with all 4 recids. */ /* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
const unsigned char sigb64[64] = { const unsigned char sigb64[64] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -1830,14 +1815,18 @@ void test_ecdsa_edge_cases(void) {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
}; };
unsigned char pubkeyb[33]; secp256k1_pubkey_t pubkeyb;
int pubkeyblen = 33; secp256k1_ecdsa_signature_t sig;
int recid; int recid;
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 0)); CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 0));
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 1)); CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey));
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 2)); CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 1));
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 3)); CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey));
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 2));
CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey));
CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sig64, 3));
CHECK(!secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey));
for (recid = 0; recid < 4; recid++) { for (recid = 0; recid < 4; recid++) {
int i; int i;
@ -1882,34 +1871,41 @@ void test_ecdsa_edge_cases(void) {
0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E, 0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,
0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04 0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04
}; };
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid)); CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigb64, recid) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyb) == 1);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1);
for (recid2 = 0; recid2 < 4; recid2++) { for (recid2 = 0; recid2 < 4; recid2++) {
unsigned char pubkey2b[33]; secp256k1_pubkey_t pubkey2b;
int pubkey2blen = 33; CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigb64, recid2) == 1);
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2)); CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkey2b) == 1);
/* Verifying with (order + r,4) should always fail. */ /* Verifying with (order + r,4) should always fail. */
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderlong, sizeof(sigbderlong), pubkey2b, pubkey2blen) != 1); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderlong, sizeof(sigbderlong)) == 0);
} }
/* DER parsing tests. */ /* DER parsing tests. */
/* Zero length r/s. */ /* Zero length r/s. */
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zr, sizeof(sigcder_zr), pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zr, sizeof(sigcder_zr)) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zs, sizeof(sigcder_zs), pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder_zs, sizeof(sigcder_zs)) == 0);
/* Leading zeros. */ /* Leading zeros. */
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt1, sizeof(sigbderalt1)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt2, sizeof(sigbderalt2)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 1);
sigbderalt3[4] = 1; sigbderalt3[4] = 1;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt3, sizeof(sigbderalt3)) == 0);
sigbderalt4[7] = 1; sigbderalt4[7] = 1;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbderalt4, sizeof(sigbderalt4)) == 0);
/* Damage signature. */ /* Damage signature. */
sigbder[7]++; sigbder[7]++;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 0);
sigbder[7]--; sigbder[7]--;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, 6) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder) - 1) == 0);
for(i = 0; i < 8; i++) { for(i = 0; i < 8; i++) {
int c; int c;
unsigned char orig = sigbder[i]; unsigned char orig = sigbder[i];
@ -1919,8 +1915,7 @@ void test_ecdsa_edge_cases(void) {
continue; continue;
} }
sigbder[i] = c; sigbder[i] = c;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigbder, sizeof(sigbder)) == 0 || secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyb) == 0);
(i==4 || i==7) ? 0 : -2 );
} }
sigbder[i] = orig; sigbder[i] = orig;
} }
@ -1931,15 +1926,15 @@ void test_ecdsa_edge_cases(void) {
secp256k1_gej_t keyj; secp256k1_gej_t keyj;
secp256k1_ge_t key; secp256k1_ge_t key;
secp256k1_scalar_t msg; secp256k1_scalar_t msg;
secp256k1_ecdsa_sig_t sig; secp256k1_scalar_t sr, ss;
secp256k1_scalar_set_int(&sig.s, 1); secp256k1_scalar_set_int(&ss, 1);
secp256k1_scalar_negate(&sig.s, &sig.s); secp256k1_scalar_negate(&ss, &ss);
secp256k1_scalar_inverse(&sig.s, &sig.s); secp256k1_scalar_inverse(&ss, &ss);
secp256k1_scalar_set_int(&sig.r, 1); secp256k1_scalar_set_int(&sr, 1);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sig.r); secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &keyj, &sr);
secp256k1_ge_set_gej(&key, &keyj); secp256k1_ge_set_gej(&key, &keyj);
msg = sig.s; msg = ss;
CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &key, &msg) == 0); CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sr, &ss, &key, &msg) == 0);
} }
/* Test r/s equal to zero */ /* Test r/s equal to zero */
@ -1956,24 +1951,31 @@ void test_ecdsa_edge_cases(void) {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01,
}; };
unsigned char pubkeyc[65]; secp256k1_pubkey_t pubkeyc;
int pubkeyclen = 65; CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigc64, 0) == 1);
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyc) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1); CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 1);
sigcder[4] = 0; sigcder[4] = 0;
sigc64[31] = 0; sigc64[31] = 0;
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigc64, 0) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyb) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 0);
sigcder[4] = 1; sigcder[4] = 1;
sigcder[7] = 0; sigcder[7] = 0;
sigc64[31] = 1; sigc64[31] = 1;
sigc64[63] = 0; sigc64[63] = 0;
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0); CHECK(secp256k1_ecdsa_signature_parse_compact(ctx, &sig, sigc64, 0) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); CHECK(secp256k1_ecdsa_recover(ctx, msg32, &sig, &pubkeyb) == 0);
CHECK(secp256k1_ecdsa_signature_parse_der(ctx, &sig, sigcder, sizeof(sigcder)) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, &sig, &pubkeyc) == 0);
} }
/*Signature where s would be zero.*/ /*Signature where s would be zero.*/
{ {
unsigned char signature[72];
int siglen;
const unsigned char nonce[32] = { const unsigned char nonce[32] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -1998,21 +2000,15 @@ void test_ecdsa_edge_cases(void) {
0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62, 0xb8, 0x12, 0xe0, 0x0b, 0x81, 0x7a, 0x77, 0x62,
0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9, 0x65, 0xdf, 0xdd, 0x31, 0xb9, 0x3e, 0x29, 0xa9,
}; };
unsigned char sig[72]; CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce) == 0);
int siglen = 72; CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce2) == 0);
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 0);
CHECK(siglen == 0);
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 0);
CHECK(siglen == 0);
msg[31] = 0xaa; msg[31] = 0xaa;
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce) == 1);
CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, precomputed_nonce_function, nonce2) == 1);
siglen = 72; siglen = 72;
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) == 1); CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 1);
CHECK(siglen > 0);
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce2) == 1);
CHECK(siglen > 0);
siglen = 10; siglen = 10;
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, precomputed_nonce_function, nonce) != 1); CHECK(secp256k1_ecdsa_signature_serialize_der(ctx, signature, &siglen, &sig) == 0);
CHECK(siglen == 0);
} }
/* Nonce function corner cases. */ /* Nonce function corner cases. */
@ -2021,65 +2017,43 @@ void test_ecdsa_edge_cases(void) {
int i; int i;
unsigned char key[32]; unsigned char key[32];
unsigned char msg[32]; unsigned char msg[32];
unsigned char sig[72]; secp256k1_ecdsa_signature_t sig2;
unsigned char sig2[72]; secp256k1_scalar_t sr[512], ss;
secp256k1_ecdsa_sig_t s[512];
int siglen = 72;
int siglen2 = 72;
int recid2;
const unsigned char *extra; const unsigned char *extra;
extra = t == 0 ? NULL : zero; extra = t == 0 ? NULL : zero;
memset(msg, 0, 32); memset(msg, 0, 32);
msg[31] = 1; msg[31] = 1;
/* High key results in signature failure. */ /* High key results in signature failure. */
memset(key, 0xFF, 32); memset(key, 0xFF, 32);
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, NULL, extra) == 0);
CHECK(siglen == 0); CHECK(is_empty_signature(&sig));
/* Zero key results in signature failure. */ /* Zero key results in signature failure. */
memset(key, 0, 32); memset(key, 0, 32);
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 0); CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, NULL, extra) == 0);
CHECK(siglen == 0); CHECK(is_empty_signature(&sig));
/* Nonce function failure results in signature failure. */ /* Nonce function failure results in signature failure. */
key[31] = 1; key[31] = 1;
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_fail, extra) == 0); CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, nonce_function_test_fail, extra) == 0);
CHECK(siglen == 0); CHECK(is_empty_signature(&sig));
CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_fail, extra, &recid) == 0);
CHECK(is_empty_compact_signature(sig));
/* The retry loop successfully makes its way to the first good value. */ /* The retry loop successfully makes its way to the first good value. */
siglen = 72; CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig, key, nonce_function_test_retry, extra) == 1);
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, nonce_function_test_retry, extra) == 1); CHECK(!is_empty_signature(&sig));
CHECK(siglen > 0); CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, nonce_function_rfc6979, extra) == 1);
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, nonce_function_rfc6979, extra) == 1); CHECK(!is_empty_signature(&sig2));
CHECK(siglen > 0); CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);
CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0));
CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, nonce_function_test_retry, extra, &recid) == 1);
CHECK(!is_empty_compact_signature(sig));
CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, nonce_function_rfc6979, extra, &recid2) == 1);
CHECK(!is_empty_compact_signature(sig2));
CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0));
/* The default nonce function is determinstic. */ /* The default nonce function is determinstic. */
siglen = 72; CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
siglen2 = 72; CHECK(!is_empty_signature(&sig2));
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig, &siglen, key, NULL, extra) == 1); CHECK(memcmp(&sig, &sig2, sizeof(sig)) == 0);
CHECK(siglen > 0);
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1);
CHECK(siglen2 > 0);
CHECK((siglen == siglen2) && (memcmp(sig, sig2, siglen) == 0));
CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig, key, NULL, extra, &recid) == 1);
CHECK(!is_empty_compact_signature(sig));
CHECK(secp256k1_ecdsa_sign_compact(ctx, msg, sig2, key, NULL, extra, &recid2) == 1);
CHECK(!is_empty_compact_signature(sig));
CHECK((recid == recid2) && (memcmp(sig, sig2, 64) == 0));
/* The default nonce function changes output with different messages. */ /* The default nonce function changes output with different messages. */
for(i = 0; i < 256; i++) { for(i = 0; i < 256; i++) {
int j; int j;
siglen2 = 72;
msg[0] = i; msg[0] = i;
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
CHECK(!is_empty_compact_signature(sig)); CHECK(!is_empty_signature(&sig2));
CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); secp256k1_ecdsa_signature_load(&sr[i], &ss, NULL, &sig2);
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
} }
} }
msg[0] = 0; msg[0] = 0;
@ -2087,12 +2061,12 @@ void test_ecdsa_edge_cases(void) {
/* The default nonce function changes output with different keys. */ /* The default nonce function changes output with different keys. */
for(i = 256; i < 512; i++) { for(i = 256; i < 512; i++) {
int j; int j;
siglen2 = 72;
key[0] = i - 256; key[0] = i - 256;
CHECK(secp256k1_ecdsa_sign(ctx, msg, sig2, &siglen2, key, NULL, extra) == 1); CHECK(secp256k1_ecdsa_sign(ctx, msg, &sig2, key, NULL, extra) == 1);
CHECK(secp256k1_ecdsa_sig_parse(&s[i], sig2, siglen2)); CHECK(!is_empty_signature(&sig2));
secp256k1_ecdsa_signature_load(&sr[i], &ss, NULL, &sig2);
for (j = 0; j < i; j++) { for (j = 0; j < i; j++) {
CHECK(!secp256k1_scalar_eq(&s[i].r, &s[j].r)); CHECK(!secp256k1_scalar_eq(&sr[i], &sr[j]));
} }
} }
key[0] = 0; key[0] = 0;
@ -2133,7 +2107,7 @@ EC_KEY *get_openssl_key(const secp256k1_scalar_t *key) {
void test_ecdsa_openssl(void) { void test_ecdsa_openssl(void) {
secp256k1_gej_t qj; secp256k1_gej_t qj;
secp256k1_ge_t q; secp256k1_ge_t q;
secp256k1_ecdsa_sig_t sig; secp256k1_scalar_t sigr, sigs;
secp256k1_scalar_t one; secp256k1_scalar_t one;
secp256k1_scalar_t msg2; secp256k1_scalar_t msg2;
secp256k1_scalar_t key, msg; secp256k1_scalar_t key, msg;
@ -2150,14 +2124,14 @@ void test_ecdsa_openssl(void) {
ec_key = get_openssl_key(&key); ec_key = get_openssl_key(&key);
CHECK(ec_key); CHECK(ec_key);
CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key)); CHECK(ECDSA_sign(0, message, sizeof(message), signature, &sigsize, ec_key));
CHECK(secp256k1_ecdsa_sig_parse(&sig, signature, sigsize)); CHECK(secp256k1_ecdsa_sig_parse(&sigr, &sigs, signature, sigsize));
CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg)); CHECK(secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg));
secp256k1_scalar_set_int(&one, 1); secp256k1_scalar_set_int(&one, 1);
secp256k1_scalar_add(&msg2, &msg, &one); secp256k1_scalar_add(&msg2, &msg, &one);
CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sig, &q, &msg2)); CHECK(!secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &sigr, &sigs, &q, &msg2));
random_sign(&sig, &key, &msg, NULL); random_sign(&sigr, &sigs, &key, &msg, NULL);
CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sig)); CHECK(secp256k1_ecdsa_sig_serialize(signature, &secp_sigsize, &sigr, &sigs));
CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1); CHECK(ECDSA_verify(0, message, sizeof(message), signature, secp_sigsize, ec_key) == 1);
EC_KEY_free(ec_key); EC_KEY_free(ec_key);