Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
blake_util.hpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: Complete, auditors: [Nishat], commit: 66052c96cc754339ac3f2761f341f150130555b3}
3// external_1: { status: not started, auditors: [], commit: }
4// external_2: { status: not started, auditors: [], commit: }
5// =====================
6
7#pragma once
11
13
14using namespace bb::plookup;
15
16// constants
18
19constexpr uint8_t MSG_SCHEDULE_BLAKE3[7][16] = {
20 { 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 },
21 { 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 },
22 { 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 },
23 { 11, 15, 5, 0, 1, 9, 8, 6, 14, 10, 2, 12, 3, 4, 7, 13 },
24};
25
26constexpr uint8_t MSG_SCHEDULE_BLAKE2[10][16] = {
27 { 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 },
28 { 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 },
29 { 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 },
30 { 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 },
31 { 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 },
32};
33
80template <typename Builder>
82 size_t a,
83 size_t b,
84 size_t c,
85 size_t d,
88{
90
91 // For simplicity, state[a] is written as `a' in comments.
92 // a = a + b + x
93 state[a] = state[a].add_two(state[b], x);
94
95 // d = (d ^ a).ror(16)
96 // Get the lookup accumulator where `lookup_1[ColumnIdx::C3][0]` contains the
97 // XORed and rotated (by 16) value scaled by 2^{-16}.
98 const auto lookup_1 = plookup_read<Builder>::get_lookup_accumulators(BLAKE_XOR_ROTATE_16, state[d], state[a], true);
99 // Compute the scaling factor 2^{32-16} = 2^{16} to get the correct rotated value.
100 field_pt scaling_factor_1 = (1 << (32 - 16));
101 // Multiply by the scaling factor to get the final rotated value.
102 state[d] = lookup_1[ColumnIdx::C3][0] * scaling_factor_1;
103
104 // c = c + d
105 state[c] = state[c] + state[d];
106
107 // b = (b ^ c).ror(12)
108 // Does not require a special XOR_ROTATE_12 table since we can get the correct value
109 // by combining values from BLAKE_XOR table itself.
110 // Let u = s_0 + 2^6 * s_1 + 2^{12} * s_2 + 2^{18} * s_3 + 2^{24} * s_4 + 2^{30} * s_5
111 // be a 32-bit output of XOR, split into slices s_0, s_1, s_2, s_3, s_4 (6-bits each) and s_5 (5-bit).
112 // We want to compute ROTATE_12(u) = s_2 + 2^6 * s_3 + 2^{12} * s_4 + 2^{18} * s_5 + 2^{20} * s_0 + 2^{26} * s_1.
113 // The BLAKE_XOR table gives:
114 // lookup_2[ColumnIdx::C3][0] = s_0 + 2^6 * s_1 + 2^{12} * s_2 + 2^{18} * s_3 + 2^{24} * s_4 + 2^{30} * s_5 = u.
115 // lookup_2[ColumnIdx::C3][2] = s_2 + 2^6 * s_3 + 2^{12} * s_4 + 2^{18} * s_5 (i.e., u without s_0 and s_1).
116 // Thus, we can compute ROTATE_12(u) as:
117 // ROTATE_12(u) = lookup_2[ColumnIdx::C3][2] + (lookup_2[ColumnIdx::C3][0] - 2^{12} * lookup_2[ColumnIdx::C3][2]) *
118 // 2^{20}.
119
120 // Get the lookup accumulator for BLAKE_XOR table where lookup_2[ColumnIdx::C3][0] = u.
121 const auto lookup_2 = plookup_read<Builder>::get_lookup_accumulators(BLAKE_XOR, state[b], state[c], true);
122 // lookup_2[ColumnIdx::C3][2] = s_2 + 2^6 * s_3 + 2^{12} * s_4 + 2^{18} * s_5 (i.e., u without s_0 and s_1).
123 field_pt lookup_output = lookup_2[ColumnIdx::C3][2];
124 // Compute 2^{12} * lookup_2[ColumnIdx::C3][2].
125 field_pt t2_term = field_pt(1 << 12) * lookup_2[ColumnIdx::C3][2];
126 // Compute the final rotated value as described for ROTATE_12(u) above.
127 lookup_output += (lookup_2[ColumnIdx::C3][0] - t2_term) * field_pt(1 << 20);
128 state[b] = lookup_output;
129
130 // a = a + b + y
131 state[a] = hash_utils::add_normalize_unsafe(state[a], state[b] + y, /*overflow_bits=*/3);
132
133 // d = (d ^ a).ror(8)
134 // Get the lookup accumulator where `lookup_3[ColumnIdx::C3][0]` contains the
135 // XORed and rotated (by 8) value scaled by 2^{-24}.
136 const auto lookup_3 = plookup_read<Builder>::get_lookup_accumulators(BLAKE_XOR_ROTATE_8, state[d], state[a], true);
137 // Compute the scaling factor 2^{32-8} = 2^{24} to get the correct rotated value.
138 field_pt scaling_factor_3 = (1 << (32 - 8));
139 // Multiply by the scaling factor to get the final rotated value.
140 state[d] = lookup_3[ColumnIdx::C3][0] * scaling_factor_3;
141
142 // c = c + d
143 state[c] = hash_utils::add_normalize_unsafe(state[c], state[d], /*overflow_bits=*/3);
144
145 // b = (b ^ c).ror(7)
146 // Get the lookup accumulator where `lookup_4[ColumnIdx::C3][0]` contains the
147 // XORed and rotated (by 7) value scaled by 2^{-25}.
148 const auto lookup_4 = plookup_read<Builder>::get_lookup_accumulators(BLAKE_XOR_ROTATE_7, state[b], state[c], true);
149 // Compute the scaling factor 2^{32-7} = 2^{25} to get the correct rotated value.
150 field_pt scaling_factor_4 = (1 << (32 - 7));
151 // Multiply by the scaling factor to get the final rotated value.
152 state[b] = lookup_4[ColumnIdx::C3][0] * scaling_factor_4;
153}
154
155/*
156 * This is the round function used in Blake2s and Blake3s for Ultra.
157 * Inputs: - 16-word state
158 * - 16-word msg
159 * - round number
160 * - which_blake to choose Blake2 or Blake3 (false -> Blake2)
161 */
162template <typename Builder>
165 size_t round,
166 const bool which_blake = false)
167{
168 // Select the message schedule based on the round.
169 const uint8_t* schedule = which_blake ? MSG_SCHEDULE_BLAKE3[round] : MSG_SCHEDULE_BLAKE2[round];
170
171 // Mix the columns.
172 g<Builder>(state, 0, 4, 8, 12, msg[schedule[0]], msg[schedule[1]]);
173 g<Builder>(state, 1, 5, 9, 13, msg[schedule[2]], msg[schedule[3]]);
174 g<Builder>(state, 2, 6, 10, 14, msg[schedule[4]], msg[schedule[5]]);
175 g<Builder>(state, 3, 7, 11, 15, msg[schedule[6]], msg[schedule[7]]);
176
177 // Mix the rows.
178 g<Builder>(state, 0, 5, 10, 15, msg[schedule[8]], msg[schedule[9]]);
179 g<Builder>(state, 1, 6, 11, 12, msg[schedule[10]], msg[schedule[11]]);
180 g<Builder>(state, 2, 7, 8, 13, msg[schedule[12]], msg[schedule[13]]);
181 g<Builder>(state, 3, 4, 9, 14, msg[schedule[14]], msg[schedule[15]]);
182}
183
184} // namespace bb::stdlib::blake_util
field_t add_two(const field_t &add_b, const field_t &add_c) const
Efficiently compute (this + a + b) using big_mul gate.
Definition field.cpp:583
static plookup::ReadData< field_pt > get_lookup_accumulators(const plookup::MultiTableId id, const field_pt &key_a, const field_pt &key_b=0, const bool is_2_to_1_lookup=false)
Definition plookup.cpp:19
FF a
FF b
stdlib::field_t< UltraCircuitBuilder > field_pt
@ BLAKE_XOR_ROTATE_16
Definition types.hpp:122
@ BLAKE_XOR_ROTATE_7
Definition types.hpp:124
@ BLAKE_XOR_ROTATE_8
Definition types.hpp:123
constexpr uint8_t MSG_SCHEDULE_BLAKE2[10][16]
constexpr uint8_t MSG_SCHEDULE_BLAKE3[7][16]
void round_fn(field_t< Builder > state[BLAKE_STATE_SIZE], field_t< Builder > msg[BLAKE_STATE_SIZE], size_t round, const bool which_blake=false)
void g(field_t< Builder > state[BLAKE_STATE_SIZE], size_t a, size_t b, size_t c, size_t d, field_t< Builder > x, field_t< Builder > y)
field_t< Builder > add_normalize_unsafe(const field_t< Builder > &a, const field_t< Builder > &b, size_t overflow_bits)
Compute (a + b) mod 2^32 with circuit constraints.