Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
mp_pcd_circuits.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3 
4  Implementation of functionality for creating and using the two PCD circuits in
5  a multi-predicate PCD construction.
6 
7  See mp_pcd_circuits.hpp .
8 
9  *****************************************************************************
10  * @author This file is part of libsnark, developed by SCIPR Lab
11  * and contributors (see AUTHORS).
12  * @copyright MIT license (see LICENSE file)
13  *****************************************************************************/
14 
15 #ifndef MP_PCD_CIRCUITS_TCC_
16 #define MP_PCD_CIRCUITS_TCC_
17 
18 #include <algorithm>
19 #include <libff/common/utils.hpp>
20 #include <libsnark/gadgetlib1/constraint_profiling.hpp>
21 
22 namespace libsnark
23 {
24 
25 template<typename ppT>
26 mp_compliance_step_pcd_circuit_maker<ppT>::mp_compliance_step_pcd_circuit_maker(
27  const r1cs_pcd_compliance_predicate<FieldT> &compliance_predicate,
28  const size_t max_number_of_predicates)
29  : compliance_predicate(compliance_predicate)
30 {
31  /* calculate some useful sizes */
32  const size_t digest_size =
33  CRH_with_field_out_gadget<FieldT>::get_digest_len();
34  const size_t outgoing_msg_size_in_bits =
35  field_logsize() *
36  (1 + compliance_predicate.outgoing_message_payload_length);
37  assert(compliance_predicate.has_equal_input_lengths());
38  const size_t translation_step_vk_size_in_bits =
39  r1cs_ppzksnark_verification_key_variable<ppT>::size_in_bits(
40  mp_translation_step_pcd_circuit_maker<
41  other_curve<ppT>>::input_size_in_elts());
42  const size_t padded_verifier_input_size =
43  mp_translation_step_pcd_circuit_maker<
44  other_curve<ppT>>::input_capacity_in_bits();
45  const size_t commitment_size =
46  set_commitment_gadget<FieldT, CRH_with_bit_out_gadget<FieldT>>::
47  root_size_in_bits();
48 
49  const size_t output_block_size =
50  commitment_size + outgoing_msg_size_in_bits;
51  const size_t max_incoming_payload_length = *std::max_element(
52  compliance_predicate.incoming_message_payload_lengths.begin(),
53  compliance_predicate.incoming_message_payload_lengths.end());
54  const size_t max_input_block_size =
55  commitment_size + field_logsize() * (1 + max_incoming_payload_length);
56 
57  CRH_with_bit_out_gadget<FieldT>::sample_randomness(
58  std::max(output_block_size, max_input_block_size));
59 
60  /* allocate input of the compliance MP_PCD circuit */
61  mp_compliance_step_pcd_circuit_input.allocate(
62  pb, input_size_in_elts(), "mp_compliance_step_pcd_circuit_input");
63 
64  /* allocate inputs to the compliance predicate */
65  outgoing_message_type.allocate(pb, "outgoing_message_type");
66  outgoing_message_payload.allocate(
67  pb,
68  compliance_predicate.outgoing_message_payload_length,
69  "outgoing_message_payload");
70 
71  outgoing_message_vars.insert(
72  outgoing_message_vars.end(), outgoing_message_type);
73  outgoing_message_vars.insert(
74  outgoing_message_vars.end(),
75  outgoing_message_payload.begin(),
76  outgoing_message_payload.end());
77 
78  arity.allocate(pb, "arity");
79 
80  incoming_message_types.resize(compliance_predicate.max_arity);
81  incoming_message_payloads.resize(compliance_predicate.max_arity);
82  incoming_message_vars.resize(compliance_predicate.max_arity);
83  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
84  incoming_message_types[i].allocate(
85  pb, FMT("", "incoming_message_type_%zu", i));
86  incoming_message_payloads[i].allocate(
87  pb,
88  compliance_predicate.incoming_message_payload_lengths[i],
89  FMT("", "incoming_message_payloads_%zu", i));
90 
91  incoming_message_vars[i].insert(
92  incoming_message_vars[i].end(), incoming_message_types[i]);
93  incoming_message_vars[i].insert(
94  incoming_message_vars[i].end(),
95  incoming_message_payloads[i].begin(),
96  incoming_message_payloads[i].end());
97  }
98 
99  local_data.allocate(
100  pb, compliance_predicate.local_data_length, "local_data");
101  cp_witness.allocate(pb, compliance_predicate.witness_length, "cp_witness");
102 
103  /* convert compliance predicate from a constraint system into a gadget */
104  pb_variable_array<FieldT> incoming_messages_concat;
105  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
106  incoming_messages_concat.insert(
107  incoming_messages_concat.end(),
108  incoming_message_vars[i].begin(),
109  incoming_message_vars[i].end());
110  }
111 
112  compliance_predicate_as_gadget.reset(new gadget_from_r1cs<FieldT>(
113  pb,
114  {outgoing_message_vars,
115  pb_variable_array<FieldT>(1, arity),
116  incoming_messages_concat,
117  local_data,
118  cp_witness},
119  compliance_predicate.constraint_system,
120  "compliance_predicate_as_gadget"));
121 
122  /* unpack messages to bits */
123  outgoing_message_bits.allocate(
124  pb, outgoing_msg_size_in_bits, "outgoing_message_bits");
125  unpack_outgoing_message.reset(new multipacking_gadget<FieldT>(
126  pb,
127  outgoing_message_bits,
128  outgoing_message_vars,
129  field_logsize(),
130  "unpack_outgoing_message"));
131 
132  incoming_messages_bits.resize(compliance_predicate.max_arity);
133  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
134  const size_t incoming_msg_size_in_bits =
135  field_logsize() *
136  (1 + compliance_predicate.incoming_message_payload_lengths[i]);
137 
138  incoming_messages_bits[i].allocate(
139  pb,
140  incoming_msg_size_in_bits,
141  FMT("", "incoming_messages_bits_%zu", i));
142  unpack_incoming_messages.emplace_back(multipacking_gadget<FieldT>(
143  pb,
144  incoming_messages_bits[i],
145  incoming_message_vars[i],
146  field_logsize(),
147  FMT("", "unpack_incoming_messages_%zu", i)));
148  }
149 
150  /* allocate digests */
151  commitment_and_incoming_message_digests.resize(
152  compliance_predicate.max_arity);
153  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
154  commitment_and_incoming_message_digests[i].allocate(
155  pb,
156  digest_size,
157  FMT("", "commitment_and_incoming_message_digests_%zu", i));
158  }
159 
160  /* allocate commitment, verification key(s) and membership
161  * checker(s)/proof(s) */
162  commitment.reset(
163  new set_commitment_variable<FieldT, CRH_with_bit_out_gadget<FieldT>>(
164  pb, commitment_size, "commitment"));
165 
166  libff::print_indent();
167  printf(
168  "* %s perform same type optimization for compliance predicate with "
169  "type %zu\n",
170  (compliance_predicate.relies_on_same_type_inputs ? "Will" : "Will NOT"),
171  compliance_predicate.type);
172  if (compliance_predicate.relies_on_same_type_inputs) {
173  /* only one set_commitment_gadget is needed */
174  common_type.allocate(pb, "common_type");
175  common_type_check_aux.allocate(
176  pb,
177  compliance_predicate.accepted_input_types.size(),
178  "common_type_check_aux");
179 
180  translation_step_vks_bits.resize(1);
181  translation_step_vks_bits[0].allocate(
182  pb, translation_step_vk_size_in_bits, "translation_step_vk_bits");
183  membership_check_results.allocate(pb, 1, "membership_check_results");
184 
185  membership_proofs.emplace_back(set_membership_proof_variable<
186  FieldT,
187  CRH_with_bit_out_gadget<FieldT>>(
188  pb, max_number_of_predicates, "membership_proof"));
189  membership_checkers.emplace_back(
190  set_commitment_gadget<FieldT, CRH_with_bit_out_gadget<FieldT>>(
191  pb,
192  max_number_of_predicates,
193  translation_step_vks_bits[0],
194  *commitment,
195  membership_proofs[0],
196  membership_check_results[0],
197  "membership_checker"));
198  } else {
199  /* check for max_arity possibly different VKs */
200  translation_step_vks_bits.resize(compliance_predicate.max_arity);
201  membership_check_results.allocate(
202  pb, compliance_predicate.max_arity, "membership_check_results");
203 
204  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
205  translation_step_vks_bits[i].allocate(
206  pb,
207  translation_step_vk_size_in_bits,
208  FMT("", "translation_step_vks_bits_%zu", i));
209 
210  membership_proofs.emplace_back(set_membership_proof_variable<
211  FieldT,
212  CRH_with_bit_out_gadget<FieldT>>(
213  pb,
214  max_number_of_predicates,
215  FMT("", "membership_proof_%zu", i)));
216  membership_checkers.emplace_back(
217  set_commitment_gadget<FieldT, CRH_with_bit_out_gadget<FieldT>>(
218  pb,
219  max_number_of_predicates,
220  translation_step_vks_bits[i],
221  *commitment,
222  membership_proofs[i],
223  membership_check_results[i],
224  FMT("", "membership_checkers_%zu", i)));
225  }
226  }
227 
228  /* allocate blocks */
229  block_for_outgoing_message.reset(new block_variable<FieldT>(
230  pb,
231  {commitment->bits, outgoing_message_bits},
232  "block_for_outgoing_message"));
233 
234  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
235  block_for_incoming_messages.emplace_back(block_variable<FieldT>(
236  pb,
237  {commitment->bits, incoming_messages_bits[i]},
238  FMT("", "block_for_incoming_messages_%zu", i)));
239  }
240 
241  /* allocate hash checkers */
242  hash_outgoing_message.reset(new CRH_with_field_out_gadget<FieldT>(
243  pb,
244  output_block_size,
245  *block_for_outgoing_message,
246  mp_compliance_step_pcd_circuit_input,
247  "hash_outgoing_message"));
248 
249  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
250  const size_t input_block_size =
251  commitment_size + incoming_messages_bits[i].size();
252  hash_incoming_messages.emplace_back(CRH_with_field_out_gadget<FieldT>(
253  pb,
254  input_block_size,
255  block_for_incoming_messages[i],
256  commitment_and_incoming_message_digests[i],
257  FMT("", "hash_incoming_messages_%zu", i)));
258  }
259 
260  /* allocate useful zero variable */
261  zero.allocate(pb, "zero");
262 
263  /* prepare arguments for the verifier */
264  if (compliance_predicate.relies_on_same_type_inputs) {
265  translation_step_vks.emplace_back(
266  r1cs_ppzksnark_verification_key_variable<ppT>(
267  pb,
268  translation_step_vks_bits[0],
269  mp_translation_step_pcd_circuit_maker<
270  other_curve<ppT>>::input_size_in_elts(),
271  "translation_step_vk"));
272  } else {
273  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
274  translation_step_vks.emplace_back(
275  r1cs_ppzksnark_verification_key_variable<ppT>(
276  pb,
277  translation_step_vks_bits[i],
278  mp_translation_step_pcd_circuit_maker<
279  other_curve<ppT>>::input_size_in_elts(),
280  FMT("", "translation_step_vks_%zu", i)));
281  }
282  }
283 
284  verification_results.allocate(
285  pb, compliance_predicate.max_arity, "verification_results");
286  commitment_and_incoming_messages_digest_bits.resize(
287  compliance_predicate.max_arity);
288 
289  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
290  commitment_and_incoming_messages_digest_bits[i].allocate(
291  pb,
292  digest_size * field_logsize(),
293  FMT("", "commitment_and_incoming_messages_digest_bits_%zu", i));
294  unpack_commitment_and_incoming_message_digests.emplace_back(
295  multipacking_gadget<FieldT>(
296  pb,
297  commitment_and_incoming_messages_digest_bits[i],
298  commitment_and_incoming_message_digests[i],
299  field_logsize(),
300  FMT("",
301  "unpack_commitment_and_incoming_message_digests_%zu",
302  i)));
303 
304  verifier_input.emplace_back(
305  commitment_and_incoming_messages_digest_bits[i]);
306  while (verifier_input[i].size() < padded_verifier_input_size) {
307  verifier_input[i].emplace_back(zero);
308  }
309 
310  proof.emplace_back(
311  r1cs_ppzksnark_proof_variable<ppT>(pb, FMT("", "proof_%zu", i)));
312  const r1cs_ppzksnark_verification_key_variable<ppT> &vk_to_be_used =
313  (compliance_predicate.relies_on_same_type_inputs
314  ? translation_step_vks[0]
315  : translation_step_vks[i]);
316  verifier.emplace_back(r1cs_ppzksnark_verifier_gadget<ppT>(
317  pb,
318  vk_to_be_used,
319  verifier_input[i],
320  mp_translation_step_pcd_circuit_maker<
321  other_curve<ppT>>::field_capacity(),
322  proof[i],
323  verification_results[i],
324  FMT("", "verifier_%zu", i)));
325  }
326 
327  pb.set_input_sizes(input_size_in_elts());
328 }
329 
330 template<typename ppT>
331 void mp_compliance_step_pcd_circuit_maker<ppT>::generate_r1cs_constraints()
332 {
333  const size_t digest_size =
334  CRH_with_bit_out_gadget<FieldT>::get_digest_len();
335  const size_t dimension = knapsack_dimension<FieldT>::dimension;
336  libff::print_indent();
337  printf("* Knapsack dimension: %zu\n", dimension);
338 
339  libff::print_indent();
340  printf(
341  "* Compliance predicate arity: %zu\n", compliance_predicate.max_arity);
342  libff::print_indent();
343  printf(
344  "* Compliance predicate outgoing payload length: %zu\n",
345  compliance_predicate.outgoing_message_payload_length);
346  libff::print_indent();
347  printf("* Compliance predicate incoming payload lengths:");
348  for (auto l : compliance_predicate.incoming_message_payload_lengths) {
349  printf(" %zu", l);
350  }
351  printf("\n");
352  libff::print_indent();
353  printf(
354  "* Compliance predicate local data length: %zu\n",
355  compliance_predicate.local_data_length);
356  libff::print_indent();
357  printf(
358  "* Compliance predicate witness length: %zu\n",
359  compliance_predicate.witness_length);
360 
361  PROFILE_CONSTRAINTS(pb, "booleanity")
362  {
363  PROFILE_CONSTRAINTS(pb, "booleanity: unpack outgoing_message")
364  {
365  unpack_outgoing_message->generate_r1cs_constraints(true);
366  }
367 
368  PROFILE_CONSTRAINTS(pb, "booleanity: unpack s incoming_messages")
369  {
370  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
371  unpack_incoming_messages[i].generate_r1cs_constraints(true);
372  }
373  }
374 
375  PROFILE_CONSTRAINTS(pb, "booleanity: unpack verification key")
376  {
377  for (size_t i = 0; i < translation_step_vks.size(); ++i) {
378  translation_step_vks[i].generate_r1cs_constraints(true);
379  }
380  }
381  }
382 
383  PROFILE_CONSTRAINTS(pb, "(1+s) copies of hash")
384  {
385  libff::print_indent();
386  printf("* Digest-size: %zu\n", digest_size);
387  hash_outgoing_message->generate_r1cs_constraints();
388 
389  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
390  hash_incoming_messages[i].generate_r1cs_constraints();
391  }
392  }
393 
394  PROFILE_CONSTRAINTS(pb, "s copies of repacking circuit for verifier")
395  {
396  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
397  unpack_commitment_and_incoming_message_digests[i]
398  .generate_r1cs_constraints(true);
399  }
400  }
401 
402  PROFILE_CONSTRAINTS(pb, "set membership check")
403  {
404  for (auto &membership_proof : membership_proofs) {
405  membership_proof.generate_r1cs_constraints();
406  }
407 
408  for (auto &membership_checker : membership_checkers) {
409  membership_checker.generate_r1cs_constraints();
410  }
411  }
412 
413  PROFILE_CONSTRAINTS(pb, "compliance predicate")
414  {
415  compliance_predicate_as_gadget->generate_r1cs_constraints();
416  }
417 
418  PROFILE_CONSTRAINTS(pb, "s copies of verifier for translated proofs")
419  {
420  PROFILE_CONSTRAINTS(pb, "check that s proofs lie on the curve")
421  {
422  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
423  proof[i].generate_r1cs_constraints();
424  }
425  }
426 
427  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
428  verifier[i].generate_r1cs_constraints();
429  }
430  }
431 
432  PROFILE_CONSTRAINTS(pb, "miscellaneous")
433  {
434  generate_r1cs_equals_const_constraint<FieldT>(
435  pb, zero, FieldT::zero(), "zero");
436 
437  PROFILE_CONSTRAINTS(pb, "check that s proofs lie on the curve")
438  {
439  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
440  generate_boolean_r1cs_constraint<FieldT>(
441  pb,
442  verification_results[i],
443  FMT("", "verification_results_%zu", i));
444  }
445  }
446 
447  /* either type = 0 or proof verified w.r.t. a valid verification key */
448  PROFILE_CONSTRAINTS(
449  pb, "check that s messages have valid proofs (or are base case)")
450  {
451  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
452  pb.add_r1cs_constraint(
453  r1cs_constraint<FieldT>(
454  incoming_message_types[i],
455  1 - verification_results[i],
456  0),
457  FMT("", "not_base_case_implies_valid_proof_%zu", i));
458  }
459  }
460 
461  if (compliance_predicate.relies_on_same_type_inputs) {
462  PROFILE_CONSTRAINTS(
463  pb,
464  "check that all non-base case messages are of same type and "
465  "that VK is validly selected")
466  {
467  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
468  pb.add_r1cs_constraint(
469  r1cs_constraint<FieldT>(
470  incoming_message_types[i],
471  incoming_message_types[i] - common_type,
472  0),
473  FMT("", "non_base_types_equal_%zu", i));
474  }
475 
476  pb.add_r1cs_constraint(
477  r1cs_constraint<FieldT>(
478  common_type, 1 - membership_check_results[0], 0),
479  "valid_vk_for_the_common_type");
480 
481  auto it = compliance_predicate.accepted_input_types.begin();
482  for (size_t i = 0;
483  i < compliance_predicate.accepted_input_types.size();
484  ++i, ++it) {
485  pb.add_r1cs_constraint(
486  r1cs_constraint<FieldT>(
487  (i == 0 ? common_type
488  : common_type_check_aux[i - 1]),
489  common_type - FieldT(*it),
490  (i == compliance_predicate.accepted_input_types
491  .size() -
492  1
493  ? 0 * ONE
494  : common_type_check_aux[i])),
495  FMT("",
496  "common_type_in_prescribed_set_%zu_must_equal_%zu",
497  i,
498  *it));
499  }
500  }
501  } else {
502  PROFILE_CONSTRAINTS(
503  pb, "check that all s messages have validly selected VKs")
504  {
505  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
506  pb.add_r1cs_constraint(
507  r1cs_constraint<FieldT>(
508  incoming_message_types[i],
509  1 - membership_check_results[i],
510  0),
511  FMT("", "not_base_case_implies_valid_vk_%zu", i));
512  }
513  }
514  }
515  pb.add_r1cs_constraint(
516  r1cs_constraint<FieldT>(
517  1, outgoing_message_type, FieldT(compliance_predicate.type)),
518  "enforce_outgoing_type");
519  }
520 
521  PRINT_CONSTRAINT_PROFILING();
522  libff::print_indent();
523  printf(
524  "* Number of constraints in mp_compliance_step_pcd_circuit: %zu\n",
525  pb.num_constraints());
526 }
527 
528 template<typename ppT>
529 r1cs_constraint_system<libff::Fr<ppT>> mp_compliance_step_pcd_circuit_maker<
530  ppT>::get_circuit() const
531 {
532  return pb.get_constraint_system();
533 }
534 
535 template<typename ppT>
536 r1cs_primary_input<libff::Fr<ppT>> mp_compliance_step_pcd_circuit_maker<
537  ppT>::get_primary_input() const
538 {
539  return pb.primary_input();
540 }
541 
542 template<typename ppT>
543 r1cs_auxiliary_input<libff::Fr<ppT>> mp_compliance_step_pcd_circuit_maker<
544  ppT>::get_auxiliary_input() const
545 {
546  return pb.auxiliary_input();
547 }
548 
549 template<typename ppT>
550 void mp_compliance_step_pcd_circuit_maker<ppT>::generate_r1cs_witness(
551  const set_commitment &commitment_to_translation_step_r1cs_vks,
552  const std::vector<r1cs_ppzksnark_verification_key<other_curve<ppT>>>
553  &mp_translation_step_pcd_circuit_vks,
554  const std::vector<set_membership_proof> &vk_membership_proofs,
555  const r1cs_pcd_compliance_predicate_primary_input<FieldT>
556  &compliance_predicate_primary_input,
557  const r1cs_pcd_compliance_predicate_auxiliary_input<FieldT>
558  &compliance_predicate_auxiliary_input,
559  const std::vector<r1cs_ppzksnark_proof<other_curve<ppT>>>
560  &translation_step_proofs)
561 {
562  this->pb.clear_values();
563  this->pb.val(zero) = FieldT::zero();
564 
565  compliance_predicate_as_gadget->generate_r1cs_witness(
566  compliance_predicate_primary_input.as_r1cs_primary_input(),
567  compliance_predicate_auxiliary_input.as_r1cs_auxiliary_input(
568  compliance_predicate.incoming_message_payload_lengths));
569 
570  unpack_outgoing_message->generate_r1cs_witness_from_packed();
571  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
572  unpack_incoming_messages[i].generate_r1cs_witness_from_packed();
573  }
574 
575  for (size_t i = 0; i < translation_step_vks.size(); ++i) {
576  translation_step_vks[i].generate_r1cs_witness(
577  mp_translation_step_pcd_circuit_vks[i]);
578  }
579 
580  commitment->generate_r1cs_witness(commitment_to_translation_step_r1cs_vks);
581 
582  if (compliance_predicate.relies_on_same_type_inputs) {
583  /* all messages (except base case) must be of the same type */
584  this->pb.val(common_type) = FieldT::zero();
585  size_t nonzero_type_idx = 0;
586  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
587  if (this->pb.val(incoming_message_types[i]) == 0) {
588  continue;
589  }
590 
591  if (this->pb.val(common_type).is_zero()) {
592  this->pb.val(common_type) =
593  this->pb.val(incoming_message_types[i]);
594  nonzero_type_idx = i;
595  } else {
596  assert(
597  this->pb.val(common_type) ==
598  this->pb.val(incoming_message_types[i]));
599  }
600  }
601 
602  this->pb.val(membership_check_results[0]) =
603  (this->pb.val(common_type).is_zero() ? FieldT::zero()
604  : FieldT::one());
605  membership_proofs[0].generate_r1cs_witness(
606  vk_membership_proofs[nonzero_type_idx]);
607  membership_checkers[0].generate_r1cs_witness();
608 
609  auto it = compliance_predicate.accepted_input_types.begin();
610  for (size_t i = 0; i < compliance_predicate.accepted_input_types.size();
611  ++i, ++it) {
612  pb.val(common_type_check_aux[i]) =
613  ((i == 0 ? pb.val(common_type)
614  : pb.val(common_type_check_aux[i - 1])) *
615  (pb.val(common_type) - FieldT(*it)));
616  }
617  } else {
618  for (size_t i = 0; i < membership_checkers.size(); ++i) {
619  this->pb.val(membership_check_results[i]) =
620  (this->pb.val(incoming_message_types[i]).is_zero()
621  ? FieldT::zero()
622  : FieldT::one());
623  membership_proofs[i].generate_r1cs_witness(vk_membership_proofs[i]);
624  membership_checkers[i].generate_r1cs_witness();
625  }
626  }
627 
628  hash_outgoing_message->generate_r1cs_witness();
629  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
630  hash_incoming_messages[i].generate_r1cs_witness();
631  unpack_commitment_and_incoming_message_digests[i]
632  .generate_r1cs_witness_from_packed();
633  }
634 
635  for (size_t i = 0; i < compliance_predicate.max_arity; ++i) {
636  proof[i].generate_r1cs_witness(translation_step_proofs[i]);
637  verifier[i].generate_r1cs_witness();
638  }
639 
640 #ifdef DEBUG
641  get_circuit(); // force generating constraints
642  assert(this->pb.is_satisfied());
643 #endif
644 }
645 
646 template<typename ppT>
647 size_t mp_compliance_step_pcd_circuit_maker<ppT>::field_logsize()
648 {
649  return libff::Fr<ppT>::size_in_bits();
650 }
651 
652 template<typename ppT>
653 size_t mp_compliance_step_pcd_circuit_maker<ppT>::field_capacity()
654 {
655  return libff::Fr<ppT>::capacity();
656 }
657 
658 template<typename ppT>
659 size_t mp_compliance_step_pcd_circuit_maker<ppT>::input_size_in_elts()
660 {
661  const size_t digest_size =
662  CRH_with_field_out_gadget<FieldT>::get_digest_len();
663  return digest_size;
664 }
665 
666 template<typename ppT>
667 size_t mp_compliance_step_pcd_circuit_maker<ppT>::input_capacity_in_bits()
668 {
669  return input_size_in_elts() * field_capacity();
670 }
671 
672 template<typename ppT>
673 size_t mp_compliance_step_pcd_circuit_maker<ppT>::input_size_in_bits()
674 {
675  return input_size_in_elts() * field_logsize();
676 }
677 
678 template<typename ppT>
679 mp_translation_step_pcd_circuit_maker<ppT>::
680  mp_translation_step_pcd_circuit_maker(
681  const r1cs_ppzksnark_verification_key<other_curve<ppT>>
682  &compliance_step_vk)
683 {
684  /* allocate input of the translation MP_PCD circuit */
685  mp_translation_step_pcd_circuit_input.allocate(
686  pb, input_size_in_elts(), "mp_translation_step_pcd_circuit_input");
687 
688  /* unpack translation step MP_PCD circuit input */
689  unpacked_mp_translation_step_pcd_circuit_input.allocate(
690  pb,
691  mp_compliance_step_pcd_circuit_maker<
692  other_curve<ppT>>::input_size_in_bits(),
693  "unpacked_mp_translation_step_pcd_circuit_input");
694  unpack_mp_translation_step_pcd_circuit_input.reset(
695  new multipacking_gadget<FieldT>(
696  pb,
697  unpacked_mp_translation_step_pcd_circuit_input,
698  mp_translation_step_pcd_circuit_input,
699  field_capacity(),
700  "unpack_mp_translation_step_pcd_circuit_input"));
701 
702  /* prepare arguments for the verifier */
703  hardcoded_compliance_step_vk.reset(
704  new r1cs_ppzksnark_preprocessed_r1cs_ppzksnark_verification_key_variable<
705  ppT>(pb, compliance_step_vk, "hardcoded_compliance_step_vk"));
706  proof.reset(new r1cs_ppzksnark_proof_variable<ppT>(pb, "proof"));
707 
708  /* verify previous proof */
709  online_verifier.reset(new r1cs_ppzksnark_online_verifier_gadget<ppT>(
710  pb,
711  *hardcoded_compliance_step_vk,
712  unpacked_mp_translation_step_pcd_circuit_input,
713  mp_compliance_step_pcd_circuit_maker<other_curve<ppT>>::field_logsize(),
714  *proof,
715  ONE, // must always accept
716  "verifier"));
717 
718  pb.set_input_sizes(input_size_in_elts());
719 }
720 
721 template<typename ppT>
722 void mp_translation_step_pcd_circuit_maker<ppT>::generate_r1cs_constraints()
723 {
724  PROFILE_CONSTRAINTS(pb, "repacking: unpack circuit input")
725  {
726  unpack_mp_translation_step_pcd_circuit_input->generate_r1cs_constraints(
727  true);
728  }
729 
730  PROFILE_CONSTRAINTS(pb, "verifier for compliance proofs")
731  {
732  PROFILE_CONSTRAINTS(pb, "check that proof lies on the curve")
733  {
734  proof->generate_r1cs_constraints();
735  }
736 
737  online_verifier->generate_r1cs_constraints();
738  }
739 
740  PRINT_CONSTRAINT_PROFILING();
741  libff::print_indent();
742  printf(
743  "* Number of constraints in mp_translation_step_pcd_circuit: %zu\n",
744  pb.num_constraints());
745 }
746 
747 template<typename ppT>
748 r1cs_constraint_system<libff::Fr<ppT>> mp_translation_step_pcd_circuit_maker<
749  ppT>::get_circuit() const
750 {
751  return pb.get_constraint_system();
752 }
753 
754 template<typename ppT>
755 void mp_translation_step_pcd_circuit_maker<ppT>::generate_r1cs_witness(
756  const r1cs_primary_input<libff::Fr<ppT>> translation_step_input,
757  const r1cs_ppzksnark_proof<other_curve<ppT>> &prev_proof)
758 {
759  this->pb.clear_values();
760  mp_translation_step_pcd_circuit_input.fill_with_field_elements(
761  pb, translation_step_input);
762  unpack_mp_translation_step_pcd_circuit_input
763  ->generate_r1cs_witness_from_packed();
764 
765  proof->generate_r1cs_witness(prev_proof);
766  online_verifier->generate_r1cs_witness();
767 
768 #ifdef DEBUG
769  get_circuit(); // force generating constraints
770  assert(this->pb.is_satisfied());
771 #endif
772 }
773 
774 template<typename ppT>
775 r1cs_primary_input<libff::Fr<ppT>> mp_translation_step_pcd_circuit_maker<
776  ppT>::get_primary_input() const
777 {
778  return pb.primary_input();
779 }
780 
781 template<typename ppT>
782 r1cs_auxiliary_input<libff::Fr<ppT>> mp_translation_step_pcd_circuit_maker<
783  ppT>::get_auxiliary_input() const
784 {
785  return pb.auxiliary_input();
786 }
787 
788 template<typename ppT>
789 size_t mp_translation_step_pcd_circuit_maker<ppT>::field_logsize()
790 {
791  return libff::Fr<ppT>::size_in_bits();
792 }
793 
794 template<typename ppT>
795 size_t mp_translation_step_pcd_circuit_maker<ppT>::field_capacity()
796 {
797  return libff::Fr<ppT>::capacity();
798 }
799 
800 template<typename ppT>
801 size_t mp_translation_step_pcd_circuit_maker<ppT>::input_size_in_elts()
802 {
803  return libff::div_ceil(
804  mp_compliance_step_pcd_circuit_maker<
805  other_curve<ppT>>::input_size_in_bits(),
806  mp_translation_step_pcd_circuit_maker<ppT>::field_capacity());
807 }
808 
809 template<typename ppT>
810 size_t mp_translation_step_pcd_circuit_maker<ppT>::input_capacity_in_bits()
811 {
812  return input_size_in_elts() * field_capacity();
813 }
814 
815 template<typename ppT>
816 size_t mp_translation_step_pcd_circuit_maker<ppT>::input_size_in_bits()
817 {
818  return input_size_in_elts() * field_logsize();
819 }
820 
821 template<typename ppT>
822 r1cs_primary_input<libff::Fr<ppT>> get_mp_compliance_step_pcd_circuit_input(
823  const set_commitment &commitment_to_translation_step_r1cs_vks,
824  const r1cs_pcd_compliance_predicate_primary_input<libff::Fr<ppT>>
825  &primary_input)
826 {
827  libff::enter_block("Call to get_mp_compliance_step_pcd_circuit_input");
828  typedef libff::Fr<ppT> FieldT;
829 
830  const r1cs_variable_assignment<FieldT> outgoing_message_as_va =
831  primary_input.outgoing_message->as_r1cs_variable_assignment();
832  libff::bit_vector msg_bits;
833  for (const FieldT &elt : outgoing_message_as_va) {
834  const libff::bit_vector elt_bits =
835  libff::convert_field_element_to_bit_vector(elt);
836  msg_bits.insert(msg_bits.end(), elt_bits.begin(), elt_bits.end());
837  }
838 
839  libff::bit_vector block;
840  block.insert(
841  block.end(),
842  commitment_to_translation_step_r1cs_vks.begin(),
843  commitment_to_translation_step_r1cs_vks.end());
844  block.insert(block.end(), msg_bits.begin(), msg_bits.end());
845 
846  libff::enter_block("Sample CRH randomness");
847  CRH_with_field_out_gadget<FieldT>::sample_randomness(block.size());
848  libff::leave_block("Sample CRH randomness");
849 
850  const std::vector<FieldT> digest =
851  CRH_with_field_out_gadget<FieldT>::get_hash(block);
852  libff::leave_block("Call to get_mp_compliance_step_pcd_circuit_input");
853 
854  return digest;
855 }
856 
857 template<typename ppT>
858 r1cs_primary_input<libff::Fr<ppT>> get_mp_translation_step_pcd_circuit_input(
859  const set_commitment &commitment_to_translation_step_r1cs_vks,
860  const r1cs_pcd_compliance_predicate_primary_input<
861  libff::Fr<other_curve<ppT>>> &primary_input)
862 {
863  libff::enter_block("Call to get_mp_translation_step_pcd_circuit_input");
864  typedef libff::Fr<ppT> FieldT;
865 
866  const std::vector<libff::Fr<other_curve<ppT>>>
867  mp_compliance_step_pcd_circuit_input =
868  get_mp_compliance_step_pcd_circuit_input<other_curve<ppT>>(
869  commitment_to_translation_step_r1cs_vks, primary_input);
870  libff::bit_vector mp_compliance_step_pcd_circuit_input_bits;
871  for (const libff::Fr<other_curve<ppT>> &elt :
872  mp_compliance_step_pcd_circuit_input) {
873  const libff::bit_vector elt_bits =
874  libff::convert_field_element_to_bit_vector<
875  libff::Fr<other_curve<ppT>>>(elt);
876  mp_compliance_step_pcd_circuit_input_bits.insert(
877  mp_compliance_step_pcd_circuit_input_bits.end(),
878  elt_bits.begin(),
879  elt_bits.end());
880  }
881 
882  mp_compliance_step_pcd_circuit_input_bits.resize(
883  mp_translation_step_pcd_circuit_maker<ppT>::input_capacity_in_bits(),
884  false);
885 
886  const r1cs_primary_input<FieldT> result =
887  libff::pack_bit_vector_into_field_element_vector<FieldT>(
888  mp_compliance_step_pcd_circuit_input_bits,
889  mp_translation_step_pcd_circuit_maker<ppT>::field_capacity());
890  libff::leave_block("Call to get_mp_translation_step_pcd_circuit_input");
891 
892  return result;
893 }
894 
895 } // namespace libsnark
896 
897 #endif // MP_PCD_CIRCUITS_TCC_