Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(avm): poseidon2 in vm2 #11597

Merged
merged 1 commit into from
Feb 14, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions barretenberg/cpp/pil/vm2/execution.pil
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ include "bitwise.pil";
include "precomputed.pil";
include "sha256.pil";
include "ecc.pil";
include "poseidon2_hash.pil";
include "poseidon2_perm.pil";

namespace execution;

Expand Down
92 changes: 92 additions & 0 deletions barretenberg/cpp/pil/vm2/poseidon2_hash.pil
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
include "poseidon2_perm.pil";

// Performs the poseidon2 full hash
// It is **mostly** well-constrained
namespace poseidon2_hash;

#[skippable_if]
sel = 0;

// These are the inputs to be hashed this round, we hash chunks of 3 field elements
pol commit input_0;
pol commit input_1;
pol commit input_2;

// Output of the hash it is matched with the result of the last permutation round
pol commit output;

pol commit sel;
sel * (1 - sel) = 0;
sel = execute_perm + end;
pol TWOPOW64 = 18446744073709551616;

pol commit input_len;
// Only used at the start of a new poseidon2 hash
pol IV = TWOPOW64 * input_len;


// Start of a poseidon2 computation
pol commit start;
start * (1 - start) = 0;
// When we end a poseidon, the next row must naturally have a start
sel' * (1 - precomputed.first_row) * (start' - end) = 0;

// We track the num of rounds remaining, excluding the first round that has to be performed by the start selector.
// We use the padded length to calculate the num of rounds to perform and the unpadded length is used in the IV.
pol commit num_perm_rounds_rem;
pol commit padding;
// Padding can either be 0, 1 or 2
padding * (padding - 1) * (padding - 2) = 0;
pol PADDED_LEN = input_len + padding;
start * ((num_perm_rounds_rem + 1) * 3 - PADDED_LEN) = 0;


// The row with the final result of the poseidon computation
pol commit end;
end * (1 - end) = 0;
// The final result of the output of the hash should match the output from the last permutation (b_0)
end * (output - b_0) = 0;
pol commit num_perm_rounds_rem_inv;
// end == 1 when the num_perm_rounds_rem == 0
sel * (num_perm_rounds_rem * (end * (1 - num_perm_rounds_rem_inv) + num_perm_rounds_rem_inv) - 1 + end) = 0;

// We perform the "squeeze" / perm operation until end
pol commit execute_perm;
execute_perm * (1 - execute_perm) = 0;
// The squeeze and end selector must be mutually exclusive
sel * (1 - end - execute_perm) = 0;
// Need an additional helper that holds the inverse of the num_perm_rounds_rem;
// If we still have rounds to perform, the num_perm_rounds_rem is decremented
execute_perm * (num_perm_rounds_rem' - num_perm_rounds_rem + 1) = 0;


// The input values are represented by a_0, a_1, a_2, a_3
// This most definitely could be simplified to a lower degree check
// the next perm input is constrained to be the previous perm output + the new values to be hashed.
// This occurs when we execute_perm = 1 and we are not the start or the end of the poseidon perm
pol NEXT_INPUT_IS_PREV_OUTPUT_SEL = execute_perm' * (1 - start) * execute_perm;
pol commit a_0;
start * (a_0 - input_0) = 0;
sel * NEXT_INPUT_IS_PREV_OUTPUT_SEL * (a_0' - b_0 - input_0') = 0;
pol commit a_1;
start * (a_1 - input_1) = 0;
sel * NEXT_INPUT_IS_PREV_OUTPUT_SEL * (a_1' - b_1 - input_1') = 0;
pol commit a_2;
start * (a_2 - input_2) = 0;
sel * NEXT_INPUT_IS_PREV_OUTPUT_SEL * (a_2' - b_2 - input_2') = 0;
pol commit a_3;
start * (a_3 - IV) = 0; // IV is placed in the last slot if this is the start
sel * NEXT_INPUT_IS_PREV_OUTPUT_SEL * (a_3' - b_3) = 0;

// Output value represented by b_0
pol commit b_0;
pol commit b_1;
pol commit b_2;
pol commit b_3;

#[LOOKUP_POS2_PERM]
sel { a_0, a_1, a_2, a_3, b_0, b_1, b_2, b_3}
in
poseidon2_perm.sel
{ poseidon2_perm.a_0, poseidon2_perm.a_1, poseidon2_perm.a_2, poseidon2_perm.a_3,
poseidon2_perm.b_0, poseidon2_perm.b_1, poseidon2_perm.b_2, poseidon2_perm.b_3 };
Loading