barretenberg
Loading...
Searching...
No Matches
blake_util.hpp
1#pragma once
2#include "barretenberg/proof_system/plookup_tables/plookup_tables.hpp"
3#include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp"
4#include "barretenberg/stdlib/primitives/plookup/plookup.hpp"
5#include "barretenberg/stdlib/primitives/uint/uint.hpp"
6
7namespace proof_system::plonk {
8namespace stdlib {
9
10namespace blake_util {
11
12using namespace plookup;
13
14// constants
15enum blake_constant { BLAKE3_STATE_SIZE = 16 };
16
17constexpr uint8_t MSG_SCHEDULE_BLAKE3[7][16] = {
18 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, { 2, 6, 3, 10, 7, 0, 4, 13, 1, 11, 12, 5, 9, 14, 15, 8 },
19 { 3, 4, 10, 12, 13, 2, 7, 14, 6, 5, 9, 0, 11, 15, 8, 1 }, { 10, 7, 12, 9, 14, 3, 13, 15, 4, 0, 11, 2, 5, 8, 1, 6 },
20 { 12, 13, 9, 11, 15, 10, 14, 8, 7, 2, 5, 3, 0, 1, 6, 4 }, { 9, 14, 11, 5, 8, 12, 15, 1, 13, 3, 0, 10, 2, 6, 4, 7 },
21 { 11, 15, 5, 0, 1, 9, 8, 6, 14, 10, 2, 12, 3, 4, 7, 13 },
22};
23
24constexpr uint8_t MSG_SCHEDULE_BLAKE2[10][16] = {
25 { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }, { 14, 10, 4, 8, 9, 15, 13, 6, 1, 12, 0, 2, 11, 7, 5, 3 },
26 { 11, 8, 12, 0, 5, 2, 15, 13, 10, 14, 3, 6, 7, 1, 9, 4 }, { 7, 9, 3, 1, 13, 12, 11, 14, 2, 6, 5, 10, 4, 0, 15, 8 },
27 { 9, 0, 5, 7, 2, 4, 10, 15, 14, 1, 11, 12, 6, 8, 3, 13 }, { 2, 12, 6, 10, 0, 11, 8, 3, 4, 13, 7, 5, 15, 14, 1, 9 },
28 { 12, 5, 1, 15, 14, 13, 4, 10, 0, 7, 6, 3, 9, 2, 8, 11 }, { 13, 11, 7, 14, 12, 1, 3, 9, 5, 0, 15, 4, 8, 6, 2, 10 },
29 { 6, 15, 14, 9, 11, 3, 0, 8, 12, 2, 13, 7, 1, 4, 10, 5 }, { 10, 2, 8, 4, 7, 6, 1, 5, 15, 11, 9, 14, 3, 12, 13, 0 },
30};
31
38template <typename Builder> field_t<Builder> add_normalize(const field_t<Builder>& a, const field_t<Builder>& b)
39{
40 typedef field_t<Builder> field_pt;
41 typedef witness_t<Builder> witness_pt;
42
43 Builder* ctx = a.get_context() ? a.get_context() : b.get_context();
44
45 uint256_t sum = a.get_value() + b.get_value();
46
47 uint256_t normalized_sum = static_cast<uint32_t>(sum.data[0]);
48
49 if (a.witness_index == IS_CONSTANT && b.witness_index == IS_CONSTANT) {
50 return field_pt(ctx, normalized_sum);
51 }
52
53 field_pt overflow = witness_pt(ctx, fr((sum - normalized_sum) >> 32));
54
55 // The overflow here could be of 2 bits because we allow that much overflow in the Blake rounds.
56 overflow.create_range_constraint(3);
57
58 // a + b - (overflow * 2^{32})
59 field_pt result = a.add_two(b, overflow * field_pt(ctx, -fr((uint64_t)(1ULL << 32ULL))));
60
61 return result;
62}
63
75template <typename Builder>
76void g(uint32<Builder> state[BLAKE3_STATE_SIZE],
77 size_t a,
78 size_t b,
79 size_t c,
80 size_t d,
81 uint32<Builder> x,
82 uint32<Builder> y)
83{
84 state[a] = state[a] + state[b] + x;
85 state[d] = (state[d] ^ state[a]).ror(16);
86 state[c] = state[c] + state[d];
87 state[b] = (state[b] ^ state[c]).ror(12);
88 state[a] = state[a] + state[b] + y;
89 state[d] = (state[d] ^ state[a]).ror(8);
90 state[c] = state[c] + state[d];
91 state[b] = (state[b] ^ state[c]).ror(7);
92}
93
141template <typename Builder>
142void g_lookup(field_t<Builder> state[BLAKE3_STATE_SIZE],
143 size_t a,
144 size_t b,
145 size_t c,
146 size_t d,
149 const bool last_update = false)
150{
151 typedef field_t<Builder> field_pt;
152
153 // For simplicity, state[a] is written as `a' in comments.
154 // a = a + b + x
155 state[a] = state[a].add_two(state[b], x);
156
157 // d = (d ^ a).ror(16)
158 const auto lookup_1 = plookup_read<Builder>::get_lookup_accumulators(BLAKE_XOR_ROTATE_16, state[d], state[a], true);
159 field_pt scaling_factor_1 = (1 << (32 - 16));
160 state[d] = lookup_1[ColumnIdx::C3][0] * scaling_factor_1;
161
162 // c = c + d
163 state[c] = state[c] + state[d];
164
165 // b = (b ^ c).ror(12)
166 const auto lookup_2 = plookup_read<Builder>::get_lookup_accumulators(BLAKE_XOR, state[b], state[c], true);
167 field_pt lookup_output = lookup_2[ColumnIdx::C3][2];
168 field_pt t2_term = field_pt(1 << 12) * lookup_2[ColumnIdx::C3][2];
169 lookup_output += (lookup_2[ColumnIdx::C3][0] - t2_term) * field_pt(1 << 20);
170 state[b] = lookup_output;
171
172 // a = a + b + y
173 if (!last_update) {
174 state[a] = state[a].add_two(state[b], y);
175 } else {
176 state[a] = add_normalize(state[a], state[b] + y);
177 }
178
179 // d = (d ^ a).ror(8)
180 const auto lookup_3 = plookup_read<Builder>::get_lookup_accumulators(BLAKE_XOR_ROTATE_8, state[d], state[a], true);
181 field_pt scaling_factor_3 = (1 << (32 - 8));
182 state[d] = lookup_3[ColumnIdx::C3][0] * scaling_factor_3;
183
184 // c = c + d
185 if (!last_update) {
186 state[c] = state[c] + state[d];
187 } else {
188 state[c] = add_normalize(state[c], state[d]);
189 }
190
191 // b = (b ^ c).ror(7)
192 const auto lookup_4 = plookup_read<Builder>::get_lookup_accumulators(BLAKE_XOR_ROTATE_7, state[b], state[c], true);
193 field_pt scaling_factor_4 = (1 << (32 - 7));
194 state[b] = lookup_4[ColumnIdx::C3][0] * scaling_factor_4;
195}
196
197/*
198 * This is the round function used in Blake2s and Blake3s.
199 * Inputs: - 16-word state
200 * - 16-word msg
201 * - round numbe
202 * - which_blake to choose Blake2 or Blake3 (false -> Blake2)
203 */
204template <typename Builder>
205void round_fn(uint32<Builder> state[BLAKE3_STATE_SIZE],
206 uint32<Builder> msg[BLAKE3_STATE_SIZE],
207 size_t round,
208 const bool which_blake = false)
209{
210 // Select the message schedule based on the round.
211 const uint8_t* schedule = which_blake ? MSG_SCHEDULE_BLAKE3[round] : MSG_SCHEDULE_BLAKE2[round];
212
213 // Mix the columns.
214 g<Builder>(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]]);
215 g<Builder>(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]]);
216 g<Builder>(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]]);
217 g<Builder>(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]]);
218
219 // Mix the rows.
220 g<Builder>(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]]);
221 g<Builder>(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]]);
222 g<Builder>(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]]);
223 g<Builder>(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]]);
224}
225
226/*
227 * This is the round function used in Blake2s and Blake3s for UltraPlonk.
228 * Inputs: - 16-word state
229 * - 16-word msg
230 * - round numbe
231 * - which_blake to choose Blake2 or Blake3 (false -> Blake2)
232 */
233template <typename Builder>
234void round_fn_lookup(field_t<Builder> state[BLAKE3_STATE_SIZE],
235 field_t<Builder> msg[BLAKE3_STATE_SIZE],
236 size_t round,
237 const bool which_blake = false)
238{
239 // Select the message schedule based on the round.
240 const uint8_t* schedule = which_blake ? MSG_SCHEDULE_BLAKE3[round] : MSG_SCHEDULE_BLAKE2[round];
241
242 // Mix the columns.
243 g_lookup<Builder>(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]]);
244 g_lookup<Builder>(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]]);
245 g_lookup<Builder>(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]]);
246 g_lookup<Builder>(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]]);
247
248 // Mix the rows.
249 g_lookup<Builder>(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]], true);
250 g_lookup<Builder>(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]], true);
251 g_lookup<Builder>(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]], true);
252 g_lookup<Builder>(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]], true);
253}
254
255} // namespace blake_util
256
257} // namespace stdlib
258} // namespace proof_system::plonk
Definition: uint256.hpp:25
Definition: standard_circuit_builder.hpp:12
Definition: field.hpp:10
uint32_t witness_index
Definition: field.hpp:423
Definition: witness.hpp:10
Definition: widget.bench.cpp:13