Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

surjectionproof: fail to generate proofs when an input equals the output #196

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions src/modules/surjection/main_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -307,10 +307,14 @@ int secp256k1_surjectionproof_generate(const secp256k1_context* ctx, secp256k1_s
if (overflow) {
return 0;
}
/* The only time the input may equal the output is if neither one was blinded in the first place,
* i.e. both blinding keys are zero. Otherwise this is a privacy leak. */
if (secp256k1_scalar_eq(&tmps, &blinding_key) && !secp256k1_scalar_is_zero(&blinding_key)) {
return 0;
/* If any input tag is equal to an output tag, verification will fail, because our ring
* signature logic would receive a zero-key, which is illegal. This is unfortunate but
* it is deployed on Liquid and cannot be fixed without a hardfork. We should review
* this at the same time that we relax the max-256-inputs rule. */
Comment on lines +312 to +313
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I doubt that this note will have an effect. Tthere's perhaps a better place to collect backwards-incompatible changes under consideration and if not we may want to create one (a la "hardfork wishlist").

for (i = 0; i < n_ephemeral_input_tags; i++) {
if (secp256k1_memcmp_var(ephemeral_input_tags[i].data, ephemeral_output_tag->data, sizeof(ephemeral_output_tag->data)) == 0) {
return 0;
}
}
secp256k1_scalar_negate(&tmps, &tmps);
secp256k1_scalar_add(&blinding_key, &blinding_key, &tmps);
Expand Down
26 changes: 26 additions & 0 deletions src/modules/surjection/tests_impl.h
Original file line number Diff line number Diff line change
Expand Up @@ -524,6 +524,31 @@ void test_bad_parse(void) {
CHECK(secp256k1_surjectionproof_parse(ctx, &proof, serialized_proof2, sizeof(serialized_proof2)) == 0);
}

void test_input_eq_output(void) {
secp256k1_surjectionproof proof;
secp256k1_fixed_asset_tag fixed_tag;
secp256k1_generator ephemeral_tag;
unsigned char blinding_key[32];
unsigned char entropy[32];
size_t input_index;

secp256k1_testrand256(fixed_tag.data);
secp256k1_testrand256(blinding_key);
secp256k1_testrand256(entropy);

CHECK(secp256k1_surjectionproof_initialize(ctx, &proof, &input_index, &fixed_tag, 1, 1, &fixed_tag, 100, entropy) == 1);
CHECK(input_index == 0);

/* Generation should fail */
CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_tag, fixed_tag.data, blinding_key));
CHECK(!secp256k1_surjectionproof_generate(ctx, &proof, &ephemeral_tag, 1, &ephemeral_tag, input_index, blinding_key, blinding_key));

/* ...even when the blinding key is zero */
memset(blinding_key, 0, 32);
CHECK(secp256k1_generator_generate_blinded(ctx, &ephemeral_tag, fixed_tag.data, blinding_key));
CHECK(!secp256k1_surjectionproof_generate(ctx, &proof, &ephemeral_tag, 1, &ephemeral_tag, input_index, blinding_key, blinding_key));
}

void test_fixed_vectors(void) {
const unsigned char tag0_ser[] = {
0x0a,
Expand Down Expand Up @@ -672,6 +697,7 @@ void test_fixed_vectors(void) {

void run_surjection_tests(void) {
test_surjectionproof_api();
test_input_eq_output();
test_fixed_vectors();

test_input_selection(0);
Expand Down