Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
blake2s.tcc
Go to the documentation of this file.
1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
2 //
3 // SPDX-License-Identifier: LGPL-3.0+
4 
5 #ifndef __ZETH_CIRCUITS_BLAKE2S_TCC__
6 #define __ZETH_CIRCUITS_BLAKE2S_TCC__
7 
8 #include "libzeth/circuits/blake2s/blake2s.hpp"
9 
10 namespace libzeth
11 {
12 
13 static const size_t BYTE_LEN = 8;
14 
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)
23  , input(input)
24  , output(output)
25 {
26  size_t nb_blocks = libff::div_ceil(input.bits.size(), BLAKE2s_block_size);
27 
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);
33 
34  libsnark::block_variable<FieldT> temp_block(
35  pb,
36  BLAKE2s_block_size,
37  FMT(this->annotation_prefix, " block_%zu", i));
38  block.emplace_back(temp_block);
39  }
40 
41  for (size_t i = 0; i < nb_blocks - 1; i++) {
42  BLAKE2sC_vector.emplace_back(BLAKE2s_256_comp<FieldT>(
43  pb,
44  h[i],
45  block[i],
46  h[i + 1],
47  FMT(this->annotation_prefix, " BLAKE2sC_%zu", i)));
48  }
49  BLAKE2sC_vector.emplace_back(BLAKE2s_256_comp<FieldT>(
50  pb,
51  h[nb_blocks - 1],
52  block[nb_blocks - 1],
53  output,
54  FMT(this->annotation_prefix, " BLAKE2sC_%zu", nb_blocks - 1)));
55 };
56 
57 template<typename FieldT>
58 void BLAKE2s_256<FieldT>::generate_r1cs_constraints(
59  const bool ensure_output_bitness)
60 {
61  for (auto &gadget : BLAKE2sC_vector) {
62  gadget.generate_r1cs_constraints(ensure_output_bitness);
63  }
64 };
65 
66 template<typename FieldT> void BLAKE2s_256<FieldT>::generate_r1cs_witness()
67 {
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))
77 
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]));
82  }
83 
84  // [SANITY CHECK] Pad if necessary (if input_size % BLAKE2s_block_size != 0)
85  size_t to_pad = input_size % BLAKE2s_block_size;
86  if (to_pad != 0) {
87  for (size_t i = 0; i < BLAKE2s_block_size - to_pad; i++) {
88  padded_input.push_back(FieldT("0"));
89  }
90  }
91 
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);
97  }
98 
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());
106  }
107  h[0].bits.fill_with_bits(this->pb, h_bits);
108 
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);
112  }
113  BLAKE2sC_vector[nb_blocks - 1].generate_r1cs_witness(
114  libff::div_ceil(input_size, BYTE_LEN), true);
115 };
116 
117 template<typename FieldT> constexpr size_t BLAKE2s_256<FieldT>::get_digest_len()
118 {
119  return BLAKE2s_digest_size;
120 }
121 
122 template<typename FieldT> constexpr size_t BLAKE2s_256<FieldT>::get_block_len()
123 {
124  return BLAKE2s_block_size;
125 }
126 
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)
135 {
136  libff::UNUSED(ensure_output_bitness);
137  return 21472;
138 }
139 
140 template<typename FieldT>
141 libff::bit_vector BLAKE2s_256<FieldT>::get_hash(const libff::bit_vector &input)
142 {
143  libsnark::protoboard<FieldT> pb;
144 
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");
151 
152  input_block.generate_r1cs_witness(input);
153  blake2s_hasher.generate_r1cs_witness();
154 
155  return output_variable.get_digest();
156 }
157 
158 } // namespace libzeth
159 
160 #endif // __ZETH_CIRCUITS_BLAKE2S_TCC__