Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
circuit_wrapper.tcc
Go to the documentation of this file.
1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
2 //
3 // SPDX-License-Identifier: LGPL-3.0+
4 
5 #ifndef __ZETH_CIRCUITS_CIRCUIT_WRAPPER_TCC__
6 #define __ZETH_CIRCUITS_CIRCUIT_WRAPPER_TCC__
7 
8 #include "libzeth/circuits/circuit_wrapper.hpp"
9 
10 namespace libzeth
11 {
12 
13 template<
14  typename HashT,
15  typename HashTreeT,
16  typename ppT,
17  typename snarkT,
18  size_t NumInputs,
19  size_t NumOutputs,
20  size_t TreeDepth>
21 circuit_wrapper<
22  HashT,
23  HashTreeT,
24  ppT,
25  snarkT,
26  NumInputs,
27  NumOutputs,
28  TreeDepth>::circuit_wrapper()
29 {
30  // Allocate a single public variable to hold the hash of the public
31  // joinsplit inputs. The public joinsplit inputs are then allocated
32  // immediately following this.
33  public_data_hash.allocate(pb, "public_data_hash");
34  pb.set_input_sizes(1);
35 
36  // Joinsplit gadget internally allocates its public data first.
37  // TODO: joinsplit_gadget should be refactored to be properly composable.
38  joinsplit = std::make_shared<joinsplit_type>(pb);
39  const size_t num_public_elements = joinsplit->get_num_public_elements();
40 
41  // Populate public_data to represent the joinsplit public data. Skip
42  // the first 2 variables (the constant 1, and the digest of the
43  // public_data), and use the num_public_elements variables that follow.
44  public_data.reserve(num_public_elements);
45  for (size_t i = 0; i < num_public_elements; ++i) {
46  public_data.emplace_back(i + 2);
47  }
48  assert(public_data.size() == num_public_elements);
49 
50  // Initialize the input hasher gadget
51  input_hasher = std::make_shared<input_hasher_type>(
52  pb, public_data, public_data_hash, "input_hasher");
53 
54  // Generate constraints
55  joinsplit->generate_r1cs_constraints();
56  input_hasher->generate_r1cs_constraints();
57 }
58 
59 template<
60  typename HashT,
61  typename HashTreeT,
62  typename ppT,
63  typename snarkT,
64  size_t NumInputs,
65  size_t NumOutputs,
66  size_t TreeDepth>
67 typename snarkT::keypair circuit_wrapper<
68  HashT,
69  HashTreeT,
70  ppT,
71  snarkT,
72  NumInputs,
73  NumOutputs,
74  TreeDepth>::generate_trusted_setup() const
75 {
76  // Generate a verification and proving key (trusted setup) and write them
77  // in a file
78  return snarkT::generate_setup(pb);
79 }
80 
81 template<
82  typename HashT,
83  typename HashTreeT,
84  typename ppT,
85  typename snarkT,
86  size_t NumInputs,
87  size_t NumOutputs,
88  size_t TreeDepth>
89 const libsnark::r1cs_constraint_system<libff::Fr<ppT>> &circuit_wrapper<
90  HashT,
91  HashTreeT,
92  ppT,
93  snarkT,
94  NumInputs,
95  NumOutputs,
96  TreeDepth>::get_constraint_system() const
97 {
98  return pb.get_constraint_system();
99 }
100 
101 template<
102  typename HashT,
103  typename HashTreeT,
104  typename ppT,
105  typename snarkT,
106  size_t NumInputs,
107  size_t NumOutputs,
108  size_t TreeDepth>
109 extended_proof<ppT, snarkT> circuit_wrapper<
110  HashT,
111  HashTreeT,
112  ppT,
113  snarkT,
114  NumInputs,
115  NumOutputs,
116  TreeDepth>::
117  prove(
118  const Field &root,
119  const std::array<joinsplit_input<Field, TreeDepth>, NumInputs> &inputs,
120  const std::array<zeth_note, NumOutputs> &outputs,
121  const bits64 &vpub_in,
122  const bits64 &vpub_out,
123  const bits256 &h_sig_in,
124  const bits256 &phi_in,
125  const typename snarkT::proving_key &proving_key,
126  std::vector<Field> &out_public_data) const
127 {
128  // left hand side and right hand side of the joinsplit
129  bits64 lhs_value = vpub_in;
130  bits64 rhs_value = vpub_out;
131 
132  // Compute the sum on the left hand side of the joinsplit
133  for (size_t i = 0; i < NumInputs; i++) {
134  lhs_value = bits_add<ZETH_V_SIZE>(lhs_value, inputs[i].note.value);
135  }
136 
137  // Compute the sum on the right hand side of the joinsplit
138  for (size_t i = 0; i < NumOutputs; i++) {
139  rhs_value = bits_add<ZETH_V_SIZE>(rhs_value, outputs[i].value);
140  }
141 
142  // [CHECK] Make sure that the balance between rhs and lfh is respected
143  // Used to stop any proof computation that would inevitably fail
144  // due to a violation of the constraint:
145  // `1 * left_value = right_value` in the JoinSplit circuit
146  if (lhs_value != rhs_value) {
147  throw std::invalid_argument("invalid joinsplit balance");
148  }
149 
150  joinsplit->generate_r1cs_witness(
151  root, inputs, outputs, vpub_in, vpub_out, h_sig_in, phi_in);
152  input_hasher->generate_r1cs_witness();
153 
154  bool is_valid_witness = pb.is_satisfied();
155  std::cout << "******* [DEBUG] Satisfiability result: " << is_valid_witness
156  << " *******" << std::endl;
157 
158  // Fill out the public data vector
159  const size_t num_public_elements =
160  joinsplit_type::get_num_public_elements();
161  out_public_data.resize(0);
162  out_public_data.reserve(num_public_elements);
163  for (size_t i = 0; i < num_public_elements; ++i) {
164  out_public_data.push_back(pb.val(public_data[i]));
165  }
166 
167  // Instantiate an extended_proof from the proof we generated and the given
168  // primary_input
169  return extended_proof<ppT, snarkT>(
170  snarkT::generate_proof(proving_key, pb), pb.primary_input());
171 }
172 
173 template<
174  typename HashT,
175  typename HashTreeT,
176  typename ppT,
177  typename snarkT,
178  size_t NumInputs,
179  size_t NumOutputs,
180  size_t TreeDepth>
181 const std::vector<libff::Fr<ppT>> &circuit_wrapper<
182  HashT,
183  HashTreeT,
184  ppT,
185  snarkT,
186  NumInputs,
187  NumOutputs,
188  TreeDepth>::get_last_assignment() const
189 {
190  return pb.full_variable_assignment();
191 }
192 
193 } // namespace libzeth
194 
195 #endif // __ZETH_CIRCUITS_CIRCUIT_WRAPPER_TCC__