Introduce secp256k1_pubkey_t type

This commit is contained in:
Pieter Wuille 2015-07-20 13:36:55 -04:00
parent 4c63780710
commit 23cfa914d2
5 changed files with 216 additions and 250 deletions

View file

@ -74,25 +74,70 @@ 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);
/** 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 * siglen: the length of the signature
* pubkey: the public key to verify with (cannot be NULL) * pubkey: pointer to an initialized 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 unsigned char *sig,
int siglen, int siglen,
const unsigned char *pubkey, const secp256k1_pubkey_t *pubkey
int pubkeylen
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(5); ) 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.
@ -124,7 +169,6 @@ 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, the private key was invalid, or there is not
@ -202,20 +246,16 @@ int secp256k1_ecdsa_sign_compact(
* 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: signature as 64 byte array (cannot be NULL)
* compressed: whether to recover a compressed or uncompressed pubkey
* recid: the recovery id (0-3, as returned by ecdsa_sign_compact) * 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) * Out: pubkey: pointer to the recoved public key (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_compact(
const secp256k1_context_t* ctx, const secp256k1_context_t* ctx,
const unsigned char *msg32, const unsigned char *msg32,
const unsigned char *sig64, const unsigned char *sig64,
unsigned char *pubkey, secp256k1_pubkey_t *pubkey,
int *pubkeylen,
int compressed,
int recid int recid
) 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);
/** Verify an ECDSA secret key. /** Verify an ECDSA secret key.
* Returns: 1: secret key is valid * Returns: 1: secret key is valid
@ -228,71 +268,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 +312,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 +328,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,18 @@ 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)); CHECK(secp256k1_ecdsa_recover_compact(data->ctx, data->msg, data->sig, &pubkey, i % 2));
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

@ -26,10 +26,12 @@ 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;
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_verify(data->ctx, data->msg, data->sig, data->siglen, &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 +40,7 @@ static void benchmark_verify(void* arg) {
int main(void) { int main(void) {
int i; int i;
secp256k1_pubkey_t pubkey;
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);
@ -46,8 +49,8 @@ int main(void) {
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); secp256k1_ecdsa_sign(data.ctx, data.msg, data.sig, &data.siglen, data.key, NULL, NULL);
data.pubkeylen = 33; CHECK(secp256k1_ec_pubkey_create(data.ctx, &pubkey, data.key));
CHECK(secp256k1_ec_pubkey_create(data.ctx, data.pubkey, &data.pubkeylen, data.key, 1)); 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

@ -54,11 +54,65 @@ 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);
}
int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig, int siglen, const secp256k1_pubkey_t *pubkey) {
secp256k1_ge_t q; secp256k1_ge_t q;
secp256k1_ecdsa_sig_t s; secp256k1_ecdsa_sig_t s;
secp256k1_scalar_t m; secp256k1_scalar_t m;
int ret = -3; int ret = 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);
@ -67,19 +121,12 @@ int secp256k1_ecdsa_verify(const secp256k1_context_t* ctx, const unsigned char *
secp256k1_scalar_set_b32(&m, msg32, NULL); secp256k1_scalar_set_b32(&m, msg32, NULL);
if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) { secp256k1_pubkey_load(&q, pubkey);
if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) { if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) {
if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) { if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) {
/* success is 1, all other values are fail */ /* success is 1, all other values are fail */
ret = 1; ret = 1;
} else {
ret = 0;
}
} else {
ret = -2;
} }
} else {
ret = -1;
} }
return ret; return ret;
@ -206,7 +253,7 @@ int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned
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_compact(const secp256k1_context_t* ctx, const unsigned char *msg32, const unsigned char *sig64, secp256k1_pubkey_t *pubkey, int recid) {
secp256k1_ge_t q; secp256k1_ge_t q;
secp256k1_ecdsa_sig_t sig; secp256k1_ecdsa_sig_t sig;
secp256k1_scalar_t m; secp256k1_scalar_t m;
@ -217,7 +264,6 @@ int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsign
DEBUG_CHECK(msg32 != NULL); DEBUG_CHECK(msg32 != NULL);
DEBUG_CHECK(sig64 != NULL); DEBUG_CHECK(sig64 != NULL);
DEBUG_CHECK(pubkey != NULL); DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(pubkeylen != NULL);
DEBUG_CHECK(recid >= 0 && recid <= 3); DEBUG_CHECK(recid >= 0 && recid <= 3);
secp256k1_scalar_set_b32(&sig.r, sig64, &overflow); secp256k1_scalar_set_b32(&sig.r, sig64, &overflow);
@ -226,8 +272,11 @@ int secp256k1_ecdsa_recover_compact(const secp256k1_context_t* ctx, const unsign
if (!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, &sig, &q, &m, recid)) { ret = secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid);
ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed); if (ret) {
secp256k1_pubkey_save(pubkey, &q);
} else {
memset(pubkey, 0, sizeof(*pubkey));
} }
} }
} }
@ -248,16 +297,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 +306,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); secp256k1_pubkey_save(pubkey, &p);
ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed); 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 +343,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 +354,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); ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term);
if (ret) { if (ret) {
ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term); secp256k1_pubkey_save(pubkey, &p);
} } else {
if (ret) { memset(pubkey, 0, sizeof(*pubkey));
int oldlen = pubkeylen;
ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
VERIFY_CHECK(pubkeylen == oldlen);
} }
} }
@ -382,7 +389,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 +400,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); ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor);
if (ret) { if (ret) {
ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor); secp256k1_pubkey_save(pubkey, &p);
} } else {
if (ret) { memset(pubkey, 0, sizeof(*pubkey));
int oldlen = pubkeylen;
ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
VERIFY_CHECK(pubkeylen == oldlen);
} }
} }

