Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
r1cs_examples.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3 
4  Implementation of functions to sample R1CS examples with prescribed parameters
5  (according to some distribution).
6 
7  See r1cs_examples.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 R1CS_EXAMPLES_TCC_
16 #define R1CS_EXAMPLES_TCC_
17 
18 #include <cassert>
19 #include <libff/common/utils.hpp>
20 
21 namespace libsnark
22 {
23 
24 template<typename FieldT>
25 r1cs_example<FieldT> generate_r1cs_example_with_field_input(
26  const size_t num_constraints, const size_t num_inputs)
27 {
28  libff::enter_block("Call to generate_r1cs_example_with_field_input");
29 
30  assert(num_inputs <= num_constraints + 2);
31 
32  r1cs_constraint_system<FieldT> cs;
33  cs.primary_input_size = num_inputs;
34  // TODO: explain this
35  cs.auxiliary_input_size = 2 + num_constraints - num_inputs;
36 
37  r1cs_variable_assignment<FieldT> full_variable_assignment;
38  FieldT a = FieldT::random_element();
39  FieldT b = FieldT::random_element();
40  full_variable_assignment.push_back(a);
41  full_variable_assignment.push_back(b);
42 
43  for (size_t i = 0; i < num_constraints - 1; ++i) {
44  linear_combination<FieldT> A, B, C;
45 
46  if (i % 2) {
47  // a * b = c
48  A.add_term(i + 1, 1);
49  B.add_term(i + 2, 1);
50  C.add_term(i + 3, 1);
51  FieldT tmp = a * b;
52  full_variable_assignment.push_back(tmp);
53  a = b;
54  b = tmp;
55  } else {
56  // a + b = c
57  B.add_term(0, 1);
58  A.add_term(i + 1, 1);
59  A.add_term(i + 2, 1);
60  C.add_term(i + 3, 1);
61  FieldT tmp = a + b;
62  full_variable_assignment.push_back(tmp);
63  a = b;
64  b = tmp;
65  }
66 
67  cs.add_constraint(r1cs_constraint<FieldT>(A, B, C));
68  }
69 
70  linear_combination<FieldT> A, B, C;
71  FieldT fin = FieldT::zero();
72  for (size_t i = 1; i < cs.num_variables(); ++i) {
73  A.add_term(i, 1);
74  B.add_term(i, 1);
75  fin = fin + full_variable_assignment[i - 1];
76  }
77  C.add_term(cs.num_variables(), 1);
78  cs.add_constraint(r1cs_constraint<FieldT>(A, B, C));
79  full_variable_assignment.push_back(fin.squared());
80 
81  /* split variable assignment */
82  r1cs_primary_input<FieldT> primary_input(
83  full_variable_assignment.begin(),
84  full_variable_assignment.begin() + num_inputs);
85  r1cs_primary_input<FieldT> auxiliary_input(
86  full_variable_assignment.begin() + num_inputs,
87  full_variable_assignment.end());
88 
89  /* sanity checks */
90  assert(cs.num_variables() == full_variable_assignment.size());
91  assert(cs.num_variables() >= num_inputs);
92  assert(cs.num_inputs() == num_inputs);
93  assert(cs.num_constraints() == num_constraints);
94  assert(cs.is_satisfied(primary_input, auxiliary_input));
95 
96  libff::leave_block("Call to generate_r1cs_example_with_field_input");
97 
98  return r1cs_example<FieldT>(
99  std::move(cs), std::move(primary_input), std::move(auxiliary_input));
100 }
101 
102 template<typename FieldT>
103 r1cs_example<FieldT> generate_r1cs_example_with_binary_input(
104  const size_t num_constraints, const size_t num_inputs)
105 {
106  libff::enter_block("Call to generate_r1cs_example_with_binary_input");
107 
108  assert(num_inputs >= 1);
109 
110  r1cs_constraint_system<FieldT> cs;
111  cs.primary_input_size = num_inputs;
112  // we will add one auxiliary variable per constraint
113  cs.auxiliary_input_size = num_constraints;
114 
115  r1cs_variable_assignment<FieldT> full_variable_assignment;
116  for (size_t i = 0; i < num_inputs; ++i) {
117  full_variable_assignment.push_back(FieldT(std::rand() % 2));
118  }
119 
120  size_t lastvar = num_inputs - 1;
121  for (size_t i = 0; i < num_constraints; ++i) {
122  ++lastvar;
123  const size_t u = (i == 0 ? std::rand() % num_inputs : std::rand() % i);
124  const size_t v = (i == 0 ? std::rand() % num_inputs : std::rand() % i);
125 
126  /* chose two random bits and XOR them together:
127  res = u + v - 2 * u * v
128  2 * u * v = u + v - res
129  */
130  linear_combination<FieldT> A, B, C;
131  A.add_term(u + 1, 2);
132  B.add_term(v + 1, 1);
133  if (u == v) {
134  C.add_term(u + 1, 2);
135  } else {
136  C.add_term(u + 1, 1);
137  C.add_term(v + 1, 1);
138  }
139  C.add_term(lastvar + 1, -FieldT::one());
140 
141  cs.add_constraint(r1cs_constraint<FieldT>(A, B, C));
142  full_variable_assignment.push_back(
143  full_variable_assignment[u] + full_variable_assignment[v] -
144  full_variable_assignment[u] * full_variable_assignment[v] -
145  full_variable_assignment[u] * full_variable_assignment[v]);
146  }
147 
148  /* split variable assignment */
149  r1cs_primary_input<FieldT> primary_input(
150  full_variable_assignment.begin(),
151  full_variable_assignment.begin() + num_inputs);
152  r1cs_primary_input<FieldT> auxiliary_input(
153  full_variable_assignment.begin() + num_inputs,
154  full_variable_assignment.end());
155 
156  /* sanity checks */
157  assert(cs.num_variables() == full_variable_assignment.size());
158  assert(cs.num_variables() >= num_inputs);
159  assert(cs.num_inputs() == num_inputs);
160  assert(cs.num_constraints() == num_constraints);
161  assert(cs.is_satisfied(primary_input, auxiliary_input));
162 
163  libff::leave_block("Call to generate_r1cs_example_with_binary_input");
164 
165  return r1cs_example<FieldT>(
166  std::move(cs), std::move(primary_input), std::move(auxiliary_input));
167 }
168 
169 } // namespace libsnark
170 
171 #endif // R1CS_EXAMPLES_TCC