Barretenberg
The ZK-SNARK library at the core of Aztec
Loading...
Searching...
No Matches
poseidon2_permutation.cpp
Go to the documentation of this file.
1// === AUDIT STATUS ===
2// internal: { status: not started, auditors: [], date: YYYY-MM-DD }
3// external_1: { status: not started, auditors: [], date: YYYY-MM-DD }
4// external_2: { status: not started, auditors: [], date: YYYY-MM-DD }
5// =====================
6
8
12
13namespace bb::stdlib {
14
23template <typename Params, typename Builder>
26{
27 // deep copy
28 State current_state(input);
29 NativeState current_native_state;
30 for (size_t i = 0; i < t; ++i) {
31 current_native_state[i] = current_state[i].get_value();
32 }
33
34 // Apply 1st linear layer
35 NativePermutation::matrix_multiplication_external(current_native_state);
36 matrix_multiplication_external(builder, current_state);
37
38 // First set of external rounds
39 constexpr size_t rounds_f_beginning = rounds_f / 2;
40 for (size_t i = 0; i < rounds_f_beginning; ++i) {
41 poseidon2_external_gate_<FF> in{ current_state[0].witness_index,
42 current_state[1].witness_index,
43 current_state[2].witness_index,
44 current_state[3].witness_index,
45 i };
46 builder->create_poseidon2_external_gate(in);
47 // calculate the new witnesses
48 NativePermutation::add_round_constants(current_native_state, round_constants[i]);
49 NativePermutation::apply_sbox(current_native_state);
50 NativePermutation::matrix_multiplication_external(current_native_state);
51 for (size_t j = 0; j < t; ++j) {
52 current_state[j] = witness_t<Builder>(builder, current_native_state[j]);
53 }
54 }
55
56 // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy gate required since the last external gate
57 // from above otherwise expects to read into the first internal gate which is sorted out of sequence
58 builder->create_dummy_gate(builder->blocks.poseidon2_external,
59 current_state[0].witness_index,
60 current_state[1].witness_index,
61 current_state[2].witness_index,
62 current_state[3].witness_index);
63
64 // Internal rounds
65 const size_t p_end = rounds_f_beginning + rounds_p;
66 for (size_t i = rounds_f_beginning; i < p_end; ++i) {
67 poseidon2_internal_gate_<FF> in{ current_state[0].witness_index,
68 current_state[1].witness_index,
69 current_state[2].witness_index,
70 current_state[3].witness_index,
71 i };
72 builder->create_poseidon2_internal_gate(in);
73 current_native_state[0] += round_constants[i][0];
74 NativePermutation::apply_single_sbox(current_native_state[0]);
75 NativePermutation::matrix_multiplication_internal(current_native_state);
76 for (size_t j = 0; j < t; ++j) {
77 current_state[j] = witness_t<Builder>(builder, current_native_state[j]);
78 }
79 }
80
81 // TODO(https://github.com/AztecProtocol/barretenberg/issues/879): dummy gate required since the last internal gate
82 // otherwise expects to read into the next external gate which is sorted out of sequence
83 builder->create_dummy_gate(builder->blocks.poseidon2_internal,
84 current_state[0].witness_index,
85 current_state[1].witness_index,
86 current_state[2].witness_index,
87 current_state[3].witness_index);
88
89 // Remaining external rounds
90 for (size_t i = p_end; i < NUM_ROUNDS; ++i) {
91 poseidon2_external_gate_<FF> in{ current_state[0].witness_index,
92 current_state[1].witness_index,
93 current_state[2].witness_index,
94 current_state[3].witness_index,
95 i };
96 builder->create_poseidon2_external_gate(in);
97 // calculate the new witnesses
98 NativePermutation::add_round_constants(current_native_state, round_constants[i]);
99 NativePermutation::apply_sbox(current_native_state);
100 NativePermutation::matrix_multiplication_external(current_native_state);
101 for (size_t j = 0; j < t; ++j) {
102 current_state[j] = witness_t<Builder>(builder, current_native_state[j]);
103 }
104 }
105 // The Poseidon2 permutation is 64 rounds, but needs to be a block of 65 rows, since the result of
106 // applying a round of Poseidon2 is stored in the next row (the shifted row). As a result, we need this end row to
107 // compare with the result from the 64th round of Poseidon2. Note that it does not activate any selectors since it
108 // only serves as a comparison through the shifted wires.
109 builder->create_dummy_gate(builder->blocks.poseidon2_external,
110 current_state[0].witness_index,
111 current_state[1].witness_index,
112 current_state[2].witness_index,
113 current_state[3].witness_index);
114 return current_state;
115}
116
130template <typename Params, typename Builder>
133{
134 // create the 6 gates for the initial matrix multiplication
135 // gate 1: Compute tmp1 = state[0] + state[1] + 2 * state[3]
136 field_t<Builder> tmp1 =
137 witness_t<Builder>(builder, state[0].get_value() + state[1].get_value() + FF(2) * state[3].get_value());
138 builder->create_big_add_gate({
139 .a = state[0].witness_index,
140 .b = state[1].witness_index,
141 .c = state[3].witness_index,
142 .d = tmp1.witness_index,
143 .a_scaling = 1,
144 .b_scaling = 1,
145 .c_scaling = 2,
146 .d_scaling = -1,
147 .const_scaling = 0,
148 });
149
150 // gate 2: Compute tmp2 = 2 * state[1] + state[2] + state[3]
151 field_t<Builder> tmp2 =
152 witness_t<Builder>(builder, FF(2) * state[1].get_value() + state[2].get_value() + state[3].get_value());
153 builder->create_big_add_gate({
154 .a = state[1].witness_index,
155 .b = state[2].witness_index,
156 .c = state[3].witness_index,
157 .d = tmp2.witness_index,
158 .a_scaling = 2,
159 .b_scaling = 1,
160 .c_scaling = 1,
161 .d_scaling = -1,
162 .const_scaling = 0,
163 });
164
165 // gate 3: Compute v2 = 4 * state[0] + 4 * state[1] + tmp2
167 witness_t<Builder>(builder, FF(4) * state[0].get_value() + FF(4) * state[1].get_value() + tmp2.get_value());
168 builder->create_big_add_gate({
169 .a = state[0].witness_index,
170 .b = state[1].witness_index,
171 .c = tmp2.witness_index,
172 .d = v2.witness_index,
173 .a_scaling = 4,
174 .b_scaling = 4,
175 .c_scaling = 1,
176 .d_scaling = -1,
177 .const_scaling = 0,
178 });
179
180 // gate 4: Compute v1 = v2 + tmp1
182 builder->create_big_add_gate({
183 .a = v2.witness_index,
184 .b = tmp1.witness_index,
185 .c = v1.witness_index,
186 .d = builder->zero_idx,
187 .a_scaling = 1,
188 .b_scaling = 1,
189 .c_scaling = -1,
190 .d_scaling = 0,
191 .const_scaling = 0,
192 });
193
194 // gate 5: Compute v4 = tmp1 + 4 * state[2] + 4 * state[3]
196 witness_t<Builder>(builder, tmp1.get_value() + FF(4) * state[2].get_value() + FF(4) * state[3].get_value());
197 builder->create_big_add_gate({
198 .a = tmp1.witness_index,
199 .b = state[2].witness_index,
200 .c = state[3].witness_index,
201 .d = v4.witness_index,
202 .a_scaling = 1,
203 .b_scaling = 4,
204 .c_scaling = 4,
205 .d_scaling = -1,
206 .const_scaling = 0,
207 });
208
209 // gate 6: Compute v3 = v4 + tmp2
211 builder->create_big_add_gate({
212 .a = v4.witness_index,
213 .b = tmp2.witness_index,
214 .c = v3.witness_index,
215 .d = builder->zero_idx,
216 .a_scaling = 1,
217 .b_scaling = 1,
218 .c_scaling = -1,
219 .d_scaling = 0,
220 .const_scaling = 0,
221 });
222
223 state[0] = v1;
224 state[1] = v2;
225 state[2] = v3;
226 state[3] = v4;
227}
228
229template class Poseidon2Permutation<crypto::Poseidon2Bn254ScalarFieldParams, MegaCircuitBuilder>;
230template class Poseidon2Permutation<crypto::Poseidon2Bn254ScalarFieldParams, UltraCircuitBuilder>;
231
232} // namespace bb::stdlib
std::array< field_t< Builder >, t > State
static State permutation(Builder *builder, const State &input)
Circuit form of Poseidon2 permutation from https://eprint.iacr.org/2023/323.
static void matrix_multiplication_external(Builder *builder, State &state)
Separate function to do just the first linear layer (equivalent to external matrix mul).
bb::fr get_value() const
Given a := *this, compute its value given by a.v * a.mul + a.add.
Definition field.cpp:827
uint32_t witness_index
Definition field.hpp:132
AluTraceBuilder builder
Definition alu.test.cpp:123
constexpr uint32_t round_constants[64]
Value get_value(int64_t keyCount, int64_t valueCount)
Definition fixtures.hpp:35
typename Flavor::FF FF