2 *****************************************************************************
4 Implementation of interfaces for the FOORAM CPU checker gadget.
6 See fooram_cpu_checker.hpp .
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 *****************************************************************************/
14 #ifndef FOORAM_CPU_CHECKER_TCC_
15 #define FOORAM_CPU_CHECKER_TCC_
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)
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)
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>(
51 FMT(annotation_prefix, " pack_next_pc_addr")));
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);
59 /* packed_next_pc_addr = prev_pc_addr + one_as_addr */
60 increment_pc.reset(new bar_gadget<FieldT>(
67 FMT(annotation_prefix, " increment_pc")));
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>(
79 FMT(annotation_prefix, " compute_packed_store_addr")));
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>(
90 FMT(annotation_prefix, " compute_packed_load_addr")));
93 packed_ls_addr = x0 * packed_load_addr + (1-x0) * packed_store_addr
94 packed_ls_addr ~ ls_addr
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"));
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>(
109 FMT(annotation_prefix, " compute_packed_store_val")));
112 packed_ls_next_val = x0 * packed_ls_prev_val + (1-x0) * packed_store_val
113 packed_ls_next_val ~ ls_next_val
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>(
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>(
128 FMT(annotation_prefix, " pack_ls_next_val")));
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
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"));
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"));
145 /* next_has_accepted = 1 */
148 template<typename FieldT>
149 void fooram_cpu_checker<FieldT>::generate_r1cs_constraints()
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();
155 /* packed_store_addr = prev_pc_addr + prev_pc_val */
156 compute_packed_store_addr->generate_r1cs_constraints();
158 /* packed_load_addr = 2 * x + next_pc_addr */
159 compute_packed_load_addr->generate_r1cs_constraints();
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
166 pack_ls_addr->generate_r1cs_constraints(false);
167 this->pb.add_r1cs_constraint(
168 r1cs_constraint<FieldT>(
170 packed_load_addr - packed_store_addr,
171 packed_ls_addr - packed_store_addr),
172 FMT(this->annotation_prefix, " compute_ls_addr_packed"));
174 /* packed_store_val = prev_state_bits + prev_pc_addr */
175 compute_packed_store_val->generate_r1cs_constraints();
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
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>(
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"));
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 ~
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>(
202 packed_ls_prev_val - packed_prev_state,
203 packed_next_state - packed_prev_state),
204 FMT(this->annotation_prefix, " compute_packed_next_state"));
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"));
212 template<typename FieldT>
213 void fooram_cpu_checker<FieldT>::generate_r1cs_witness_address()
215 one_as_addr.evaluate(this->pb);
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();
221 /* packed_store_addr = prev_pc_addr + prev_pc_val */
222 compute_packed_store_addr->generate_r1cs_witness();
224 /* packed_load_addr = 2 * x + next_pc_addr */
225 compute_packed_load_addr->generate_r1cs_witness();
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
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();
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)
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();
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
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();
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 ~
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();
274 /* next_has_accepted = 1 */
275 this->pb.val(next_has_accepted) = FieldT::one();
278 template<typename FieldT> void fooram_cpu_checker<FieldT>::dump() const
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();
294 } // namespace libsnark
296 #endif // FOORAM_CPU_CHECKER_TCC