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_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.
* Returns: 1: correct signature
* 0: incorrect signature
* -1: invalid public key
* -2: invalid signature
* 0: incorrect or unparseable signature
* In: ctx: a secp256k1 context object, initialized for verification.
* msg32: the 32-byte message hash being verified (cannot be NULL)
* sig: the signature being verified (cannot be NULL)
* siglen: the length of the signature
* pubkey: the public key to verify with (cannot be NULL)
* pubkeylen: the length of pubkey
* pubkey: pointer to an initialized public key to verify with (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT 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
const secp256k1_pubkey_t *pubkey
) 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.
@ -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). */
extern const secp256k1_nonce_function_t secp256k1_nonce_function_default;
/** Create an ECDSA signature.
* Returns: 1: signature created
* 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)
* msg32: the 32-byte message hash assumed to be signed (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)
* 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)
* Out: pubkey: pointer to the recoved public key (cannot be NULL)
*/
SECP256K1_WARN_UNUSED_RESULT 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,
secp256k1_pubkey_t *pubkey,
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.
* Returns: 1: secret key is valid
@ -228,71 +268,18 @@ SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_seckey_verify(
const unsigned char *seckey
) 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.
* 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)
* Out: pubkey: pointer to a 33-byte (if compressed) or 65-byte (if uncompressed)
* 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)
* Out: pubkey: pointer to the created public key (cannot be NULL)
* Returns: 1: secret was valid, public key stores
* 0: secret was invalid, try again
*/
SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_create(
const secp256k1_context_t* ctx,
unsigned char *pubkey,
int *pubkeylen,
const unsigned char *seckey,
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);
secp256k1_pubkey_t *pubkey,
const unsigned char *seckey
) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3);
/** Export a private key in DER format.
* 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(
const secp256k1_context_t* ctx,
unsigned char *pubkey,
int pubkeylen,
secp256k1_pubkey_t *pubkey,
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. */
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(
const secp256k1_context_t* ctx,
unsigned char *pubkey,
int pubkeylen,
secp256k1_pubkey_t *pubkey,
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.
* Returns: 1: randomization successfully updated

View file

@ -17,16 +17,18 @@ typedef struct {
void bench_recover(void* arg) {
int i;
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++) {
int j;
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++) {
data->sig[j + 32] = data->msg[j]; /* Move former message to S. */
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;
for (i = 0; i < 20000; i++) {
secp256k1_pubkey_t pubkey;
data->sig[data->siglen - 1] ^= (i & 0xFF);
data->sig[data->siglen - 2] ^= ((i >> 8) & 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 - 2] ^= ((i >> 8) & 0xFF);
data->sig[data->siglen - 3] ^= ((i >> 16) & 0xFF);
@ -38,6 +40,7 @@ static void benchmark_verify(void* arg) {
int main(void) {
int i;
secp256k1_pubkey_t pubkey;
benchmark_verify_t data;
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;
data.siglen = 72;
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, 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);

View file

@ -54,11 +54,65 @@ void secp256k1_context_destroy(secp256k1_context_t* 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_ecdsa_sig_t s;
secp256k1_scalar_t m;
int ret = -3;
int ret = 0;
DEBUG_CHECK(ctx != NULL);
DEBUG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx));
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);
if (secp256k1_eckey_pubkey_parse(&q, pubkey, pubkeylen)) {
if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) {
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;
secp256k1_pubkey_load(&q, pubkey);
if (secp256k1_ecdsa_sig_parse(&s, sig, siglen)) {
if (secp256k1_ecdsa_sig_verify(&ctx->ecmult_ctx, &s, &q, &m)) {
/* success is 1, all other values are fail */
ret = 1;
}
} else {
ret = -1;
}
return ret;
@ -206,7 +253,7 @@ int secp256k1_ecdsa_sign_compact(const secp256k1_context_t* ctx, const unsigned
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_ecdsa_sig_t sig;
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(sig64 != NULL);
DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(pubkeylen != NULL);
DEBUG_CHECK(recid >= 0 && recid <= 3);
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) {
secp256k1_scalar_set_b32(&m, msg32, NULL);
if (secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid)) {
ret = secp256k1_eckey_pubkey_serialize(&q, pubkey, pubkeylen, compressed);
ret = secp256k1_ecdsa_sig_recover(&ctx->ecmult_ctx, &sig, &q, &m, recid);
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;
}
int secp256k1_ec_pubkey_verify(const secp256k1_context_t* ctx, const unsigned char *pubkey, int pubkeylen) {
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) {
int secp256k1_ec_pubkey_create(const secp256k1_context_t* ctx, secp256k1_pubkey_t *pubkey, const unsigned char *seckey) {
secp256k1_gej_t pj;
secp256k1_ge_t p;
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(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
DEBUG_CHECK(pubkey != NULL);
DEBUG_CHECK(pubkeylen != NULL);
DEBUG_CHECK(seckey != NULL);
secp256k1_scalar_set_b32(&sec, seckey, &overflow);
if (!overflow) {
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
secp256k1_scalar_clear(&sec);
secp256k1_ge_set_gej(&p, &pj);
ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, pubkeylen, compressed);
}
ret = !overflow & !secp256k1_scalar_is_zero(&sec);
secp256k1_ecmult_gen(&ctx->ecmult_gen_ctx, &pj, &sec);
secp256k1_ge_set_gej(&p, &pj);
secp256k1_pubkey_save(pubkey, &p);
secp256k1_scalar_clear(&sec);
if (!ret) {
*pubkeylen = 0;
memset(pubkey, 0, sizeof(*pubkey));
}
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) {
secp256k1_scalar_t term;
secp256k1_scalar_t sec;
@ -334,7 +343,7 @@ int secp256k1_ec_privkey_tweak_add(const secp256k1_context_t* ctx, unsigned char
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_scalar_t term;
int ret = 0;
@ -345,15 +354,13 @@ int secp256k1_ec_pubkey_tweak_add(const secp256k1_context_t* ctx, unsigned char
DEBUG_CHECK(tweak != NULL);
secp256k1_scalar_set_b32(&term, tweak, &overflow);
secp256k1_pubkey_load(&p, pubkey);
if (!overflow) {
ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term);
if (ret) {
ret = secp256k1_eckey_pubkey_tweak_add(&ctx->ecmult_ctx, &p, &term);
}
if (ret) {
int oldlen = pubkeylen;
ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
VERIFY_CHECK(pubkeylen == oldlen);
secp256k1_pubkey_save(pubkey, &p);
} else {
memset(pubkey, 0, sizeof(*pubkey));
}
}
@ -382,7 +389,7 @@ int secp256k1_ec_privkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char
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_scalar_t factor;
int ret = 0;
@ -393,15 +400,13 @@ int secp256k1_ec_pubkey_tweak_mul(const secp256k1_context_t* ctx, unsigned char
DEBUG_CHECK(tweak != NULL);
secp256k1_scalar_set_b32(&factor, tweak, &overflow);
secp256k1_pubkey_load(&p, pubkey);
if (!overflow) {
ret = secp256k1_eckey_pubkey_parse(&p, pubkey, pubkeylen);
ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor);
if (ret) {
ret = secp256k1_eckey_pubkey_tweak_mul(&ctx->ecmult_ctx, &p, &factor);
}
if (ret) {
int oldlen = pubkeylen;
ret = secp256k1_eckey_pubkey_serialize(&p, pubkey, &pubkeylen, oldlen <= 33);
VERIFY_CHECK(pubkeylen == oldlen);
secp256k1_pubkey_save(pubkey, &p);
} else {
memset(pubkey, 0, sizeof(*pubkey));
}
}

View file

@ -1585,16 +1585,16 @@ void test_ecdsa_end_to_end(void) {
unsigned char signature2[72];
unsigned char signature3[72];
unsigned char signature4[72];
unsigned char pubkey[65];
unsigned char recpubkey[65];
unsigned char pubkeyc[65];
int pubkeyclen = 65;
secp256k1_pubkey_t pubkey;
secp256k1_pubkey_t recpubkey;
unsigned char seckey[300];
int signaturelen = 72;
int signaturelen2 = 72;
int signaturelen3 = 72;
int signaturelen4 = 72;
int recid = 0;
int recpubkeylen = 0;
int pubkeylen = 65;
int seckeylen = 300;
/* Generate a random key and message. */
@ -1608,31 +1608,12 @@ void test_ecdsa_end_to_end(void) {
/* Construct and verify corresponding public key. */
CHECK(secp256k1_ec_seckey_verify(ctx, privkey) == 1);
CHECK(secp256k1_ec_pubkey_create(ctx, pubkey, &pubkeylen, privkey, (secp256k1_rand32() & 3) != 0) == 1);
if (secp256k1_rand32() & 1) {
unsigned char pubkey2[65] = {0};
unsigned char pubkey3RE[33] = {0};
int pubkey2len = pubkeylen, pubkey3len = pubkeylen;
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
/* Decompress into a new array */
CHECK(secp256k1_ec_pubkey_decompress(ctx, pubkey, pubkey2, &pubkey2len));
/* Compress into a new array */
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 exporting and importing public key. */
CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand32() % 2) == 1);
memset(&pubkey, 0, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
/* Verify private key import and export. */
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 ret2;
unsigned char rnd[32];
unsigned char pubkey2[65];
int pubkeylen2 = 65;
secp256k1_pubkey_t pubkey2;
secp256k1_rand256_test(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);
if (ret1 == 0) {
return;
}
CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1);
CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
}
/* Optionally tweak the keys using multiplication. */
@ -1662,17 +1642,16 @@ void test_ecdsa_end_to_end(void) {
int ret1;
int ret2;
unsigned char rnd[32];
unsigned char pubkey2[65];
int pubkeylen2 = 65;
secp256k1_pubkey_t pubkey2;
secp256k1_rand256_test(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);
if (ret1 == 0) {
return;
}
CHECK(secp256k1_ec_pubkey_create(ctx, pubkey2, &pubkeylen2, privkey, pubkeylen == 33) == 1);
CHECK(memcmp(pubkey, pubkey2, pubkeylen) == 0);
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey2, privkey) == 1);
CHECK(memcmp(&pubkey, &pubkey2, sizeof(pubkey)) == 0);
}
/* Sign. */
@ -1694,27 +1673,24 @@ void test_ecdsa_end_to_end(void) {
CHECK((signaturelen4 != signaturelen2) || (memcmp(signature4, signature2, signaturelen4) != 0));
CHECK((signaturelen4 != signaturelen) || (memcmp(signature4, signature, signaturelen4) != 0));
/* Verify. */
CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, pubkey, pubkeylen) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, pubkey, pubkeylen) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, pubkey, pubkeylen) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, pubkey, pubkeylen) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, &pubkey) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature2, signaturelen2, &pubkey) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature3, signaturelen3, &pubkey) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature4, signaturelen4, &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);
CHECK(secp256k1_ecdsa_verify(ctx, message, signature, signaturelen, &pubkey) != 1);
/* Compact sign. */
CHECK(secp256k1_ecdsa_sign_compact(ctx, message, csignature, privkey, NULL, NULL, &recid) == 1);
CHECK(!is_empty_compact_signature(csignature));
/* Recover. */
CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) == 1);
CHECK(recpubkeylen == pubkeylen);
CHECK(memcmp(pubkey, recpubkey, pubkeylen) == 0);
CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, &recpubkey, recid) == 1);
CHECK(memcmp(&pubkey, &recpubkey, sizeof(pubkey)) == 0);
/* Destroy signature and verify again. */
csignature[secp256k1_rand32() % 64] += 1 + (secp256k1_rand32() % 255);
CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, recpubkey, &recpubkeylen, pubkeylen == 33, recid) != 1 ||
memcmp(pubkey, recpubkey, pubkeylen) != 0);
CHECK(recpubkeylen == pubkeylen);
CHECK(secp256k1_ecdsa_recover_compact(ctx, message, csignature, &recpubkey, recid) != 1 ||
memcmp(&pubkey, &recpubkey, sizeof(pubkey)) != 0);
}
void test_random_pubkeys(void) {
@ -1816,9 +1792,8 @@ void test_ecdsa_edge_cases(void) {
0x7D, 0xD7, 0x3E, 0x38, 0x7E, 0xE4, 0xFC, 0x86,
0x6E, 0x1B, 0xE8, 0xEC, 0xC7, 0xDD, 0x95, 0x57
};
unsigned char pubkey[65];
secp256k1_pubkey_t pubkey;
int t;
int pubkeylen = 65;
/* signature (r,s) = (4,4), which can be recovered with all 4 recids. */
const unsigned char sigb64[64] = {
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, 0x04,
};
unsigned char pubkeyb[33];
int pubkeyblen = 33;
secp256k1_pubkey_t pubkeyb;
int recid;
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 0));
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 1));
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 2));
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, pubkey, &pubkeylen, 0, 3));
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, &pubkey, 0));
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, &pubkey, 1));
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, &pubkey, 2));
CHECK(!secp256k1_ecdsa_recover_compact(ctx, msg32, sig64, &pubkey, 3));
for (recid = 0; recid < 4; recid++) {
int i;
@ -1882,34 +1856,33 @@ void test_ecdsa_edge_cases(void) {
0xE6, 0xAF, 0x48, 0xA0, 0x3B, 0xBF, 0xD2, 0x5E,
0x8C, 0xD0, 0x36, 0x41, 0x45, 0x02, 0x01, 0x04
};
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkeyb, &pubkeyblen, 1, recid));
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) == 1);
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, &pubkeyb, recid));
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), &pubkeyb) == 1);
for (recid2 = 0; recid2 < 4; recid2++) {
unsigned char pubkey2b[33];
int pubkey2blen = 33;
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, pubkey2b, &pubkey2blen, 1, recid2));
secp256k1_pubkey_t pubkey2b;
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigb64, &pubkey2b, recid2));
/* 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. */
/* 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_zs, sizeof(sigcder_zs), 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) != 1);
/* Leading zeros. */
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), pubkeyb, pubkeyblen) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), pubkeyb, pubkeyblen) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), pubkeyb, pubkeyblen) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), pubkeyb, pubkeyblen) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt1, sizeof(sigbderalt1), &pubkeyb) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt2, sizeof(sigbderalt2), &pubkeyb) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt3, sizeof(sigbderalt3), &pubkeyb) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbderalt4, sizeof(sigbderalt4), &pubkeyb) == 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;
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. */
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]--;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, pubkeyb, pubkeyblen) == -2);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, pubkeyb, pubkeyblen) == -2);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, 6, &pubkeyb) != 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder)-1, &pubkeyb) != 1);
for(i = 0; i < 8; i++) {
int c;
unsigned char orig = sigbder[i];
@ -1919,8 +1892,7 @@ void test_ecdsa_edge_cases(void) {
continue;
}
sigbder[i] = c;
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), pubkeyb, pubkeyblen) ==
(i==4 || i==7) ? 0 : -2 );
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigbder, sizeof(sigbder), &pubkeyb) != 1);
}
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, 0x01,
};
unsigned char pubkeyc[65];
int pubkeyclen = 65;
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyc, &pubkeyclen, 0, 0) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 1);
secp256k1_pubkey_t pubkeyc;
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, &pubkeyc, 0) == 1);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), &pubkeyc) == 1);
sigcder[4] = 0;
sigc64[31] = 0;
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0);
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, &pubkeyb, 0) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), &pubkeyc) == 0);
sigcder[4] = 1;
sigcder[7] = 0;
sigc64[31] = 1;
sigc64[63] = 0;
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, pubkeyb, &pubkeyblen, 1, 0) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), pubkeyc, pubkeyclen) == 0);
CHECK(secp256k1_ecdsa_recover_compact(ctx, msg32, sigc64, &pubkeyb, 0) == 0);
CHECK(secp256k1_ecdsa_verify(ctx, msg32, sigcder, sizeof(sigcder), &pubkeyc) == 0);
}
/*Signature where s would be zero.*/