]> Git Repo - VerusCoin.git/blame - src/zcash/circuit/gadget.tcc
Enforce first four bits are zero for all spending keys and phi.
[VerusCoin.git] / src / zcash / circuit / gadget.tcc
CommitLineData
074eb3a2 1#include "zcash/circuit/utils.tcc"
ca8d6c93 2#include "zcash/circuit/prfs.tcc"
5e61a78f 3#include "zcash/circuit/commitment.tcc"
59c3d926 4#include "zcash/circuit/merkle.tcc"
ca8d6c93 5#include "zcash/circuit/note.tcc"
074eb3a2 6
369df065
SB
7template<typename FieldT, size_t NumInputs, size_t NumOutputs>
8class joinsplit_gadget : gadget<FieldT> {
074eb3a2
SB
9private:
10 // Verifier inputs
11 pb_variable_array<FieldT> zk_packed_inputs;
12 pb_variable_array<FieldT> zk_unpacked_inputs;
13 std::shared_ptr<multipacking_gadget<FieldT>> unpacker;
14
15 std::shared_ptr<digest_variable<FieldT>> zk_merkle_root;
16 std::shared_ptr<digest_variable<FieldT>> zk_h_sig;
17 boost::array<std::shared_ptr<digest_variable<FieldT>>, NumInputs> zk_input_nullifiers;
032164d5 18 boost::array<std::shared_ptr<digest_variable<FieldT>>, NumInputs> zk_input_macs;
074eb3a2
SB
19 boost::array<std::shared_ptr<digest_variable<FieldT>>, NumOutputs> zk_output_commitments;
20 pb_variable_array<FieldT> zk_vpub_old;
21 pb_variable_array<FieldT> zk_vpub_new;
22
53d2ade7
SB
23 // Aux inputs
24 pb_variable<FieldT> ZERO;
6b010d9b 25 std::shared_ptr<digest_variable<FieldT>> zk_phi;
dbab2437 26 pb_variable_array<FieldT> zk_total_uint64;
53d2ade7 27
ca8d6c93
SB
28 // Input note gadgets
29 boost::array<std::shared_ptr<input_note_gadget<FieldT>>, NumInputs> zk_input_notes;
032164d5 30 boost::array<std::shared_ptr<PRF_pk_gadget<FieldT>>, NumInputs> zk_mac_authentication;
ca8d6c93 31
6b010d9b
SB
32 // Output note gadgets
33 boost::array<std::shared_ptr<output_note_gadget<FieldT>>, NumOutputs> zk_output_notes;
34
369df065 35public:
e52f40e8 36 // PRF_pk only has a 1-bit domain separation "nonce"
6b010d9b 37 // for different macs.
e52f40e8
SB
38 BOOST_STATIC_ASSERT(NumInputs <= 2);
39
6b010d9b
SB
40 // PRF_rho only has a 1-bit domain separation "nonce"
41 // for different output `rho`.
42 BOOST_STATIC_ASSERT(NumOutputs <= 2);
43
369df065 44 joinsplit_gadget(protoboard<FieldT> &pb) : gadget<FieldT>(pb) {
074eb3a2
SB
45 // Verification
46 {
47 // The verification inputs are all bit-strings of various
48 // lengths (256-bit digests and 64-bit integers) and so we
49 // pack them into as few field elements as possible. (The
50 // more verification inputs you have, the more expensive
51 // verification is.)
52 zk_packed_inputs.allocate(pb, verifying_field_element_size());
53 pb.set_input_sizes(verifying_field_element_size());
54
55 alloc_uint256(zk_unpacked_inputs, zk_merkle_root);
56 alloc_uint256(zk_unpacked_inputs, zk_h_sig);
57
58 for (size_t i = 0; i < NumInputs; i++) {
59 alloc_uint256(zk_unpacked_inputs, zk_input_nullifiers[i]);
032164d5 60 alloc_uint256(zk_unpacked_inputs, zk_input_macs[i]);
074eb3a2
SB
61 }
62
63 for (size_t i = 0; i < NumOutputs; i++) {
64 alloc_uint256(zk_unpacked_inputs, zk_output_commitments[i]);
65 }
369df065 66
074eb3a2
SB
67 alloc_uint64(zk_unpacked_inputs, zk_vpub_old);
68 alloc_uint64(zk_unpacked_inputs, zk_vpub_new);
69
70 assert(zk_unpacked_inputs.size() == verifying_input_bit_size());
71
72 // This gadget will ensure that all of the inputs we provide are
73 // boolean constrained.
74 unpacker.reset(new multipacking_gadget<FieldT>(
75 pb,
76 zk_unpacked_inputs,
77 zk_packed_inputs,
78 FieldT::capacity(),
79 "unpacker"
80 ));
81 }
53d2ade7
SB
82
83 // We need a constant "zero" variable in some contexts. In theory
84 // it should never be necessary, but libsnark does not synthesize
85 // optimal circuits.
86 //
87 // The first variable of our constraint system is constrained
88 // to be one automatically for us, and is known as `ONE`.
89 ZERO.allocate(pb);
90
6b010d9b
SB
91 zk_phi.reset(new digest_variable<FieldT>(pb, 252, ""));
92
dbab2437
DH
93 zk_total_uint64.allocate(pb, 64);
94
ca8d6c93 95 for (size_t i = 0; i < NumInputs; i++) {
032164d5 96 // Input note gadget for commitments, macs, nullifiers,
ca8d6c93
SB
97 // and spend authority.
98 zk_input_notes[i].reset(new input_note_gadget<FieldT>(
99 pb,
2a2f3fb8 100 ZERO,
59c3d926
SB
101 zk_input_nullifiers[i],
102 *zk_merkle_root
ca8d6c93 103 ));
e52f40e8
SB
104
105 // The input keys authenticate h_sig to prevent
106 // malleability.
032164d5 107 zk_mac_authentication[i].reset(new PRF_pk_gadget<FieldT>(
e52f40e8
SB
108 pb,
109 ZERO,
110 zk_input_notes[i]->a_sk->bits,
111 zk_h_sig->bits,
112 i ? true : false,
032164d5 113 zk_input_macs[i]
e52f40e8 114 ));
ca8d6c93 115 }
6b010d9b
SB
116
117 for (size_t i = 0; i < NumOutputs; i++) {
118 zk_output_notes[i].reset(new output_note_gadget<FieldT>(
119 pb,
120 ZERO,
121 zk_phi->bits,
122 zk_h_sig->bits,
5e61a78f
SB
123 i ? true : false,
124 zk_output_commitments[i]
6b010d9b
SB
125 ));
126 }
369df065
SB
127 }
128
129 void generate_r1cs_constraints() {
074eb3a2
SB
130 // The true passed here ensures all the inputs
131 // are boolean constrained.
132 unpacker->generate_r1cs_constraints(true);
53d2ade7
SB
133
134 // Constrain `ZERO`
135 generate_r1cs_equals_const_constraint<FieldT>(this->pb, ZERO, FieldT::zero(), "ZERO");
ca8d6c93 136
6b010d9b
SB
137 // Constrain bitness of phi
138 zk_phi->generate_r1cs_constraints();
139
ca8d6c93
SB
140 for (size_t i = 0; i < NumInputs; i++) {
141 // Constrain the JoinSplit input constraints.
142 zk_input_notes[i]->generate_r1cs_constraints();
e52f40e8
SB
143
144 // Authenticate h_sig with a_sk
032164d5 145 zk_mac_authentication[i]->generate_r1cs_constraints();
ca8d6c93 146 }
6b010d9b
SB
147
148 for (size_t i = 0; i < NumOutputs; i++) {
149 // Constrain the JoinSplit output constraints.
150 zk_output_notes[i]->generate_r1cs_constraints();
151 }
e5f7c49d
SB
152
153 // Value balance
154 {
155 linear_combination<FieldT> left_side = packed_addition(zk_vpub_old);
156 for (size_t i = 0; i < NumInputs; i++) {
157 left_side = left_side + packed_addition(zk_input_notes[i]->value);
158 }
159
160 linear_combination<FieldT> right_side = packed_addition(zk_vpub_new);
161 for (size_t i = 0; i < NumOutputs; i++) {
162 right_side = right_side + packed_addition(zk_output_notes[i]->value);
163 }
164
165 // Ensure that both sides are equal
166 this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(
167 1,
168 left_side,
169 right_side
170 ));
171
dbab2437
DH
172 // #854: Ensure that left_side is a 64-bit integer.
173 for (size_t i = 0; i < 64; i++) {
174 generate_boolean_r1cs_constraint<FieldT>(
175 this->pb,
176 zk_total_uint64[i],
177 ""
178 );
179 }
180
181 this->pb.add_r1cs_constraint(r1cs_constraint<FieldT>(
182 1,
183 left_side,
184 packed_addition(zk_total_uint64)
185 ));
e5f7c49d 186 }
369df065
SB
187 }
188
189 void generate_r1cs_witness(
defe37a6 190 const uint252& phi,
369df065
SB
191 const uint256& rt,
192 const uint256& h_sig,
193 const boost::array<JSInput, NumInputs>& inputs,
194 const boost::array<Note, NumOutputs>& outputs,
195 uint64_t vpub_old,
196 uint64_t vpub_new
197 ) {
53d2ade7
SB
198 // Witness `zero`
199 this->pb.val(ZERO) = FieldT::zero();
200
59c3d926
SB
201 // Witness rt. This is not a sanity check.
202 //
203 // This ensures the read gadget constrains
204 // the intended root in the event that
205 // both inputs are zero-valued.
206 zk_merkle_root->bits.fill_with_bits(
207 this->pb,
208 uint256_to_bool_vector(rt)
209 );
210
e5f7c49d
SB
211 // Witness public balance values
212 zk_vpub_old.fill_with_bits(
213 this->pb,
214 uint64_to_bool_vector(vpub_old)
215 );
216 zk_vpub_new.fill_with_bits(
217 this->pb,
218 uint64_to_bool_vector(vpub_new)
219 );
220
dbab2437
DH
221 {
222 // Witness total_uint64 bits
223 uint64_t left_side_acc = vpub_old;
224 for (size_t i = 0; i < NumInputs; i++) {
225 left_side_acc += inputs[i].note.value;
226 }
227
228 zk_total_uint64.fill_with_bits(
229 this->pb,
230 uint64_to_bool_vector(left_side_acc)
231 );
232 }
233
6b010d9b
SB
234 // Witness phi
235 zk_phi->bits.fill_with_bits(
236 this->pb,
defe37a6 237 uint252_to_bool_vector(phi)
6b010d9b
SB
238 );
239
e52f40e8
SB
240 // Witness h_sig
241 zk_h_sig->bits.fill_with_bits(
242 this->pb,
243 uint256_to_bool_vector(h_sig)
244 );
245
ca8d6c93
SB
246 for (size_t i = 0; i < NumInputs; i++) {
247 // Witness the input information.
59c3d926
SB
248 auto merkle_path = inputs[i].witness.path();
249 zk_input_notes[i]->generate_r1cs_witness(
250 merkle_path,
251 inputs[i].key,
252 inputs[i].note
253 );
e52f40e8 254
032164d5
SB
255 // Witness macs
256 zk_mac_authentication[i]->generate_r1cs_witness();
ca8d6c93
SB
257 }
258
6b010d9b
SB
259 for (size_t i = 0; i < NumOutputs; i++) {
260 // Witness the output information.
261 zk_output_notes[i]->generate_r1cs_witness(outputs[i]);
262 }
263
59c3d926
SB
264 // [SANITY CHECK] Ensure that the intended root
265 // was witnessed by the inputs, even if the read
266 // gadget overwrote it. This allows the prover to
267 // fail instead of the verifier, in the event that
268 // the roots of the inputs do not match the
269 // treestate provided to the proving API.
270 zk_merkle_root->bits.fill_with_bits(
271 this->pb,
272 uint256_to_bool_vector(rt)
273 );
274
074eb3a2
SB
275 // This happens last, because only by now are all the
276 // verifier inputs resolved.
277 unpacker->generate_r1cs_witness_from_bits();
369df065
SB
278 }
279
280 static r1cs_primary_input<FieldT> witness_map(
281 const uint256& rt,
282 const uint256& h_sig,
032164d5 283 const boost::array<uint256, NumInputs>& macs,
369df065
SB
284 const boost::array<uint256, NumInputs>& nullifiers,
285 const boost::array<uint256, NumOutputs>& commitments,
286 uint64_t vpub_old,
287 uint64_t vpub_new
288 ) {
074eb3a2
SB
289 std::vector<bool> verify_inputs;
290
59c3d926 291 insert_uint256(verify_inputs, rt);
e52f40e8 292 insert_uint256(verify_inputs, h_sig);
074eb3a2
SB
293
294 for (size_t i = 0; i < NumInputs; i++) {
2a2f3fb8 295 insert_uint256(verify_inputs, nullifiers[i]);
032164d5 296 insert_uint256(verify_inputs, macs[i]);
074eb3a2
SB
297 }
298
299 for (size_t i = 0; i < NumOutputs; i++) {
5e61a78f 300 insert_uint256(verify_inputs, commitments[i]);
074eb3a2
SB
301 }
302
e5f7c49d
SB
303 insert_uint64(verify_inputs, vpub_old);
304 insert_uint64(verify_inputs, vpub_new);
369df065 305
074eb3a2
SB
306 assert(verify_inputs.size() == verifying_input_bit_size());
307 auto verify_field_elements = pack_bit_vector_into_field_element_vector<FieldT>(verify_inputs);
308 assert(verify_field_elements.size() == verifying_field_element_size());
309 return verify_field_elements;
310 }
311
312 static size_t verifying_input_bit_size() {
313 size_t acc = 0;
314
315 acc += 256; // the merkle root (anchor)
316 acc += 256; // h_sig
317 for (size_t i = 0; i < NumInputs; i++) {
318 acc += 256; // nullifier
032164d5 319 acc += 256; // mac
074eb3a2
SB
320 }
321 for (size_t i = 0; i < NumOutputs; i++) {
322 acc += 256; // new commitment
323 }
324 acc += 64; // vpub_old
325 acc += 64; // vpub_new
369df065 326
074eb3a2
SB
327 return acc;
328 }
329
330 static size_t verifying_field_element_size() {
331 return div_ceil(verifying_input_bit_size(), FieldT::capacity());
332 }
333
334 void alloc_uint256(
335 pb_variable_array<FieldT>& packed_into,
336 std::shared_ptr<digest_variable<FieldT>>& var
337 ) {
338 var.reset(new digest_variable<FieldT>(this->pb, 256, ""));
339 packed_into.insert(packed_into.end(), var->bits.begin(), var->bits.end());
340 }
341
342 void alloc_uint64(
343 pb_variable_array<FieldT>& packed_into,
344 pb_variable_array<FieldT>& integer
345 ) {
346 integer.allocate(this->pb, 64, "");
347 packed_into.insert(packed_into.end(), integer.begin(), integer.end());
369df065 348 }
dbab2437 349};
This page took 0.065878 seconds and 4 git commands to generate.