1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
3 // SPDX-License-Identifier: LGPL-3.0+
5 #ifndef __ZETH_CIRCUITS_BLAKE2S_TCC__
6 #define __ZETH_CIRCUITS_BLAKE2S_TCC__
8 #include "libzeth/circuits/blake2s/blake2s.hpp"
13 static const size_t BYTE_LEN = 8;
15 /// This gadget implements the interface of the HashT template
16 template<typename FieldT>
17 BLAKE2s_256<FieldT>::BLAKE2s_256(
18 libsnark::protoboard<FieldT> &pb,
19 const libsnark::block_variable<FieldT> &input,
20 const libsnark::digest_variable<FieldT> &output,
21 const std::string &annotation_prefix)
22 : libsnark::gadget<FieldT>(pb, annotation_prefix)
26 size_t nb_blocks = libff::div_ceil(input.bits.size(), BLAKE2s_block_size);
28 // Allocate and format the 16 input block variable
29 for (size_t i = 0; i < nb_blocks; i++) {
30 libsnark::digest_variable<FieldT> temp_digest(
31 pb, BLAKE2s_digest_size, FMT(this->annotation_prefix, " h_%zu", i));
32 h.emplace_back(temp_digest);
34 libsnark::block_variable<FieldT> temp_block(
37 FMT(this->annotation_prefix, " block_%zu", i));
38 block.emplace_back(temp_block);
41 for (size_t i = 0; i < nb_blocks - 1; i++) {
42 BLAKE2sC_vector.emplace_back(BLAKE2s_256_comp<FieldT>(
47 FMT(this->annotation_prefix, " BLAKE2sC_%zu", i)));
49 BLAKE2sC_vector.emplace_back(BLAKE2s_256_comp<FieldT>(
54 FMT(this->annotation_prefix, " BLAKE2sC_%zu", nb_blocks - 1)));
57 template<typename FieldT>
58 void BLAKE2s_256<FieldT>::generate_r1cs_constraints(
59 const bool ensure_output_bitness)
61 for (auto &gadget : BLAKE2sC_vector) {
62 gadget.generate_r1cs_constraints(ensure_output_bitness);
66 template<typename FieldT> void BLAKE2s_256<FieldT>::generate_r1cs_witness()
68 // Format two 256-bit long big endian inputs into one 512 long little endian
69 // input (with padding if necessary)
70 size_t input_size = input.bits.size();
71 size_t nb_blocks = libff::div_ceil(input_size, BLAKE2s_block_size);
72 // We do not use block_size because the value might not be entered
73 // (c.f. block_variable<FieldT>::block_variable(
74 // protoboard<FieldT> &pb,
75 // const std::vector<pb_variable_array<FieldT>> &parts,
76 // const std::string &annotation_prefix))
78 // Push the block variable in local variable to be padded
79 std::vector<FieldT> padded_input;
80 for (size_t i = 0; i < input_size; i++) {
81 padded_input.push_back(this->pb.val(input.bits[i]));
84 // [SANITY CHECK] Pad if necessary (if input_size % BLAKE2s_block_size != 0)
85 size_t to_pad = input_size % BLAKE2s_block_size;
87 for (size_t i = 0; i < BLAKE2s_block_size - to_pad; i++) {
88 padded_input.push_back(FieldT("0"));
92 for (size_t i = 0; i < nb_blocks; i++) {
93 std::vector<FieldT> temp_vector(
94 padded_input.begin() + BLAKE2s_block_size * i,
95 padded_input.begin() + BLAKE2s_block_size * (i + 1));
96 block[i].bits.fill_with_field_elements(this->pb, temp_vector);
99 // See: Appendix A.1 of https://blake2.net/blake2.pdf
100 std::vector<bool> h_bits;
101 for (size_t i = 0; i < 8; i++) {
102 bits<BLAKE2s_word_size> pb_swapped = parameter_block[i];
103 std::vector<bool> h_part =
104 bits_xor(pb_swapped, BLAKE2s_IV[i]).to_vector();
105 h_bits.insert(h_bits.end(), h_part.begin(), h_part.end());
107 h[0].bits.fill_with_bits(this->pb, h_bits);
109 for (size_t i = 0; i < nb_blocks - 1; i++) {
110 BLAKE2sC_vector[i].generate_r1cs_witness(
111 libff::div_ceil((i + 1) * BLAKE2s_block_size, BYTE_LEN), false);
113 BLAKE2sC_vector[nb_blocks - 1].generate_r1cs_witness(
114 libff::div_ceil(input_size, BYTE_LEN), true);
117 template<typename FieldT> constexpr size_t BLAKE2s_256<FieldT>::get_digest_len()
119 return BLAKE2s_digest_size;
122 template<typename FieldT> constexpr size_t BLAKE2s_256<FieldT>::get_block_len()
124 return BLAKE2s_block_size;
127 /// This function returns the number of gates necessary
128 /// to implement the compression function of blake2s
129 /// To obtain the number of gates for blake2s hash,
130 /// the output of the function must be multiplied by
131 /// the number of input blocks.
132 template<typename FieldT>
133 size_t BLAKE2s_256<FieldT>::expected_constraints(
134 const bool ensure_output_bitness)
136 libff::UNUSED(ensure_output_bitness);
140 template<typename FieldT>
141 libff::bit_vector BLAKE2s_256<FieldT>::get_hash(const libff::bit_vector &input)
143 libsnark::protoboard<FieldT> pb;
145 libsnark::block_variable<FieldT> input_block(
146 pb, input.size(), "input_block");
147 libsnark::digest_variable<FieldT> output_variable(
148 pb, BLAKE2s_digest_size, "output_variable");
149 BLAKE2s_256<FieldT> blake2s_hasher(
150 pb, input_block, output_variable, "blake2s_hasher_gadget");
152 input_block.generate_r1cs_witness(input);
153 blake2s_hasher.generate_r1cs_witness();
155 return output_variable.get_digest();
158 } // namespace libzeth
160 #endif // __ZETH_CIRCUITS_BLAKE2S_TCC__