1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
3 // SPDX-License-Identifier: LGPL-3.0+
5 #ifndef __ZETH_CIRCUITS_BLAKE2S_COMP_TCC__
6 #define __ZETH_CIRCUITS_BLAKE2S_COMP_TCC__
8 #include "libzeth/circuits/blake2s/blake2s_comp.hpp"
13 /// This gadget implements the interface of the HashT template
14 template<typename FieldT>
15 BLAKE2s_256_comp<FieldT>::BLAKE2s_256_comp(
16 libsnark::protoboard<FieldT> &pb,
17 const libsnark::digest_variable<FieldT> &h,
18 const libsnark::block_variable<FieldT> &input_block,
19 const libsnark::digest_variable<FieldT> &output,
20 const std::string &annotation_prefix)
21 : libsnark::gadget<FieldT>(pb, annotation_prefix)
23 , input_block(input_block)
26 // Allocate and format the 16 input block variable
27 for (size_t i = 0; i < BLAKE2s_word_number; i++) {
31 FMT(this->annotation_prefix, " block_%zu", i));
34 // Allocate the init state variables and output bytes (before swapping
35 // endianness and appending)
36 for (size_t i = 0; i < 8; i++) {
40 FMT(this->annotation_prefix, " h_%zu", i));
45 FMT(this->annotation_prefix, " out_temp_%zu", i));
47 output_bytes[i].allocate(
50 FMT(this->annotation_prefix, " output_byte_%zu", i));
53 // Allocate the state variables
54 for (size_t i = 0; i < rounds + 1; i++) {
55 for (size_t j = 0; j < BLAKE2s_word_number; j++) {
59 FMT(this->annotation_prefix, " v_%zu", i * rounds + j));
62 for (size_t i = 0; i < rounds; i++) {
63 for (size_t j = 0; j < BLAKE2s_word_number; j++) {
64 v_temp[i][j].allocate(
67 FMT(this->annotation_prefix, " v_temp_%zu", i * rounds + j));
71 // Set up the g_primitive gadgets used in the compression function
72 setup_mixing_gadgets();
75 template<typename FieldT>
76 void BLAKE2s_256_comp<FieldT>::generate_r1cs_constraints(
77 const bool ensure_output_bitness)
79 libff::UNUSED(ensure_output_bitness);
81 for (size_t i = 0; i < rounds; i++) {
82 for (auto &gadget : g_arrays[i]) {
83 gadget.generate_r1cs_constraints();
87 for (auto &gadget : xor_vector) {
88 gadget.generate_r1cs_constraints();
92 template<typename FieldT>
93 void BLAKE2s_256_comp<FieldT>::generate_r1cs_witness(
94 size_t len_byte_total, bool is_last_block)
96 // Format two 256-bit long big endian inputs into one 512 long little endian
97 // input (with padding if necessary)
98 size_t input_size = input_block.bits.size();
99 // We do not use block_size because the value might not be entered
100 // (c.f. block_variable<FieldT>::block_variable(
101 // protoboard<FieldT> &pb,
102 // const std::vector<pb_variable_array<FieldT>> &parts,
103 // const std::string &annotation_prefix))
105 // Push the block variable in local to be swapped
106 std::vector<FieldT> padded_input;
107 for (size_t i = 0; i < input_size; i++) {
108 padded_input.push_back(this->pb.val(input_block.bits[i]));
111 // [SANITY CHECK] Pad if necessary (if input_size < BLAKE2s_block_size)
112 for (size_t i = 0; i < BLAKE2s_block_size - input_size; i++) {
113 padded_input.push_back(FieldT("0"));
116 // Allocate and format the 16 input block variable
117 for (size_t i = 0; i < BLAKE2s_word_number; i++) {
118 std::vector<FieldT> temp_vector(
119 padded_input.begin() + BLAKE2s_word_size * i,
120 padded_input.begin() + BLAKE2s_word_size * (i + 1));
121 temp_vector = swap_byte_endianness(temp_vector);
122 block[i].fill_with_field_elements(this->pb, temp_vector);
125 BLAKE2s_256_comp<FieldT>::setup_h();
126 BLAKE2s_256_comp<FieldT>::setup_counter(len_byte_total);
127 BLAKE2s_256_comp<FieldT>::setup_v(is_last_block);
129 for (size_t i = 0; i < rounds; i++) {
130 for (auto &gadget : g_arrays[i]) {
131 gadget.generate_r1cs_witness();
135 // TODO: batch equality constraints (should save ~200 constraints (~1%))
137 for (auto &gadget : xor_vector) {
138 gadget.generate_r1cs_witness();
141 // Retrieve values, swap endianness of each bit32 and append them to get
143 std::vector<FieldT> output_conversion;
144 for (size_t i = 0; i < 8; i++) {
145 std::vector<FieldT> output_byte_value =
146 output_bytes[i].get_vals(this->pb);
148 // We swap to big endian if it is the last call.
150 output_byte_value = swap_byte_endianness(output_byte_value);
152 output_conversion.insert(
153 output_conversion.end(),
154 output_byte_value.begin(),
155 output_byte_value.end());
158 output.bits.fill_with_field_elements(this->pb, output_conversion);
161 template<typename FieldT> size_t BLAKE2s_256_comp<FieldT>::get_digest_len()
163 return BLAKE2s_digest_size;
166 template<typename FieldT> size_t BLAKE2s_256_comp<FieldT>::get_block_len()
168 return BLAKE2s_block_size;
171 template<typename FieldT>
172 size_t BLAKE2s_256_comp<FieldT>::expected_constraints(
173 const bool ensure_output_bitness)
175 libff::UNUSED(ensure_output_bitness);
177 // ~38.89% of sha256_ethereum
180 template<typename FieldT>
181 libff::bit_vector BLAKE2s_256_comp<FieldT>::get_hash(
182 const libff::bit_vector &input)
184 libsnark::protoboard<FieldT> pb;
186 libsnark::block_variable<FieldT> input_block(
187 pb, BLAKE2s_block_size, "input_block");
188 libsnark::digest_variable<FieldT> output_variable(
189 pb, BLAKE2s_digest_size, "output_variable");
190 BLAKE2s_256_comp<FieldT> blake2s_hasher(
191 pb, input_block, output_variable, "blake2s_hasher_gadget");
193 input_block.generate_r1cs_witness(input);
194 blake2s_hasher.generate_r1cs_witness();
196 return output_variable.get_digest();
199 } // namespace libzeth
201 #endif // __ZETH_CIRCUITS_BLAKE2S_COMP_TCC__