1 // Copyright (c) 2015-2022 Clearmatics Technologies Ltd
3 // SPDX-License-Identifier: LGPL-3.0+
5 #ifndef __ZETH_CIRCUITS_BLAKE2S_COMP_SETUP_TCC__
6 #define __ZETH_CIRCUITS_BLAKE2S_COMP_SETUP_TCC__
8 #include "libzeth/circuits/blake2s/blake2s_comp.hpp"
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
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
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},
48 template<typename FieldT>
49 const std::array<bits<BLAKE2s_word_size>, 8>
50 BLAKE2s_256_comp<FieldT>::BLAKE2s_IV = {{
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
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
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
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
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
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
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
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
101 template<typename FieldT> void BLAKE2s_256_comp<FieldT>::setup_h()
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);
113 template<typename FieldT>
114 void BLAKE2s_256_comp<FieldT>::setup_counter(size_t len_byte_total)
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;
122 // Initialize the low word of the offset
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
129 for (size_t i = 0; int(i) < std::min(int(BLAKE2s_word_size), int(bit_size));
131 t[0][BLAKE2s_word_size - i - 1] = length_bits[bit_size - i - 1];
134 // Initialize the high word of the offset
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
141 // If we hash more that 2^32 bytes, then set the high word of the offset
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];
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)
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));
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]);
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]);
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]);
173 // v_14 = f0 XOR IV_6
175 temp_xored = bits_xor(BLAKE2s_IV[6], flag_to_1);
177 temp_xored = BLAKE2s_IV[6];
179 temp_xored.fill_pb_variable_array(this->pb, v[0][14]);
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]);
186 template<typename FieldT> void BLAKE2s_256_comp<FieldT>::setup_mixing_gadgets()
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];
193 g_arrays[i].emplace_back(g_primitive<FieldT>(
205 FMT(this->annotation_prefix, " g_primitive_1_round_%zu", i)));
207 g_arrays[i].emplace_back(g_primitive<FieldT>(
219 FMT(this->annotation_prefix, " g_primitive_2_round_%zu", i)));
221 g_arrays[i].emplace_back(g_primitive<FieldT>(
233 FMT(this->annotation_prefix, " g_primitive_3_round_%zu", i)));
235 g_arrays[i].emplace_back(g_primitive<FieldT>(
247 FMT(this->annotation_prefix, " g_primitive_4_round_%zu", i)));
249 g_arrays[i].emplace_back(g_primitive<FieldT>(
261 FMT(this->annotation_prefix, " g_primitive_5_round_%zu", i)));
263 g_arrays[i].emplace_back(g_primitive<FieldT>(
275 FMT(this->annotation_prefix, " g_primitive_6_round_%zu", i)));
277 g_arrays[i].emplace_back(g_primitive<FieldT>(
289 FMT(this->annotation_prefix, " g_primitive_7_round_%zu", i)));
291 g_arrays[i].emplace_back(g_primitive<FieldT>(
303 FMT(this->annotation_prefix, " g_primitive_8_round_%zu", i)));
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>(
310 // cppcheck-suppress arrayIndexOutOfBounds
312 // cppcheck-suppress arrayIndexOutOfBounds
315 FMT(this->annotation_prefix, " xor_output_temp_%zu", i)));
318 for (size_t i = 0; i < 8; i++) {
319 xor_vector.emplace_back(xor_gadget<FieldT>(
324 FMT(this->annotation_prefix, " xor_output_%zu", i)));
328 } // namespace libzeth
330 #endif // __ZETH_CIRCUITS_BLAKE2S_COMP_SETUP_TCC__