Zeth - Zerocash on Ethereum  0.8
Reference implementation of the Zeth protocol by Clearmatics
blake2s_comp_setup.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_COMP_SETUP_TCC__
6 #define __ZETH_CIRCUITS_BLAKE2S_COMP_SETUP_TCC__
7 
8 #include "libzeth/circuits/blake2s/blake2s_comp.hpp"
9 
10 namespace libzeth
11 {
12 
13 namespace
14 {
15 
16 // Finalization flags. See Section 2.3 of https://blake2.net/blake2.pdf
17 // We do a single call to the compression function: the first block is the
18 // last. Thus, f0 is set to xFFFFFFFF
19 //
20 // Note:
21 // We use the workaround described here
22 // https://stackoverflow.com/questions/32912921/whats-wrong-with-this-inline-initialization-of-stdarray
23 // to initialize the const std::arrays
24 static const bits<BLAKE2s_word_size> flag_to_1{
25  1, 1, 1, 1, 1, 1, 1, 1, // FF
26  1, 1, 1, 1, 1, 1, 1, 1, // FF
27  1, 1, 1, 1, 1, 1, 1, 1, // FF
28  1, 1, 1, 1, 1, 1, 1, 1, // FF
29 };
30 
31 // See: Appendix A.1 of https://blake2.net/blake2.pdf for the specification
32 // of the permutations used in BLAKE2s
33 static const std::array<std::array<uint8_t, 16>, 10> sigma = {{
34  {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
35  {14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3},
36  {11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4},
37  {7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8},
38  {9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13},
39  {2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9},
40  {12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11},
41  {13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10},
42  {6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5},
43  {10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0},
44 }};
45 
46 } // namespace
47 
48 template<typename FieldT>
49 const std::array<bits<BLAKE2s_word_size>, 8>
50  BLAKE2s_256_comp<FieldT>::BLAKE2s_IV = {{
51  {
52  0, 1, 1, 0, 1, 0, 1, 0, // 6A
53  0, 0, 0, 0, 1, 0, 0, 1, // 09
54  1, 1, 1, 0, 0, 1, 1, 0, // E6
55  0, 1, 1, 0, 0, 1, 1, 1 // 67
56  },
57  {
58  1, 0, 1, 1, 1, 0, 1, 1, // BB
59  0, 1, 1, 0, 0, 1, 1, 1, // 67
60  1, 0, 1, 0, 1, 1, 1, 0, // AE
61  1, 0, 0, 0, 0, 1, 0, 1 // 85
62  },
63  {
64  0, 0, 1, 1, 1, 1, 0, 0, // 3C
65  0, 1, 1, 0, 1, 1, 1, 0, // 6E
66  1, 1, 1, 1, 0, 0, 1, 1, // F3
67  0, 1, 1, 1, 0, 0, 1, 0 // 72
68  },
69  {
70  1, 0, 1, 0, 0, 1, 0, 1, // A5
71  0, 1, 0, 0, 1, 1, 1, 1, // 4F
72  1, 1, 1, 1, 0, 1, 0, 1, // F5
73  0, 0, 1, 1, 1, 0, 1, 0 // 3A
74  },
75  {
76  0, 1, 0, 1, 0, 0, 0, 1, // 51
77  0, 0, 0, 0, 1, 1, 1, 0, // 0E
78  0, 1, 0, 1, 0, 0, 1, 0, // 52
79  0, 1, 1, 1, 1, 1, 1, 1 // 7F
80  },
81  {
82  1, 0, 0, 1, 1, 0, 1, 1, // 9B
83  0, 0, 0, 0, 0, 1, 0, 1, // 05
84  0, 1, 1, 0, 1, 0, 0, 0, // 68
85  1, 0, 0, 0, 1, 1, 0, 0 // 8C
86  },
87  {
88  0, 0, 0, 1, 1, 1, 1, 1, // 1F
89  1, 0, 0, 0, 0, 0, 1, 1, // 83
90  1, 1, 0, 1, 1, 0, 0, 1, // D9
91  1, 0, 1, 0, 1, 0, 1, 1 // AB
92  },
93  {
94  0, 1, 0, 1, 1, 0, 1, 1, // 5B
95  1, 1, 1, 0, 0, 0, 0, 0, // E0
96  1, 1, 0, 0, 1, 1, 0, 1, // CD
97  0, 0, 0, 1, 1, 0, 0, 1 // 19
98  },
99  }};
100 
101 template<typename FieldT> void BLAKE2s_256_comp<FieldT>::setup_h()
102 {
103  std::vector<bool> bits = h.get_digest();
104  // See: Appendix A.1 of https://blake2.net/blake2.pdf
105  for (size_t i = 0; i < 8; i++) {
106  std::vector<bool> temp_vector(
107  bits.begin() + BLAKE2s_word_size * i,
108  bits.begin() + BLAKE2s_word_size * (i + 1));
109  h_array[i].fill_with_bits(this->pb, temp_vector);
110  }
111 }
112 
113 template<typename FieldT>
114 void BLAKE2s_256_comp<FieldT>::setup_counter(size_t len_byte_total)
115 {
116  // len_byte_total represents the BYTE length all the input blocks
117  // compressed so far, up to 2^64 - 1 bytes for blake2s
118  std::vector<bool> length_bits = bit_vector_from_size_t_be(len_byte_total);
119  size_t bit_size = length_bits.size();
120  size_t padding = 64 - bit_size;
121 
122  // Initialize the low word of the offset
123  t[0] = {
124  0, 0, 0, 0, 0, 0, 0, 0, // 00
125  0, 0, 0, 0, 0, 0, 0, 0, // 00
126  0, 0, 0, 0, 0, 0, 0, 0, // 00
127  0, 0, 0, 0, 0, 0, 0, 0 // 00
128  };
129  for (size_t i = 0; int(i) < std::min(int(BLAKE2s_word_size), int(bit_size));
130  i++) {
131  t[0][BLAKE2s_word_size - i - 1] = length_bits[bit_size - i - 1];
132  }
133 
134  // Initialize the high word of the offset
135  t[1] = {
136  0, 0, 0, 0, 0, 0, 0, 0, // 00
137  0, 0, 0, 0, 0, 0, 0, 0, // 00
138  0, 0, 0, 0, 0, 0, 0, 0, // 00
139  0, 0, 0, 0, 0, 0, 0, 0 // 00
140  };
141  // If we hash more that 2^32 bytes, then set the high word of the offset
142  // accordingly
143  if (bit_size > BLAKE2s_word_size) {
144  for (size_t i = 0; i < bit_size - BLAKE2s_word_size; i++) {
145  t[1][padding + i] = length_bits[i];
146  }
147  }
148 }
149 
150 /// setup_v initializes the internal state matrix as documented
151 /// Appendix A.1 https://blake2.net/blake2.pdf
152 template<typename FieldT>
153 void BLAKE2s_256_comp<FieldT>::setup_v(bool is_last_block)
154 {
155  // [v_0, ..., v_7] = [h_0, ..., h_7]
156  for (size_t i = 0; i < 8; i++) {
157  v[0][i].fill_with_bits(this->pb, h_array[i].get_bits(this->pb));
158  }
159 
160  // [v_8, v_9, v_10, v_11] = [IV_0, IV_1, IV_2, IV_3]
161  for (size_t i = 8; i < 12; i++) {
162  BLAKE2s_IV[i - 8].fill_pb_variable_array(this->pb, v[0][i]);
163  }
164 
165  // v_12 = t0 XOR IV_4
166  bits32 temp_xored = bits_xor(BLAKE2s_IV[4], t[0]);
167  temp_xored.fill_pb_variable_array(this->pb, v[0][12]);
168 
169  // v_13 = t1 XOR IV_5
170  temp_xored = bits_xor(BLAKE2s_IV[5], t[1]);
171  temp_xored.fill_pb_variable_array(this->pb, v[0][13]);
172 
173  // v_14 = f0 XOR IV_6
174  if (is_last_block) {
175  temp_xored = bits_xor(BLAKE2s_IV[6], flag_to_1);
176  } else {
177  temp_xored = BLAKE2s_IV[6];
178  }
179  temp_xored.fill_pb_variable_array(this->pb, v[0][14]);
180 
181  // v_15 = f1 XOR IV_7
182  temp_xored = BLAKE2s_IV[7];
183  temp_xored.fill_pb_variable_array(this->pb, v[0][15]);
184 }
185 
186 template<typename FieldT> void BLAKE2s_256_comp<FieldT>::setup_mixing_gadgets()
187 {
188  // See: Section 3.2 of https://tools.ietf.org/html/rfc7693
189  for (size_t i = 0; i < rounds; i++) {
190  // Message word selection permutation for this round
191  std::array<uint8_t, 16> s = sigma[i % rounds];
192 
193  g_arrays[i].emplace_back(g_primitive<FieldT>(
194  this->pb,
195  v[i][0],
196  v[i][4],
197  v[i][8],
198  v[i][12],
199  block[s[0]],
200  block[s[1]],
201  v_temp[i][0],
202  v_temp[i][4],
203  v_temp[i][8],
204  v_temp[i][12],
205  FMT(this->annotation_prefix, " g_primitive_1_round_%zu", i)));
206 
207  g_arrays[i].emplace_back(g_primitive<FieldT>(
208  this->pb,
209  v[i][1],
210  v[i][5],
211  v[i][9],
212  v[i][13],
213  block[s[2]],
214  block[s[3]],
215  v_temp[i][1],
216  v_temp[i][5],
217  v_temp[i][9],
218  v_temp[i][13],
219  FMT(this->annotation_prefix, " g_primitive_2_round_%zu", i)));
220 
221  g_arrays[i].emplace_back(g_primitive<FieldT>(
222  this->pb,
223  v[i][2],
224  v[i][6],
225  v[i][10],
226  v[i][14],
227  block[s[4]],
228  block[s[5]],
229  v_temp[i][2],
230  v_temp[i][6],
231  v_temp[i][10],
232  v_temp[i][14],
233  FMT(this->annotation_prefix, " g_primitive_3_round_%zu", i)));
234 
235  g_arrays[i].emplace_back(g_primitive<FieldT>(
236  this->pb,
237  v[i][3],
238  v[i][7],
239  v[i][11],
240  v[i][15],
241  block[s[6]],
242  block[s[7]],
243  v_temp[i][3],
244  v_temp[i][7],
245  v_temp[i][11],
246  v_temp[i][15],
247  FMT(this->annotation_prefix, " g_primitive_4_round_%zu", i)));
248 
249  g_arrays[i].emplace_back(g_primitive<FieldT>(
250  this->pb,
251  v_temp[i][0],
252  v_temp[i][5],
253  v_temp[i][10],
254  v_temp[i][15],
255  block[s[8]],
256  block[s[9]],
257  v[i + 1][0],
258  v[i + 1][5],
259  v[i + 1][10],
260  v[i + 1][15],
261  FMT(this->annotation_prefix, " g_primitive_5_round_%zu", i)));
262 
263  g_arrays[i].emplace_back(g_primitive<FieldT>(
264  this->pb,
265  v_temp[i][1],
266  v_temp[i][6],
267  v_temp[i][11],
268  v_temp[i][12],
269  block[s[10]],
270  block[s[11]],
271  v[i + 1][1],
272  v[i + 1][6],
273  v[i + 1][11],
274  v[i + 1][12],
275  FMT(this->annotation_prefix, " g_primitive_6_round_%zu", i)));
276 
277  g_arrays[i].emplace_back(g_primitive<FieldT>(
278  this->pb,
279  v_temp[i][2],
280  v_temp[i][7],
281  v_temp[i][8],
282  v_temp[i][13],
283  block[s[12]],
284  block[s[13]],
285  v[i + 1][2],
286  v[i + 1][7],
287  v[i + 1][8],
288  v[i + 1][13],
289  FMT(this->annotation_prefix, " g_primitive_7_round_%zu", i)));
290 
291  g_arrays[i].emplace_back(g_primitive<FieldT>(
292  this->pb,
293  v_temp[i][3],
294  v_temp[i][4],
295  v_temp[i][9],
296  v_temp[i][14],
297  block[s[14]],
298  block[s[15]],
299  v[i + 1][3],
300  v[i + 1][4],
301  v[i + 1][9],
302  v[i + 1][14],
303  FMT(this->annotation_prefix, " g_primitive_8_round_%zu", i)));
304  }
305 
306  for (size_t i = 0; i < 8; i++) {
307  // Some versions of cppcheck raise a false-positive here
308  xor_vector.emplace_back(xor_gadget<FieldT>(
309  this->pb,
310  // cppcheck-suppress arrayIndexOutOfBounds
311  v[rounds][i],
312  // cppcheck-suppress arrayIndexOutOfBounds
313  v[rounds][8 + i],
314  out_temp[i],
315  FMT(this->annotation_prefix, " xor_output_temp_%zu", i)));
316  }
317 
318  for (size_t i = 0; i < 8; i++) {
319  xor_vector.emplace_back(xor_gadget<FieldT>(
320  this->pb,
321  out_temp[i],
322  h_array[i],
323  output_bytes[i],
324  FMT(this->annotation_prefix, " xor_output_%zu", i)));
325  }
326 }
327 
328 } // namespace libzeth
329 
330 #endif // __ZETH_CIRCUITS_BLAKE2S_COMP_SETUP_TCC__