2 *****************************************************************************
4 Implementation of interfaces for memory_checker_gadget.
6 See memory_checker_gadget.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 MEMORY_CHECKER_GADGET_TCC_
15 #define MEMORY_CHECKER_GADGET_TCC_
20 template<typename ramT>
21 memory_checker_gadget<ramT>::memory_checker_gadget(
22 ram_protoboard<ramT> &pb,
23 const size_t timestamp_size,
24 const memory_line_variable_gadget<ramT> &line1,
25 const memory_line_variable_gadget<ramT> &line2,
26 const std::string &annotation_prefix)
27 : ram_gadget_base<ramT>(pb, annotation_prefix), line1(line1), line2(line2)
29 /* compare the two timestamps */
30 timestamps_leq.allocate(
31 pb, FMT(this->annotation_prefix, " timestamps_leq"));
32 timestamps_less.allocate(
33 pb, FMT(this->annotation_prefix, " timestamps_less"));
34 compare_timestamps.reset(new comparison_gadget<FieldT>(
37 line1.timestamp->packed,
38 line2.timestamp->packed,
41 FMT(this->annotation_prefix, " compare_ts")));
43 /* compare the two addresses */
44 const size_t address_size = pb.ap.address_size();
45 addresses_eq.allocate(pb, FMT(this->annotation_prefix, " addresses_eq"));
46 addresses_leq.allocate(pb, FMT(this->annotation_prefix, " addresses_leq"));
47 addresses_less.allocate(
48 pb, FMT(this->annotation_prefix, " addresses_less"));
49 compare_addresses.reset(new comparison_gadget<FieldT>(
52 line1.address->packed,
53 line2.address->packed,
56 FMT(this->annotation_prefix, " compare_addresses")));
59 Add variables that will contain flags representing the following
61 - "line1.contents_after = line2.contents_before" (to check that contents
62 do not change between instructions);
63 - "line2.contents_before = 0" (for the first access at an address); and
64 - "line2.timestamp = 0" (for wrap-around checks to ensure only one 'cycle'
67 More precisely, each of the above flags is "loose" (i.e., it equals 0 if
68 the relation holds, but can be either 0 or 1 if the relation does not
71 loose_contents_after1_equals_contents_before2.allocate(
73 FMT(this->annotation_prefix,
74 " loose_contents_after1_equals_contents_before2"));
75 loose_contents_before2_equals_zero.allocate(
77 FMT(this->annotation_prefix, " loose_contents_before2_equals_zero"));
78 loose_timestamp2_is_zero.allocate(
79 pb, FMT(this->annotation_prefix, " loose_timestamp2_is_zero"));
82 template<typename ramT>
83 void memory_checker_gadget<ramT>::generate_r1cs_constraints()
85 /* compare the two timestamps */
86 compare_timestamps->generate_r1cs_constraints();
88 /* compare the two addresses */
89 compare_addresses->generate_r1cs_constraints();
90 this->pb.add_r1cs_constraint(
91 r1cs_constraint<FieldT>(
92 addresses_leq, 1 - addresses_less, addresses_eq),
93 FMT(this->annotation_prefix, " addresses_eq"));
96 Add constraints for the following three flags:
97 - loose_contents_after1_equals_contents_before2;
98 - loose_contents_before2_equals_zero;
99 - loose_timestamp2_is_zero.
101 this->pb.add_r1cs_constraint(
102 r1cs_constraint<FieldT>(
103 loose_contents_after1_equals_contents_before2,
104 line1.contents_after->packed - line2.contents_before->packed,
106 FMT(this->annotation_prefix,
107 " loose_contents_after1_equals_contents_before2"));
108 generate_boolean_r1cs_constraint<FieldT>(
110 loose_contents_after1_equals_contents_before2,
111 FMT(this->annotation_prefix,
112 " loose_contents_after1_equals_contents_before2"));
114 this->pb.add_r1cs_constraint(
115 r1cs_constraint<FieldT>(
116 loose_contents_before2_equals_zero,
117 line2.contents_before->packed,
119 FMT(this->annotation_prefix, " loose_contents_before2_equals_zero"));
120 generate_boolean_r1cs_constraint<FieldT>(
122 loose_contents_before2_equals_zero,
123 FMT(this->annotation_prefix, " loose_contents_before2_equals_zero"));
125 this->pb.add_r1cs_constraint(
126 r1cs_constraint<FieldT>(
127 loose_timestamp2_is_zero, line2.timestamp->packed, 0),
128 FMT(this->annotation_prefix, " loose_timestamp2_is_zero"));
129 generate_boolean_r1cs_constraint<FieldT>(
131 loose_timestamp2_is_zero,
132 FMT(this->annotation_prefix, " loose_timestamp2_is_zero"));
135 The three cases that need to be checked are:
137 line1.address = line2.address => line1.contents_after =
138 line2.contents_before (i.e. contents do not change between accesses to the
141 line1.address < line2.address => line2.contents_before = 0
142 (i.e. access to new address has the "before" value set to 0)
144 line1.address > line2.address => line2.timestamp = 0
145 (i.e. there is only one cycle with non-decreasing addresses, except
146 for the case where we go back to a unique pre-set timestamp; we choose
147 timestamp 0 to be the one that touches address 0)
149 As usual, we implement "A => B" as "NOT (A AND (NOT B))".
151 this->pb.add_r1cs_constraint(
152 r1cs_constraint<FieldT>(
153 addresses_eq, 1 - loose_contents_after1_equals_contents_before2, 0),
154 FMT(this->annotation_prefix,
155 " memory_retains_contents_between_accesses"));
156 this->pb.add_r1cs_constraint(
157 r1cs_constraint<FieldT>(
158 addresses_less, 1 - loose_contents_before2_equals_zero, 0),
159 FMT(this->annotation_prefix, " new_address_starts_at_zero"));
160 this->pb.add_r1cs_constraint(
161 r1cs_constraint<FieldT>(
162 1 - addresses_leq, 1 - loose_timestamp2_is_zero, 0),
163 FMT(this->annotation_prefix, " only_one_cycle"));
166 template<typename ramT>
167 void memory_checker_gadget<ramT>::generate_r1cs_witness()
169 /* compare the two addresses */
170 compare_addresses->generate_r1cs_witness();
171 this->pb.val(addresses_eq) = this->pb.val(addresses_leq) *
172 (FieldT::one() - this->pb.val(addresses_less));
174 /* compare the two timestamps */
175 compare_timestamps->generate_r1cs_witness();
178 compare the values of:
179 - loose_contents_after1_equals_contents_before2;
180 - loose_contents_before2_equals_zero;
181 - loose_timestamp2_is_zero.
183 this->pb.val(loose_contents_after1_equals_contents_before2) =
184 (this->pb.val(line1.contents_after->packed) ==
185 this->pb.val(line2.contents_before->packed))
188 this->pb.val(loose_contents_before2_equals_zero) =
189 this->pb.val(line2.contents_before->packed).is_zero() ? FieldT::one()
191 this->pb.val(loose_timestamp2_is_zero) =
192 (this->pb.val(line2.timestamp->packed) == FieldT::zero()
197 } // namespace libsnark
199 #endif // MEMORY_CHECKER_GADGET_TCC_