2 *****************************************************************************
3 * @author This file is part of libsnark, developed by SCIPR Lab
4 * and contributors (see AUTHORS).
5 * @copyright MIT license (see LICENSE file)
6 *****************************************************************************/
7 #ifndef SET_COMMITMENT_GADGET_TCC_
8 #define SET_COMMITMENT_GADGET_TCC_
10 #include <libsnark/common/data_structures/set_commitment.hpp>
15 template<typename FieldT, typename HashT>
16 set_commitment_gadget<FieldT, HashT>::set_commitment_gadget(
17 protoboard<FieldT> &pb,
18 const size_t max_entries,
19 const pb_variable_array<FieldT> &element_bits,
20 const set_commitment_variable<FieldT, HashT> &root_digest,
21 const set_membership_proof_variable<FieldT, HashT> &proof,
22 const pb_linear_combination<FieldT> &check_successful,
23 const std::string &annotation_prefix)
24 : gadget<FieldT>(pb, annotation_prefix)
25 , tree_depth(libff::log2(max_entries))
26 , element_bits(element_bits)
27 , root_digest(root_digest)
29 , check_successful(check_successful)
31 element_block.reset(new block_variable<FieldT>(
32 pb, {element_bits}, FMT(annotation_prefix, " element_block")));
34 if (tree_depth == 0) {
35 hash_element.reset(new HashT(
40 FMT(annotation_prefix, " hash_element")));
42 element_digest.reset(new digest_variable<FieldT>(
44 HashT::get_digest_len(),
45 FMT(annotation_prefix, " element_digest")));
46 hash_element.reset(new HashT(
51 FMT(annotation_prefix, " hash_element")));
52 check_membership.reset(new merkle_tree_check_read_gadget<FieldT, HashT>(
60 FMT(annotation_prefix, " check_membership")));
64 template<typename FieldT, typename HashT>
65 void set_commitment_gadget<FieldT, HashT>::generate_r1cs_constraints()
67 hash_element->generate_r1cs_constraints();
70 check_membership->generate_r1cs_constraints();
74 template<typename FieldT, typename HashT>
75 void set_commitment_gadget<FieldT, HashT>::generate_r1cs_witness()
77 hash_element->generate_r1cs_witness();
80 check_membership->generate_r1cs_witness();
84 template<typename FieldT, typename HashT>
85 size_t set_commitment_gadget<FieldT, HashT>::root_size_in_bits()
87 return merkle_tree_check_read_gadget<FieldT, HashT>::root_size_in_bits();
90 template<typename FieldT, typename HashT> void test_set_commitment_gadget()
92 const size_t digest_len = HashT::get_digest_len();
93 const size_t max_set_size = 16;
94 const size_t value_size =
95 (HashT::get_block_len() > 0 ? HashT::get_block_len() : 10);
97 set_commitment_accumulator<HashT> accumulator(max_set_size, value_size);
99 std::vector<libff::bit_vector> set_elems;
100 for (size_t i = 0; i < max_set_size; ++i) {
101 libff::bit_vector elem(value_size);
103 elem.begin(), elem.end(), [&]() { return std::rand() % 2; });
104 set_elems.emplace_back(elem);
105 accumulator.add(elem);
106 assert(accumulator.is_in_set(elem));
109 protoboard<FieldT> pb;
110 pb_variable_array<FieldT> element_bits;
111 element_bits.allocate(pb, value_size, "element_bits");
112 set_commitment_variable<FieldT, HashT> root_digest(
113 pb, digest_len, "root_digest");
115 pb_variable<FieldT> check_succesful;
116 check_succesful.allocate(pb, "check_succesful");
118 set_membership_proof_variable<FieldT, HashT> proof(
119 pb, max_set_size, "proof");
121 set_commitment_gadget<FieldT, HashT> sc(
129 sc.generate_r1cs_constraints();
131 // test all elements from set
132 for (size_t i = 0; i < max_set_size; ++i) {
133 element_bits.fill_with_bits(pb, set_elems[i]);
134 pb.val(check_succesful) = FieldT::one();
135 proof.generate_r1cs_witness(
136 accumulator.get_membership_proof(set_elems[i]));
137 sc.generate_r1cs_witness();
138 root_digest.generate_r1cs_witness(accumulator.get_commitment());
139 assert(pb.is_satisfied());
141 printf("membership tests OK\n");
143 /* test an element not in set */
144 for (size_t i = 0; i < value_size; ++i) {
145 pb.val(element_bits[i]) = FieldT(std::rand() % 2);
148 // do not require the check result to be successful
149 pb.val(check_succesful) = FieldT::zero();
150 // try it with invalid proof
151 proof.generate_r1cs_witness(accumulator.get_membership_proof(set_elems[0]));
152 sc.generate_r1cs_witness();
153 root_digest.generate_r1cs_witness(accumulator.get_commitment());
154 assert(pb.is_satisfied());
156 // now require the check result to be succesful
157 pb.val(check_succesful) = FieldT::one();
158 // try it with invalid proof
159 proof.generate_r1cs_witness(accumulator.get_membership_proof(set_elems[0]));
160 sc.generate_r1cs_witness();
161 root_digest.generate_r1cs_witness(accumulator.get_commitment());
162 // the protoboard should be unsatisfied
163 assert(!pb.is_satisfied());
164 printf("non-membership test OK\n");
167 } // namespace libsnark
169 #endif // SET_COMMITMENT_GADGET_TCC_