2 *****************************************************************************
4 Implementation of interfaces for auxiliary gadgets for the SHA256 gadget.
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 SHA256_AUX_TCC_
15 #define SHA256_AUX_TCC_
20 template<typename FieldT>
21 lastbits_gadget<FieldT>::lastbits_gadget(
22 protoboard<FieldT> &pb,
23 const pb_variable<FieldT> &X,
25 const pb_variable<FieldT> &result,
26 const pb_linear_combination_array<FieldT> &result_bits,
27 const std::string &annotation_prefix)
28 : gadget<FieldT>(pb, annotation_prefix)
32 , result_bits(result_bits)
34 full_bits = result_bits;
35 for (size_t i = result_bits.size(); i < X_bits; ++i) {
36 pb_variable<FieldT> full_bits_overflow;
37 full_bits_overflow.allocate(
38 pb, FMT(this->annotation_prefix, " full_bits_%zu", i));
39 full_bits.emplace_back(full_bits_overflow);
42 unpack_bits.reset(new packing_gadget<FieldT>(
43 pb, full_bits, X, FMT(this->annotation_prefix, " unpack_bits")));
44 pack_result.reset(new packing_gadget<FieldT>(
45 pb, result_bits, result, FMT(this->annotation_prefix, " pack_result")));
48 template<typename FieldT>
49 void lastbits_gadget<FieldT>::generate_r1cs_constraints()
51 unpack_bits->generate_r1cs_constraints(true);
52 pack_result->generate_r1cs_constraints(false);
55 template<typename FieldT> void lastbits_gadget<FieldT>::generate_r1cs_witness()
57 unpack_bits->generate_r1cs_witness_from_packed();
58 pack_result->generate_r1cs_witness_from_bits();
61 template<typename FieldT>
62 XOR3_gadget<FieldT>::XOR3_gadget(
63 protoboard<FieldT> &pb,
64 const pb_linear_combination<FieldT> &A,
65 const pb_linear_combination<FieldT> &B,
66 const pb_linear_combination<FieldT> &C,
67 const bool assume_C_is_zero,
68 const pb_linear_combination<FieldT> &out,
69 const std::string &annotation_prefix)
70 : gadget<FieldT>(pb, annotation_prefix)
74 , assume_C_is_zero(assume_C_is_zero)
77 if (!assume_C_is_zero) {
78 tmp.allocate(pb, FMT(this->annotation_prefix, " tmp"));
82 template<typename FieldT> void XOR3_gadget<FieldT>::generate_r1cs_constraints()
85 tmp = A + B - 2AB i.e. tmp = A xor B
86 out = tmp + C - 2tmp C i.e. out = tmp xor C
88 if (assume_C_is_zero) {
89 this->pb.add_r1cs_constraint(
90 r1cs_constraint<FieldT>(2 * A, B, A + B - out),
91 FMT(this->annotation_prefix, " implicit_tmp_equals_out"));
93 this->pb.add_r1cs_constraint(
94 r1cs_constraint<FieldT>(2 * A, B, A + B - tmp),
95 FMT(this->annotation_prefix, " tmp"));
96 this->pb.add_r1cs_constraint(
97 r1cs_constraint<FieldT>(2 * tmp, C, tmp + C - out),
98 FMT(this->annotation_prefix, " out"));
102 template<typename FieldT> void XOR3_gadget<FieldT>::generate_r1cs_witness()
104 if (assume_C_is_zero) {
105 this->pb.lc_val(out) =
106 this->pb.lc_val(A) + this->pb.lc_val(B) -
107 FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B);
109 this->pb.val(tmp) = this->pb.lc_val(A) + this->pb.lc_val(B) -
110 FieldT(2) * this->pb.lc_val(A) * this->pb.lc_val(B);
111 this->pb.lc_val(out) =
112 this->pb.val(tmp) + this->pb.lc_val(C) -
113 FieldT(2) * this->pb.val(tmp) * this->pb.lc_val(C);
117 #define SHA256_GADGET_ROTR(A, i, k) A[((i) + (k)) % 32]
119 /* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
120 template<typename FieldT>
121 small_sigma_gadget<FieldT>::small_sigma_gadget(
122 protoboard<FieldT> &pb,
123 const pb_variable_array<FieldT> &W,
124 const pb_variable<FieldT> &result,
128 const std::string &annotation_prefix)
129 : gadget<FieldT>(pb, annotation_prefix), W(W), result(result)
131 result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
132 compute_bits.resize(32);
133 for (size_t i = 0; i < 32; ++i) {
134 compute_bits[i].reset(new XOR3_gadget<FieldT>(
136 SHA256_GADGET_ROTR(W, i, rot1),
137 SHA256_GADGET_ROTR(W, i, rot2),
138 (i + shift < 32 ? W[i + shift] : ONE),
141 FMT(this->annotation_prefix, " compute_bits_%zu", i)));
143 pack_result.reset(new packing_gadget<FieldT>(
144 pb, result_bits, result, FMT(this->annotation_prefix, " pack_result")));
147 template<typename FieldT>
148 void small_sigma_gadget<FieldT>::generate_r1cs_constraints()
150 for (size_t i = 0; i < 32; ++i) {
151 compute_bits[i]->generate_r1cs_constraints();
154 pack_result->generate_r1cs_constraints(false);
157 template<typename FieldT>
158 void small_sigma_gadget<FieldT>::generate_r1cs_witness()
160 for (size_t i = 0; i < 32; ++i) {
161 compute_bits[i]->generate_r1cs_witness();
164 pack_result->generate_r1cs_witness_from_bits();
167 template<typename FieldT>
168 big_sigma_gadget<FieldT>::big_sigma_gadget(
169 protoboard<FieldT> &pb,
170 const pb_linear_combination_array<FieldT> &W,
171 const pb_variable<FieldT> &result,
175 const std::string &annotation_prefix)
176 : gadget<FieldT>(pb, annotation_prefix), W(W), result(result)
178 result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
179 compute_bits.resize(32);
180 for (size_t i = 0; i < 32; ++i) {
181 compute_bits[i].reset(new XOR3_gadget<FieldT>(
183 SHA256_GADGET_ROTR(W, i, rot1),
184 SHA256_GADGET_ROTR(W, i, rot2),
185 SHA256_GADGET_ROTR(W, i, rot3),
188 FMT(this->annotation_prefix, " compute_bits_%zu", i)));
191 pack_result.reset(new packing_gadget<FieldT>(
192 pb, result_bits, result, FMT(this->annotation_prefix, " pack_result")));
195 template<typename FieldT>
196 void big_sigma_gadget<FieldT>::generate_r1cs_constraints()
198 for (size_t i = 0; i < 32; ++i) {
199 compute_bits[i]->generate_r1cs_constraints();
202 pack_result->generate_r1cs_constraints(false);
205 template<typename FieldT> void big_sigma_gadget<FieldT>::generate_r1cs_witness()
207 for (size_t i = 0; i < 32; ++i) {
208 compute_bits[i]->generate_r1cs_witness();
211 pack_result->generate_r1cs_witness_from_bits();
214 /* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
215 template<typename FieldT>
216 choice_gadget<FieldT>::choice_gadget(
217 protoboard<FieldT> &pb,
218 const pb_linear_combination_array<FieldT> &X,
219 const pb_linear_combination_array<FieldT> &Y,
220 const pb_linear_combination_array<FieldT> &Z,
221 const pb_variable<FieldT> &result,
222 const std::string &annotation_prefix)
223 : gadget<FieldT>(pb, annotation_prefix), X(X), Y(Y), Z(Z), result(result)
225 result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
226 pack_result.reset(new packing_gadget<FieldT>(
227 pb, result_bits, result, FMT(this->annotation_prefix, " result")));
230 template<typename FieldT>
231 void choice_gadget<FieldT>::generate_r1cs_constraints()
233 for (size_t i = 0; i < 32; ++i) {
235 result = x * y + (1-x) * z
236 result - z = x * (y - z)
238 this->pb.add_r1cs_constraint(
239 r1cs_constraint<FieldT>(X[i], Y[i] - Z[i], result_bits[i] - Z[i]),
240 FMT(this->annotation_prefix, " result_bits_%zu", i));
242 pack_result->generate_r1cs_constraints(false);
245 template<typename FieldT> void choice_gadget<FieldT>::generate_r1cs_witness()
247 for (size_t i = 0; i < 32; ++i) {
248 this->pb.val(result_bits[i]) =
249 this->pb.lc_val(X[i]) * this->pb.lc_val(Y[i]) +
250 (FieldT::one() - this->pb.lc_val(X[i])) * this->pb.lc_val(Z[i]);
252 pack_result->generate_r1cs_witness_from_bits();
255 /* Page 10 of http://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf */
256 template<typename FieldT>
257 majority_gadget<FieldT>::majority_gadget(
258 protoboard<FieldT> &pb,
259 const pb_linear_combination_array<FieldT> &X,
260 const pb_linear_combination_array<FieldT> &Y,
261 const pb_linear_combination_array<FieldT> &Z,
262 const pb_variable<FieldT> &result,
263 const std::string &annotation_prefix)
264 : gadget<FieldT>(pb, annotation_prefix), X(X), Y(Y), Z(Z), result(result)
266 result_bits.allocate(pb, 32, FMT(this->annotation_prefix, " result_bits"));
267 pack_result.reset(new packing_gadget<FieldT>(
268 pb, result_bits, result, FMT(this->annotation_prefix, " result")));
271 template<typename FieldT>
272 void majority_gadget<FieldT>::generate_r1cs_constraints()
274 for (size_t i = 0; i < 32; ++i) {
276 2*result + aux = x + y + z
278 aux = x + y + z - 2*result
280 generate_boolean_r1cs_constraint<FieldT>(
283 FMT(this->annotation_prefix, " result_%zu", i));
284 this->pb.add_r1cs_constraint(
285 r1cs_constraint<FieldT>(
286 X[i] + Y[i] + Z[i] - 2 * result_bits[i],
287 1 - (X[i] + Y[i] + Z[i] - 2 * result_bits[i]),
289 FMT(this->annotation_prefix, " result_bits_%zu", i));
291 pack_result->generate_r1cs_constraints(false);
294 template<typename FieldT> void majority_gadget<FieldT>::generate_r1cs_witness()
296 for (size_t i = 0; i < 32; ++i) {
297 const long v = (this->pb.lc_val(X[i]) + this->pb.lc_val(Y[i]) +
298 this->pb.lc_val(Z[i]))
300 this->pb.val(result_bits[i]) = FieldT(v / 2);
303 pack_result->generate_r1cs_witness_from_bits();
306 } // namespace libsnark
308 #endif // SHA256_AUX_TCC_