View file

@ -1585,16 +1585,16 @@ void test_ecdsa_end_to_end(void) {
unsigned char signature2[72]; unsigned char signature2[72];
unsigned char signature3[72]; unsigned char signature3[72];
unsigned char signature4[72]; unsigned char signature4[72];
unsigned char pubkey[65]; unsigned char pubkeyc[65];
unsigned char recpubkey[65]; int pubkeyclen = 65;
secp256k1_pubkey_t pubkey;
secp256k1_pubkey_t recpubkey;
unsigned char seckey[300]; unsigned char seckey[300];
int signaturelen = 72; int signaturelen = 72;
int signaturelen2 = 72; int signaturelen2 = 72;
int signaturelen3 = 72; int signaturelen3 = 72;
int signaturelen4 = 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 +1608,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 +1625,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,17 +1642,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_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. */
@ -1694,27 +1673,24 @@ void test_ecdsa_end_to_end(void) {
CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0)); CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0));
CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0)); CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0));
/* Verify. */ /* Verify. */
CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, &pubkey) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, pubkey, pubkeylen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, &pubkey) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, pubkey, pubkeylen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, &pubkey) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, pubkey, pubkeylen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, &pubkey) == 1);
/* Destroy signature and verify again. */ /* Destroy signature and verify again. */
signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255); signature[signaturelen - 1 - secp256k1_rand32() % 20] += 1 + (secp256k1_rand32() % 255);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) != 1); CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, &pubkey) != 1);
/* Compact sign. */ /* Compact sign. */
CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1); CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1);
CHECK(!is_empty_compact_signature(csignature)); CHECK(!is_empty_compact_signature(csignature));
/* Recover. */ /* Recover. */
CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1); CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, &recpubkey, recid) == 1);
CHECK(recpubkeylen == pubkeylen); CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0);
/* Destroy signature and verify again. */ /* Destroy signature and verify again. */
csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255); csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255);
CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 || CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, &recpubkey, recid) != 1 ||
memcmp(pubkey, recpubkey, pubkeylen) != 0); memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
CHECK(recpubkeylen == pubkeylen);
} }
void test_random_pubkeys(void) { void test_random_pubkeys(void) {
@ -1816,9 +1792,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 +1805,13 @@ 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;
int recid; int recid;
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 0)); CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, &pubkey, 0));
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 1)); CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, &pubkey, 1));
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 2)); CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, &pubkey, 2));
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 3)); CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, &pubkey, 3));
for (recid = 0; recid < 4; recid++) { for (recid = 0; recid < 4; recid++) {
int i; int i;
@ -1882,34 +1856,33 @@ 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_recover_compact(ctx, msg32, sigb64, &pubkeyb, recid));
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), &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_recover_compact(ctx, msg32, sigb64, &pubkey2b, recid2));
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2));
/* 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_verify(ctx, msg32, sigbderlong, sizeof(sigbderlong), &pubkey2b) != 1);
} }
/* 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_verify(ctx, msg32, sigcder_zr, sizeof(sigcder_zr), &pubkeyb) != 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zs, sizeof(sigcder_zs), pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder_zs, sizeof(sigcder_zs), &pubkeyb) != 1);
/* Leading zeros. */ /* Leading zeros. */
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), &pubkeyb) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), &pubkeyb) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), &pubkeyb) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), &pubkeyb) == 1);
sigbderalt3[4] = 1; sigbderalt3[4] = 1;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), &pubkeyb) != 1);
sigbderalt4[7] = 1; sigbderalt4[7] = 1;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), &pubkeyb) != 1);
/* Damage signature. */ /* Damage signature. */
sigbder[7]++; sigbder[7]++;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 0); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), &pubkeyb) == 0);
sigbder[7]--; sigbder[7]--;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, &pubkeyb) != 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, &pubkeyb) != 1);
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 +1892,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_verify(ctx, msg32, sigbder, sizeof(sigbder), &pubkeyb) != 1);
(i==4 || i==7) ? 0 : -2 );
} }
sigbder[i] = orig; sigbder[i] = orig;
} }
@ -1956,20 +1928,19 @@ 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_recover_compact(ctx, msg32, sigc64, &pubkeyc, 0) == 1);
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), &pubkeyc) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 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_recover_compact(ctx, msg32, sigc64, &pubkeyb, 0) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), &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_recover_compact(ctx, msg32, sigc64, &pubkeyb, 0) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0); CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), &pubkeyc) == 0);
} }
/*Signature where s would be zero.*/ /*Signature where s would be zero.*/