Merge pull request #339

9234391 Overhaul flags handling (Pieter Wuille)
1a36898 Make flags more explicit, add runtime checks. (Rusty Russell)
This commit is contained in:
Pieter Wuille
2015-10-25 20:09:48 +01:00
6 changed files with 44 additions and 28 deletions

View File

@ -34,22 +34,22 @@
* privkeylen: Pointer to an int where the length of the private key in * privkeylen: Pointer to an int where the length of the private key in
* privkey will be stored. * privkey will be stored.
* In: seckey: pointer to a 32-byte secret key to export. * In: seckey: pointer to a 32-byte secret key to export.
* flags: SECP256K1_EC_COMPRESSED if the key should be exported in * compressed: 1 if the key should be exported in
* compressed format. * compressed format, 0 otherwise
* *
* This function is purely meant for compatibility with applications that * This function is purely meant for compatibility with applications that
* require BER encoded keys. When working with secp256k1-specific code, the * require BER encoded keys. When working with secp256k1-specific code, the
* simple 32-byte private keys are sufficient. * simple 32-byte private keys are sufficient.
* *
* Note that this function does not guarantee correct DER output. It is * Note that this function does not guarantee correct DER output. It is
* guaranteed to be parsable by secp256k1_ec_privkey_import. * guaranteed to be parsable by secp256k1_ec_privkey_import_der
*/ */
static SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export_der( static SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_privkey_export_der(
const secp256k1_context* ctx, const secp256k1_context* ctx,
unsigned char *privkey, unsigned char *privkey,
size_t *privkeylen, size_t *privkeylen,
const unsigned char *seckey, const unsigned char *seckey,
unsigned int flags int compressed
) 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);
/** Import a private key in DER format. /** Import a private key in DER format.
@ -116,13 +116,13 @@ static int secp256k1_eckey_privkey_parse(secp256k1_scalar *key, const unsigned c
return !overflow; return !overflow;
} }
static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context *ctx, unsigned char *privkey, size_t *privkeylen, const secp256k1_scalar *key, unsigned int flags) { static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context *ctx, unsigned char *privkey, size_t *privkeylen, const secp256k1_scalar *key, int compressed) {
secp256k1_gej rp; secp256k1_gej rp;
secp256k1_ge r; secp256k1_ge r;
size_t pubkeylen = 0; size_t pubkeylen = 0;
secp256k1_ecmult_gen(ctx, &rp, key); secp256k1_ecmult_gen(ctx, &rp, key);
secp256k1_ge_set_gej(&r, &rp); secp256k1_ge_set_gej(&r, &rp);
if (flags & SECP256K1_EC_COMPRESSED) { if (compressed) {
static const unsigned char begin[] = { static const unsigned char begin[] = {
0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20 0x30,0x81,0xD3,0x02,0x01,0x01,0x04,0x20
}; };
@ -176,7 +176,7 @@ static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context
return 1; return 1;
} }
static int secp256k1_ec_privkey_export_der(const secp256k1_context* ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *seckey, unsigned int flags) { static int secp256k1_ec_privkey_export_der(const secp256k1_context* ctx, unsigned char *privkey, size_t *privkeylen, const unsigned char *seckey, int compressed) {
secp256k1_scalar key; secp256k1_scalar key;
int ret = 0; int ret = 0;
VERIFY_CHECK(ctx != NULL); VERIFY_CHECK(ctx != NULL);
@ -186,7 +186,7 @@ static int secp256k1_ec_privkey_export_der(const secp256k1_context* ctx, unsigne
ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx));
secp256k1_scalar_set_b32(&key, seckey, NULL); secp256k1_scalar_set_b32(&key, seckey, NULL);
ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, privkeylen, &key, flags); ret = secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, privkeylen, &key, compressed);
secp256k1_scalar_clear(&key); secp256k1_scalar_clear(&key);
return ret; return ret;
} }

View File

@ -147,12 +147,23 @@ typedef int (*secp256k1_nonce_function)(
# define SECP256K1_ARG_NONNULL(_x) # define SECP256K1_ARG_NONNULL(_x)
# endif # endif
/** All flags' lower 8 bits indicate what they're for. Do not use directly. */
#define SECP256K1_FLAGS_TYPE_MASK ((1 << 8) - 1)
#define SECP256K1_FLAGS_TYPE_CONTEXT (1 << 0)
#define SECP256K1_FLAGS_TYPE_COMPRESSION (1 << 1)
/** The higher bits contain the actual data. Do not use directly. */
#define SECP256K1_FLAGS_BIT_CONTEXT_VERIFY (1 << 8)
#define SECP256K1_FLAGS_BIT_CONTEXT_SIGN (1 << 9)
#define SECP256K1_FLAGS_BIT_COMPRESSION (1 << 8)
/** Flags to pass to secp256k1_context_create. */ /** Flags to pass to secp256k1_context_create. */
# define SECP256K1_CONTEXT_VERIFY (1 << 0) #define SECP256K1_CONTEXT_VERIFY (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_VERIFY)
# define SECP256K1_CONTEXT_SIGN (1 << 1) #define SECP256K1_CONTEXT_SIGN (SECP256K1_FLAGS_TYPE_CONTEXT | SECP256K1_FLAGS_BIT_CONTEXT_SIGN)
#define SECP256K1_CONTEXT_NONE (SECP256K1_FLAGS_TYPE_CONTEXT)
/** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */ /** Flag to pass to secp256k1_ec_pubkey_serialize and secp256k1_ec_privkey_export. */
# define SECP256K1_EC_COMPRESSED (1 << 0) #define SECP256K1_EC_COMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION | SECP256K1_FLAGS_BIT_COMPRESSION)
#define SECP256K1_EC_UNCOMPRESSED (SECP256K1_FLAGS_TYPE_COMPRESSION)
/** Create a secp256k1 context object. /** Create a secp256k1 context object.
* *
@ -261,7 +272,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_ec_pubkey_parse(
* In: pubkey: a pointer to a secp256k1_pubkey containing an initialized * In: pubkey: a pointer to a secp256k1_pubkey containing an initialized
* public key. * public key.
* flags: SECP256K1_EC_COMPRESSED if serialization should be in * flags: SECP256K1_EC_COMPRESSED if serialization should be in
* compressed format. * compressed format, otherwise SECP256K1_EC_UNCOMPRESSED.
*/ */
SECP256K1_API int secp256k1_ec_pubkey_serialize( SECP256K1_API int secp256k1_ec_pubkey_serialize(
const secp256k1_context* ctx, const secp256k1_context* ctx,

View File

@ -15,10 +15,7 @@
#include "ecmult_gen.h" #include "ecmult_gen.h"
static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size); static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char *pub, size_t size);
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, unsigned int flags); static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed);
static int secp256k1_eckey_privkey_parse(secp256k1_scalar *key, const unsigned char *privkey, size_t privkeylen);
static int secp256k1_eckey_privkey_serialize(const secp256k1_ecmult_gen_context *ctx, unsigned char *privkey, size_t *privkeylen, const secp256k1_scalar *key, unsigned int flags);
static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak); static int secp256k1_eckey_privkey_tweak_add(secp256k1_scalar *key, const secp256k1_scalar *tweak);
static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak); static int secp256k1_eckey_pubkey_tweak_add(const secp256k1_ecmult_context *ctx, secp256k1_ge *key, const secp256k1_scalar *tweak);

