From 2dc868f35b5790ca74c1dfc4880f802d3f8f52af Mon Sep 17 00:00:00 2001 From: Dmitry Petukhov Date: Sun, 21 Apr 2019 21:23:13 +0500 Subject: [PATCH] work in progress: add _allocate_initialized/destroy funcs --- include/secp256k1_surjectionproof.h | 46 +++++++++++++++++++++++++++++ src/modules/surjection/main_impl.h | 31 +++++++++++++++++++ src/modules/surjection/tests_impl.h | 41 +++++++++++++++++++++++++ 3 files changed, 118 insertions(+) diff --git a/include/secp256k1_surjectionproof.h b/include/secp256k1_surjectionproof.h index 38f67990..d9a38e40 100644 --- a/include/secp256k1_surjectionproof.h +++ b/include/secp256k1_surjectionproof.h @@ -134,6 +134,7 @@ SECP256K1_API size_t secp256k1_surjectionproof_serialized_size( ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2); /** Surjection proof initialization function; decides on inputs to use + * To be used to initialize stack-allocated secp256k1_surjectionproof struct * Returns 0: inputs could not be selected * n: inputs were selected after n iterations of random selection * @@ -166,6 +167,51 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_initial const unsigned char *random_seed32 ) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7); + +/** Surjection proof allocation and initialization function; decides on inputs to use + * Returns 0: inputs could not be selected, or malloc failure + * n: inputs were selected after n iterations of random selection + * + * In: ctx: pointer to a context object + * proof_out_p: a pointer to a pointer to `secp256k1_surjectionproof*`. + * the newly-allocated struct pointer will be saved here. + * fixed_input_tags: fixed input tags `A_i` for all inputs. (If the fixed tag is not known, + * e.g. in a coinjoin with others' inputs, an ephemeral tag can be given; + * this won't match the output tag but might be used in the anonymity set.) + * n_input_tags: the number of entries in the fixed_input_tags array + * n_input_tags_to_use: the number of inputs to select randomly to put in the anonymity set + * fixed_output_tag: fixed output tag + * max_n_iterations: the maximum number of iterations to do before giving up. Because the + * maximum number of inputs (SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS) is + * limited to 256 the probability of giving up is smaller than + * (255/256)^(n_input_tags_to_use*max_n_iterations). + * + * random_seed32: a random seed to be used for input selection + * Out: proof_out_p: The pointer to newly-allocated proof whose bitvector will be initialized. + * In case of failure, the pointer will be NULL. + * input_index: The index of the actual input that is secretly mapped to the output + */ +SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_surjectionproof_allocate_initialized( + const secp256k1_context* ctx, + secp256k1_surjectionproof** proof_out_p, + size_t *input_index, + const secp256k1_fixed_asset_tag* fixed_input_tags, + const size_t n_input_tags, + const size_t n_input_tags_to_use, + const secp256k1_fixed_asset_tag* fixed_output_tag, + const size_t n_max_iterations, + const unsigned char *random_seed32 +) SECP256K1_ARG_NONNULL(1) SECP256K1_ARG_NONNULL(2) SECP256K1_ARG_NONNULL(3) SECP256K1_ARG_NONNULL(4) SECP256K1_ARG_NONNULL(7); + +/** Surjection proof destroy function + * deallocates the struct that was allocated with secp256k1_surjectionproof_allocate_initialized + * + * In: proof: pointer to secp256k1_surjectionproof struct + */ +SECP256K1_API void secp256k1_surjectionproof_destroy( + secp256k1_surjectionproof* proof +) SECP256K1_ARG_NONNULL(1); + /** Surjection proof generation function * Returns 0: proof could not be created * 1: proof was successfully created diff --git a/src/modules/surjection/main_impl.h b/src/modules/surjection/main_impl.h index c67d4c0d..ce13e86b 100644 --- a/src/modules/surjection/main_impl.h +++ b/src/modules/surjection/main_impl.h @@ -151,6 +151,37 @@ static size_t secp256k1_surjectionproof_csprng_next(secp256k1_surjectionproof_cs } } +/* XXX secp256k1_surjectionproof_create is not a good name, because it can be confused with secp256k1_surjectionproof_generate */ +int secp256k1_surjectionproof_allocate_initialized(const secp256k1_context* ctx, secp256k1_surjectionproof** proof_out_p, size_t *input_index, const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) { + int ret = 0; + secp256k1_surjectionproof* proof; + + VERIFY_CHECK(ctx != NULL); + + ARG_CHECK(proof_out_p != NULL); + *proof_out_p = 0; + + proof = (secp256k1_surjectionproof*)checked_malloc(&ctx->error_callback, sizeof(secp256k1_surjectionproof)); + if (proof != NULL) { + ret = secp256k1_surjectionproof_initialize(ctx, proof, input_index, fixed_input_tags, n_input_tags, n_input_tags_to_use, fixed_output_tag, n_max_iterations, random_seed32); + if (ret) { + *proof_out_p = proof; + } + else { + free(proof); + } + } + return ret; +} + +/* XXX add checks to prevent destroy of stack-allocated struct ? */ +void secp256k1_surjectionproof_destroy(secp256k1_surjectionproof* proof) { + if (proof != NULL) { + VERIFY_CHECK(proof->n_inputs <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); + free(proof); + } +} + int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1_surjectionproof* proof, size_t *input_index, const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, const secp256k1_fixed_asset_tag* fixed_output_tag, const size_t n_max_iterations, const unsigned char *random_seed32) { secp256k1_surjectionproof_csprng csprng; size_t n_iterations = 0; diff --git a/src/modules/surjection/tests_impl.h b/src/modules/surjection/tests_impl.h index a0856e22..ee959f38 100644 --- a/src/modules/surjection/tests_impl.h +++ b/src/modules/surjection/tests_impl.h @@ -28,6 +28,7 @@ static void test_surjectionproof_api(void) { unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX]; size_t serialized_len; secp256k1_surjectionproof proof; + secp256k1_surjectionproof* proof_on_heap; size_t n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]); size_t input_index; int32_t ecount = 0; @@ -52,6 +53,46 @@ static void test_surjectionproof_api(void) { memcpy(&fixed_output_tag, &fixed_input_tags[0], sizeof(fixed_input_tags[0])); CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, output_blinding_key)); + /* check allocate_initialized */ + CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0); + CHECK(proof_on_heap == 0); + CHECK(ecount == 0); + CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); + CHECK(proof_on_heap != 0); + secp256k1_surjectionproof_destroy(proof_on_heap); + CHECK(ecount == 0); + CHECK(secp256k1_surjectionproof_allocate_initialized(none, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(proof_on_heap == 0); + CHECK(ecount == 2); + CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(proof_on_heap == 0); + CHECK(ecount == 3); + CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(proof_on_heap == 0); + CHECK(ecount == 4); + CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], 100, seed) != 0); + CHECK(proof_on_heap != 0); + secp256k1_surjectionproof_destroy(proof_on_heap); + CHECK(ecount == 4); + CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed) == 0); + CHECK(proof_on_heap == 0); + CHECK(ecount == 5); + CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed) == 0); + CHECK(proof_on_heap == 0); + CHECK(ecount == 6); + CHECK((secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 0, seed) & 1) == 0); + CHECK(proof_on_heap == 0); + CHECK(ecount == 6); + CHECK(secp256k1_surjectionproof_allocate_initialized(none, &proof_on_heap, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL) == 0); + CHECK(proof_on_heap == 0); + CHECK(ecount == 7); + + /* we are now going to test essentially the same functions, just without heap allocation. + * reset ecount. */ + ecount = 0; + /* check initialize */ CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, seed) == 0); CHECK(ecount == 0);