From d702d210b82abfe6b8fba2f04bc534facebb7dfa Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Sat, 22 Apr 2017 18:31:28 +0000 Subject: [PATCH 1/5] rangeproof: fix memory leak in unit tests --- src/modules/rangeproof/tests_impl.h | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/modules/rangeproof/tests_impl.h b/src/modules/rangeproof/tests_impl.h index 29b0a659..ea3c12e9 100644 --- a/src/modules/rangeproof/tests_impl.h +++ b/src/modules/rangeproof/tests_impl.h @@ -353,6 +353,12 @@ void test_multiple_generators(void) { /* Verify */ CHECK(secp256k1_pedersen_verify_tally(ctx, &commit_ptr[0], n_inputs, &commit_ptr[n_inputs], n_outputs)); + + /* Cleanup */ + for (i = 0; i < n_generators; i++) { + free(generator_blind[i]); + free(pedersen_blind[i]); + } } void run_rangeproof_tests(void) { From 8454a98521eee9b8cb42a1d89e238ed152cbce9f Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 2 May 2017 13:50:58 +0000 Subject: [PATCH 2/5] surjectionproof: tests_impl.h s/assert/CHECK/g --- src/modules/surjection/tests_impl.h | 152 ++++++++++++++-------------- 1 file changed, 75 insertions(+), 77 deletions(-) diff --git a/src/modules/surjection/tests_impl.h b/src/modules/surjection/tests_impl.h index f02046b0..73f6d745 100644 --- a/src/modules/surjection/tests_impl.h +++ b/src/modules/surjection/tests_impl.h @@ -7,8 +7,6 @@ #ifndef SECP256K1_MODULE_SURJECTIONPROOF_TESTS #define SECP256K1_MODULE_SURJECTIONPROOF_TESTS -#include - #include "testrand.h" #include "group.h" #include "include/secp256k1_generator.h" @@ -25,7 +23,7 @@ static void run_input_selection_tests(size_t n_inputs) { secp256k1_fixed_asset_tag fixed_input_tags[1000]; const size_t max_n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]) - 1; - assert(n_inputs < max_n_inputs); + CHECK(n_inputs < max_n_inputs); secp256k1_rand256(seed); for (i = 0; i < n_inputs + 1; i++) { @@ -34,50 +32,50 @@ static void run_input_selection_tests(size_t n_inputs) { /* cannot match output when told to use zero keys */ result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], try_count, seed); - assert(result == 0); - assert(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == 0); - assert(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); - assert(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 34 + (n_inputs + 7) / 8); + CHECK(result == 0); + CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == 0); + CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 34 + (n_inputs + 7) / 8); if (n_inputs > 0) { /* succeed in 100*n_inputs tries (probability of failure e^-100) */ result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 1, &fixed_input_tags[0], try_count, seed); - assert(result > 0); - assert(result < n_inputs * 10); - assert(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == 1); - assert(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); - assert(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 66 + (n_inputs + 7) / 8); - assert(input_index == 0); + CHECK(result > 0); + CHECK(result < n_inputs * 10); + CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == 1); + CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 66 + (n_inputs + 7) / 8); + CHECK(input_index == 0); } if (n_inputs >= 3) { /* succeed in 10*n_inputs tries (probability of failure e^-10) */ result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[1], try_count, seed); - assert(result > 0); - assert(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == 3); - assert(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); - assert(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 130 + (n_inputs + 7) / 8); - assert(input_index == 1); + CHECK(result > 0); + CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == 3); + CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 130 + (n_inputs + 7) / 8); + CHECK(input_index == 1); /* fail, key not found */ result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[n_inputs], try_count, seed); - assert(result == 0); + CHECK(result == 0); /* succeed on first try when told to use all keys */ result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], try_count, seed); - assert(result == 1); - assert(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs); - assert(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); - assert(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs + 1) + (n_inputs + 7) / 8); - assert(input_index == 0); + CHECK(result == 1); + CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs + 1) + (n_inputs + 7) / 8); + CHECK(input_index == 0); /* succeed in less than 64 tries when told to use half keys. (probability of failure 2^-64) */ result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs / 2, &fixed_input_tags[0], 64, seed); - assert(result > 0); - assert(result < 64); - assert(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs / 2); - assert(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); - assert(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs / 2 + 1) + (n_inputs + 7) / 8); - assert(input_index == 0); + CHECK(result > 0); + CHECK(result < 64); + CHECK(secp256k1_surjectionproof_n_used_inputs(ctx, &proof) == n_inputs / 2); + CHECK(secp256k1_surjectionproof_n_total_inputs(ctx, &proof) == n_inputs); + CHECK(secp256k1_surjectionproof_serialized_size(ctx, &proof) == 2 + 32 * (n_inputs / 2 + 1) + (n_inputs + 7) / 8); + CHECK(input_index == 0); } } @@ -96,7 +94,7 @@ static void run_input_selection_distribution_tests_helper(const secp256k1_fixed_ for(j = 0; j < 10000; j++) { secp256k1_rand256(seed); result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_input_tags, n_input_tags_to_use, &fixed_input_tags[0], 64, seed); - assert(result > 0); + CHECK(result > 0); for (i = 0; i < n_input_tags; i++) { if (proof.used_inputs[i / 8] & (1 << (i % 8))) { @@ -123,10 +121,10 @@ static void run_input_selection_distribution_tests(void) { /* If there is one input tag to use, initialize must choose the one equal to fixed_output_tag. */ n_input_tags_to_use = 1; run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - assert(used_inputs[0] == 10000); - assert(used_inputs[1] == 0); - assert(used_inputs[2] == 0); - assert(used_inputs[3] == 0); + CHECK(used_inputs[0] == 10000); + CHECK(used_inputs[1] == 0); + CHECK(used_inputs[2] == 0); + CHECK(used_inputs[3] == 0); n_input_tags_to_use = 2; /* The input equal to the fixed_output_tag must be included in all used_inputs sets. @@ -134,18 +132,18 @@ static void run_input_selection_distribution_tests(void) { * in the used_inputs set is P(used_input|not fixed_output_tag) = 1/3. */ run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - assert(used_inputs[0] == 10000); - assert(used_inputs[1] > 2725 && used_inputs[1] < 3961); - assert(used_inputs[2] > 2725 && used_inputs[2] < 3961); - assert(used_inputs[3] > 2725 && used_inputs[3] < 3961); + CHECK(used_inputs[0] == 10000); + CHECK(used_inputs[1] > 2725 && used_inputs[1] < 3961); + CHECK(used_inputs[2] > 2725 && used_inputs[2] < 3961); + CHECK(used_inputs[3] > 2725 && used_inputs[3] < 3961); n_input_tags_to_use = 3; /* P(used_input|not fixed_output_tag) = 2/3 */ run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - assert(used_inputs[0] == 10000); - assert(used_inputs[1] > 6039 && used_inputs[1] < 7275); - assert(used_inputs[2] > 6039 && used_inputs[2] < 7275); - assert(used_inputs[3] > 6039 && used_inputs[3] < 7275); + CHECK(used_inputs[0] == 10000); + CHECK(used_inputs[1] > 6039 && used_inputs[1] < 7275); + CHECK(used_inputs[2] > 6039 && used_inputs[2] < 7275); + CHECK(used_inputs[3] > 6039 && used_inputs[3] < 7275); n_input_tags_to_use = 1; @@ -154,10 +152,10 @@ static void run_input_selection_distribution_tests(void) { */ memcpy(fixed_input_tags[0].data, fixed_input_tags[1].data, 32); run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - assert(used_inputs[0] > 4345 && used_inputs[0] < 5655); - assert(used_inputs[1] > 4345 && used_inputs[1] < 5655); - assert(used_inputs[2] == 0); - assert(used_inputs[3] == 0); + CHECK(used_inputs[0] > 4345 && used_inputs[0] < 5655); + CHECK(used_inputs[1] > 4345 && used_inputs[1] < 5655); + CHECK(used_inputs[2] == 0); + CHECK(used_inputs[3] == 0); n_input_tags_to_use = 2; /* When choosing 2 inputs in initialization there are 5 possible combinations of @@ -165,20 +163,20 @@ static void run_input_selection_distribution_tests(void) { * P(used_input|fixed_output_tag) = 3/5 and P(used_input|not fixed_output_tag) = 2/5. */ run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - assert(used_inputs[0] > 5352 && used_inputs[0] < 6637); - assert(used_inputs[1] > 5352 && used_inputs[1] < 6637); - assert(used_inputs[2] > 3363 && used_inputs[2] < 4648); - assert(used_inputs[3] > 3363 && used_inputs[3] < 4648); + CHECK(used_inputs[0] > 5352 && used_inputs[0] < 6637); + CHECK(used_inputs[1] > 5352 && used_inputs[1] < 6637); + CHECK(used_inputs[2] > 3363 && used_inputs[2] < 4648); + CHECK(used_inputs[3] > 3363 && used_inputs[3] < 4648); n_input_tags_to_use = 3; /* There are 4 combinations, each with all inputs except one. Therefore we have * P(used_input|fixed_output_tag) = 3/4 and P(used_input|not fixed_output_tag) = 3/4. */ run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); - assert(used_inputs[0] > 6918 && used_inputs[0] < 8053); - assert(used_inputs[1] > 6918 && used_inputs[1] < 8053); - assert(used_inputs[2] > 6918 && used_inputs[2] < 8053); - assert(used_inputs[3] > 6918 && used_inputs[3] < 8053); + CHECK(used_inputs[0] > 6918 && used_inputs[0] < 8053); + CHECK(used_inputs[1] > 6918 && used_inputs[1] < 8053); + CHECK(used_inputs[2] > 6918 && used_inputs[2] < 8053); + CHECK(used_inputs[3] > 6918 && used_inputs[3] < 8053); } static void run_gen_verify(size_t n_inputs, size_t n_used) { @@ -197,8 +195,8 @@ static void run_gen_verify(size_t n_inputs, size_t n_used) { int result; /* setup */ - assert(n_used <= n_inputs); - assert(n_inputs < max_n_inputs); + CHECK(n_used <= n_inputs); + CHECK(n_inputs < max_n_inputs); secp256k1_rand256(seed); key_index = (((size_t) seed[0] << 8) + seed[1]) % n_inputs; @@ -212,38 +210,38 @@ static void run_gen_verify(size_t n_inputs, size_t n_used) { } else { memcpy(&fixed_input_tags[i], &fixed_input_tags[key_index], sizeof(fixed_input_tags[i])); } - assert(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i])); + CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i])); } /* test */ result = secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, fixed_input_tags, n_inputs, n_used, &fixed_input_tags[key_index], try_count, seed); if (n_used == 0) { - assert(result == 0); + CHECK(result == 0); return; } - assert(result > 0); - assert(input_index == key_index); + CHECK(result > 0); + CHECK(input_index == key_index); result = secp256k1_surjectionproof_generate(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs], input_index, input_blinding_key[input_index], input_blinding_key[n_inputs]); - assert(result == 1); + CHECK(result == 1); - assert(secp256k1_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof)); - assert(serialized_len == secp256k1_surjectionproof_serialized_size(ctx, &proof)); - assert(serialized_len == SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used)); - assert(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len)); + CHECK(secp256k1_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof)); + CHECK(serialized_len == secp256k1_surjectionproof_serialized_size(ctx, &proof)); + CHECK(serialized_len == SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES(n_inputs, n_used)); + CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof, serialized_len)); result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs]); - assert(result == 1); + CHECK(result == 1); /* various fail cases */ if (n_inputs > 1) { result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]); - assert(result == 0); + CHECK(result == 0); /* number of entries in ephemeral_input_tags array is less than proof.n_inputs */ n_inputs -= 1; result = secp256k1_surjectionproof_generate(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs], input_index, input_blinding_key[input_index], input_blinding_key[n_inputs]); - assert(result == 0); + CHECK(result == 0); result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_inputs, &ephemeral_input_tags[n_inputs - 1]); - assert(result == 0); + CHECK(result == 0); n_inputs += 1; } @@ -278,8 +276,8 @@ static void run_no_used_inputs_verify(void) { /* blind fixed output tags with random blinding key */ secp256k1_rand256(blinding_key); - assert(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[0], fixed_input_tag.data, blinding_key)); - assert(secp256k1_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, blinding_key)); + CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[0], fixed_input_tag.data, blinding_key)); + CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_output_tag, fixed_output_tag.data, blinding_key)); /* create "borromean signature" which is just a hash of metadata (pubkeys, etc) in this case */ secp256k1_generator_load(&output, &ephemeral_output_tag); @@ -290,7 +288,7 @@ static void run_no_used_inputs_verify(void) { secp256k1_sha256_finalize(&sha256_e0, proof.data); result = secp256k1_surjectionproof_verify(ctx, &proof, ephemeral_input_tags, n_ephemeral_input_tags, &ephemeral_output_tag); - assert(result == 0); + CHECK(result == 0); } void run_bad_serialize(void) { @@ -301,7 +299,7 @@ void run_bad_serialize(void) { proof.n_inputs = 0; serialized_len = 2 + 31; /* e0 is one byte too short */ - assert(secp256k1_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof) == 0); + CHECK(secp256k1_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof) == 0); } void run_bad_parse(void) { @@ -311,11 +309,11 @@ void run_bad_parse(void) { unsigned char serialized_proof2[33] = { 0 }; /* Missing total input count */ - assert(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof0, sizeof(serialized_proof0)) == 0); + CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof0, sizeof(serialized_proof0)) == 0); /* Missing bitmap */ - assert(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof1, sizeof(serialized_proof1)) == 0); + CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof1, sizeof(serialized_proof1)) == 0); /* Missing e0 value */ - assert(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof2, sizeof(serialized_proof2)) == 0); + CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof2, sizeof(serialized_proof2)) == 0); } void run_surjection_tests(void) { From 5eae1b97932d5e5ef479ec5fa1aa5e8556bc583c Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Tue, 2 May 2017 16:54:14 +0000 Subject: [PATCH 3/5] surjectionproof: add API unit tests --- src/modules/surjection/main_impl.h | 4 + src/modules/surjection/tests_impl.h | 153 ++++++++++++++++++++++++++++ 2 files changed, 157 insertions(+) diff --git a/src/modules/surjection/main_impl.h b/src/modules/surjection/main_impl.h index d7fb3f53..fc0745aa 100644 --- a/src/modules/surjection/main_impl.h +++ b/src/modules/surjection/main_impl.h @@ -163,6 +163,7 @@ int secp256k1_surjectionproof_initialize(const secp256k1_context* ctx, secp256k1 ARG_CHECK(random_seed32 != NULL); ARG_CHECK(n_input_tags <= SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); ARG_CHECK(n_input_tags_to_use <= n_input_tags); + (void) ctx; secp256k1_surjectionproof_csprng_init(&csprng, random_seed32); memset(proof->data, 0, sizeof(proof->data)); @@ -225,6 +226,8 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s unsigned char msg32[32]; VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); + ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); ARG_CHECK(proof != NULL); ARG_CHECK(ephemeral_input_tags != NULL); ARG_CHECK(ephemeral_output_tag != NULL); @@ -298,6 +301,7 @@ int secp256k1_surjectionproof_verify(const secp256k1_context* ctx, const secp256 unsigned char msg32[32]; VERIFY_CHECK(ctx != NULL); + ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); ARG_CHECK(proof != NULL); ARG_CHECK(ephemeral_input_tags != NULL); ARG_CHECK(ephemeral_output_tag != NULL); diff --git a/src/modules/surjection/tests_impl.h b/src/modules/surjection/tests_impl.h index 73f6d745..840a9acb 100644 --- a/src/modules/surjection/tests_impl.h +++ b/src/modules/surjection/tests_impl.h @@ -13,6 +13,154 @@ #include "include/secp256k1_rangeproof.h" #include "include/secp256k1_surjectionproof.h" +static void run_surjectionproof_api_tests(void) { + unsigned char seed[32]; + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + secp256k1_fixed_asset_tag fixed_input_tags[10]; + secp256k1_fixed_asset_tag fixed_output_tag; + secp256k1_generator ephemeral_input_tags[10]; + secp256k1_generator ephemeral_output_tag; + unsigned char input_blinding_key[10][32]; + unsigned char output_blinding_key[32]; + unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX]; + size_t serialized_len; + secp256k1_surjectionproof proof; + size_t n_inputs = sizeof(fixed_input_tags) / sizeof(fixed_input_tags[0]); + size_t input_index; + int32_t ecount = 0; + size_t i; + + secp256k1_rand256(seed); + secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + for (i = 0; i < n_inputs; i++) { + secp256k1_rand256(input_blinding_key[i]); + secp256k1_rand256(fixed_input_tags[i].data); + CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_input_tags[i], fixed_input_tags[i].data, input_blinding_key[i])); + } + secp256k1_rand256(output_blinding_key); + 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 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); + CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); + CHECK(ecount == 0); + CHECK(secp256k1_surjectionproof_initialize(none, NULL, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 1); + CHECK(secp256k1_surjectionproof_initialize(none, &proof, NULL, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 2); + CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, NULL, n_inputs, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 3); + CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS + 1, 3, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 4); + CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs, &fixed_input_tags[0], 100, seed) != 0); + CHECK(ecount == 4); + CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, n_inputs + 1, &fixed_input_tags[0], 100, seed) == 0); + CHECK(ecount == 5); + CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, NULL, 100, seed) == 0); + CHECK(ecount == 6); + CHECK((secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 0, seed) & 1) == 0); + CHECK(ecount == 6); + CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 0, &fixed_input_tags[0], 100, NULL) == 0); + CHECK(ecount == 7); + + CHECK(secp256k1_surjectionproof_initialize(none, &proof, &input_index, fixed_input_tags, n_inputs, 3, &fixed_input_tags[0], 100, seed) != 0); + /* check generate */ + CHECK(secp256k1_surjectionproof_generate(none, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 8); + CHECK(secp256k1_surjectionproof_generate(vrfy, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 9); + + CHECK(secp256k1_surjectionproof_generate(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 10); + CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0); + CHECK(ecount == 10); + + CHECK(secp256k1_surjectionproof_generate(both, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 11); + CHECK(secp256k1_surjectionproof_generate(both, &proof, NULL, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, 0, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 12); + CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, NULL, 0, input_blinding_key[0], output_blinding_key) == 0); + CHECK(ecount == 13); + CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 1, input_blinding_key[0], output_blinding_key) != 0); + CHECK(ecount == 13); /* the above line "succeeds" but generates an invalid proof as the input_index is wrong. it is fairly expensive to detect this. should we? */ + CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, n_inputs + 1, input_blinding_key[0], output_blinding_key) != 0); + CHECK(ecount == 13); + CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, NULL, output_blinding_key) == 0); + CHECK(ecount == 14); + CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], NULL) == 0); + CHECK(ecount == 15); + + CHECK(secp256k1_surjectionproof_generate(both, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag, 0, input_blinding_key[0], output_blinding_key) != 0); + /* check verify */ + CHECK(secp256k1_surjectionproof_verify(none, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0); + CHECK(ecount == 16); + CHECK(secp256k1_surjectionproof_verify(sign, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0); + CHECK(ecount == 17); + CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) != 0); + CHECK(ecount == 17); + + CHECK(secp256k1_surjectionproof_verify(vrfy, NULL, ephemeral_input_tags, n_inputs, &ephemeral_output_tag) == 0); + CHECK(ecount == 18); + CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, NULL, n_inputs, &ephemeral_output_tag) == 0); + CHECK(ecount == 19); + CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs - 1, &ephemeral_output_tag) == 0); + CHECK(ecount == 19); + CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs + 1, &ephemeral_output_tag) == 0); + CHECK(ecount == 19); + CHECK(secp256k1_surjectionproof_verify(vrfy, &proof, ephemeral_input_tags, n_inputs, NULL) == 0); + CHECK(ecount == 20); + + /* Check serialize */ + serialized_len = sizeof(serialized_proof); + CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0); + CHECK(ecount == 20); + serialized_len = sizeof(serialized_proof); + CHECK(secp256k1_surjectionproof_serialize(none, NULL, &serialized_len, &proof) == 0); + CHECK(ecount == 21); + serialized_len = sizeof(serialized_proof); + CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, NULL, &proof) == 0); + CHECK(ecount == 22); + serialized_len = sizeof(serialized_proof); + CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, NULL) == 0); + CHECK(ecount == 23); + + serialized_len = sizeof(serialized_proof); + CHECK(secp256k1_surjectionproof_serialize(none, serialized_proof, &serialized_len, &proof) != 0); + /* Check parse */ + CHECK(secp256k1_surjectionproof_parse(none, &proof, serialized_proof, serialized_len) != 0); + CHECK(ecount == 23); + CHECK(secp256k1_surjectionproof_parse(none, NULL, serialized_proof, serialized_len) == 0); + CHECK(ecount == 24); + CHECK(secp256k1_surjectionproof_parse(none, &proof, NULL, serialized_len) == 0); + CHECK(ecount == 25); + CHECK(secp256k1_surjectionproof_parse(none, &proof, serialized_proof, 0) == 0); + CHECK(ecount == 25); + + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); +} + static void run_input_selection_tests(size_t n_inputs) { unsigned char seed[32]; size_t i; @@ -317,6 +465,11 @@ void run_bad_parse(void) { } void run_surjection_tests(void) { + int i; + for (i = 0; i < count; i++) { + run_surjectionproof_api_tests(); + } + run_input_selection_tests(0); run_input_selection_tests(1); run_input_selection_tests(5); From d8295970d2919cea578276424cc2c9e8b497d5c0 Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Wed, 3 May 2017 17:06:39 +0000 Subject: [PATCH 4/5] surjectionproof: rename unit test functions to be more consistent with other modules --- src/modules/surjection/tests_impl.h | 52 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 26 deletions(-) diff --git a/src/modules/surjection/tests_impl.h b/src/modules/surjection/tests_impl.h index 840a9acb..4e430a8a 100644 --- a/src/modules/surjection/tests_impl.h +++ b/src/modules/surjection/tests_impl.h @@ -13,7 +13,7 @@ #include "include/secp256k1_rangeproof.h" #include "include/secp256k1_surjectionproof.h" -static void run_surjectionproof_api_tests(void) { +static void test_surjectionproof_api(void) { unsigned char seed[32]; secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); @@ -161,7 +161,7 @@ static void run_surjectionproof_api_tests(void) { secp256k1_context_destroy(both); } -static void run_input_selection_tests(size_t n_inputs) { +static void test_input_selection(size_t n_inputs) { unsigned char seed[32]; size_t i; size_t result; @@ -229,7 +229,7 @@ static void run_input_selection_tests(size_t n_inputs) { /** Runs surjectionproof_initilize multiple times and records the number of times each input was used. */ -static void run_input_selection_distribution_tests_helper(const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, size_t *used_inputs) { +static void test_input_selection_distribution_helper(const secp256k1_fixed_asset_tag* fixed_input_tags, const size_t n_input_tags, const size_t n_input_tags_to_use, size_t *used_inputs) { secp256k1_surjectionproof proof; size_t input_index; size_t i; @@ -255,7 +255,7 @@ static void run_input_selection_distribution_tests_helper(const secp256k1_fixed_ /** Probabilistic test of the distribution of used_inputs after surjectionproof_initialize. * Each confidence interval assertion fails incorrectly with a probability of 2^-128. */ -static void run_input_selection_distribution_tests(void) { +static void test_input_selection_distribution(void) { size_t i; size_t n_input_tags_to_use; const size_t n_inputs = 4; @@ -268,7 +268,7 @@ static void run_input_selection_distribution_tests(void) { /* If there is one input tag to use, initialize must choose the one equal to fixed_output_tag. */ n_input_tags_to_use = 1; - run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); CHECK(used_inputs[0] == 10000); CHECK(used_inputs[1] == 0); CHECK(used_inputs[2] == 0); @@ -279,7 +279,7 @@ static void run_input_selection_distribution_tests(void) { * For each fixed_input_tag != fixed_output_tag the probability that it's included * in the used_inputs set is P(used_input|not fixed_output_tag) = 1/3. */ - run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); CHECK(used_inputs[0] == 10000); CHECK(used_inputs[1] > 2725 && used_inputs[1] < 3961); CHECK(used_inputs[2] > 2725 && used_inputs[2] < 3961); @@ -287,7 +287,7 @@ static void run_input_selection_distribution_tests(void) { n_input_tags_to_use = 3; /* P(used_input|not fixed_output_tag) = 2/3 */ - run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); CHECK(used_inputs[0] == 10000); CHECK(used_inputs[1] > 6039 && used_inputs[1] < 7275); CHECK(used_inputs[2] > 6039 && used_inputs[2] < 7275); @@ -299,7 +299,7 @@ static void run_input_selection_distribution_tests(void) { * one input we have P(used_input|fixed_output_tag) = 1/2 and P(used_input|not fixed_output_tag) = 0 */ memcpy(fixed_input_tags[0].data, fixed_input_tags[1].data, 32); - run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); CHECK(used_inputs[0] > 4345 && used_inputs[0] < 5655); CHECK(used_inputs[1] > 4345 && used_inputs[1] < 5655); CHECK(used_inputs[2] == 0); @@ -310,7 +310,7 @@ static void run_input_selection_distribution_tests(void) { * input indexes {(0, 1), (1, 2), (0, 3), (1, 3), (0, 2)}. Therefore we have * P(used_input|fixed_output_tag) = 3/5 and P(used_input|not fixed_output_tag) = 2/5. */ - run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); CHECK(used_inputs[0] > 5352 && used_inputs[0] < 6637); CHECK(used_inputs[1] > 5352 && used_inputs[1] < 6637); CHECK(used_inputs[2] > 3363 && used_inputs[2] < 4648); @@ -320,14 +320,14 @@ static void run_input_selection_distribution_tests(void) { /* There are 4 combinations, each with all inputs except one. Therefore we have * P(used_input|fixed_output_tag) = 3/4 and P(used_input|not fixed_output_tag) = 3/4. */ - run_input_selection_distribution_tests_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); + test_input_selection_distribution_helper(fixed_input_tags, n_inputs, n_input_tags_to_use, used_inputs); CHECK(used_inputs[0] > 6918 && used_inputs[0] < 8053); CHECK(used_inputs[1] > 6918 && used_inputs[1] < 8053); CHECK(used_inputs[2] > 6918 && used_inputs[2] < 8053); CHECK(used_inputs[3] > 6918 && used_inputs[3] < 8053); } -static void run_gen_verify(size_t n_inputs, size_t n_used) { +static void test_gen_verify(size_t n_inputs, size_t n_used) { unsigned char seed[32]; secp256k1_surjectionproof proof; unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX]; @@ -400,7 +400,7 @@ static void run_gen_verify(size_t n_inputs, size_t n_used) { } /* check that a proof with empty n_used_inputs is invalid */ -static void run_no_used_inputs_verify(void) { +static void test_no_used_inputs_verify(void) { secp256k1_surjectionproof proof; secp256k1_fixed_asset_tag fixed_input_tag; secp256k1_fixed_asset_tag fixed_output_tag; @@ -439,7 +439,7 @@ static void run_no_used_inputs_verify(void) { CHECK(result == 0); } -void run_bad_serialize(void) { +void test_bad_serialize(void) { secp256k1_surjectionproof proof; unsigned char serialized_proof[SECP256K1_SURJECTIONPROOF_SERIALIZATION_BYTES_MAX]; size_t serialized_len; @@ -450,7 +450,7 @@ void run_bad_serialize(void) { CHECK(secp256k1_surjectionproof_serialize(ctx, serialized_proof, &serialized_len, &proof) == 0); } -void run_bad_parse(void) { +void test_bad_parse(void) { secp256k1_surjectionproof proof; unsigned char serialized_proof0[] = { 0x00 }; unsigned char serialized_proof1[] = { 0x01, 0x00 }; @@ -467,21 +467,21 @@ void run_bad_parse(void) { void run_surjection_tests(void) { int i; for (i = 0; i < count; i++) { - run_surjectionproof_api_tests(); + test_surjectionproof_api(); } - run_input_selection_tests(0); - run_input_selection_tests(1); - run_input_selection_tests(5); - run_input_selection_tests(100); - run_input_selection_tests(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); + test_input_selection(0); + test_input_selection(1); + test_input_selection(5); + test_input_selection(100); + test_input_selection(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); - run_input_selection_distribution_tests(); - run_gen_verify(10, 3); - run_gen_verify(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); - run_no_used_inputs_verify(); - run_bad_serialize(); - run_bad_parse(); + test_input_selection_distribution(); + test_gen_verify(10, 3); + test_gen_verify(SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS, SECP256K1_SURJECTIONPROOF_MAX_N_INPUTS); + test_no_used_inputs_verify(); + test_bad_serialize(); + test_bad_parse(); } #endif From 0cfa29f87a5385c3533f55ff6df34fa46cb3d5ef Mon Sep 17 00:00:00 2001 From: Andrew Poelstra Date: Wed, 3 May 2017 18:08:31 +0000 Subject: [PATCH 5/5] rangeproof: add API tests --- include/secp256k1_rangeproof.h | 2 +- src/modules/rangeproof/main_impl.h | 27 ++- src/modules/rangeproof/tests_impl.h | 244 ++++++++++++++++++++++++++++ 3 files changed, 266 insertions(+), 7 deletions(-) diff --git a/include/secp256k1_rangeproof.h b/include/secp256k1_rangeproof.h index 528b6662..a41d2be5 100644 --- a/include/secp256k1_rangeproof.h +++ b/include/secp256k1_rangeproof.h @@ -98,7 +98,7 @@ SECP256K1_API SECP256K1_WARN_UNUSED_RESULT int secp256k1_pedersen_blind_sum( /** Verify a tally of pedersen commitments * Returns 1: commitments successfully sum to zero. * 0: Commitments do not sum to zero or other error. - * In: ctx: pointer to a context object, initialized for Pedersen commitment (cannot be NULL) + * In: ctx: pointer to a context object (cannot be NULL) * commits: pointer to array of pointers to the commitments. (cannot be NULL if pcnt is non-zero) * pcnt: number of commitments pointed to by commits. * ncommits: pointer to array of pointers to the negative commitments. (cannot be NULL if ncnt is non-zero) diff --git a/src/modules/rangeproof/main_impl.h b/src/modules/rangeproof/main_impl.h index 4427667a..f16a0abf 100644 --- a/src/modules/rangeproof/main_impl.h +++ b/src/modules/rangeproof/main_impl.h @@ -46,6 +46,7 @@ int secp256k1_pedersen_commitment_parse(const secp256k1_context* ctx, secp256k1_ VERIFY_CHECK(ctx != NULL); ARG_CHECK(commit != NULL); ARG_CHECK(input != NULL); + (void) ctx; if ((input[0] & 0xFE) != 8) { return 0; } @@ -69,10 +70,11 @@ int secp256k1_pedersen_commit(const secp256k1_context* ctx, secp256k1_pedersen_c secp256k1_scalar sec; int overflow; int ret = 0; - ARG_CHECK(ctx != NULL); + VERIFY_CHECK(ctx != NULL); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); ARG_CHECK(commit != NULL); ARG_CHECK(blind != NULL); + ARG_CHECK(gen != NULL); secp256k1_generator_load(&genp, gen); secp256k1_scalar_set_b32(&sec, blind, &overflow); if (!overflow) { @@ -97,9 +99,11 @@ int secp256k1_pedersen_blind_sum(const secp256k1_context* ctx, unsigned char *bl secp256k1_scalar x; size_t i; int overflow; - ARG_CHECK(ctx != NULL); + VERIFY_CHECK(ctx != NULL); ARG_CHECK(blind_out != NULL); ARG_CHECK(blinds != NULL); + ARG_CHECK(npositive <= n); + (void) ctx; secp256k1_scalar_set_int(&acc, 0); for (i = 0; i < n; i++) { secp256k1_scalar_set_b32(&x, blinds[i], &overflow); @@ -122,9 +126,10 @@ int secp256k1_pedersen_verify_tally(const secp256k1_context* ctx, const secp256k secp256k1_gej accj; secp256k1_ge add; size_t i; - ARG_CHECK(ctx != NULL); + VERIFY_CHECK(ctx != NULL); ARG_CHECK(!pcnt || (commits != NULL)); ARG_CHECK(!ncnt || (ncommits != NULL)); + (void) ctx; secp256k1_gej_set_infinity(&accj); for (i = 0; i < ncnt; i++) { secp256k1_pedersen_commitment_load(&add, ncommits[i]); @@ -200,6 +205,7 @@ int secp256k1_rangeproof_info(const secp256k1_context* ctx, int *exp, int *manti ARG_CHECK(mantissa != NULL); ARG_CHECK(min_value != NULL); ARG_CHECK(max_value != NULL); + ARG_CHECK(proof != NULL); offset = 0; scale = 1; (void)ctx; @@ -212,11 +218,15 @@ int secp256k1_rangeproof_rewind(const secp256k1_context* ctx, const secp256k1_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen) { secp256k1_ge commitp; secp256k1_ge genp; - ARG_CHECK(ctx != NULL); + VERIFY_CHECK(ctx != NULL); ARG_CHECK(commit != NULL); ARG_CHECK(proof != NULL); ARG_CHECK(min_value != NULL); ARG_CHECK(max_value != NULL); + ARG_CHECK(message_out != NULL || outlen == NULL); + ARG_CHECK(nonce != NULL); + ARG_CHECK(extra_commit != NULL || extra_commit_len == 0); + ARG_CHECK(gen != NULL); ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); secp256k1_pedersen_commitment_load(&commitp, commit); @@ -229,11 +239,13 @@ int secp256k1_rangeproof_verify(const secp256k1_context* ctx, uint64_t *min_valu const secp256k1_pedersen_commitment *commit, const unsigned char *proof, size_t plen, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen) { secp256k1_ge commitp; secp256k1_ge genp; - ARG_CHECK(ctx != NULL); + VERIFY_CHECK(ctx != NULL); ARG_CHECK(commit != NULL); ARG_CHECK(proof != NULL); ARG_CHECK(min_value != NULL); ARG_CHECK(max_value != NULL); + ARG_CHECK(extra_commit != NULL || extra_commit_len == 0); + ARG_CHECK(gen != NULL); ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); secp256k1_pedersen_commitment_load(&commitp, commit); secp256k1_generator_load(&genp, gen); @@ -246,12 +258,15 @@ int secp256k1_rangeproof_sign(const secp256k1_context* ctx, unsigned char *proof const unsigned char *message, size_t msg_len, const unsigned char *extra_commit, size_t extra_commit_len, const secp256k1_generator* gen){ secp256k1_ge commitp; secp256k1_ge genp; - ARG_CHECK(ctx != NULL); + VERIFY_CHECK(ctx != NULL); ARG_CHECK(proof != NULL); ARG_CHECK(plen != NULL); ARG_CHECK(commit != NULL); ARG_CHECK(blind != NULL); ARG_CHECK(nonce != NULL); + ARG_CHECK(message != NULL || msg_len == 0); + ARG_CHECK(extra_commit != NULL || extra_commit_len == 0); + ARG_CHECK(gen != NULL); ARG_CHECK(secp256k1_ecmult_context_is_built(&ctx->ecmult_ctx)); ARG_CHECK(secp256k1_ecmult_gen_context_is_built(&ctx->ecmult_gen_ctx)); secp256k1_pedersen_commitment_load(&commitp, commit); diff --git a/src/modules/rangeproof/tests_impl.h b/src/modules/rangeproof/tests_impl.h index ea3c12e9..f604aa60 100644 --- a/src/modules/rangeproof/tests_impl.h +++ b/src/modules/rangeproof/tests_impl.h @@ -16,6 +16,249 @@ #include "include/secp256k1_rangeproof.h" +static void test_pedersen_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const int32_t *ecount) { + secp256k1_pedersen_commitment commit; + const secp256k1_pedersen_commitment *commit_ptr = &commit; + unsigned char blind[32]; + unsigned char blind_out[32]; + const unsigned char *blind_ptr = blind; + unsigned char *blind_out_ptr = blind_out; + uint64_t val = secp256k1_rand32(); + + secp256k1_rand256(blind); + CHECK(secp256k1_pedersen_commit(none, &commit, blind, val, secp256k1_generator_h) == 0); + CHECK(*ecount == 1); + CHECK(secp256k1_pedersen_commit(vrfy, &commit, blind, val, secp256k1_generator_h) == 0); + CHECK(*ecount == 2); + CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0); + CHECK(*ecount == 2); + + CHECK(secp256k1_pedersen_commit(sign, NULL, blind, val, secp256k1_generator_h) == 0); + CHECK(*ecount == 3); + CHECK(secp256k1_pedersen_commit(sign, &commit, NULL, val, secp256k1_generator_h) == 0); + CHECK(*ecount == 4); + CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, NULL) == 0); + CHECK(*ecount == 5); + + CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 1, 1) != 0); + CHECK(*ecount == 5); + CHECK(secp256k1_pedersen_blind_sum(none, NULL, &blind_ptr, 1, 1) == 0); + CHECK(*ecount == 6); + CHECK(secp256k1_pedersen_blind_sum(none, blind_out, NULL, 1, 1) == 0); + CHECK(*ecount == 7); + CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 1) == 0); + CHECK(*ecount == 8); + CHECK(secp256k1_pedersen_blind_sum(none, blind_out, &blind_ptr, 0, 0) != 0); + CHECK(*ecount == 8); + + CHECK(secp256k1_pedersen_commit(sign, &commit, blind, val, secp256k1_generator_h) != 0); + CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, &commit_ptr, 1) != 0); + CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, &commit_ptr, 1) == 0); + CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 0) == 0); + CHECK(secp256k1_pedersen_verify_tally(none, NULL, 0, NULL, 0) != 0); + CHECK(*ecount == 8); + CHECK(secp256k1_pedersen_verify_tally(none, NULL, 1, &commit_ptr, 1) == 0); + CHECK(*ecount == 9); + CHECK(secp256k1_pedersen_verify_tally(none, &commit_ptr, 1, NULL, 1) == 0); + CHECK(*ecount == 10); + + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 0) != 0); + CHECK(*ecount == 10); + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 1, 1) == 0); + CHECK(*ecount == 11); + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, &blind_out_ptr, 0, 0) == 0); + CHECK(*ecount == 12); + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, NULL, &blind_ptr, &blind_out_ptr, 1, 0) == 0); + CHECK(*ecount == 13); + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, NULL, &blind_out_ptr, 1, 0) == 0); + CHECK(*ecount == 14); + CHECK(secp256k1_pedersen_blind_generator_blind_sum(none, &val, &blind_ptr, NULL, 1, 0) == 0); + CHECK(*ecount == 15); +} + +static void test_rangeproof_api(const secp256k1_context *none, const secp256k1_context *sign, const secp256k1_context *vrfy, const secp256k1_context *both, const int32_t *ecount) { + unsigned char proof[5134]; + unsigned char blind[32]; + secp256k1_pedersen_commitment commit; + uint64_t vmin = secp256k1_rand32(); + uint64_t val = vmin + secp256k1_rand32(); + size_t len = sizeof(proof); + /* we'll switch to dylan thomas for this one */ + const unsigned char message[68] = "My tears are like the quiet drift / Of petals from some magic rose;"; + size_t mlen = sizeof(message); + const unsigned char ext_commit[72] = "And all my grief flows from the rift / Of unremembered skies and snows."; + size_t ext_commit_len = sizeof(ext_commit); + + secp256k1_rand256(blind); + CHECK(secp256k1_pedersen_commit(ctx, &commit, blind, val, secp256k1_generator_h)); + + CHECK(secp256k1_rangeproof_sign(none, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 1); + CHECK(secp256k1_rangeproof_sign(sign, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 2); + CHECK(secp256k1_rangeproof_sign(vrfy, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 3); + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); + CHECK(*ecount == 3); + + CHECK(secp256k1_rangeproof_sign(both, NULL, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 4); + CHECK(secp256k1_rangeproof_sign(both, proof, NULL, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 5); + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, NULL, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 6); + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, NULL, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 7); + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, NULL, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 8); + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, vmin - 1, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 8); + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 9); + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); + CHECK(*ecount == 9); + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 10); + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, secp256k1_generator_h) != 0); + CHECK(*ecount == 10); + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, NULL, 0, NULL, 0, NULL) == 0); + CHECK(*ecount == 11); + + CHECK(secp256k1_rangeproof_sign(both, proof, &len, vmin, &commit, blind, commit.data, 0, 0, val, message, mlen, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); + { + int exp; + int mantissa; + uint64_t min_value; + uint64_t max_value; + CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, proof, len) != 0); + CHECK(exp == 0); + CHECK(((uint64_t) 1 << mantissa) > val - vmin); + CHECK(((uint64_t) 1 << (mantissa - 1)) <= val - vmin); + CHECK(min_value == vmin); + CHECK(max_value >= val); + + CHECK(secp256k1_rangeproof_info(none, NULL, &mantissa, &min_value, &max_value, proof, len) == 0); + CHECK(*ecount == 12); + CHECK(secp256k1_rangeproof_info(none, &exp, NULL, &min_value, &max_value, proof, len) == 0); + CHECK(*ecount == 13); + CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, NULL, &max_value, proof, len) == 0); + CHECK(*ecount == 14); + CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, NULL, proof, len) == 0); + CHECK(*ecount == 15); + CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, NULL, len) == 0); + CHECK(*ecount == 16); + CHECK(secp256k1_rangeproof_info(none, &exp, &mantissa, &min_value, &max_value, proof, 0) == 0); + CHECK(*ecount == 16); + } + { + uint64_t min_value; + uint64_t max_value; + CHECK(secp256k1_rangeproof_verify(none, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 17); + CHECK(secp256k1_rangeproof_verify(sign, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 18); + CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); + CHECK(*ecount == 18); + + CHECK(secp256k1_rangeproof_verify(vrfy, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 19); + CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 20); + CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 21); + CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 22); + CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 22); + CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 23); + CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, 0, secp256k1_generator_h) == 0); + CHECK(*ecount == 23); + CHECK(secp256k1_rangeproof_verify(vrfy, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0); + CHECK(*ecount == 24); + } + { + unsigned char blind_out[32]; + unsigned char message_out[68]; + uint64_t value_out; + uint64_t min_value; + uint64_t max_value; + size_t message_len = sizeof(message_out); + + CHECK(secp256k1_rangeproof_rewind(none, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 25); + CHECK(secp256k1_rangeproof_rewind(sign, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 26); + CHECK(secp256k1_rangeproof_rewind(vrfy, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 27); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); + CHECK(*ecount == 27); + + CHECK(min_value == vmin); + CHECK(max_value >= val); + CHECK(value_out == val); + CHECK(message_len == sizeof(message_out)); + CHECK(memcmp(message, message_out, sizeof(message_out)) == 0); + + CHECK(secp256k1_rangeproof_rewind(both, NULL, &value_out, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); + CHECK(*ecount == 27); /* blindout may be NULL */ + CHECK(secp256k1_rangeproof_rewind(both, blind_out, NULL, message_out, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); + CHECK(*ecount == 27); /* valueout may be NULL */ + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, &message_len, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 28); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) != 0); + CHECK(*ecount == 28); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, NULL, &min_value, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 29); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, NULL, &max_value, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 30); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, NULL, &commit, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 31); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, NULL, proof, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 32); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, NULL, len, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 33); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, 0, ext_commit, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 33); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, ext_commit_len, secp256k1_generator_h) == 0); + CHECK(*ecount == 34); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, secp256k1_generator_h) == 0); + CHECK(*ecount == 34); + CHECK(secp256k1_rangeproof_rewind(both, blind_out, &value_out, NULL, 0, commit.data, &min_value, &max_value, &commit, proof, len, NULL, 0, NULL) == 0); + CHECK(*ecount == 35); + } +} + +static void test_api(void) { + secp256k1_context *none = secp256k1_context_create(SECP256K1_CONTEXT_NONE); + secp256k1_context *sign = secp256k1_context_create(SECP256K1_CONTEXT_SIGN); + secp256k1_context *vrfy = secp256k1_context_create(SECP256K1_CONTEXT_VERIFY); + secp256k1_context *both = secp256k1_context_create(SECP256K1_CONTEXT_SIGN | SECP256K1_CONTEXT_VERIFY); + int32_t ecount; + int i; + + secp256k1_context_set_error_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_error_callback(both, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(none, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(sign, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(vrfy, counting_illegal_callback_fn, &ecount); + secp256k1_context_set_illegal_callback(both, counting_illegal_callback_fn, &ecount); + + for (i = 0; i < count; i++) { + ecount = 0; + test_pedersen_api(none, sign, vrfy, &ecount); + ecount = 0; + test_rangeproof_api(none, sign, vrfy, both, &ecount); + } + + secp256k1_context_destroy(none); + secp256k1_context_destroy(sign); + secp256k1_context_destroy(vrfy); + secp256k1_context_destroy(both); +} + static void test_pedersen(void) { secp256k1_pedersen_commitment commits[19]; const secp256k1_pedersen_commitment *cptr[19]; @@ -363,6 +606,7 @@ void test_multiple_generators(void) { void run_rangeproof_tests(void) { int i; + test_api(); for (i = 0; i < 10*count; i++) { test_pedersen(); }