View File

@ -33,14 +33,14 @@ static int secp256k1_eckey_pubkey_parse(secp256k1_ge *elem, const unsigned char
} }
} }
static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, unsigned int flags) { static int secp256k1_eckey_pubkey_serialize(secp256k1_ge *elem, unsigned char *pub, size_t *size, int compressed) {
if (secp256k1_ge_is_infinity(elem)) { if (secp256k1_ge_is_infinity(elem)) {
return 0; return 0;
} }
secp256k1_fe_normalize_var(&elem->x); secp256k1_fe_normalize_var(&elem->x);
secp256k1_fe_normalize_var(&elem->y); secp256k1_fe_normalize_var(&elem->y);
secp256k1_fe_get_b32(&pub[1], &elem->x); secp256k1_fe_get_b32(&pub[1], &elem->x);
if (flags & SECP256K1_EC_COMPRESSED) { if (compressed) {
*size = 33; *size = 33;
pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00); pub[0] = 0x02 | (secp256k1_fe_is_odd(&elem->y) ? 0x01 : 0x00);
} else { } else {

View File

@ -62,13 +62,20 @@ secp256k1_context* secp256k1_context_create(unsigned int flags) {
ret->illegal_callback = default_illegal_callback; ret->illegal_callback = default_illegal_callback;
ret->error_callback = default_error_callback; ret->error_callback = default_error_callback;
if (EXPECT((flags & SECP256K1_FLAGS_TYPE_MASK) != SECP256K1_FLAGS_TYPE_CONTEXT, 0)) {
secp256k1_callback_call(&ret->illegal_callback,
"Invalid flags");
free(ret);
return NULL;
}
secp256k1_ecmult_context_init(&ret->ecmult_ctx); secp256k1_ecmult_context_init(&ret->ecmult_ctx);
secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx); secp256k1_ecmult_gen_context_init(&ret->ecmult_gen_ctx);
if (flags & SECP256K1_CONTEXT_SIGN) { if (flags & SECP256K1_FLAGS_BIT_CONTEXT_SIGN) {
secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback); secp256k1_ecmult_gen_context_build(&ret->ecmult_gen_ctx, &ret->error_callback);
} }
if (flags & SECP256K1_CONTEXT_VERIFY) { if (flags & SECP256K1_FLAGS_BIT_CONTEXT_VERIFY) {
secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback); secp256k1_ecmult_context_build(&ret->ecmult_ctx, &ret->error_callback);
} }
@ -166,8 +173,9 @@ int secp256k1_ec_pubkey_serialize(const secp256k1_context* ctx, unsigned char *o
ARG_CHECK(output != NULL); ARG_CHECK(output != NULL);
ARG_CHECK(outputlen != NULL); ARG_CHECK(outputlen != NULL);
ARG_CHECK(pubkey != NULL); ARG_CHECK(pubkey != NULL);
ARG_CHECK((flags & SECP256K1_FLAGS_TYPE_MASK) == SECP256K1_FLAGS_TYPE_COMPRESSION);
return (secp256k1_pubkey_load(ctx, &Q, pubkey) && return (secp256k1_pubkey_load(ctx, &Q, pubkey) &&
secp256k1_eckey_pubkey_serialize(&Q, output, outputlen, flags)); secp256k1_eckey_pubkey_serialize(&Q, output, outputlen, flags & SECP256K1_FLAGS_BIT_COMPRESSION));
} }
static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) { static void secp256k1_ecdsa_signature_load(const secp256k1_context* ctx, secp256k1_scalar* r, secp256k1_scalar* s, const secp256k1_ecdsa_signature* sig) {

View File

@ -139,7 +139,7 @@ void run_context_tests(void) {
unsigned char ctmp[32]; unsigned char ctmp[32];
int32_t ecount; int32_t ecount;
int32_t ecount2; int32_t ecount2;
secp256k1_context *none = secp256k1_context_create(0); secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE);
secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN);
secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY);
secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY);
@ -1964,7 +1964,7 @@ void ec_pubkey_parse_pointtest(const unsigned char *input, int xvalid, int yvali
VG_CHECK(&pubkey, sizeof(pubkey)); VG_CHECK(&pubkey, sizeof(pubkey));
outl = 65; outl = 65;
VG_UNDEF(pubkeyo, 65); VG_UNDEF(pubkeyo, 65);
CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, 0) == 1); CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyo, &outl, &pubkey, SECP256K1_EC_UNCOMPRESSED) == 1);
VG_CHECK(pubkeyo, outl); VG_CHECK(pubkeyo, outl);
CHECK(outl == 65); CHECK(outl == 65);
CHECK(pubkeyo[0] == 4); CHECK(pubkeyo[0] == 4);
@ -2575,12 +2575,12 @@ void test_ecdsa_end_to_end(void) {
CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1); CHECK(secp256k1_ec_pubkey_create(ctx, &pubkey, privkey) == 1);
/* Verify exporting and importing public key. */ /* Verify exporting and importing public key. */
CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1)) == 1); CHECK(secp256k1_ec_pubkey_serialize(ctx, pubkeyc, &pubkeyclen, &pubkey, secp256k1_rand_bits(1) == 1 ? SECP256K1_EC_COMPRESSED : SECP256K1_EC_UNCOMPRESSED));
memset(&pubkey, 0, sizeof(pubkey)); memset(&pubkey, 0, sizeof(pubkey));
CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1); CHECK(secp256k1_ec_pubkey_parse(ctx, &pubkey, pubkeyc, pubkeyclen) == 1);
/* Verify private key import and export. */ /* Verify private key import and export. */
CHECK(secp256k1_ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1) ? SECP256K1_EC_COMPRESSED : 0); CHECK(secp256k1_ec_privkey_export_der(ctx, seckey, &seckeylen, privkey, secp256k1_rand_bits(1) == 1));
CHECK(secp256k1_ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1); CHECK(secp256k1_ec_privkey_import_der(ctx, privkey2, seckey, seckeylen) == 1);
CHECK(memcmp(privkey, privkey2, 32) == 0); CHECK(memcmp(privkey, privkey2, 32) == 0);
@ -2698,7 +2698,7 @@ void test_random_pubkeys(void) {
size_t size = len; size_t size = len;
firstb = in[0]; firstb = in[0];
/* If the pubkey can be parsed, it should round-trip... */ /* If the pubkey can be parsed, it should round-trip... */
CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, (len == 33) ? SECP256K1_EC_COMPRESSED : 0)); CHECK(secp256k1_eckey_pubkey_serialize(&elem, out, &size, len == 33));
CHECK(size == len); CHECK(size == len);
CHECK(memcmp(&in[1], &out[1], len-1) == 0); CHECK(memcmp(&in[1], &out[1], len-1) == 0);
/* ... except for the type of hybrid inputs. */ /* ... except for the type of hybrid inputs. */
@ -3401,7 +3401,7 @@ void test_ecdsa_edge_cases(void) {
size_t outlen = 300; size_t outlen = 300;
CHECK(!secp256k1_ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0)); CHECK(!secp256k1_ec_privkey_export_der(ctx, privkey, &outlen, seckey, 0));
outlen = 300; outlen = 300;
CHECK(!secp256k1_ec_privkey_export_der(ctx, privkey, &outlen, seckey, SECP256K1_EC_COMPRESSED)); CHECK(!secp256k1_ec_privkey_export_der(ctx, privkey, &outlen, seckey, 1));
} }
} }
@ -3416,7 +3416,7 @@ EC_KEY *get_openssl_key(const secp256k1_scalar *key) {
const unsigned char* pbegin = privkey; const unsigned char* pbegin = privkey;
int compr = secp256k1_rand_bits(1); int compr = secp256k1_rand_bits(1);
EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1); EC_KEY *ec_key = EC_KEY_new_by_curve_name(NID_secp256k1);
CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, &privkeylen, key, compr ? SECP256K1_EC_COMPRESSED : 0)); CHECK(secp256k1_eckey_privkey_serialize(&ctx->ecmult_gen_ctx, privkey, &privkeylen, key, compr));
CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen)); CHECK(d2i_ECPrivateKey(&ec_key, &pbegin, privkeylen));
CHECK(EC_KEY_check_key(ec_key)); CHECK(EC_KEY_check_key(ec_key));
return ec_key; return ec_key;