Clearmatics Libsnark  0.1
C++ library for zkSNARK proofs
fooram_cpu_checker.tcc
Go to the documentation of this file.
1 /** @file
2  *****************************************************************************
3 
4  Implementation of interfaces for the FOORAM CPU checker gadget.
5 
6  See fooram_cpu_checker.hpp .
7 
8  *****************************************************************************
9  * @author This file is part of libsnark, developed by SCIPR Lab
10  * and contributors (see AUTHORS).
11  * @copyright MIT license (see LICENSE file)
12  *****************************************************************************/
13 
14 #ifndef FOORAM_CPU_CHECKER_TCC_
15 #define FOORAM_CPU_CHECKER_TCC_
16 
17 namespace libsnark
18 {
19 
20 template<typename FieldT>
21 fooram_cpu_checker<FieldT>::fooram_cpu_checker(
22  fooram_protoboard<FieldT> &pb,
23  pb_variable_array<FieldT> &prev_pc_addr,
24  pb_variable_array<FieldT> &prev_pc_val,
25  pb_variable_array<FieldT> &prev_state,
26  pb_variable_array<FieldT> &ls_addr,
27  pb_variable_array<FieldT> &ls_prev_val,
28  pb_variable_array<FieldT> &ls_next_val,
29  pb_variable_array<FieldT> &next_state,
30  pb_variable_array<FieldT> &next_pc_addr,
31  pb_variable<FieldT> &next_has_accepted,
32  const std::string &annotation_prefix)
33  : fooram_gadget<FieldT>(pb, annotation_prefix)
34  , prev_pc_addr(prev_pc_addr)
35  , prev_pc_val(prev_pc_val)
36  , prev_state(prev_state)
37  , ls_addr(ls_addr)
38  , ls_prev_val(ls_prev_val)
39  , ls_next_val(ls_next_val)
40  , next_state(next_state)
41  , next_pc_addr(next_pc_addr)
42  , next_has_accepted(next_has_accepted)
43 {
44  /* increment PC */
45  packed_next_pc_addr.allocate(
46  pb, FMT(annotation_prefix, " packed_next_pc_addr"));
47  pack_next_pc_addr.reset(new packing_gadget<FieldT>(
48  pb,
49  next_pc_addr,
50  packed_next_pc_addr,
51  FMT(annotation_prefix, " pack_next_pc_addr")));
52 
53  one_as_addr.resize(next_pc_addr.size());
54  one_as_addr[0].assign(this->pb, 1);
55  for (size_t i = 1; i < next_pc_addr.size(); ++i) {
56  one_as_addr[i].assign(this->pb, 0);
57  }
58 
59  /* packed_next_pc_addr = prev_pc_addr + one_as_addr */
60  increment_pc.reset(new bar_gadget<FieldT>(
61  pb,
62  prev_pc_addr,
63  FieldT::one(),
64  one_as_addr,
65  FieldT::one(),
66  packed_next_pc_addr,
67  FMT(annotation_prefix, " increment_pc")));
68 
69  /* packed_store_addr = prev_pc_addr + prev_pc_val */
70  packed_store_addr.allocate(
71  pb, FMT(annotation_prefix, " packed_store_addr"));
72  compute_packed_store_addr.reset(new bar_gadget<FieldT>(
73  pb,
74  prev_pc_addr,
75  FieldT::one(),
76  prev_pc_val,
77  FieldT::one(),
78  packed_store_addr,
79  FMT(annotation_prefix, " compute_packed_store_addr")));
80 
81  /* packed_load_addr = 2 * x + next_pc_addr */
82  packed_load_addr.allocate(pb, FMT(annotation_prefix, " packed_load_addr"));
83  compute_packed_load_addr.reset(new bar_gadget<FieldT>(
84  pb,
85  prev_pc_val,
86  FieldT(2),
87  next_pc_addr,
88  FieldT::one(),
89  packed_load_addr,
90  FMT(annotation_prefix, " compute_packed_load_addr")));
91 
92  /*
93  packed_ls_addr = x0 * packed_load_addr + (1-x0) * packed_store_addr
94  packed_ls_addr ~ ls_addr
95  */
96  packed_ls_addr.allocate(pb, FMT(annotation_prefix, " packed_ls_addr"));
97  pack_ls_addr.reset(new packing_gadget<FieldT>(
98  pb, ls_addr, packed_ls_addr, " pack_ls_addr"));
99 
100  /* packed_store_val = prev_state_bits + prev_pc_addr */
101  packed_store_val.allocate(pb, FMT(annotation_prefix, " packed_store_val"));
102  compute_packed_store_val.reset(new bar_gadget<FieldT>(
103  pb,
104  prev_state,
105  FieldT::one(),
106  prev_pc_addr,
107  FieldT::one(),
108  packed_store_val,
109  FMT(annotation_prefix, " compute_packed_store_val")));
110 
111  /*
112  packed_ls_next_val = x0 * packed_ls_prev_val + (1-x0) * packed_store_val
113  packed_ls_next_val ~ ls_next_val
114  */
115  packed_ls_prev_val.allocate(
116  pb, FMT(annotation_prefix, " packed_ls_prev_val"));
117  pack_ls_prev_val.reset(new packing_gadget<FieldT>(
118  this->pb,
119  ls_prev_val,
120  packed_ls_prev_val,
121  FMT(annotation_prefix, " pack_ls_prev_val")));
122  packed_ls_next_val.allocate(
123  pb, FMT(annotation_prefix, " packed_ls_next_val"));
124  pack_ls_next_val.reset(new packing_gadget<FieldT>(
125  this->pb,
126  ls_next_val,
127  packed_ls_next_val,
128  FMT(annotation_prefix, " pack_ls_next_val")));
129 
130  /*
131  packed_next_state = x0 * packed_ls_prev_val + (1-x0) * packed_prev_state
132  packed_next_state ~ next_state
133  packed_prev_state ~ prev_state
134  */
135  packed_prev_state.allocate(
136  pb, FMT(annotation_prefix, " packed_prev_state"));
137  pack_prev_state.reset(new packing_gadget<FieldT>(
138  pb, prev_state, packed_prev_state, " pack_prev_state"));
139 
140  packed_next_state.allocate(
141  pb, FMT(annotation_prefix, " packed_next_state"));
142  pack_next_state.reset(new packing_gadget<FieldT>(
143  pb, next_state, packed_next_state, " pack_next_state"));
144 
145  /* next_has_accepted = 1 */
146 }
147 
148 template<typename FieldT>
149 void fooram_cpu_checker<FieldT>::generate_r1cs_constraints()
150 {
151  /* packed_next_pc_addr = prev_pc_addr + one_as_addr */
152  pack_next_pc_addr->generate_r1cs_constraints(false);
153  increment_pc->generate_r1cs_constraints();
154 
155  /* packed_store_addr = prev_pc_addr + prev_pc_val */
156  compute_packed_store_addr->generate_r1cs_constraints();
157 
158  /* packed_load_addr = 2 * x + next_pc_addr */
159  compute_packed_load_addr->generate_r1cs_constraints();
160 
161  /*
162  packed_ls_addr = x0 * packed_load_addr + (1-x0) * packed_store_addr
163  packed_ls_addr - packed_store_addr = x0 * (packed_load_addr -
164  packed_store_addr) packed_ls_addr ~ ls_addr
165  */
166  pack_ls_addr->generate_r1cs_constraints(false);
167  this->pb.add_r1cs_constraint(
168  r1cs_constraint<FieldT>(
169  prev_pc_val[0],
170  packed_load_addr - packed_store_addr,
171  packed_ls_addr - packed_store_addr),
172  FMT(this->annotation_prefix, " compute_ls_addr_packed"));
173 
174  /* packed_store_val = prev_state_bits + prev_pc_addr */
175  compute_packed_store_val->generate_r1cs_constraints();
176 
177  /*
178  packed_ls_next_val = x0 * packed_ls_prev_val + (1-x0) * packed_store_val
179  packed_ls_next_val - packed_store_val = x0 * (packed_ls_prev_val -
180  packed_store_val) packed_ls_next_val ~ ls_next_val
181  */
182  pack_ls_prev_val->generate_r1cs_constraints(false);
183  pack_ls_next_val->generate_r1cs_constraints(false);
184  this->pb.add_r1cs_constraint(
185  r1cs_constraint<FieldT>(
186  prev_pc_val[0],
187  packed_ls_prev_val - packed_store_val,
188  packed_ls_next_val - packed_store_val),
189  FMT(this->annotation_prefix, " compute_packed_ls_next_val"));
190 
191  /*
192  packed_next_state = x0 * packed_ls_prev_val + (1-x0) * packed_prev_state
193  packed_next_state - packed_prev_state = x0 * (packed_ls_prev_val -
194  packed_prev_state) packed_next_state ~ next_state packed_prev_state ~
195  prev_state
196  */
197  pack_prev_state->generate_r1cs_constraints(false);
198  pack_next_state->generate_r1cs_constraints(false);
199  this->pb.add_r1cs_constraint(
200  r1cs_constraint<FieldT>(
201  prev_pc_val[0],
202  packed_ls_prev_val - packed_prev_state,
203  packed_next_state - packed_prev_state),
204  FMT(this->annotation_prefix, " compute_packed_next_state"));
205 
206  /* next_has_accepted = 1 */
207  this->pb.add_r1cs_constraint(
208  r1cs_constraint<FieldT>(1, next_has_accepted, 1),
209  FMT(this->annotation_prefix, " always_accepted"));
210 }
211 
212 template<typename FieldT>
213 void fooram_cpu_checker<FieldT>::generate_r1cs_witness_address()
214 {
215  one_as_addr.evaluate(this->pb);
216 
217  /* packed_next_pc_addr = prev_pc_addr + one_as_addr */
218  increment_pc->generate_r1cs_witness();
219  pack_next_pc_addr->generate_r1cs_witness_from_packed();
220 
221  /* packed_store_addr = prev_pc_addr + prev_pc_val */
222  compute_packed_store_addr->generate_r1cs_witness();
223 
224  /* packed_load_addr = 2 * x + next_pc_addr */
225  compute_packed_load_addr->generate_r1cs_witness();
226 
227  /*
228  packed_ls_addr = x0 * packed_load_addr + (1-x0) * packed_store_addr
229  packed_ls_addr - packed_store_addr = x0 * (packed_load_addr -
230  packed_store_addr) packed_ls_addr ~ ls_addr
231  */
232  this->pb.val(packed_ls_addr) =
233  (this->pb.val(prev_pc_val[0]) * this->pb.val(packed_load_addr) +
234  (FieldT::one() - this->pb.val(prev_pc_val[0])) *
235  this->pb.val(packed_store_addr));
236  pack_ls_addr->generate_r1cs_witness_from_packed();
237 }
238 
239 template<typename FieldT>
240 void fooram_cpu_checker<FieldT>::generate_r1cs_witness_other(
241  fooram_input_tape_iterator &aux_it,
242  const fooram_input_tape_iterator &aux_end)
243 {
244  /* fooram memory contents do not depend on program/input. */
245  libff::UNUSED(aux_it, aux_end);
246  /* packed_store_val = prev_state_bits + prev_pc_addr */
247  compute_packed_store_val->generate_r1cs_witness();
248 
249  /*
250  packed_ls_next_val = x0 * packed_ls_prev_val + (1-x0) * packed_store_val
251  packed_ls_next_val - packed_store_val = x0 * (packed_ls_prev_val -
252  packed_store_val) packed_ls_next_val ~ ls_next_val
253  */
254  pack_ls_prev_val->generate_r1cs_witness_from_bits();
255  this->pb.val(packed_ls_next_val) =
256  (this->pb.val(prev_pc_val[0]) * this->pb.val(packed_ls_prev_val) +
257  (FieldT::one() - this->pb.val(prev_pc_val[0])) *
258  this->pb.val(packed_store_val));
259  pack_ls_next_val->generate_r1cs_witness_from_packed();
260 
261  /*
262  packed_next_state = x0 * packed_ls_prev_val + (1-x0) * packed_prev_state
263  packed_next_state - packed_prev_state = x0 * (packed_ls_prev_val -
264  packed_prev_state) packed_next_state ~ next_state packed_prev_state ~
265  prev_state
266  */
267  pack_prev_state->generate_r1cs_witness_from_bits();
268  this->pb.val(packed_next_state) =
269  (this->pb.val(prev_pc_val[0]) * this->pb.val(packed_ls_prev_val) +
270  (FieldT::one() - this->pb.val(prev_pc_val[0])) *
271  this->pb.val(packed_prev_state));
272  pack_next_state->generate_r1cs_witness_from_packed();
273 
274  /* next_has_accepted = 1 */
275  this->pb.val(next_has_accepted) = FieldT::one();
276 }
277 
278 template<typename FieldT> void fooram_cpu_checker<FieldT>::dump() const
279 {
280  printf("packed_store_addr: ");
281  this->pb.val(packed_store_addr).print();
282  printf("packed_load_addr: ");
283  this->pb.val(packed_load_addr).print();
284  printf("packed_ls_addr: ");
285  this->pb.val(packed_ls_addr).print();
286  printf("packed_store_val: ");
287  this->pb.val(packed_store_val).print();
288  printf("packed_ls_next_val: ");
289  this->pb.val(packed_ls_next_val).print();
290  printf("packed_next_state: ");
291  this->pb.val(packed_next_state).print();
292 }
293 
294 } // namespace libsnark
295 
296 #endif // FOORAM_CPU_CHECKER_TCC