14template <
typename Builder>
20 for (
auto& state_limb : state) {
21 if (state_limb.is_constant()) {
28template <
typename Builder>
32 for (
size_t i = 0; i < Poseidon2Permutation<Builder>::t; ++i) {
33 native_state[i] = state[i].get_value();
37template <
typename Builder>
48 for (
size_t i = begin; i < end; ++i) {
49 poseidon2_external_gate_<FF> in{ current_state[0].get_witness_index(),
50 current_state[1].get_witness_index(),
51 current_state[2].get_witness_index(),
52 current_state[3].get_witness_index(),
54 builder->create_poseidon2_external_gate(in);
56 Permutation::NativePermutation::apply_sbox(current_native_state);
59 current_state[j] = Witness(
builder, current_native_state[j]);
64template <
typename Builder>
68 const size_t rounds_f_beginning,
74 for (
size_t i = rounds_f_beginning; i < p_end; ++i) {
75 poseidon2_internal_gate_<typename Permutation::FF> in{ current_state[0].get_witness_index(),
76 current_state[1].get_witness_index(),
77 current_state[2].get_witness_index(),
78 current_state[3].get_witness_index(),
80 builder->create_poseidon2_internal_gate(in);
82 Permutation::NativePermutation::apply_single_sbox(current_native_state[0]);
83 Permutation::NativePermutation::matrix_multiplication_internal(current_native_state);
85 current_state[j] = Witness(
builder, current_native_state[j]);
94 const size_t rounds_f_beginning)
96 using Permutation = Poseidon2Permutation<MegaCircuitBuilder>;
111 poseidon2_transition_entry_gate_<FF> in{
112 current_state[0].get_witness_index(),
113 current_state[1].get_witness_index(),
114 current_state[2].get_witness_index(),
115 current_state[3].get_witness_index(),
118 builder->create_poseidon2_transition_entry_gate(in);
121 auto advance_internal_round = [](NativeState& state,
const FF& round_constant) {
122 state[0] += round_constant;
123 Permutation::NativePermutation::apply_single_sbox(state[0]);
124 Permutation::NativePermutation::matrix_multiplication_internal(state);
129 auto emit_quad_row = [&](
size_t quad_idx,
bool is_terminal) {
130 const size_t start = rounds_f_beginning + (4 * quad_idx);
131 const size_t next_start = start + 4;
133 NativeState state_after_1 = current_native_state;
135 auto s0_at_1 = Witness(
builder, state_after_1[0]);
137 NativeState state_after_2 = state_after_1;
139 auto s0_at_2 = Witness(
builder, state_after_2[0]);
141 NativeState state_after_3 = state_after_2;
143 auto s0_at_3 = Witness(
builder, state_after_3[0]);
145 poseidon2_quad_internal_gate_<FF> in{
146 current_state[0].get_witness_index(),
147 s0_at_1.witness_index,
148 s0_at_2.witness_index,
149 s0_at_3.witness_index,
154 builder->create_poseidon2_quad_internal_gate(in);
157 current_native_state = state_after_3;
163 current_state[0] = Witness(
builder, current_native_state[0]);
166 current_state[j] = Witness(
builder, current_native_state[j]);
172 for (
size_t q = 0; q < num_quad_rows - 1; ++q) {
173 emit_quad_row(q,
false);
176 emit_quad_row(num_quad_rows - 1,
true);
181template <
typename Builder>
185 State current_state(input);
186 NativeState current_native_state;
188 matrix_multiplication_external(current_state);
189 sync_native_state_from_state<Builder>(current_native_state, current_state);
192 constexpr size_t rounds_f_beginning = rounds_f / 2;
193 apply_external_rounds(
builder, current_state, current_native_state, 0, rounds_f_beginning);
199 propagate_current_state_to_next_row(
builder, current_state,
builder->blocks.poseidon2_external);
203 const size_t p_end = rounds_f_beginning + rounds_p;
205 apply_mega_internal_rounds(
builder, current_state, current_native_state, rounds_f_beginning);
207 apply_standard_internal_rounds(
builder, current_state, current_native_state, rounds_f_beginning, p_end);
211 apply_external_rounds(
builder, current_state, current_native_state, p_end, NUM_ROUNDS);
216 propagate_current_state_to_next_row(
builder, current_state,
builder->blocks.poseidon2);
218 propagate_current_state_to_next_row(
builder, current_state,
builder->blocks.poseidon2_external);
221 return current_state;
229template <
typename Builder>
243 state[1] = tmp2.
add_two(state[0] * four, state[1] * four);
246 state[0] = state[1] + tmp1;
249 state[3] = tmp1.
add_two(state[2] * four, state[3] * four);
252 state[2] = state[3] + tmp2;
255template <
typename Builder>
260 BB_ASSERT(
builder !=
nullptr,
"Poseidon2 Mega initial external layer needs a builder context");
262 NativeState native_state;
263 for (
size_t i = 0; i < t; ++i) {
264 native_state[i] = state[i].get_value();
266 NativePermutation::matrix_multiplication_external(native_state);
268 materialize_constants_for_initial_layer(
builder, state);
271 state[1].get_witness_index(),
272 state[2].get_witness_index(),
273 state[3].get_witness_index() };
274 builder->create_poseidon2_initial_external_gate(in);
275 for (
size_t j = 0; j < t; ++j) {
280template class Poseidon2Permutation<MegaCircuitBuilder>;
281template class Poseidon2Permutation<UltraCircuitBuilder>;
#define BB_ASSERT(expression,...)
Circuit form of Poseidon2 permutation from https://eprint.iacr.org/2023/323.
static void propagate_current_state_to_next_row(Builder *builder, const State &state, auto &block)
The result of applying a round of Poseidon2 is stored in the next row and is accessed by Poseidon2 In...
static void matrix_multiplication_external(State &state)
In-circuit method to efficiently multiply the initial state by the external matrix .
static constexpr size_t rounds_p
static constexpr RoundConstantsContainer round_constants
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.
std::array< FF, t > NativeState
static constexpr size_t t
static field_t from_witness_index(Builder *ctx, uint32_t witness_index)
field_t add_two(const field_t &add_b, const field_t &add_c) const
Efficiently compute (this + a + b) using big_mul gate.
MegaCircuitBuilder_< field< Bn254FrParams > > MegaCircuitBuilder