diff --git a/include/secp256k1.h b/include/secp256k1.h index 4652c6c878..bcc2be0379 100644 --- a/include/secp256k1.h +++ b/include/secp256k1.h @@ -59,6 +59,14 @@ secp256k1_context_t* secp256k1_context_create( int flags ) SECP256K1_WARN_UNUSED_RESULT; +/** Copies a secp256k1 context object. + * Returns: a newly created context object. + * In: ctx: an existing context to copy + */ +secp256k1_context_t* secp256k1_context_clone( + const secp256k1_context_t* ctx +) SECP256K1_WARN_UNUSED_RESULT; + /** Destroy a secp256k1 context object. * The context pointer may not be used afterwards. */ diff --git a/src/ecmult.h b/src/ecmult.h index a6efb7bfff..bab9e4ef52 100644 --- a/src/ecmult.h +++ b/src/ecmult.h @@ -20,6 +20,8 @@ typedef struct { static void secp256k1_ecmult_context_init(secp256k1_ecmult_context_t *ctx); static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx); +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, + const secp256k1_ecmult_context_t *src); static void secp256k1_ecmult_context_clear(secp256k1_ecmult_context_t *ctx); static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx); diff --git a/src/ecmult_gen.h b/src/ecmult_gen.h index b369089f9b..c65e5cd0e0 100644 --- a/src/ecmult_gen.h +++ b/src/ecmult_gen.h @@ -28,6 +28,8 @@ typedef struct { static void secp256k1_ecmult_gen_context_init(secp256k1_ecmult_gen_context_t* ctx); static void secp256k1_ecmult_gen_context_build(secp256k1_ecmult_gen_context_t* ctx); +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, + const secp256k1_ecmult_gen_context_t* src); static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t* ctx); static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_context_t* ctx); diff --git a/src/ecmult_gen_impl.h b/src/ecmult_gen_impl.h index 3d43b3dc6f..9c8f7209e7 100644 --- a/src/ecmult_gen_impl.h +++ b/src/ecmult_gen_impl.h @@ -80,6 +80,16 @@ static int secp256k1_ecmult_gen_context_is_built(const secp256k1_ecmult_gen_cont return ctx->prec != NULL; } +static void secp256k1_ecmult_gen_context_clone(secp256k1_ecmult_gen_context_t *dst, + const secp256k1_ecmult_gen_context_t *src) { + if (src->prec == NULL) { + dst->prec = NULL; + } else { + dst->prec = (secp256k1_ge_storage_t (*)[64][16])checked_malloc(sizeof(*dst->prec)); + memcpy(dst->prec, src->prec, sizeof(*dst->prec)); + } +} + static void secp256k1_ecmult_gen_context_clear(secp256k1_ecmult_gen_context_t *ctx) { free(ctx->prec); ctx->prec = NULL; diff --git a/src/ecmult_impl.h b/src/ecmult_impl.h index ef62d35145..1b2856f83d 100644 --- a/src/ecmult_impl.h +++ b/src/ecmult_impl.h @@ -131,6 +131,26 @@ static void secp256k1_ecmult_context_build(secp256k1_ecmult_context_t *ctx) { #endif } +static void secp256k1_ecmult_context_clone(secp256k1_ecmult_context_t *dst, + const secp256k1_ecmult_context_t *src) { + if (src->pre_g == NULL) { + dst->pre_g = NULL; + } else { + size_t size = sizeof((*dst->pre_g)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); + dst->pre_g = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + memcpy(dst->pre_g, src->pre_g, size); + } +#ifdef USE_ENDOMORPHISM + if (src->pre_g_128 == NULL) { + dst->pre_g_128 = NULL; + } else { + size_t size = sizeof((*dst->pre_g_128)[0]) * ECMULT_TABLE_SIZE(WINDOW_G); + dst->pre_g_128 = (secp256k1_ge_storage_t (*)[])checked_malloc(size); + memcpy(dst->pre_g_128, src->pre_g_128, size); + } +#endif +} + static int secp256k1_ecmult_context_is_built(const secp256k1_ecmult_context_t *ctx) { return ctx->pre_g != NULL; } diff --git a/src/secp256k1.c b/src/secp256k1.c index 745d6bd1bc..90f9d4e31a 100644 --- a/src/secp256k1.c +++ b/src/secp256k1.c @@ -40,6 +40,13 @@ secp256k1_context_t* secp256k1_context_create(int flags) { return ret; } +secp256k1_context_t* secp256k1_context_clone(const secp256k1_context_t* ctx) { + secp256k1_context_t* ret = (secp256k1_context_t*)checked_malloc(sizeof(secp256k1_context_t)); + secp256k1_ecmult_context_clone(&ret->ecmult_ctx, &ctx->ecmult_ctx); + secp256k1_ecmult_gen_context_clone(&ret->ecmult_gen_ctx, &ctx->ecmult_gen_ctx); + return ret; +} + void secp256k1_context_destroy(secp256k1_context_t* ctx) { secp256k1_ecmult_context_clear(&ctx->ecmult_ctx); secp256k1_ecmult_gen_context_clear(&ctx->ecmult_gen_ctx); diff --git a/src/tests.c b/src/tests.c index 45795f9619..df26b9a093 100644 --- a/src/tests.c +++ b/src/tests.c @@ -103,6 +103,47 @@ void random_scalar_order(secp256k1_scalar_t *num) { } while(1); } +void run_context_tests(void) { + secp256k1_context_t *none = secp256k1_context_create(0); + secp256k1_context_t *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context_t *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context_t *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + + secp256k1_gej_t pubj; + secp256k1_ge_t pub; + secp256k1_scalar_t msg, key, nonce; + secp256k1_ecdsa_sig_t sig; + + /*** clone and destroy all of them to make sure cloning was complete ***/ + { + secp256k1_context_t *ctx_tmp; + + ctx_tmp = none; none = secp256k1_context_clone(none); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = sign; sign = secp256k1_context_clone(sign); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = vrfy; vrfy = secp256k1_context_clone(vrfy); secp256k1_context_destroy(ctx_tmp); + ctx_tmp = both; both = secp256k1_context_clone(both); secp256k1_context_destroy(ctx_tmp); + } + + /*** attempt to use them ***/ + random_scalar_order_test(&msg); + random_scalar_order_test(&key); + secp256k1_ecmult_gen(&both->ecmult_gen_ctx, &pubj, &key); + secp256k1_ge_set_gej(&pub, &pubj); + + /* obtain a working nonce */ + do { + random_scalar_order_test(&nonce); + } while(!secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + + /* try signing */ + CHECK(secp256k1_ecdsa_sig_sign(&sign->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + CHECK(secp256k1_ecdsa_sig_sign(&both->ecmult_gen_ctx, &sig, &key, &msg, &nonce, NULL)); + + /* try verifying */ + CHECK(secp256k1_ecdsa_sig_verify(&vrfy->ecmult_ctx, &sig, &pub, &msg)); + CHECK(secp256k1_ecdsa_sig_verify(&both->ecmult_ctx, &sig, &pub, &msg)); +} + /***** HASH TESTS *****/ void run_sha256_tests(void) { @@ -1863,6 +1904,7 @@ int main(int argc, char **argv) { printf("random seed = %02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x%02x\n", seed16[0], seed16[1], seed16[2], seed16[3], seed16[4], seed16[5], seed16[6], seed16[7], seed16[8], seed16[9], seed16[10], seed16[11], seed16[12], seed16[13], seed16[14], seed16[15]); /* initialize */ + run_context_tests(); ctx = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); run_sha256_tests();