Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
set_commitment_gadget.tcc
Go to the documentation of this file.
1 /** @file
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_
9 
10 #include <libsnark/common/data_structures/set_commitment.hpp>
11 
12 namespace libsnark
13 {
14 
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)
28  , proof(proof)
29  , check_successful(check_successful)
30 {
31  element_block.reset(new block_variable<FieldT>(
32  pb, {element_bits}, FMT(annotation_prefix, " element_block")));
33 
34  if (tree_depth == 0) {
35  hash_element.reset(new HashT(
36  pb,
37  element_bits.size(),
38  *element_block,
39  root_digest,
40  FMT(annotation_prefix, " hash_element")));
41  } else {
42  element_digest.reset(new digest_variable<FieldT>(
43  pb,
44  HashT::get_digest_len(),
45  FMT(annotation_prefix, " element_digest")));
46  hash_element.reset(new HashT(
47  pb,
48  element_bits.size(),
49  *element_block,
50  *element_digest,
51  FMT(annotation_prefix, " hash_element")));
52  check_membership.reset(new merkle_tree_check_read_gadget<FieldT, HashT>(
53  pb,
54  tree_depth,
55  proof.address_bits,
56  *element_digest,
57  root_digest,
58  *proof.merkle_path,
59  check_successful,
60  FMT(annotation_prefix, " check_membership")));
61  }
62 }
63 
64 template<typename FieldT, typename HashT>
65 void set_commitment_gadget<FieldT, HashT>::generate_r1cs_constraints()
66 {
67  hash_element->generate_r1cs_constraints();
68 
69  if (tree_depth > 0) {
70  check_membership->generate_r1cs_constraints();
71  }
72 }
73 
74 template<typename FieldT, typename HashT>
75 void set_commitment_gadget<FieldT, HashT>::generate_r1cs_witness()
76 {
77  hash_element->generate_r1cs_witness();
78 
79  if (tree_depth > 0) {
80  check_membership->generate_r1cs_witness();
81  }
82 }
83 
84 template<typename FieldT, typename HashT>
85 size_t set_commitment_gadget<FieldT, HashT>::root_size_in_bits()
86 {
87  return merkle_tree_check_read_gadget<FieldT, HashT>::root_size_in_bits();
88 }
89 
90 template<typename FieldT, typename HashT> void test_set_commitment_gadget()
91 {
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);
96 
97  set_commitment_accumulator<HashT> accumulator(max_set_size, value_size);
98 
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);
102  std::generate(
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));
107  }
108 
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");
114 
115  pb_variable<FieldT> check_succesful;
116  check_succesful.allocate(pb, "check_succesful");
117 
118  set_membership_proof_variable<FieldT, HashT> proof(
119  pb, max_set_size, "proof");
120 
121  set_commitment_gadget<FieldT, HashT> sc(
122  pb,
123  max_set_size,
124  element_bits,
125  root_digest,
126  proof,
127  check_succesful,
128  "sc");
129  sc.generate_r1cs_constraints();
130 
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());
140  }
141  printf("membership tests OK\n");
142 
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);
146  }
147 
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());
155 
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");
165 }
166 
167 } // namespace libsnark
168 
169 #endif // SET_COMMITMENT_GADGET_TCC_