2 *****************************************************************************
4 Implementation of interfaces for top-level SHA256 gadgets.
6 See sha256_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 SHA256_GADGET_TCC_
15 #define SHA256_GADGET_TCC_
20 template<typename FieldT>
21 sha256_compression_function_gadget<FieldT>::sha256_compression_function_gadget(
22 protoboard<FieldT> &pb,
23 const pb_linear_combination_array<FieldT> &prev_output,
24 const pb_variable_array<FieldT> &new_block,
25 const digest_variable<FieldT> &output,
26 const std::string &annotation_prefix)
27 : gadget<FieldT>(pb, annotation_prefix)
28 , prev_output(prev_output)
29 , new_block(new_block)
32 /* message schedule and inputs for it */
33 packed_W.allocate(pb, 64, FMT(this->annotation_prefix, " packed_W"));
34 message_schedule.reset(new sha256_message_schedule_gadget<FieldT>(
38 FMT(this->annotation_prefix, " message_schedule")));
41 round_a.push_back(pb_linear_combination_array<FieldT>(
42 prev_output.rbegin() + 7 * 32, prev_output.rbegin() + 8 * 32));
43 round_b.push_back(pb_linear_combination_array<FieldT>(
44 prev_output.rbegin() + 6 * 32, prev_output.rbegin() + 7 * 32));
45 round_c.push_back(pb_linear_combination_array<FieldT>(
46 prev_output.rbegin() + 5 * 32, prev_output.rbegin() + 6 * 32));
47 round_d.push_back(pb_linear_combination_array<FieldT>(
48 prev_output.rbegin() + 4 * 32, prev_output.rbegin() + 5 * 32));
49 round_e.push_back(pb_linear_combination_array<FieldT>(
50 prev_output.rbegin() + 3 * 32, prev_output.rbegin() + 4 * 32));
51 round_f.push_back(pb_linear_combination_array<FieldT>(
52 prev_output.rbegin() + 2 * 32, prev_output.rbegin() + 3 * 32));
53 round_g.push_back(pb_linear_combination_array<FieldT>(
54 prev_output.rbegin() + 1 * 32, prev_output.rbegin() + 2 * 32));
55 round_h.push_back(pb_linear_combination_array<FieldT>(
56 prev_output.rbegin() + 0 * 32, prev_output.rbegin() + 1 * 32));
59 for (size_t i = 0; i < 64; ++i) {
60 round_h.push_back(round_g[i]);
61 round_g.push_back(round_f[i]);
62 round_f.push_back(round_e[i]);
63 round_d.push_back(round_c[i]);
64 round_c.push_back(round_b[i]);
65 round_b.push_back(round_a[i]);
67 pb_variable_array<FieldT> new_round_a_variables;
68 new_round_a_variables.allocate(
71 FMT(this->annotation_prefix, " new_round_a_variables_%zu", i + 1));
72 round_a.emplace_back(new_round_a_variables);
74 pb_variable_array<FieldT> new_round_e_variables;
75 new_round_e_variables.allocate(
78 FMT(this->annotation_prefix, " new_round_e_variables_%zu", i + 1));
79 round_e.emplace_back(new_round_e_variables);
81 round_functions.push_back(sha256_round_function_gadget<FieldT>(
95 FMT(this->annotation_prefix, " round_functions_%zu", i)));
99 unreduced_output.allocate(
100 pb, 8, FMT(this->annotation_prefix, " unreduced_output"));
101 reduced_output.allocate(
102 pb, 8, FMT(this->annotation_prefix, " reduced_output"));
103 for (size_t i = 0; i < 8; ++i) {
104 reduce_output.push_back(lastbits_gadget<FieldT>(
109 pb_variable_array<FieldT>(
110 output.bits.rbegin() + (7 - i) * 32,
111 output.bits.rbegin() + (8 - i) * 32),
112 FMT(this->annotation_prefix, " reduce_output_%zu", i)));
116 template<typename FieldT>
117 void sha256_compression_function_gadget<FieldT>::generate_r1cs_constraints()
119 message_schedule->generate_r1cs_constraints();
120 for (size_t i = 0; i < 64; ++i) {
121 round_functions[i].generate_r1cs_constraints();
124 for (size_t i = 0; i < 4; ++i) {
125 this->pb.add_r1cs_constraint(
126 r1cs_constraint<FieldT>(
128 round_functions[3 - i].packed_d +
129 round_functions[63 - i].packed_new_a,
130 unreduced_output[i]),
131 FMT(this->annotation_prefix, " unreduced_output_%zu", i));
133 this->pb.add_r1cs_constraint(
134 r1cs_constraint<FieldT>(
136 round_functions[3 - i].packed_h +
137 round_functions[63 - i].packed_new_e,
138 unreduced_output[4 + i]),
139 FMT(this->annotation_prefix, " unreduced_output_%zu", 4 + i));
142 for (size_t i = 0; i < 8; ++i) {
143 reduce_output[i].generate_r1cs_constraints();
147 template<typename FieldT>
148 void sha256_compression_function_gadget<FieldT>::generate_r1cs_witness()
150 message_schedule->generate_r1cs_witness();
154 for (size_t j = 0; j < 16; ++j) {
155 printf("%lx ", this->pb.val(packed_W[j]).as_ulong());
160 for (size_t i = 0; i < 64; ++i) {
161 round_functions[i].generate_r1cs_witness();
164 for (size_t i = 0; i < 4; ++i) {
165 this->pb.val(unreduced_output[i]) =
166 this->pb.val(round_functions[3 - i].packed_d) +
167 this->pb.val(round_functions[63 - i].packed_new_a);
168 this->pb.val(unreduced_output[4 + i]) =
169 this->pb.val(round_functions[3 - i].packed_h) +
170 this->pb.val(round_functions[63 - i].packed_new_e);
173 for (size_t i = 0; i < 8; ++i) {
174 reduce_output[i].generate_r1cs_witness();
179 for (size_t j = 0; j < 8; ++j) {
180 printf("%lx ", this->pb.val(reduced_output[j]).as_ulong());
186 template<typename FieldT>
187 sha256_two_to_one_hash_gadget<FieldT>::sha256_two_to_one_hash_gadget(
188 protoboard<FieldT> &pb,
189 const digest_variable<FieldT> &left,
190 const digest_variable<FieldT> &right,
191 const digest_variable<FieldT> &output,
192 const std::string &annotation_prefix)
193 : gadget<FieldT>(pb, annotation_prefix)
195 /* concatenate block = left || right */
196 pb_variable_array<FieldT> block;
197 block.insert(block.end(), left.bits.begin(), left.bits.end());
198 block.insert(block.end(), right.bits.begin(), right.bits.end());
200 /* compute the hash itself */
201 f.reset(new sha256_compression_function_gadget<FieldT>(
203 SHA256_default_IV<FieldT>(pb),
206 FMT(this->annotation_prefix, " f")));
209 template<typename FieldT>
210 sha256_two_to_one_hash_gadget<FieldT>::sha256_two_to_one_hash_gadget(
211 protoboard<FieldT> &pb,
212 const size_t block_length,
213 const block_variable<FieldT> &input_block,
214 const digest_variable<FieldT> &output,
215 const std::string &annotation_prefix)
216 : gadget<FieldT>(pb, annotation_prefix)
219 libff::UNUSED(block_length);
221 assert(block_length == SHA256_block_size);
222 assert(input_block.bits.size() == block_length);
223 f.reset(new sha256_compression_function_gadget<FieldT>(
225 SHA256_default_IV<FieldT>(pb),
228 FMT(this->annotation_prefix, " f")));
231 template<typename FieldT>
232 void sha256_two_to_one_hash_gadget<FieldT>::generate_r1cs_constraints(
233 const bool ensure_output_bitness)
235 libff::UNUSED(ensure_output_bitness);
236 f->generate_r1cs_constraints();
239 template<typename FieldT>
240 void sha256_two_to_one_hash_gadget<FieldT>::generate_r1cs_witness()
242 f->generate_r1cs_witness();
245 template<typename FieldT>
246 size_t sha256_two_to_one_hash_gadget<FieldT>::get_block_len()
248 return SHA256_block_size;
251 template<typename FieldT>
252 size_t sha256_two_to_one_hash_gadget<FieldT>::get_digest_len()
254 return SHA256_digest_size;
257 template<typename FieldT>
258 libff::bit_vector sha256_two_to_one_hash_gadget<FieldT>::get_hash(
259 const libff::bit_vector &input)
261 protoboard<FieldT> pb;
263 block_variable<FieldT> input_variable(pb, SHA256_block_size, "input");
264 digest_variable<FieldT> output_variable(pb, SHA256_digest_size, "output");
265 sha256_two_to_one_hash_gadget<FieldT> f(
266 pb, SHA256_block_size, input_variable, output_variable, "f");
268 input_variable.generate_r1cs_witness(input);
269 f.generate_r1cs_witness();
271 return output_variable.get_digest();
274 template<typename FieldT>
275 size_t sha256_two_to_one_hash_gadget<FieldT>::expected_constraints(
276 const bool ensure_output_bitness)
278 libff::UNUSED(ensure_output_bitness);
279 return 27280; /* hardcoded for now */
282 } // namespace libsnark
284 #endif // SHA256_GADGET_TCC_