Skip to content

Commit

Permalink
Add variable input arity to pours by allowing bypass of merkle path a…
Browse files Browse the repository at this point in the history
…uthentication for zero-value input coins.
  • Loading branch information
ebfull committed Nov 25, 2015
1 parent c9f4ccb commit 6083a15
Show file tree
Hide file tree
Showing 2 changed files with 17 additions and 1 deletion.
1 change: 1 addition & 0 deletions zerocash_pour_ppzksnark/zerocash_pour_gadget.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ class zerocash_pour_gadget : public gadget<FieldT> {
/* individual components of the unpacked R1CS input */
std::shared_ptr<digest_variable<FieldT> > merkle_tree_root_variable;
std::vector<std::shared_ptr<digest_variable<FieldT> > > old_coin_serial_number_variables;
pb_variable_array<FieldT> old_coin_enforce_commitment;
std::vector<std::shared_ptr<digest_variable<FieldT> > > new_coin_commitment_variables;
pb_variable_array<FieldT> public_in_value_variable;
pb_variable_array<FieldT> public_out_value_variable;
Expand Down
17 changes: 16 additions & 1 deletion zerocash_pour_ppzksnark/zerocash_pour_gadget.tcc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ zerocash_pour_gadget<FieldT>::zerocash_pour_gadget(protoboard<FieldT> &pb,
/* allocate inputs */
merkle_tree_root_variable.reset(new digest_variable<FieldT>(pb, sha256_digest_len, FMT(annotation_prefix, " merkle_tree_root_variable")));

old_coin_enforce_commitment.allocate(pb, num_old_coins, FMT(annotation_prefix, " old_coin_enforce_commitment"));
old_coin_serial_number_variables.resize(num_old_coins);
for (size_t i = 0; i < num_old_coins; ++i)
{
Expand Down Expand Up @@ -262,7 +263,7 @@ zerocash_pour_gadget<FieldT>::zerocash_pour_gadget(protoboard<FieldT> &pb,
old_coin_authentication_path_variables[i].reset(new merkle_authentication_path_variable<FieldT, sha256_two_to_one_hash_gadget<FieldT> >(pb, tree_depth, FMT(annotation_prefix, " old_coin_authentication_path_variables_%zu", i)));
old_coin_commitments_in_tree[i].reset(new merkle_tree_check_read_gadget<FieldT, sha256_two_to_one_hash_gadget<FieldT> >(
pb, tree_depth, old_coin_merkle_tree_position_variables[i], *old_coin_commitment_variables[i], *merkle_tree_root_variable,
*old_coin_authentication_path_variables[i], ONE, FMT(annotation_prefix, " old_coin_commitments_in_tree_%zu", i)));
*old_coin_authentication_path_variables[i], old_coin_enforce_commitment[i], FMT(annotation_prefix, " old_coin_commitments_in_tree_%zu", i)));

This comment has been minimized.

Copy link
@daira

daira Dec 1, 2015

I can't tell what this does.

This comment has been minimized.

Copy link
@ebfull

ebfull Dec 2, 2015

Author

The merkle_tree_check_read_gadget has a read_success argument which allows you to constrain that the merkle path authentication is successful or not. Originally it was forced to be successful (hence ONE) but now it can be optionally successful depending on the enforcement value for that particular input coin. (The enforcement value is constrained to be 1 if the input value is nonzero).

}
}

Expand Down Expand Up @@ -312,6 +313,15 @@ void zerocash_pour_gadget<FieldT>::generate_r1cs_constraints()
generate_boolean_r1cs_constraint<FieldT>(this->pb, public_out_value_variable[j], FMT(this->annotation_prefix, " public_out_value_variable_%zu", j));
}

for (size_t i = 0; i < num_old_coins; ++i)
{
generate_boolean_r1cs_constraint<FieldT>(this->pb, old_coin_enforce_commitment[i], FMT(this->annotation_prefix, " old_coin_enforce_commitment_%zu", i));
this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(
pb_packing_sum<FieldT>(pb_variable_array<FieldT>(old_coin_value_variables[i].rbegin(), old_coin_value_variables[i].rend())),
1 - old_coin_enforce_commitment[i],
0), FMT(this->annotation_prefix, " enforce_%zu", i));

This comment has been minimized.

Copy link
@daira

daira Dec 1, 2015

We think this means: if old_coin_enforce_commitment[i] == 0 (representing false), then old_coin_value_variables[i] must be 0.

This comment has been minimized.

Copy link
@ebfull

ebfull Dec 2, 2015

Author

Actually slightly different: if old_coin_value_variables[i] is nonzero, old_coin_enforce_commitment[i] must also be nonzero.

This comment has been minimized.

Copy link
@daira

daira Jan 30, 2016

Those statements are contrapositives, hence equivalent. (For historical completeness.)

}

/* check the balance equation */
linear_combination<FieldT> old_packed_value;
for (size_t i = 0; i < num_old_coins; ++i)
Expand Down Expand Up @@ -372,6 +382,11 @@ void zerocash_pour_gadget<FieldT>::generate_r1cs_witness(const std::vector<merkl
{
old_coin_serial_number_nonce_variables[i].fill_with_bits(this->pb, old_coin_serial_number_nonces[i]);
old_coin_value_variables[i].fill_with_bits(this->pb, old_coin_values[i]);

for (size_t j = 0; j < coin_value_length; ++j)
{
this->pb.val(old_coin_enforce_commitment[i]) = (old_coin_values[i][j] ? FieldT::one() : FieldT::zero());

This comment has been minimized.

Copy link
@daira

daira Dec 1, 2015

Avoid the implicit coercion of old_coin_values[i][j] to boolean.

This comment has been minimized.

Copy link
@daira

daira Dec 1, 2015

Oh, this is fixed in the next commit.

}
}

public_in_value_variable.fill_with_bits(this->pb, public_in_value);
Expand Down

1 comment on commit 6083a15

@daira
Copy link

@daira daira commented on 6083a15 Dec 1, 2015

Choose a reason for hiding this comment

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

Otherwise LGTM (but the API to libsnark constraints seems unfortunately and perhaps unnecessarily verbose).

Please # to comment.