From aa536b5638b720cd6e8d8b017e429b553ba0664a Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Mon, 4 Dec 2023 17:11:34 +0000 Subject: [PATCH 01/38] initial files and impl --- .../stdlib/hash/poseidon2/poseidon2.cpp | 54 +++++++++++++++++++ .../stdlib/hash/poseidon2/poseidon2.hpp | 29 ++++++++++ 2 files changed, 83 insertions(+) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp new file mode 100644 index 00000000000..7d7af647048 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp @@ -0,0 +1,54 @@ +#include "poseidon2.hpp" +#include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" +namespace proof_system::plonk::stdlib { + +using namespace barretenberg; +using namespace proof_system; + +template field_t poseidon2_hash::hash(const std::vector& inputs) +{ + + /* Run the sponge by absorbing all the input and squeezing one output. + * this should just call a + * + */ +} + +/** + * Hash a byte_array. + * + */ +template field_t poseidon2_hash::hash_buffer(const stdlib::byte_array& input) +{ + const size_t num_bytes = input.size(); + const size_t bytes_per_element = 31; + size_t num_elements = static_cast(num_bytes % bytes_per_element != 0) + (num_bytes / bytes_per_element); + + std::vector elements; + for (size_t i = 0; i < num_elements; ++i) { + size_t bytes_to_slice = 0; + if (i == num_elements - 1) { + bytes_to_slice = num_bytes - (i * bytes_per_element); + } else { + bytes_to_slice = bytes_per_element; + } + auto element = static_cast(input.slice(i * bytes_per_element, bytes_to_slice)); + elements.emplace_back(element); + } + for (auto& x : elements) { + std::cout << x << std::endl; + } + field_t hashed; + if (elements.size() < 2) { + hashed = hash(elements); + } else { + hashed = hash({ elements[0], elements[1] }); + for (size_t i = 2; i < elements.size(); ++i) { + hashed = hash({ hashed, elements[i] }); + } + } + return hashed; +} +INSTANTIATE_STDLIB_TYPE(poseidon2_hash); + +} // namespace proof_system::plonk::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp new file mode 100644 index 00000000000..de85dde5970 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp @@ -0,0 +1,29 @@ +#pragma once +#include "barretenberg/stdlib/primitives/byte_array/byte_array.hpp" +#include "barretenberg/stdlib/primitives/field/field.hpp" + +#include "../../primitives/circuit_builders/circuit_builders.hpp" + +namespace proof_system::plonk::stdlib { + +using namespace barretenberg; +/** + * @brief stdlib class that evaluates in-circuit poseidon2 hashes, consistent with behavior in + * crypto::poseidon2_hash + * + * @tparam Builder + */ +template class poseidon2_hash { + + private: + using field_t = stdlib::field_t; + using bool_t = stdlib::bool_t; + + public: + static field_t hash(const std::vector& in); + static field_t hash_buffer(const stdlib::byte_array& input); +}; + +EXTERN_STDLIB_TYPE(poseidon2_hash); + +} // namespace proof_system::plonk::stdlib From 89f4bc44cdfc12b1b960c084333d93ee6a4a3f0b Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Tue, 5 Dec 2023 16:01:41 +0000 Subject: [PATCH 02/38] getting it to compile --- .../cpp/src/barretenberg/stdlib/hash/CMakeLists.txt | 3 ++- .../src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt | 1 + .../src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp | 6 ++++-- .../src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp | 4 ++++ 4 files changed, 11 insertions(+), 3 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/hash/CMakeLists.txt index 2ce247a010a..0f20819bea6 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/CMakeLists.txt @@ -3,4 +3,5 @@ add_subdirectory(blake3s) add_subdirectory(pedersen) add_subdirectory(sha256) add_subdirectory(keccak) -add_subdirectory(benchmarks) \ No newline at end of file +add_subdirectory(benchmarks) +add_subdirectory(poseidon2) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt new file mode 100644 index 00000000000..cc2413569fb --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt @@ -0,0 +1 @@ +barretenberg_module(stdlib_poseidon2_hash stdlib_primitives) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp index 7d7af647048..a44647f039e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp @@ -1,4 +1,4 @@ -#include "poseidon2.hpp" +#include "barretenberg/stdlib/hash/poseidon2/poseidon2.hpp" #include "barretenberg/ecc/curves/grumpkin/grumpkin.hpp" namespace proof_system::plonk::stdlib { @@ -9,9 +9,11 @@ template field_t poseidon2_hash::hash(const std::vector class poseidon2_hash { private: using field_t = stdlib::field_t; using bool_t = stdlib::bool_t; + using Params = crypto::Poseidon2Bn254ScalarFieldParams; + using Sponge = FieldSponge; public: static field_t hash(const std::vector& in); From e5298b48539447a678d236d18a9c97dc25fd4a1f Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Tue, 5 Dec 2023 16:02:01 +0000 Subject: [PATCH 03/38] sponge stdlib --- .../stdlib/hash/poseidon2/sponge/sponge.hpp | 169 ++++++++++++++++++ 1 file changed, 169 insertions(+) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp new file mode 100644 index 00000000000..843b93d2f43 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp @@ -0,0 +1,169 @@ +#pragma once + +#include +#include +#include +#include + +#include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/stdlib/primitives/field/field.hpp" + +namespace proof_system::plonk::stdlib { + +/** + * @brief Implements a cryptographic sponge over prime fields. + * Implements the sponge specification from the Community Cryptographic Specification Project + * see https://github.com/C2SP/C2SP/blob/792c1254124f625d459bfe34417e8f6bdd02eb28/poseidon-sponge.md + * (Note: this spec was not accepted into the C2SP repo, we might want to reference something else!) + * + * Note: If we ever use this sponge class for more than 1 hash functions, we should move this out of `poseidon2` + * and into its own directory + * @tparam FF + * @tparam rate + * @tparam capacity + * @tparam t + * @tparam Permutation + */ +template class FieldSponge { + public: + /** + * @brief Defines what phase of the sponge algorithm we are in. + * + * ABSORB: 'absorbing' field elements into the sponge + * SQUEEZE: compressing the sponge and extracting a field element + * + */ + enum Mode { + ABSORB, + SQUEEZE, + }; + + // sponge state. t = rate + capacity. capacity = 1 field element (~256 bits) + std::array state; + + // cached elements that have been absorbed. + std::array cache; + size_t cache_size = 0; + Mode mode = Mode::ABSORB; + + FieldSponge(FF domain_iv = 0) + { + for (size_t i = 0; i < rate; ++i) { + state[i] = 0; + } + state[rate] = domain_iv; + } + + std::array perform_duplex() + { + // zero-pad the cache + for (size_t i = cache_size; i < rate; ++i) { + cache[i] = 0; + } + // add the cache into sponge state + for (size_t i = 0; i < rate; ++i) { + state[i] += cache[i]; + } + // state = permutation(state); + // return `rate` number of field elements from the sponge state. + std::array output; + for (size_t i = 0; i < rate; ++i) { + output[i] = state[i]; + } + return output; + } + + void absorb(const FF& input) + { + if (mode == Mode::ABSORB && cache_size == rate) { + // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache + perform_duplex(); + cache[0] = input; + cache_size = 1; + } else if (mode == Mode::ABSORB && cache_size < rate) { + // If we're absorbing, and the cache is not full, add the input into the cache + cache[cache_size] = input; + cache_size += 1; + } else if (mode == Mode::SQUEEZE) { + // If we're in squeeze mode, switch to absorb mode and add the input into the cache. + // N.B. I don't think this code path can be reached?! + cache[0] = input; + cache_size = 1; + mode = Mode::ABSORB; + } + } + + FF squeeze() + { + if (mode == Mode::SQUEEZE && cache_size == 0) { + // If we're in squeze mode and the cache is empty, there is nothing left to squeeze out of the sponge! + // Switch to absorb mode. + mode = Mode::ABSORB; + cache_size = 0; + } + if (mode == Mode::ABSORB) { + // If we're in absorb mode, apply sponge permutation to compress the cache, populate cache with compressed + // state and switch to squeeze mode. Note: this code block will execute if the previous `if` condition was + // matched + auto new_output_elements = perform_duplex(); + mode = Mode::SQUEEZE; + for (size_t i = 0; i < rate; ++i) { + cache[i] = new_output_elements[i]; + } + cache_size = rate; + } + // By this point, we should have a non-empty cache. Pop one item off the top of the cache and return it. + FF result = cache[0]; + for (size_t i = 1; i < cache_size; ++i) { + cache[i - 1] = cache[i]; + } + cache_size -= 1; + cache[cache_size] = 0; + return result; + } + + /** + * @brief Use the sponge to hash an input string + * + * @tparam out_len + * @tparam is_variable_length. Distinguishes between hashes where the preimage length is constant/not constant + * @param input + * @return std::array + */ + template static std::array hash_internal(std::span input) + { + size_t in_len = input.size(); + const uint256_t iv = (static_cast(in_len) << 64) + out_len - 1; + FieldSponge sponge(iv); + + for (size_t i = 0; i < in_len; ++i) { + sponge.absorb(input[i]); + } + + // In the case where the hash preimage is variable-length, we append `1` to the end of the input, to distinguish + // from fixed-length hashes. (the combination of this additional field element + the hash IV ensures + // fixed-length and variable-length hashes do not collide) + if constexpr (is_variable_length) { + sponge.absorb(1); + } + + std::array output; + for (size_t i = 0; i < out_len; ++i) { + output[i] = sponge.squeeze(); + } + return output; + } + + template static std::array hash_fixed_length(std::span input) + { + return hash_internal(input); + } + static FF hash_fixed_length(std::span input) { return hash_fixed_length<1>(input)[0]; } + + template static std::array hash_variable_length(std::span input) + { + return hash_internal(input); + } + static FF hash_variable_length(std::span input) { return hash_variable_length<1>(input)[0]; } +}; +} // namespace proof_system::plonk::stdlib \ No newline at end of file From e80739d9067eb19406272a8a201fa2e0821b8a07 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Tue, 5 Dec 2023 22:32:48 +0000 Subject: [PATCH 04/38] added unconstrained permutation --- .../stdlib/hash/poseidon2/poseidon2.hpp | 3 +- .../hash/poseidon2/poseidon2_permutation.hpp | 73 +++++++++++++++++++ .../stdlib/hash/poseidon2/sponge/sponge.hpp | 46 +++++++----- 3 files changed, 103 insertions(+), 19 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp index d0973931ad5..baa82f0d6ee 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp @@ -21,7 +21,8 @@ template class poseidon2_hash { using field_t = stdlib::field_t; using bool_t = stdlib::bool_t; using Params = crypto::Poseidon2Bn254ScalarFieldParams; - using Sponge = FieldSponge; + using Permutation = Poseidon2Permutation; + using Sponge = FieldSponge; public: static field_t hash(const std::vector& in); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp new file mode 100644 index 00000000000..0c213b5ba7e --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp @@ -0,0 +1,73 @@ +#pragma once +#include +#include +#include + +#include "barretenberg/crypto/poseidon2/poseidon2_permutation.hpp" +#include "barretenberg/stdlib/primitives/field/field.hpp" + +namespace proof_system::plonk::stdlib { + +using namespace proof_system; +template class Poseidon2Permutation { + public: + using NativePermutation = crypto::Poseidon2Permutation; + // t = sponge permutation size (in field elements) + // t = rate + capacity + // capacity = 1 field element (256 bits) + // rate = number of field elements that can be compressed per permutation + static constexpr size_t t = Params::t; + // d = degree of s-box polynomials. For a given field, `d` is the smallest element of `p` such that gdc(d, p - 1) = + // 1 (excluding 1) For bn254/grumpkin, d = 5 + static constexpr size_t d = Params::d; + // sbox size = number of bits in p + static constexpr size_t sbox_size = Params::sbox_size; + // number of full sbox rounds + static constexpr size_t rounds_f = Params::rounds_f; + // number of partial sbox rounds + static constexpr size_t rounds_p = Params::rounds_p; + static constexpr size_t NUM_ROUNDS = Params::rounds_f + Params::rounds_p; + + using FF = typename Params::FF; + using State = std::array, t>; + using NativeState = std::array; + + using RoundConstants = std::array; + using RoundConstantsContainer = std::array; + static constexpr RoundConstantsContainer round_constants = Params::round_constants; + static State permutation(const State& input) + { + // deep copy + State current_state(input); + NativeState current_native_state; + for (size_t i = 0; i < t; ++i) { + current_native_state[i] = current_state[i].get_value(); + } + + // Apply 1st linear layer + NativePermutation::matrix_multiplication_external(current_native_state); + + constexpr size_t rounds_f_beginning = rounds_f / 2; + for (size_t i = 0; i < rounds_f_beginning; ++i) { + // calculate the new witnesses + NativePermutation::add_round_constants(current_native_state, round_constants[i]); + NativePermutation::apply_sbox(current_native_state); + NativePermutation::matrix_multiplication_external(current_native_state); + } + + const size_t p_end = rounds_f_beginning + rounds_p; + for (size_t i = rounds_f_beginning; i < p_end; ++i) { + current_native_state[0] += round_constants[i][0]; + NativePermutation::apply_single_sbox(current_native_state[0]); + NativePermutation::matrix_multiplication_internal(current_native_state); + } + + for (size_t i = p_end; i < NUM_ROUNDS; ++i) { + NativePermutation::add_round_constants(current_native_state, round_constants[i]); + NativePermutation::apply_sbox(current_native_state); + NativePermutation::matrix_multiplication_external(current_native_state); + } + return current_state; + } +}; +} // namespace proof_system::plonk::stdlib \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp index 843b93d2f43..9f20a6e589d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp @@ -6,6 +6,7 @@ #include #include "barretenberg/numeric/uint256/uint256.hpp" +#include "barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" namespace proof_system::plonk::stdlib { @@ -18,13 +19,13 @@ namespace proof_system::plonk::stdlib { * * Note: If we ever use this sponge class for more than 1 hash functions, we should move this out of `poseidon2` * and into its own directory - * @tparam FF + * @tparam field_t * @tparam rate * @tparam capacity * @tparam t * @tparam Permutation */ -template class FieldSponge { +template class FieldSponge { public: /** * @brief Defines what phase of the sponge algorithm we are in. @@ -39,14 +40,14 @@ template }; // sponge state. t = rate + capacity. capacity = 1 field element (~256 bits) - std::array state; + std::array, t> state; // cached elements that have been absorbed. - std::array cache; + std::array, rate> cache; size_t cache_size = 0; Mode mode = Mode::ABSORB; - FieldSponge(FF domain_iv = 0) + FieldSponge(field_t domain_iv = 0) { for (size_t i = 0; i < rate; ++i) { state[i] = 0; @@ -54,7 +55,7 @@ template state[rate] = domain_iv; } - std::array perform_duplex() + std::array, rate> perform_duplex() { // zero-pad the cache for (size_t i = cache_size; i < rate; ++i) { @@ -64,16 +65,16 @@ template for (size_t i = 0; i < rate; ++i) { state[i] += cache[i]; } - // state = permutation(state); + state = Permutation::permutation(state); // return `rate` number of field elements from the sponge state. - std::array output; + std::array, rate> output; for (size_t i = 0; i < rate; ++i) { output[i] = state[i]; } return output; } - void absorb(const FF& input) + void absorb(const field_t& input) { if (mode == Mode::ABSORB && cache_size == rate) { // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache @@ -93,7 +94,7 @@ template } } - FF squeeze() + field_t squeeze() { if (mode == Mode::SQUEEZE && cache_size == 0) { // If we're in squeze mode and the cache is empty, there is nothing left to squeeze out of the sponge! @@ -113,7 +114,7 @@ template cache_size = rate; } // By this point, we should have a non-empty cache. Pop one item off the top of the cache and return it. - FF result = cache[0]; + field_t result = cache[0]; for (size_t i = 1; i < cache_size; ++i) { cache[i - 1] = cache[i]; } @@ -128,9 +129,10 @@ template * @tparam out_len * @tparam is_variable_length. Distinguishes between hashes where the preimage length is constant/not constant * @param input - * @return std::array + * @return std::array, out_len> */ - template static std::array hash_internal(std::span input) + template + static std::array, out_len> hash_internal(std::span> input) { size_t in_len = input.size(); const uint256_t iv = (static_cast(in_len) << 64) + out_len - 1; @@ -147,23 +149,31 @@ template sponge.absorb(1); } - std::array output; + std::array, out_len> output; for (size_t i = 0; i < out_len; ++i) { output[i] = sponge.squeeze(); } return output; } - template static std::array hash_fixed_length(std::span input) + template + static std::array, out_len> hash_fixed_length(std::span> input) { return hash_internal(input); } - static FF hash_fixed_length(std::span input) { return hash_fixed_length<1>(input)[0]; } + static field_t hash_fixed_length(std::span> input) + { + return hash_fixed_length<1>(input)[0]; + } - template static std::array hash_variable_length(std::span input) + template + static std::array, out_len> hash_variable_length(std::span> input) { return hash_internal(input); } - static FF hash_variable_length(std::span input) { return hash_variable_length<1>(input)[0]; } + static field_t hash_variable_length(std::span> input) + { + return hash_variable_length<1>(input)[0]; + } }; } // namespace proof_system::plonk::stdlib \ No newline at end of file From 751d74bab75ed6d19acf46a9af467fac7c0820b9 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Tue, 5 Dec 2023 23:10:13 +0000 Subject: [PATCH 05/38] added poseidon2 end gate --- .../arithmetization/gate_data.hpp | 11 +++++++-- .../goblin_ultra_circuit_builder.cpp | 23 +++++++++++++++++++ .../goblin_ultra_circuit_builder.hpp | 1 + 3 files changed, 33 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp index 91540d90d72..f6f15ebcc0c 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp @@ -138,7 +138,7 @@ template struct poseidon2_external_gate_ { uint32_t b; uint32_t c; uint32_t d; - uint32_t round_idx; + size_t round_idx; }; template struct poseidon2_internal_gate_ { @@ -146,6 +146,13 @@ template struct poseidon2_internal_gate_ { uint32_t b; uint32_t c; uint32_t d; - uint32_t round_idx; + size_t round_idx; +}; + +template struct poseidon2_end_gate_ { + uint32_t a; + uint32_t b; + uint32_t c; + uint32_t d; }; } // namespace proof_system diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp index 108e16471e0..a7a2e67875f 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp @@ -294,6 +294,29 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseid ++this->num_gates; } +template void GoblinUltraCircuitBuilder_::create_poseidon2_end_gate(const poseidon2_end_gate_& in) +{ + this->w_l.emplace_back(in.a); + this->w_r.emplace_back(in.b); + this->w_o.emplace_back(in.c); + this->w_4.emplace_back(in.d); + this->q_m.emplace_back(0); + this->q_1.emplace_back(0); + this->q_2.emplace_back(0); + this->q_3.emplace_back(0); + this->q_c.emplace_back(0); + this->q_arith.emplace_back(0); + this->q_4.emplace_back(0); + this->q_sort.emplace_back(0); + this->q_lookup_type.emplace_back(0); + this->q_elliptic.emplace_back(0); + this->q_aux.emplace_back(0); + this->q_busread.emplace_back(0); + this->q_poseidon2_external.emplace_back(0); + this->q_poseidon2_internal.emplace_back(0); + ++this->num_gates; +} + template inline FF GoblinUltraCircuitBuilder_::compute_poseidon2_external_identity(FF q_poseidon2_external_value, FF q_1_value, diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp index af7ba39c8a5..efe23d2577b 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp @@ -136,6 +136,7 @@ template class GoblinUltraCircuitBuilder_ : public UltraCircuitBui } void create_poseidon2_external_gate(const poseidon2_external_gate_& in); void create_poseidon2_internal_gate(const poseidon2_internal_gate_& in); + void create_poseidon2_end_gate(const poseidon2_end_gate_& in); FF compute_poseidon2_external_identity(FF q_poseidon2_external_value, FF q_1_value, From 4b3ca57d5fbdb4807962607a4ea7153739f047da Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Tue, 5 Dec 2023 23:10:45 +0000 Subject: [PATCH 06/38] using the gates in poseidon2 permutation (with bugs) --- .../stdlib/hash/poseidon2/poseidon2.hpp | 2 +- .../hash/poseidon2/poseidon2_permutation.hpp | 39 +++++++++++++++++++ .../circuit_builders/circuit_builders_fwd.hpp | 3 ++ 3 files changed, 43 insertions(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp index baa82f0d6ee..16888eb86f2 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp @@ -29,6 +29,6 @@ template class poseidon2_hash { static field_t hash_buffer(const stdlib::byte_array& input); }; -EXTERN_STDLIB_TYPE(poseidon2_hash); +EXTERN_STDLIB_GOBLIN_ULTRA_TYPE(poseidon2_hash); } // namespace proof_system::plonk::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp index 0c213b5ba7e..c125eb5268b 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp @@ -4,6 +4,7 @@ #include #include "barretenberg/crypto/poseidon2/poseidon2_permutation.hpp" +#include "barretenberg/proof_system/arithmetization/gate_data.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" namespace proof_system::plonk::stdlib { @@ -37,6 +38,8 @@ template class Poseidon2Permutation { static constexpr RoundConstantsContainer round_constants = Params::round_constants; static State permutation(const State& input) { + Builder* ctx = input[0].get_context(); + assert(ctx != nullptr); // deep copy State current_state(input); NativeState current_native_state; @@ -49,24 +52,60 @@ template class Poseidon2Permutation { constexpr size_t rounds_f_beginning = rounds_f / 2; for (size_t i = 0; i < rounds_f_beginning; ++i) { + poseidon2_external_gate_ in{ current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index, + i }; + ctx->create_poseidon2_external_gate(in); // calculate the new witnesses NativePermutation::add_round_constants(current_native_state, round_constants[i]); NativePermutation::apply_sbox(current_native_state); NativePermutation::matrix_multiplication_external(current_native_state); + for (size_t j = 0; j < t; ++j) { + current_state[j] = field_t(ctx, current_native_state[j]); + } } const size_t p_end = rounds_f_beginning + rounds_p; for (size_t i = rounds_f_beginning; i < p_end; ++i) { + poseidon2_internal_gate_ in{ current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index, + i }; + ctx->create_poseidon2_internal_gate(in); current_native_state[0] += round_constants[i][0]; NativePermutation::apply_single_sbox(current_native_state[0]); NativePermutation::matrix_multiplication_internal(current_native_state); + for (size_t j = 0; j < t; ++j) { + current_state[j] = field_t(ctx, current_native_state[j]); + } } for (size_t i = p_end; i < NUM_ROUNDS; ++i) { + poseidon2_external_gate_ in{ current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index, + i }; + ctx->create_poseidon2_external_gate(in); + // calculate the new witnesses NativePermutation::add_round_constants(current_native_state, round_constants[i]); NativePermutation::apply_sbox(current_native_state); NativePermutation::matrix_multiplication_external(current_native_state); + for (size_t j = 0; j < t; ++j) { + current_state[j] = field_t(ctx, current_native_state[j]); + } } + // need to add an extra row here to ensure that things check out + poseidon2_end_gate_ in{ + current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index, + }; + ctx->create_poseidon2_end_gate(in); return current_state; } }; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp index 5b46b4c25d5..2ecb07837ce 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp @@ -59,6 +59,9 @@ using GoblinUltraCircuitBuilder = GoblinUltraCircuitBuilder_; \ extern template class stdlib_type; +#define EXTERN_STDLIB_GOBLIN_ULTRA_TYPE(stdlib_type) \ + extern template class stdlib_type; + #define EXTERN_STDLIB_ULTRA_TYPE_VA(stdlib_type, ...) \ extern template class stdlib_type; \ extern template class stdlib_type; From 4b68594171f33aeba942428cf76fe44a7216bd35 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Tue, 5 Dec 2023 23:26:41 +0000 Subject: [PATCH 07/38] compile bug with templating fixed (thanks adam) --- .../cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp | 2 +- .../cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp | 2 +- .../primitives/circuit_builders/circuit_builders_fwd.hpp | 3 --- 3 files changed, 2 insertions(+), 5 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp index a44647f039e..a2d53659624 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp @@ -51,6 +51,6 @@ template field_t poseidon2_hash::hash_buffer(const stdlib::by } return hashed; } -INSTANTIATE_STDLIB_TYPE(poseidon2_hash); +template class poseidon2_hash; } // namespace proof_system::plonk::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp index 16888eb86f2..a474a053195 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp @@ -29,6 +29,6 @@ template class poseidon2_hash { static field_t hash_buffer(const stdlib::byte_array& input); }; -EXTERN_STDLIB_GOBLIN_ULTRA_TYPE(poseidon2_hash); +extern template class poseidon2_hash; } // namespace proof_system::plonk::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp b/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp index 2ecb07837ce..5b46b4c25d5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp @@ -59,9 +59,6 @@ using GoblinUltraCircuitBuilder = GoblinUltraCircuitBuilder_; \ extern template class stdlib_type; -#define EXTERN_STDLIB_GOBLIN_ULTRA_TYPE(stdlib_type) \ - extern template class stdlib_type; - #define EXTERN_STDLIB_ULTRA_TYPE_VA(stdlib_type, ...) \ extern template class stdlib_type; \ extern template class stdlib_type; From aaec935d50e99bf300c907bcd1d203663501f9b3 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Wed, 6 Dec 2023 20:01:53 +0000 Subject: [PATCH 08/38] added initial external mul gates --- .../hash/poseidon2/poseidon2_permutation.hpp | 103 ++++++++++++++++++ 1 file changed, 103 insertions(+) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp index c125eb5268b..edccce973f5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp @@ -49,6 +49,7 @@ template class Poseidon2Permutation { // Apply 1st linear layer NativePermutation::matrix_multiplication_external(current_native_state); + initial_external_matrix_multiplication(current_state); constexpr size_t rounds_f_beginning = rounds_f / 2; for (size_t i = 0; i < rounds_f_beginning; ++i) { @@ -108,5 +109,107 @@ template class Poseidon2Permutation { ctx->create_poseidon2_end_gate(in); return current_state; } + + static void initial_external_matrix_multiplication(State& state) + { + Builder* ctx = state[0].get_context(); + assert(ctx != nullptr); + + // create the 6 gates for the initial matrix multiplication + // gate 1: Compute tmp1 = state[0] + state[1] + 2 * state[3] + field_t tmp1{ ctx, state[0].get_value() + state[1].get_value() + 2 * state[3].get_value() }; + add_quad_ in{ + .a = state[0].witness_index, + .b = state[1].witness_index, + .c = state[3].witness_index, + .d = tmp1, + .a_scaling = 1, + .b_scaling = 1, + .c_scaling = 2, + .d_scaling = -1, + .const_scaling = 0, + }; + ctx->create_add_quad_gate(in); + + // gate 2: Compute tmp2 = 2 * state[1] + state[2] + state[3] + field_t tmp2{ ctx, 2 * state[1].get_value() + state[2].get_value() + state[3].get_value() }; + in = { + .a = state[1].witness_index, + .b = state[2].witness_index, + .c = state[3].witness_index, + .d = tmp2, + .a_scaling = 2, + .b_scaling = 1, + .c_scaling = 1, + .d_scaling = -1, + .const_scaling = 0, + }; + ctx->create_add_quad_gate(in); + + // gate 3: Compute v2 = 4 * state[0] + 4 * state[1] + tmp2 + field_t v2{ ctx, 4 * state[0].get_value() + 4 * state[1].get_value() + tmp2.get_value() }; + in = { + .a = state[0].witness_index, + .b = state[1].witness_index, + .c = tmp2, + .d = v2, + .a_scaling = 4, + .b_scaling = 4, + .c_scaling = 1, + .d_scaling = -1, + .const_scaling = 0, + }; + ctx->create_add_quad_gate(in); + + // gate 4: Compute v1 = v2 + tmp1 + field_t v1{ ctx, v2.get_value() + tmp1.get_value() }; + in = { + .a = v2, + .b = tmp1, + .c = v1, + .d = ctx->zero_idx, + .a_scaling = 1, + .b_scaling = 1, + .c_scaling = -1, + .d_scaling = 0, + .const_scaling = 0, + }; + ctx->create_add_quad_gate(in); + + // gate 5: Compute v4 = tmp1 + 4 * state[2] + 4 * state[3] + field_t v4{ ctx, tmp1.get_value() + 4 * state[2].get_value() + 4 * state[3].get_value() }; + in = { + .a = tmp1, + .b = state[2].witness_index, + .c = state[3].witness_index, + .d = v4, + .a_scaling = 1, + .b_scaling = 4, + .c_scaling = 4, + .d_scaling = -1, + .const_scaling = 0, + }; + ctx->create_add_quad_gate(in); + + // gate 6: Compute v3 = v4 + tmp2 + field_t v3{ ctx, v4.get_value() + tmp2.get_value() }; + in = { + .a = v4, + .b = tmp2, + .c = v3, + .d = ctx->zero_idx, + .a_scaling = 1, + .b_scaling = 1, + .c_scaling = -1, + .d_scaling = 0, + .const_scaling = 0, + }; + ctx->create_add_quad_gate(in); + + state[0] = v1; + state[1] = v2; + state[2] = v3; + state[3] = v4; + } }; } // namespace proof_system::plonk::stdlib \ No newline at end of file From 45dc5d44e6c465e9ae9f0258606bbc5bcf1aef23 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Wed, 6 Dec 2023 20:02:04 +0000 Subject: [PATCH 09/38] renaming field_t to FF --- .../stdlib/hash/poseidon2/sponge/sponge.hpp | 42 ++++++++----------- 1 file changed, 17 insertions(+), 25 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp index 9f20a6e589d..66a1b073e75 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp @@ -19,7 +19,7 @@ namespace proof_system::plonk::stdlib { * * Note: If we ever use this sponge class for more than 1 hash functions, we should move this out of `poseidon2` * and into its own directory - * @tparam field_t + * @tparam FF * @tparam rate * @tparam capacity * @tparam t @@ -38,16 +38,17 @@ template ; // sponge state. t = rate + capacity. capacity = 1 field element (~256 bits) - std::array, t> state; + std::array state; // cached elements that have been absorbed. - std::array, rate> cache; + std::array cache; size_t cache_size = 0; Mode mode = Mode::ABSORB; - FieldSponge(field_t domain_iv = 0) + FieldSponge(FF domain_iv = 0) { for (size_t i = 0; i < rate; ++i) { state[i] = 0; @@ -55,7 +56,7 @@ template , rate> perform_duplex() + std::array perform_duplex() { // zero-pad the cache for (size_t i = cache_size; i < rate; ++i) { @@ -67,14 +68,14 @@ template , rate> output; + std::array output; for (size_t i = 0; i < rate; ++i) { output[i] = state[i]; } return output; } - void absorb(const field_t& input) + void absorb(const FF& input) { if (mode == Mode::ABSORB && cache_size == rate) { // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache @@ -94,7 +95,7 @@ template squeeze() + FF squeeze() { if (mode == Mode::SQUEEZE && cache_size == 0) { // If we're in squeze mode and the cache is empty, there is nothing left to squeeze out of the sponge! @@ -114,7 +115,7 @@ template result = cache[0]; + FF result = cache[0]; for (size_t i = 1; i < cache_size; ++i) { cache[i - 1] = cache[i]; } @@ -129,10 +130,9 @@ template , out_len> + * @return std::array */ - template - static std::array, out_len> hash_internal(std::span> input) + template static std::array hash_internal(std::span input) { size_t in_len = input.size(); const uint256_t iv = (static_cast(in_len) << 64) + out_len - 1; @@ -149,31 +149,23 @@ template , out_len> output; + std::array output; for (size_t i = 0; i < out_len; ++i) { output[i] = sponge.squeeze(); } return output; } - template - static std::array, out_len> hash_fixed_length(std::span> input) + template static std::array hash_fixed_length(std::span input) { return hash_internal(input); } - static field_t hash_fixed_length(std::span> input) - { - return hash_fixed_length<1>(input)[0]; - } + static FF hash_fixed_length(std::span input) { return hash_fixed_length<1>(input)[0]; } - template - static std::array, out_len> hash_variable_length(std::span> input) + template static std::array hash_variable_length(std::span input) { return hash_internal(input); } - static field_t hash_variable_length(std::span> input) - { - return hash_variable_length<1>(input)[0]; - } + static FF hash_variable_length(std::span input) { return hash_variable_length<1>(input)[0]; } }; } // namespace proof_system::plonk::stdlib \ No newline at end of file From d933eef2c3fd0a4d1b6a4a68c3b4ba560260efbe Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Wed, 6 Dec 2023 20:08:28 +0000 Subject: [PATCH 10/38] fixed compile problems --- .../hash/poseidon2/poseidon2_permutation.hpp | 44 +++++++++---------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp index edccce973f5..91a38f11b48 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp @@ -117,56 +117,56 @@ template class Poseidon2Permutation { // create the 6 gates for the initial matrix multiplication // gate 1: Compute tmp1 = state[0] + state[1] + 2 * state[3] - field_t tmp1{ ctx, state[0].get_value() + state[1].get_value() + 2 * state[3].get_value() }; + field_t tmp1{ ctx, state[0].get_value() + state[1].get_value() + FF(2) * state[3].get_value() }; add_quad_ in{ .a = state[0].witness_index, .b = state[1].witness_index, .c = state[3].witness_index, - .d = tmp1, + .d = tmp1.witness_index, .a_scaling = 1, .b_scaling = 1, .c_scaling = 2, .d_scaling = -1, .const_scaling = 0, }; - ctx->create_add_quad_gate(in); + ctx->create_big_add_gate(in); // gate 2: Compute tmp2 = 2 * state[1] + state[2] + state[3] - field_t tmp2{ ctx, 2 * state[1].get_value() + state[2].get_value() + state[3].get_value() }; + field_t tmp2{ ctx, FF(2) * state[1].get_value() + state[2].get_value() + state[3].get_value() }; in = { .a = state[1].witness_index, .b = state[2].witness_index, .c = state[3].witness_index, - .d = tmp2, + .d = tmp2.witness_index, .a_scaling = 2, .b_scaling = 1, .c_scaling = 1, .d_scaling = -1, .const_scaling = 0, }; - ctx->create_add_quad_gate(in); + ctx->create_big_add_gate(in); // gate 3: Compute v2 = 4 * state[0] + 4 * state[1] + tmp2 - field_t v2{ ctx, 4 * state[0].get_value() + 4 * state[1].get_value() + tmp2.get_value() }; + field_t v2{ ctx, FF(4) * state[0].get_value() + FF(4) * state[1].get_value() + tmp2.get_value() }; in = { .a = state[0].witness_index, .b = state[1].witness_index, - .c = tmp2, - .d = v2, + .c = tmp2.witness_index, + .d = v2.witness_index, .a_scaling = 4, .b_scaling = 4, .c_scaling = 1, .d_scaling = -1, .const_scaling = 0, }; - ctx->create_add_quad_gate(in); + ctx->create_big_add_gate(in); // gate 4: Compute v1 = v2 + tmp1 field_t v1{ ctx, v2.get_value() + tmp1.get_value() }; in = { - .a = v2, - .b = tmp1, - .c = v1, + .a = v2.witness_index, + .b = tmp1.witness_index, + .c = v1.witness_index, .d = ctx->zero_idx, .a_scaling = 1, .b_scaling = 1, @@ -174,29 +174,29 @@ template class Poseidon2Permutation { .d_scaling = 0, .const_scaling = 0, }; - ctx->create_add_quad_gate(in); + ctx->create_big_add_gate(in); // gate 5: Compute v4 = tmp1 + 4 * state[2] + 4 * state[3] - field_t v4{ ctx, tmp1.get_value() + 4 * state[2].get_value() + 4 * state[3].get_value() }; + field_t v4{ ctx, tmp1.get_value() + FF(4) * state[2].get_value() + FF(4) * state[3].get_value() }; in = { - .a = tmp1, + .a = tmp1.witness_index, .b = state[2].witness_index, .c = state[3].witness_index, - .d = v4, + .d = v4.witness_index, .a_scaling = 1, .b_scaling = 4, .c_scaling = 4, .d_scaling = -1, .const_scaling = 0, }; - ctx->create_add_quad_gate(in); + ctx->create_big_add_gate(in); // gate 6: Compute v3 = v4 + tmp2 field_t v3{ ctx, v4.get_value() + tmp2.get_value() }; in = { - .a = v4, - .b = tmp2, - .c = v3, + .a = v4.witness_index, + .b = tmp2.witness_index, + .c = v3.witness_index, .d = ctx->zero_idx, .a_scaling = 1, .b_scaling = 1, @@ -204,7 +204,7 @@ template class Poseidon2Permutation { .d_scaling = 0, .const_scaling = 0, }; - ctx->create_add_quad_gate(in); + ctx->create_big_add_gate(in); state[0] = v1; state[1] = v2; From 171b0e8ec73a21fb4b758bb5357881e0fc357916 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Wed, 6 Dec 2023 22:15:52 +0000 Subject: [PATCH 11/38] naming: poseidon2_hash->poseidon2 --- .../src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt | 2 +- .../src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp | 6 +++--- .../src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt index cc2413569fb..027032aaca9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(stdlib_poseidon2_hash stdlib_primitives) \ No newline at end of file +barretenberg_module(stdlib_poseidon2 stdlib_primitives) \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp index a2d53659624..e4f4a38fd39 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp @@ -5,7 +5,7 @@ namespace proof_system::plonk::stdlib { using namespace barretenberg; using namespace proof_system; -template field_t poseidon2_hash::hash(const std::vector& inputs) +template field_t poseidon2::hash(const std::vector& inputs) { /* Run the sponge by absorbing all the input and squeezing one output. @@ -20,7 +20,7 @@ template field_t poseidon2_hash::hash(const std::vector field_t poseidon2_hash::hash_buffer(const stdlib::byte_array& input) +template field_t poseidon2::hash_buffer(const stdlib::byte_array& input) { const size_t num_bytes = input.size(); const size_t bytes_per_element = 31; @@ -51,6 +51,6 @@ template field_t poseidon2_hash::hash_buffer(const stdlib::by } return hashed; } -template class poseidon2_hash; +template class poseidon2; } // namespace proof_system::plonk::stdlib diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp index a474a053195..9947e062c1f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp @@ -11,11 +11,11 @@ namespace proof_system::plonk::stdlib { using namespace barretenberg; /** * @brief stdlib class that evaluates in-circuit poseidon2 hashes, consistent with behavior in - * crypto::poseidon2_hash + * crypto::poseidon2 * * @tparam Builder */ -template class poseidon2_hash { +template class poseidon2 { private: using field_t = stdlib::field_t; @@ -29,6 +29,6 @@ template class poseidon2_hash { static field_t hash_buffer(const stdlib::byte_array& input); }; -extern template class poseidon2_hash; +extern template class poseidon2; } // namespace proof_system::plonk::stdlib From dc5f3f9955f3cd813072b26f62ed25775544dad7 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Wed, 6 Dec 2023 22:17:01 +0000 Subject: [PATCH 12/38] hash_buffers function to native poseidon2 and update to hash input type --- .../crypto/poseidon2/poseidon2.bench.cpp | 3 +- .../crypto/poseidon2/poseidon2.hpp | 35 ++++++++++++++++++- .../crypto/poseidon2/poseidon2.test.cpp | 2 +- 3 files changed, 36 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.bench.cpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.bench.cpp index 603238bf6e8..6b1b1457997 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.bench.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.bench.cpp @@ -10,9 +10,8 @@ grumpkin::fq poseidon_function(const size_t count) for (size_t i = 0; i < count; ++i) { inputs[i] = grumpkin::fq::random_element(); } - std::span tmp(inputs); // hash count many field elements - inputs[0] = crypto::Poseidon2::hash(tmp); + inputs[0] = crypto::Poseidon2::hash(inputs); return inputs[0]; } diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp index 15488e2d0b3..ff33e54fefe 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp @@ -11,6 +11,39 @@ template class Poseidon2 { using FF = typename Params::FF; using Sponge = FieldSponge>; - static FF hash(std::span input) { return Sponge::hash_fixed_length(input); } + static FF hash(const std::vector& input) + { + auto input_span = input; + return Sponge::hash_fixed_length(input_span); + } + static FF hash_buffer(const std::vector& input) + { + const size_t num_bytes = input.size(); + const size_t bytes_per_element = 31; + size_t num_elements = static_cast(num_bytes % bytes_per_element != 0) + (num_bytes / bytes_per_element); + + const auto slice = [](const std::vector& data, const size_t start, const size_t slice_size) { + uint256_t result(0); + for (size_t i = 0; i < slice_size; ++i) { + result = (result << uint256_t(8)); + result += uint256_t(data[i + start]); + } + return FF(result); + }; + + std::vector converted; + for (size_t i = 0; i < num_elements; ++i) { + size_t bytes_to_slice = 0; + if (i == num_elements - 1) { + bytes_to_slice = num_bytes - (i * bytes_per_element); + } else { + bytes_to_slice = bytes_per_element; + } + FF element = slice(input, i * bytes_per_element, bytes_to_slice); + converted.emplace_back(element); + } + + return hash(converted); + } }; } // namespace crypto \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp index 33757efd2b1..2081d531730 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp @@ -39,7 +39,7 @@ TEST(Poseidon2, ConsistencyCheck) barretenberg::fr c(std::string("0x9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); barretenberg::fr d(std::string("0x9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); - std::array input{ a, b, c, d }; + std::vector input{ a, b, c, d }; auto result = crypto::Poseidon2::hash(input); barretenberg::fr expected(std::string("0x150c19ae11b3290c137c7a4d760d9482a6581d731535f560c3601d6a766b0937")); From 26b19302470b0405ac2d7994b9bcaa0e32b60347 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Wed, 6 Dec 2023 22:17:24 +0000 Subject: [PATCH 13/38] new stdlib test file copied from pedersen --- .../stdlib/hash/poseidon2/poseidon2.test.cpp | 313 ++++++++++++++++++ 1 file changed, 313 insertions(+) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp new file mode 100644 index 00000000000..23323c953e1 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp @@ -0,0 +1,313 @@ +#include "poseidon2.hpp" +#include "barretenberg/common/test.hpp" +#include "barretenberg/crypto/poseidon2/poseidon2.hpp" +#include "barretenberg/numeric/random/engine.hpp" +#include "barretenberg/stdlib/primitives/curves/bn254.hpp" + +namespace test_StdlibPoseidon2 { +using namespace barretenberg; +using namespace proof_system::plonk; +namespace { +auto& engine = numeric::random::get_debug_engine(); +} + +template class StdlibPoseidon2 : public testing::Test { + using _curve = stdlib::bn254; + + using byte_array_ct = typename _curve::byte_array_ct; + using fr_ct = typename _curve::ScalarField; + using witness_ct = typename _curve::witness_ct; + using public_witness_ct = typename _curve::public_witness_ct; + using poseidon2 = typename stdlib::poseidon2; + using native_poseidon2 = crypto::Poseidon2; + + public: + static void test_poseidon2() + { + + Builder builder; + + fr left_in = fr::random_element(); + fr right_in = fr::random_element(); + + // ensure left has skew 1, right has skew 0 + if ((left_in.from_montgomery_form().data[0] & 1) == 1) { + left_in += fr::one(); + } + if ((right_in.from_montgomery_form().data[0] & 1) == 0) { + right_in += fr::one(); + } + + fr_ct left = public_witness_ct(&builder, left_in); + fr_ct right = witness_ct(&builder, right_in); + + builder.fix_witness(left.witness_index, left.get_value()); + builder.fix_witness(right.witness_index, right.get_value()); + + fr_ct out = poseidon2::hash({ left, right }); + + info("num gates = ", builder.get_num_gates()); + + bool result = builder.check_circuit(); + EXPECT_EQ(result, true); + + fr hash_native = native_poseidon2::hash({ left.get_value(), right.get_value() }); + EXPECT_EQ(out.get_value(), hash_native); + } + + static void test_poseidon2_edge_cases() + { + Builder builder; + + fr zero_fr = fr::zero(); + fr one_fr = fr::one(); + fr r_minus_one_fr = fr::modulus - 1; + fr r_minus_two_fr = fr::modulus - 2; + fr r_fr = fr::modulus; + + fr_ct zero = witness_ct(&builder, zero_fr); + fr_ct one = witness_ct(&builder, one_fr); + fr_ct r_minus_one = witness_ct(&builder, r_minus_one_fr); + fr_ct r_minus_two = witness_ct(&builder, r_minus_two_fr); + fr_ct r = witness_ct(&builder, r_fr); + + fr_ct out_1_with_zero = poseidon2::hash({ zero, one }); + fr_ct out_1_with_r = poseidon2::hash({ r, one }); + fr_ct out_2 = poseidon2::hash({ r_minus_one, r_minus_two }); + fr_ct out_with_zero = poseidon2::hash({ out_1_with_zero, out_2 }); + fr_ct out_with_r = poseidon2::hash({ out_1_with_r, out_2 }); + + info("num gates = ", builder.get_num_gates()); + + bool result = builder.check_circuit(); + EXPECT_EQ(result, true); + + EXPECT_EQ(bool(out_1_with_zero.get_value() == out_1_with_r.get_value()), true); + + fr hash_native_1_with_zero = native_poseidon2::hash({ zero.get_value(), one.get_value() }); + fr hash_native_1_with_r = native_poseidon2::hash({ r.get_value(), one.get_value() }); + fr hash_native_2 = native_poseidon2::hash({ r_minus_one.get_value(), r_minus_two.get_value() }); + fr hash_native_with_zero = native_poseidon2::hash({ out_1_with_zero.get_value(), out_2.get_value() }); + fr hash_native_with_r = native_poseidon2::hash({ out_1_with_r.get_value(), out_2.get_value() }); + + EXPECT_EQ(out_1_with_zero.get_value(), hash_native_1_with_zero); + EXPECT_EQ(out_1_with_r.get_value(), hash_native_1_with_r); + EXPECT_EQ(out_2.get_value(), hash_native_2); + EXPECT_EQ(out_with_zero.get_value(), hash_native_with_zero); + EXPECT_EQ(out_with_r.get_value(), hash_native_with_r); + EXPECT_EQ(hash_native_with_zero, hash_native_with_r); + } + + static void test_poseidon2_large() + { + Builder builder; + + fr left_in = fr::random_element(); + fr right_in = fr::random_element(); + // ensure left has skew 1, right has skew 0 + if ((left_in.from_montgomery_form().data[0] & 1) == 1) { + left_in += fr::one(); + } + if ((right_in.from_montgomery_form().data[0] & 1) == 0) { + right_in += fr::one(); + } + fr_ct left = witness_ct(&builder, left_in); + fr_ct right = witness_ct(&builder, right_in); + + for (size_t i = 0; i < 256; ++i) { + left = poseidon2::hash({ left, right }); + } + + builder.set_public_input(left.witness_index); + + info("num gates = ", builder.get_num_gates()); + + bool result = builder.check_circuit(); + EXPECT_EQ(result, true); + } + + static void test_hash_byte_array() + { + const size_t num_input_bytes = 351; + + Builder builder; + + std::vector input; + input.reserve(num_input_bytes); + for (size_t i = 0; i < num_input_bytes; ++i) { + input.push_back(engine.get_random_uint8()); + } + + fr expected = native_poseidon2::hash_buffer(input); + + byte_array_ct circuit_input(&builder, input); + auto result = poseidon2::hash_buffer(circuit_input); + + EXPECT_EQ(result.get_value(), expected); + + info("num gates = ", builder.get_num_gates()); + + bool proof_result = builder.check_circuit(); + EXPECT_EQ(proof_result, true); + } + + static void test_multi_hash() + { + Builder builder; + + for (size_t i = 0; i < 7; ++i) { + std::vector inputs; + inputs.push_back(barretenberg::fr::random_element()); + inputs.push_back(barretenberg::fr::random_element()); + inputs.push_back(barretenberg::fr::random_element()); + inputs.push_back(barretenberg::fr::random_element()); + + if (i == 1) { + inputs[0] = barretenberg::fr(0); + } + if (i == 2) { + inputs[1] = barretenberg::fr(0); + inputs[2] = barretenberg::fr(0); + } + if (i == 3) { + inputs[3] = barretenberg::fr(0); + } + if (i == 4) { + inputs[0] = barretenberg::fr(0); + inputs[3] = barretenberg::fr(0); + } + if (i == 5) { + inputs[0] = barretenberg::fr(0); + inputs[1] = barretenberg::fr(0); + inputs[2] = barretenberg::fr(0); + inputs[3] = barretenberg::fr(0); + } + if (i == 6) { + inputs[1] = barretenberg::fr(1); + } + std::vector witnesses; + for (auto input : inputs) { + witnesses.push_back(witness_ct(&builder, input)); + } + + barretenberg::fr expected = native_poseidon2::hash(inputs); + + fr_ct result = poseidon2::hash(witnesses); + EXPECT_EQ(result.get_value(), expected); + } + + info("num gates = ", builder.get_num_gates()); + + bool proof_result = builder.check_circuit(); + EXPECT_EQ(proof_result, true); + } + + static void test_hash_eight() + { + Builder builder; + + std::vector inputs; + inputs.reserve(8); + std::vector> witness_inputs; + + for (size_t i = 0; i < 8; ++i) { + inputs.emplace_back(barretenberg::fr::random_element()); + witness_inputs.emplace_back(witness_ct(&builder, inputs[i])); + } + + fr expected = native_poseidon2::hash(inputs); + auto result = poseidon2::hash(witness_inputs); + + EXPECT_EQ(result.get_value(), expected); + } + + static void test_hash_constants() + { + Builder builder; + + std::vector inputs; + std::vector> witness_inputs; + + for (size_t i = 0; i < 8; ++i) { + inputs.push_back(barretenberg::fr::random_element()); + if (i % 2 == 1) { + witness_inputs.push_back(witness_ct(&builder, inputs[i])); + } else { + witness_inputs.push_back(fr_ct(&builder, inputs[i])); + } + } + + barretenberg::fr expected = native_poseidon2::hash(inputs); + auto result = poseidon2::hash(witness_inputs); + + EXPECT_EQ(result.get_value(), expected); + } +}; + +using CircuitTypes = testing::Types; + +TYPED_TEST_SUITE(StdlibPoseidon2, CircuitTypes); + +TYPED_TEST(StdlibPoseidon2, TestHash) +{ + using Builder = TypeParam; + using field_ct = stdlib::field_t; + using witness_ct = stdlib::witness_t; + auto composer = Builder(); + + const size_t num_inputs = 10; + + std::vector inputs; + std::vector inputs_native; + + for (size_t i = 0; i < num_inputs; ++i) { + const auto element = fr::random_element(&engine); + inputs_native.emplace_back(element); + inputs.emplace_back(field_ct(witness_ct(&composer, element))); + } + + auto result = stdlib::poseidon2::hash(inputs); + auto expected = crypto::Poseidon2::hash(inputs_native); + + EXPECT_EQ(result.get_value(), expected); + + bool proof_result = composer.check_circuit(); + EXPECT_EQ(proof_result, true); +} + +TYPED_TEST(StdlibPoseidon2, Small) +{ + TestFixture::test_poseidon2(); +}; + +TYPED_TEST(StdlibPoseidon2, EdgeCases) +{ + TestFixture::test_poseidon2_edge_cases(); +}; + +HEAVY_TYPED_TEST(StdlibPoseidon2, Large) +{ + TestFixture::test_poseidon2_large(); +}; + +TYPED_TEST(StdlibPoseidon2, HashByteArray) +{ + TestFixture::test_hash_byte_array(); +}; + +TYPED_TEST(StdlibPoseidon2, MultiHash) +{ + TestFixture::test_multi_hash(); +}; + +TYPED_TEST(StdlibPoseidon2, HashEight) +{ + TestFixture::test_hash_eight(); +}; + +TYPED_TEST(StdlibPoseidon2, HashConstants) +{ + TestFixture::test_hash_constants(); +}; + +} // namespace test_StdlibPoseidon2 From 0e312e97f483c47deaf635db4c1b51287e714671 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Thu, 7 Dec 2023 19:22:27 +0000 Subject: [PATCH 14/38] passing builder into everything --- .../stdlib/hash/poseidon2/poseidon2.cpp | 12 +- .../stdlib/hash/poseidon2/poseidon2.hpp | 4 +- .../stdlib/hash/poseidon2/poseidon2.test.cpp | 30 ++--- .../hash/poseidon2/poseidon2_permutation.hpp | 111 +++++++++--------- .../stdlib/hash/poseidon2/sponge/sponge.hpp | 55 +++++---- 5 files changed, 110 insertions(+), 102 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp index e4f4a38fd39..5e7625a78b2 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp @@ -5,7 +5,7 @@ namespace proof_system::plonk::stdlib { using namespace barretenberg; using namespace proof_system; -template field_t poseidon2::hash(const std::vector& inputs) +template field_t poseidon2::hash(C& builder, const std::vector& inputs) { /* Run the sponge by absorbing all the input and squeezing one output. @@ -13,14 +13,14 @@ template field_t poseidon2::hash(const std::vector& * */ auto input{ inputs }; - return Sponge::hash_fixed_length(input); + return Sponge::hash_fixed_length(builder, input); } /** * Hash a byte_array. * */ -template field_t poseidon2::hash_buffer(const stdlib::byte_array& input) +template field_t poseidon2::hash_buffer(C& builder, const stdlib::byte_array& input) { const size_t num_bytes = input.size(); const size_t bytes_per_element = 31; @@ -42,11 +42,11 @@ template field_t poseidon2::hash_buffer(const stdlib::byte_ar } field_t hashed; if (elements.size() < 2) { - hashed = hash(elements); + hashed = hash(builder, elements); } else { - hashed = hash({ elements[0], elements[1] }); + hashed = hash(builder, { elements[0], elements[1] }); for (size_t i = 2; i < elements.size(); ++i) { - hashed = hash({ hashed, elements[i] }); + hashed = hash(builder, { hashed, elements[i] }); } } return hashed; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp index 9947e062c1f..d050a3850c7 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp @@ -25,8 +25,8 @@ template class poseidon2 { using Sponge = FieldSponge; public: - static field_t hash(const std::vector& in); - static field_t hash_buffer(const stdlib::byte_array& input); + static field_t hash(Builder& builder, const std::vector& in); + static field_t hash_buffer(Builder& builder, const stdlib::byte_array& input); }; extern template class poseidon2; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp index 23323c953e1..381e9d27c33 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp @@ -44,7 +44,7 @@ template class StdlibPoseidon2 : public testing::Test { builder.fix_witness(left.witness_index, left.get_value()); builder.fix_witness(right.witness_index, right.get_value()); - fr_ct out = poseidon2::hash({ left, right }); + fr_ct out = poseidon2::hash(builder, { left, right }); info("num gates = ", builder.get_num_gates()); @@ -71,11 +71,11 @@ template class StdlibPoseidon2 : public testing::Test { fr_ct r_minus_two = witness_ct(&builder, r_minus_two_fr); fr_ct r = witness_ct(&builder, r_fr); - fr_ct out_1_with_zero = poseidon2::hash({ zero, one }); - fr_ct out_1_with_r = poseidon2::hash({ r, one }); - fr_ct out_2 = poseidon2::hash({ r_minus_one, r_minus_two }); - fr_ct out_with_zero = poseidon2::hash({ out_1_with_zero, out_2 }); - fr_ct out_with_r = poseidon2::hash({ out_1_with_r, out_2 }); + fr_ct out_1_with_zero = poseidon2::hash(builder, { zero, one }); + fr_ct out_1_with_r = poseidon2::hash(builder, { r, one }); + fr_ct out_2 = poseidon2::hash(builder, { r_minus_one, r_minus_two }); + fr_ct out_with_zero = poseidon2::hash(builder, { out_1_with_zero, out_2 }); + fr_ct out_with_r = poseidon2::hash(builder, { out_1_with_r, out_2 }); info("num gates = ", builder.get_num_gates()); @@ -115,7 +115,7 @@ template class StdlibPoseidon2 : public testing::Test { fr_ct right = witness_ct(&builder, right_in); for (size_t i = 0; i < 256; ++i) { - left = poseidon2::hash({ left, right }); + left = poseidon2::hash(builder, { left, right }); } builder.set_public_input(left.witness_index); @@ -141,7 +141,7 @@ template class StdlibPoseidon2 : public testing::Test { fr expected = native_poseidon2::hash_buffer(input); byte_array_ct circuit_input(&builder, input); - auto result = poseidon2::hash_buffer(circuit_input); + auto result = poseidon2::hash_buffer(builder, circuit_input); EXPECT_EQ(result.get_value(), expected); @@ -192,7 +192,7 @@ template class StdlibPoseidon2 : public testing::Test { barretenberg::fr expected = native_poseidon2::hash(inputs); - fr_ct result = poseidon2::hash(witnesses); + fr_ct result = poseidon2::hash(builder, witnesses); EXPECT_EQ(result.get_value(), expected); } @@ -216,7 +216,7 @@ template class StdlibPoseidon2 : public testing::Test { } fr expected = native_poseidon2::hash(inputs); - auto result = poseidon2::hash(witness_inputs); + auto result = poseidon2::hash(builder, witness_inputs); EXPECT_EQ(result.get_value(), expected); } @@ -238,7 +238,7 @@ template class StdlibPoseidon2 : public testing::Test { } barretenberg::fr expected = native_poseidon2::hash(inputs); - auto result = poseidon2::hash(witness_inputs); + auto result = poseidon2::hash(builder, witness_inputs); EXPECT_EQ(result.get_value(), expected); } @@ -253,7 +253,7 @@ TYPED_TEST(StdlibPoseidon2, TestHash) using Builder = TypeParam; using field_ct = stdlib::field_t; using witness_ct = stdlib::witness_t; - auto composer = Builder(); + auto builder = Builder(); const size_t num_inputs = 10; @@ -263,15 +263,15 @@ TYPED_TEST(StdlibPoseidon2, TestHash) for (size_t i = 0; i < num_inputs; ++i) { const auto element = fr::random_element(&engine); inputs_native.emplace_back(element); - inputs.emplace_back(field_ct(witness_ct(&composer, element))); + inputs.emplace_back(field_ct(witness_ct(&builder, element))); } - auto result = stdlib::poseidon2::hash(inputs); + auto result = stdlib::poseidon2::hash(builder, inputs); auto expected = crypto::Poseidon2::hash(inputs_native); EXPECT_EQ(result.get_value(), expected); - bool proof_result = composer.check_circuit(); + bool proof_result = builder.check_circuit(); EXPECT_EQ(proof_result, true); } diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp index 91a38f11b48..98f17de73a8 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp @@ -36,10 +36,9 @@ template class Poseidon2Permutation { using RoundConstants = std::array; using RoundConstantsContainer = std::array; static constexpr RoundConstantsContainer round_constants = Params::round_constants; - static State permutation(const State& input) + + static State permutation(Builder* builder, const State& input) { - Builder* ctx = input[0].get_context(); - assert(ctx != nullptr); // deep copy State current_state(input); NativeState current_native_state; @@ -49,7 +48,7 @@ template class Poseidon2Permutation { // Apply 1st linear layer NativePermutation::matrix_multiplication_external(current_native_state); - initial_external_matrix_multiplication(current_state); + initial_external_matrix_multiplication(builder, current_state); constexpr size_t rounds_f_beginning = rounds_f / 2; for (size_t i = 0; i < rounds_f_beginning; ++i) { @@ -58,13 +57,13 @@ template class Poseidon2Permutation { current_state[2].witness_index, current_state[3].witness_index, i }; - ctx->create_poseidon2_external_gate(in); + builder->create_poseidon2_external_gate(in); // calculate the new witnesses NativePermutation::add_round_constants(current_native_state, round_constants[i]); NativePermutation::apply_sbox(current_native_state); NativePermutation::matrix_multiplication_external(current_native_state); for (size_t j = 0; j < t; ++j) { - current_state[j] = field_t(ctx, current_native_state[j]); + current_state[j] = field_t(builder, current_native_state[j]); } } @@ -75,12 +74,12 @@ template class Poseidon2Permutation { current_state[2].witness_index, current_state[3].witness_index, i }; - ctx->create_poseidon2_internal_gate(in); + builder->create_poseidon2_internal_gate(in); current_native_state[0] += round_constants[i][0]; NativePermutation::apply_single_sbox(current_native_state[0]); NativePermutation::matrix_multiplication_internal(current_native_state); for (size_t j = 0; j < t; ++j) { - current_state[j] = field_t(ctx, current_native_state[j]); + current_state[j] = field_t(builder, current_native_state[j]); } } @@ -90,13 +89,13 @@ template class Poseidon2Permutation { current_state[2].witness_index, current_state[3].witness_index, i }; - ctx->create_poseidon2_external_gate(in); + builder->create_poseidon2_external_gate(in); // calculate the new witnesses NativePermutation::add_round_constants(current_native_state, round_constants[i]); NativePermutation::apply_sbox(current_native_state); NativePermutation::matrix_multiplication_external(current_native_state); for (size_t j = 0; j < t; ++j) { - current_state[j] = field_t(ctx, current_native_state[j]); + current_state[j] = field_t(builder, current_native_state[j]); } } // need to add an extra row here to ensure that things check out @@ -106,110 +105,108 @@ template class Poseidon2Permutation { current_state[2].witness_index, current_state[3].witness_index, }; - ctx->create_poseidon2_end_gate(in); + builder->create_poseidon2_end_gate(in); return current_state; } - static void initial_external_matrix_multiplication(State& state) + static void initial_external_matrix_multiplication(Builder* builder, State& state) { - Builder* ctx = state[0].get_context(); - assert(ctx != nullptr); - // create the 6 gates for the initial matrix multiplication // gate 1: Compute tmp1 = state[0] + state[1] + 2 * state[3] - field_t tmp1{ ctx, state[0].get_value() + state[1].get_value() + FF(2) * state[3].get_value() }; - add_quad_ in{ + FF tmp1 = state[0].get_value() + state[1].get_value() + FF(2) * state[3].get_value(); + uint32_t tmp1_idx = builder->add_variable(tmp1); + + builder->create_big_add_gate({ .a = state[0].witness_index, .b = state[1].witness_index, .c = state[3].witness_index, - .d = tmp1.witness_index, + .d = tmp1_idx, .a_scaling = 1, .b_scaling = 1, .c_scaling = 2, .d_scaling = -1, .const_scaling = 0, - }; - ctx->create_big_add_gate(in); + }); // gate 2: Compute tmp2 = 2 * state[1] + state[2] + state[3] - field_t tmp2{ ctx, FF(2) * state[1].get_value() + state[2].get_value() + state[3].get_value() }; - in = { + FF tmp2 = FF(2) * state[1].get_value() + state[2].get_value() + state[3].get_value(); + uint32_t tmp2_idx = builder->add_variable(tmp2); + builder->create_big_add_gate({ .a = state[1].witness_index, .b = state[2].witness_index, .c = state[3].witness_index, - .d = tmp2.witness_index, + .d = tmp2_idx, .a_scaling = 2, .b_scaling = 1, .c_scaling = 1, .d_scaling = -1, .const_scaling = 0, - }; - ctx->create_big_add_gate(in); + }); // gate 3: Compute v2 = 4 * state[0] + 4 * state[1] + tmp2 - field_t v2{ ctx, FF(4) * state[0].get_value() + FF(4) * state[1].get_value() + tmp2.get_value() }; - in = { + FF v2 = FF(4) * state[0].get_value() + FF(4) * state[1].get_value() + tmp2; + uint32_t v2_idx = builder->add_variable(v2); + builder->create_big_add_gate({ .a = state[0].witness_index, .b = state[1].witness_index, - .c = tmp2.witness_index, - .d = v2.witness_index, + .c = tmp2_idx, + .d = v2_idx, .a_scaling = 4, .b_scaling = 4, .c_scaling = 1, .d_scaling = -1, .const_scaling = 0, - }; - ctx->create_big_add_gate(in); + }); // gate 4: Compute v1 = v2 + tmp1 - field_t v1{ ctx, v2.get_value() + tmp1.get_value() }; - in = { - .a = v2.witness_index, - .b = tmp1.witness_index, - .c = v1.witness_index, - .d = ctx->zero_idx, + FF v1 = v2 + tmp1; + uint32_t v1_idx = builder->add_variable(v1); + builder->create_big_add_gate({ + .a = v2_idx, + .b = tmp1_idx, + .c = v1_idx, + .d = builder->zero_idx, .a_scaling = 1, .b_scaling = 1, .c_scaling = -1, .d_scaling = 0, .const_scaling = 0, - }; - ctx->create_big_add_gate(in); + }); // gate 5: Compute v4 = tmp1 + 4 * state[2] + 4 * state[3] - field_t v4{ ctx, tmp1.get_value() + FF(4) * state[2].get_value() + FF(4) * state[3].get_value() }; - in = { - .a = tmp1.witness_index, + FF v4 = tmp1 + FF(4) * state[2].get_value() + FF(4) * state[3].get_value(); + uint32_t v4_idx = builder->add_variable(v4); + builder->create_big_add_gate({ + .a = tmp1_idx, .b = state[2].witness_index, .c = state[3].witness_index, - .d = v4.witness_index, + .d = v4_idx, .a_scaling = 1, .b_scaling = 4, .c_scaling = 4, .d_scaling = -1, .const_scaling = 0, - }; - ctx->create_big_add_gate(in); + }); // gate 6: Compute v3 = v4 + tmp2 - field_t v3{ ctx, v4.get_value() + tmp2.get_value() }; - in = { - .a = v4.witness_index, - .b = tmp2.witness_index, - .c = v3.witness_index, - .d = ctx->zero_idx, + FF v3 = v4 + tmp2; + uint32_t v3_idx = builder->add_variable(v3); + builder->create_big_add_gate({ + .a = v4_idx, + .b = tmp2_idx, + .c = v3_idx, + .d = builder->zero_idx, .a_scaling = 1, .b_scaling = 1, .c_scaling = -1, .d_scaling = 0, .const_scaling = 0, - }; - ctx->create_big_add_gate(in); + }); - state[0] = v1; - state[1] = v2; - state[2] = v3; - state[3] = v4; + state[0] = field_t::from_witness_index(builder, v1_idx); + state[1] = field_t::from_witness_index(builder, v2_idx); + state[2] = field_t::from_witness_index(builder, v3_idx); + state[3] = field_t::from_witness_index(builder, v4_idx); } }; } // namespace proof_system::plonk::stdlib \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp index 66a1b073e75..15f7b9e986f 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp @@ -19,7 +19,7 @@ namespace proof_system::plonk::stdlib { * * Note: If we ever use this sponge class for more than 1 hash functions, we should move this out of `poseidon2` * and into its own directory - * @tparam FF + * @tparam field_t * @tparam rate * @tparam capacity * @tparam t @@ -38,25 +38,27 @@ template ; + using field_t = field_t; // sponge state. t = rate + capacity. capacity = 1 field element (~256 bits) - std::array state; + std::array state; // cached elements that have been absorbed. - std::array cache; + std::array cache; size_t cache_size = 0; Mode mode = Mode::ABSORB; + Builder* builder; - FieldSponge(FF domain_iv = 0) + FieldSponge(Builder& builder_, field_t domain_iv = 0) { for (size_t i = 0; i < rate; ++i) { state[i] = 0; } - state[rate] = domain_iv; + builder = &builder_; + state[rate] = witness_t(&builder_, domain_iv.get_value()); } - std::array perform_duplex() + std::array perform_duplex() { // zero-pad the cache for (size_t i = cache_size; i < rate; ++i) { @@ -66,16 +68,16 @@ template output; + std::array output; for (size_t i = 0; i < rate; ++i) { output[i] = state[i]; } return output; } - void absorb(const FF& input) + void absorb(const field_t& input) { if (mode == Mode::ABSORB && cache_size == rate) { // If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache @@ -95,7 +97,7 @@ template + * @return std::array */ - template static std::array hash_internal(std::span input) + template + static std::array hash_internal(Builder& builder, std::span input) { size_t in_len = input.size(); const uint256_t iv = (static_cast(in_len) << 64) + out_len - 1; - FieldSponge sponge(iv); + FieldSponge sponge(builder, iv); for (size_t i = 0; i < in_len; ++i) { sponge.absorb(input[i]); @@ -149,23 +152,31 @@ template output; + std::array output; for (size_t i = 0; i < out_len; ++i) { output[i] = sponge.squeeze(); } return output; } - template static std::array hash_fixed_length(std::span input) + template + static std::array hash_fixed_length(Builder& builder, std::span input) { - return hash_internal(input); + return hash_internal(builder, input); + } + static field_t hash_fixed_length(Builder& builder, std::span input) + { + return hash_fixed_length<1>(builder, input)[0]; } - static FF hash_fixed_length(std::span input) { return hash_fixed_length<1>(input)[0]; } - template static std::array hash_variable_length(std::span input) + template + static std::array hash_variable_length(Builder& builder, std::span input) + { + return hash_internal(builder, input); + } + static field_t hash_variable_length(Builder& builder, std::span input) { - return hash_internal(input); + return hash_variable_length<1>(builder, input)[0]; } - static FF hash_variable_length(std::span input) { return hash_variable_length<1>(input)[0]; } }; } // namespace proof_system::plonk::stdlib \ No newline at end of file From 4126d04cbb7b127b2f445c88c99d0cd4e7c35aa9 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 8 Dec 2023 16:47:53 +0000 Subject: [PATCH 15/38] turned values into witnesses --- .../stdlib/hash/poseidon2/sponge/sponge.hpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp index 15f7b9e986f..7cc47b39b61 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp @@ -50,19 +50,20 @@ template (builder, 0); } - builder = &builder_; - state[rate] = witness_t(&builder_, domain_iv.get_value()); + info("domain iv: ", domain_iv.get_value()); + state[rate] = witness_t(builder, domain_iv.get_value()); } std::array perform_duplex() { // zero-pad the cache for (size_t i = cache_size; i < rate; ++i) { - cache[i] = 0; + cache[i] = witness_t(builder, 0); } // add the cache into sponge state for (size_t i = 0; i < rate; ++i) { @@ -122,7 +123,7 @@ template (builder, 0); return result; } From 8f8b7995ed210bdb5e4c69cea1605cf05282c870 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 8 Dec 2023 17:03:02 +0000 Subject: [PATCH 16/38] busread fix --- .../circuit_builder/goblin_ultra_circuit_builder.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp index 27682ce53f4..f657a42af01 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp @@ -311,7 +311,7 @@ template void GoblinUltraCircuitBuilder_::create_poseidon2_end this->q_lookup_type.emplace_back(0); this->q_elliptic.emplace_back(0); this->q_aux.emplace_back(0); - this->q_busread.emplace_back(0); + this->q_busread().emplace_back(0); this->q_poseidon2_external.emplace_back(0); this->q_poseidon2_internal.emplace_back(0); ++this->num_gates; From 7266f35b1f3327bf7e73496b7613470b86db2ec1 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 8 Dec 2023 17:14:17 +0000 Subject: [PATCH 17/38] other witness creations --- .../stdlib/hash/poseidon2/poseidon2_permutation.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp index 98f17de73a8..adbbfcd88f5 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp @@ -63,7 +63,7 @@ template class Poseidon2Permutation { NativePermutation::apply_sbox(current_native_state); NativePermutation::matrix_multiplication_external(current_native_state); for (size_t j = 0; j < t; ++j) { - current_state[j] = field_t(builder, current_native_state[j]); + current_state[j] = witness_t(builder, current_native_state[j]); } } @@ -79,7 +79,7 @@ template class Poseidon2Permutation { NativePermutation::apply_single_sbox(current_native_state[0]); NativePermutation::matrix_multiplication_internal(current_native_state); for (size_t j = 0; j < t; ++j) { - current_state[j] = field_t(builder, current_native_state[j]); + current_state[j] = witness_t(builder, current_native_state[j]); } } @@ -95,7 +95,7 @@ template class Poseidon2Permutation { NativePermutation::apply_sbox(current_native_state); NativePermutation::matrix_multiplication_external(current_native_state); for (size_t j = 0; j < t; ++j) { - current_state[j] = field_t(builder, current_native_state[j]); + current_state[j] = witness_t(builder, current_native_state[j]); } } // need to add an extra row here to ensure that things check out From f766e2b8ceb8522ff4c81a112ac7dcd797c863ff Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 8 Dec 2023 17:14:45 +0000 Subject: [PATCH 18/38] fixing stdlib poseidon2 hash_buffers --- .../barretenberg/stdlib/hash/poseidon2/poseidon2.cpp | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp index 5e7625a78b2..7b1162c8274 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp @@ -40,16 +40,7 @@ template field_t poseidon2::hash_buffer(C& builder, const std for (auto& x : elements) { std::cout << x << std::endl; } - field_t hashed; - if (elements.size() < 2) { - hashed = hash(builder, elements); - } else { - hashed = hash(builder, { elements[0], elements[1] }); - for (size_t i = 2; i < elements.size(); ++i) { - hashed = hash(builder, { hashed, elements[i] }); - } - } - return hashed; + return hash(builder, elements); } template class poseidon2; From db908d7d95de2d1ab27fbfd5f7ed053222219a61 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 8 Dec 2023 19:47:10 +0000 Subject: [PATCH 19/38] compile fix --- .../src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp index 7cc47b39b61..e3ade6654c0 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp @@ -38,7 +38,7 @@ template ; + using field_t = stdlib::field_t; // sponge state. t = rate + capacity. capacity = 1 field element (~256 bits) std::array state; From 9dc8392c0a17faf6aee3617f9800971d249fe799 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 8 Dec 2023 21:50:11 +0000 Subject: [PATCH 20/38] added comments --- .../cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp | 4 ++++ .../barretenberg/proof_system/arithmetization/gate_data.hpp | 3 +++ .../circuit_builder/goblin_ultra_circuit_builder.cpp | 6 ++++++ .../src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp | 4 +++- .../barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp | 3 +-- 5 files changed, 17 insertions(+), 3 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp index ff33e54fefe..6a717aa51fa 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp @@ -11,11 +11,15 @@ template class Poseidon2 { using FF = typename Params::FF; using Sponge = FieldSponge>; + /* @brief Hashes a vector of field elements + */ static FF hash(const std::vector& input) { auto input_span = input; return Sponge::hash_fixed_length(input_span); } + /* @brief Hashes vector of bytes by chunking it into 31 byte field elements and calling hash() + */ static FF hash_buffer(const std::vector& input) { const size_t num_bytes = input.size(); diff --git a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp index f6f15ebcc0c..4c69e908ddc 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/arithmetization/gate_data.hpp @@ -133,6 +133,7 @@ template struct ecc_dbl_gate_ { uint32_t y3; }; +/* External gate data for poseidon2 external round*/ template struct poseidon2_external_gate_ { uint32_t a; uint32_t b; @@ -141,6 +142,7 @@ template struct poseidon2_external_gate_ { size_t round_idx; }; +/* Internal gate data for poseidon2 internal round*/ template struct poseidon2_internal_gate_ { uint32_t a; uint32_t b; @@ -149,6 +151,7 @@ template struct poseidon2_internal_gate_ { size_t round_idx; }; +/* Last gate for poseidon2, needed because poseidon2 gates compare against the shifted wires. */ template struct poseidon2_end_gate_ { uint32_t a; uint32_t b; diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp index f657a42af01..3b3884e71f2 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp @@ -246,6 +246,8 @@ template void GoblinUltraCircuitBuilder_::populate_ecc_op_wire num_ecc_op_gates += 2; }; +/* @brief Poseidon2 external round gate, activates the q_poseidon2_external selector and relation + */ template void GoblinUltraCircuitBuilder_::create_poseidon2_external_gate(const poseidon2_external_gate_& in) { @@ -270,6 +272,8 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_external_gate(const poseid ++this->num_gates; } +/* @brief Poseidon2 internal round gate, activates the q_poseidon2_internal selector and relation + */ template void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseidon2_internal_gate_& in) { @@ -294,6 +298,8 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseid ++this->num_gates; } +/* @brief Poseidon2 end round gate, needed because poseidon2 rounds compare with shifted wires + */ template void GoblinUltraCircuitBuilder_::create_poseidon2_end_gate(const poseidon2_end_gate_& in) { this->w_l.emplace_back(in.a); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp index 7b1162c8274..ad67b585bd3 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp @@ -5,6 +5,8 @@ namespace proof_system::plonk::stdlib { using namespace barretenberg; using namespace proof_system; +/* Hash a vector of field_t. + */ template field_t poseidon2::hash(C& builder, const std::vector& inputs) { @@ -23,7 +25,7 @@ template field_t poseidon2::hash(C& builder, const std::vecto template field_t poseidon2::hash_buffer(C& builder, const stdlib::byte_array& input) { const size_t num_bytes = input.size(); - const size_t bytes_per_element = 31; + const size_t bytes_per_element = 31; // 31 bytes in a fr element size_t num_elements = static_cast(num_bytes % bytes_per_element != 0) + (num_bytes / bytes_per_element); std::vector elements; diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp index e3ade6654c0..359faf50f94 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/sponge/sponge.hpp @@ -12,7 +12,7 @@ namespace proof_system::plonk::stdlib { /** - * @brief Implements a cryptographic sponge over prime fields. + * @brief Implements the circuit form of a cryptographic sponge over prime fields. * Implements the sponge specification from the Community Cryptographic Specification Project * see https://github.com/C2SP/C2SP/blob/792c1254124f625d459bfe34417e8f6bdd02eb28/poseidon-sponge.md * (Note: this spec was not accepted into the C2SP repo, we might want to reference something else!) @@ -55,7 +55,6 @@ template (builder, 0); } - info("domain iv: ", domain_iv.get_value()); state[rate] = witness_t(builder, domain_iv.get_value()); } From 6ddfcae5e6d782ec0489c49d2cdddd047a87a5e1 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 5 Jan 2024 00:19:59 +0000 Subject: [PATCH 21/38] trying to split into source file (wip) --- .../crypto/poseidon2/poseidon2.cpp | 49 +++++++++++++++++++ .../crypto/poseidon2/poseidon2.hpp | 48 +++++------------- 2 files changed, 60 insertions(+), 37 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp new file mode 100644 index 00000000000..477232119a6 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp @@ -0,0 +1,49 @@ +#include "poseidon2.hpp" + +namespace crypto { +/** + * @brief Hashes a vector of field elements + */ +template +Poseidon2::FF Poseidon2::hash(const std::vector::FF>& input) +{ + auto input_span = input; + return Sponge::hash_fixed_length(input_span); +} + +/** + * @brief Hashes vector of bytes by chunking it into 31 byte field elements and calling hash() + * @details Slice function cuts out the required number of bytes from the byte vector + */ +template Poseidon2::FF hash_buffer(const std::vector& input) +{ + const size_t num_bytes = input.size(); + const size_t bytes_per_element = 31; + size_t num_elements = static_cast(num_bytes % bytes_per_element != 0) + (num_bytes / bytes_per_element); + + const auto slice = [](const std::vector& data, const size_t start, const size_t slice_size) { + uint256_t result(0); + for (size_t i = 0; i < slice_size; ++i) { + result = (result << uint256_t(8)); + result += uint256_t(data[i + start]); + } + return FF(result); + }; + + std::vector converted; + for (size_t i = 0; i < num_elements; ++i) { + size_t bytes_to_slice = 0; + if (i == num_elements - 1) { + bytes_to_slice = num_bytes - (i * bytes_per_element); + } else { + bytes_to_slice = bytes_per_element; + } + FF element = slice(input, i * bytes_per_element, bytes_to_slice); + converted.emplace_back(element); + } + + return hash(converted); +} + +template class Poseidon2; +} // namespace crypto \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp index 6a717aa51fa..834a7cc6759 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp @@ -8,46 +8,20 @@ namespace crypto { template class Poseidon2 { public: - using FF = typename Params::FF; + using FF = Params::FF; using Sponge = FieldSponge>; - /* @brief Hashes a vector of field elements + + /** + * @brief Hashes a vector of field elements */ - static FF hash(const std::vector& input) - { - auto input_span = input; - return Sponge::hash_fixed_length(input_span); - } - /* @brief Hashes vector of bytes by chunking it into 31 byte field elements and calling hash() + static FF hash(const std::vector& input); + /** + * @brief Hashes vector of bytes by chunking it into 31 byte field elements and calling hash() + * @details Slice function cuts out the required number of bytes from the byte vector */ - static FF hash_buffer(const std::vector& input) - { - const size_t num_bytes = input.size(); - const size_t bytes_per_element = 31; - size_t num_elements = static_cast(num_bytes % bytes_per_element != 0) + (num_bytes / bytes_per_element); - - const auto slice = [](const std::vector& data, const size_t start, const size_t slice_size) { - uint256_t result(0); - for (size_t i = 0; i < slice_size; ++i) { - result = (result << uint256_t(8)); - result += uint256_t(data[i + start]); - } - return FF(result); - }; - - std::vector converted; - for (size_t i = 0; i < num_elements; ++i) { - size_t bytes_to_slice = 0; - if (i == num_elements - 1) { - bytes_to_slice = num_bytes - (i * bytes_per_element); - } else { - bytes_to_slice = bytes_per_element; - } - FF element = slice(input, i * bytes_per_element, bytes_to_slice); - converted.emplace_back(element); - } - - return hash(converted); - } + static FF hash_buffer(const std::vector& input); }; + +extern template class Poseidon2; } // namespace crypto \ No newline at end of file From e15be667e09f418b3586a1bd7fe4501a534b0e3a Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 5 Jan 2024 00:55:31 +0000 Subject: [PATCH 22/38] fixed linker error --- .../cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp | 2 +- .../cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp | 2 +- .../cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp index 477232119a6..41588e9ce4c 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp @@ -15,7 +15,7 @@ Poseidon2::FF Poseidon2::hash(const std::vector Poseidon2::FF hash_buffer(const std::vector& input) +template Poseidon2::FF Poseidon2::hash_buffer(const std::vector& input) { const size_t num_bytes = input.size(); const size_t bytes_per_element = 31; diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp index 834a7cc6759..6c0d81afc15 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp @@ -23,5 +23,5 @@ template class Poseidon2 { static FF hash_buffer(const std::vector& input); }; -extern template class Poseidon2; +extern template class Poseidon2; } // namespace crypto \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt index 027032aaca9..6869b55d9bb 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/CMakeLists.txt @@ -1 +1 @@ -barretenberg_module(stdlib_poseidon2 stdlib_primitives) \ No newline at end of file +barretenberg_module(stdlib_poseidon2 stdlib_primitives crypto_poseidon2) \ No newline at end of file From 222e53231da1c5fafd17062c2cbc22631e47e3cd Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 5 Jan 2024 01:01:00 +0000 Subject: [PATCH 23/38] updated comments, removed debug printing --- .../goblin_ultra_circuit_builder.cpp | 13 ++++++++++--- .../stdlib/hash/pedersen/pedersen.cpp | 17 +++++++---------- .../stdlib/hash/poseidon2/poseidon2.cpp | 15 ++++++--------- 3 files changed, 23 insertions(+), 22 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp index 3b3884e71f2..7cffed8283a 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp @@ -246,7 +246,8 @@ template void GoblinUltraCircuitBuilder_::populate_ecc_op_wire num_ecc_op_gates += 2; }; -/* @brief Poseidon2 external round gate, activates the q_poseidon2_external selector and relation +/** + * @brief Poseidon2 external round gate, activates the q_poseidon2_external selector and relation */ template void GoblinUltraCircuitBuilder_::create_poseidon2_external_gate(const poseidon2_external_gate_& in) @@ -272,7 +273,8 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_external_gate(const poseid ++this->num_gates; } -/* @brief Poseidon2 internal round gate, activates the q_poseidon2_internal selector and relation +/** + * @brief Poseidon2 internal round gate, activates the q_poseidon2_internal selector and relation */ template void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseidon2_internal_gate_& in) @@ -298,7 +300,12 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseid ++this->num_gates; } -/* @brief Poseidon2 end round gate, needed because poseidon2 rounds compare with shifted wires +/** + * @brief Poseidon2 end round gate, needed because poseidon2 rounds compare with shifted wires + * @details Poseidon2 rounds need to be a block of 65 rows, since the result of applying a round of Poseidon2 is stored + * in the next row (the shifted row). As a result, we need this end row to compare with the result from the 64th round + * of Poseidon2. Note that it does not activate any selectors since it only serves as a comparison through the shifted + * wires. */ template void GoblinUltraCircuitBuilder_::create_poseidon2_end_gate(const poseidon2_end_gate_& in) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.cpp index 9f424a9cdf9..0d86f103630 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.cpp @@ -6,7 +6,7 @@ using namespace barretenberg; using namespace proof_system; template -field_t pedersen_hash::hash(const std::vector& inputs, const GeneratorContext context) +field_t pedersen_hash::hash(const std::vector& inputs, const GeneratorContext context) { using cycle_scalar = typename cycle_group::cycle_scalar; using Curve = EmbeddedCurve; @@ -15,7 +15,7 @@ field_t pedersen_hash::hash(const std::vector& inputs, const Gene std::vector scalars; std::vector points; - scalars.emplace_back(cycle_scalar::create_from_bn254_scalar(field_t(inputs.size()))); + scalars.emplace_back(cycle_scalar::create_from_bn254_scalar(field_ct(inputs.size()))); points.emplace_back(crypto::pedersen_hash_base::length_generator); for (size_t i = 0; i < inputs.size(); ++i) { scalars.emplace_back(cycle_scalar::create_from_bn254_scalar(inputs[i])); @@ -28,7 +28,7 @@ field_t pedersen_hash::hash(const std::vector& inputs, const Gene } template -field_t pedersen_hash::hash_skip_field_validation(const std::vector& inputs, +field_t pedersen_hash::hash_skip_field_validation(const std::vector& inputs, const GeneratorContext context) { using cycle_scalar = typename cycle_group::cycle_scalar; @@ -38,7 +38,7 @@ field_t pedersen_hash::hash_skip_field_validation(const std::vector scalars; std::vector points; - scalars.emplace_back(cycle_scalar::create_from_bn254_scalar(field_t(inputs.size()))); + scalars.emplace_back(cycle_scalar::create_from_bn254_scalar(field_ct(inputs.size()))); points.emplace_back(crypto::pedersen_hash_base::length_generator); for (size_t i = 0; i < inputs.size(); ++i) { // `true` param = skip primality test when performing a scalar mul @@ -64,7 +64,7 @@ field_t pedersen_hash::hash_buffer(const stdlib::byte_array& input, Gen const size_t bytes_per_element = 31; size_t num_elements = static_cast(num_bytes % bytes_per_element != 0) + (num_bytes / bytes_per_element); - std::vector elements; + std::vector elements; for (size_t i = 0; i < num_elements; ++i) { size_t bytes_to_slice = 0; if (i == num_elements - 1) { @@ -72,13 +72,10 @@ field_t pedersen_hash::hash_buffer(const stdlib::byte_array& input, Gen } else { bytes_to_slice = bytes_per_element; } - auto element = static_cast(input.slice(i * bytes_per_element, bytes_to_slice)); + auto element = static_cast(input.slice(i * bytes_per_element, bytes_to_slice)); elements.emplace_back(element); } - for (auto& x : elements) { - std::cout << x << std::endl; - } - field_t hashed; + field_ct hashed; if (elements.size() < 2) { hashed = hash(elements, context); } else { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp index ad67b585bd3..ff8e31dd56e 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.cpp @@ -5,9 +5,10 @@ namespace proof_system::plonk::stdlib { using namespace barretenberg; using namespace proof_system; -/* Hash a vector of field_t. +/** + * @brief Hash a vector of field_ct. */ -template field_t poseidon2::hash(C& builder, const std::vector& inputs) +template field_t poseidon2::hash(C& builder, const std::vector& inputs) { /* Run the sponge by absorbing all the input and squeezing one output. @@ -19,8 +20,7 @@ template field_t poseidon2::hash(C& builder, const std::vecto } /** - * Hash a byte_array. - * + * @brief Hash a byte_array. */ template field_t poseidon2::hash_buffer(C& builder, const stdlib::byte_array& input) { @@ -28,7 +28,7 @@ template field_t poseidon2::hash_buffer(C& builder, const std const size_t bytes_per_element = 31; // 31 bytes in a fr element size_t num_elements = static_cast(num_bytes % bytes_per_element != 0) + (num_bytes / bytes_per_element); - std::vector elements; + std::vector elements; for (size_t i = 0; i < num_elements; ++i) { size_t bytes_to_slice = 0; if (i == num_elements - 1) { @@ -36,12 +36,9 @@ template field_t poseidon2::hash_buffer(C& builder, const std } else { bytes_to_slice = bytes_per_element; } - auto element = static_cast(input.slice(i * bytes_per_element, bytes_to_slice)); + auto element = static_cast(input.slice(i * bytes_per_element, bytes_to_slice)); elements.emplace_back(element); } - for (auto& x : elements) { - std::cout << x << std::endl; - } return hash(builder, elements); } template class poseidon2; From eedcefb32c2c25453256a1f9dea2246e57aa306e Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 5 Jan 2024 01:02:09 +0000 Subject: [PATCH 24/38] updated type names, comments --- .../src/barretenberg/stdlib/hash/pedersen/pedersen.cpp | 2 +- .../src/barretenberg/stdlib/hash/pedersen/pedersen.hpp | 8 ++++---- .../src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp | 8 ++++---- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.cpp index 0d86f103630..efd40983af9 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/pedersen/pedersen.cpp @@ -52,7 +52,7 @@ field_t pedersen_hash::hash_skip_field_validation(const std::vector class pedersen_hash { private: - using field_t = stdlib::field_t; + using field_ct = stdlib::field_t; using bool_t = stdlib::bool_t; using EmbeddedCurve = typename cycle_group::Curve; using GeneratorContext = crypto::GeneratorContext; using cycle_group = stdlib::cycle_group; public: - static field_t hash(const std::vector& in, GeneratorContext context = {}); + static field_ct hash(const std::vector& in, GeneratorContext context = {}); // TODO health warnings! - static field_t hash_skip_field_validation(const std::vector& in, GeneratorContext context = {}); - static field_t hash_buffer(const stdlib::byte_array& input, GeneratorContext context = {}); + static field_ct hash_skip_field_validation(const std::vector& in, GeneratorContext context = {}); + static field_ct hash_buffer(const stdlib::byte_array& input, GeneratorContext context = {}); }; EXTERN_STDLIB_TYPE(pedersen_hash); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp index d050a3850c7..b6f7c7a3421 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp @@ -18,15 +18,15 @@ using namespace barretenberg; template class poseidon2 { private: - using field_t = stdlib::field_t; - using bool_t = stdlib::bool_t; + using field_ct = stdlib::field_t; + using bool_ct = stdlib::bool_t; using Params = crypto::Poseidon2Bn254ScalarFieldParams; using Permutation = Poseidon2Permutation; using Sponge = FieldSponge; public: - static field_t hash(Builder& builder, const std::vector& in); - static field_t hash_buffer(Builder& builder, const stdlib::byte_array& input); + static field_ct hash(Builder& builder, const std::vector& in); + static field_ct hash_buffer(Builder& builder, const stdlib::byte_array& input); }; extern template class poseidon2; From c24436ff4510779669a25b27042f49fef859f843 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 5 Jan 2024 01:05:48 +0000 Subject: [PATCH 25/38] circleci gcc fix --- .../cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp index 6c0d81afc15..01600012449 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp @@ -8,7 +8,7 @@ namespace crypto { template class Poseidon2 { public: - using FF = Params::FF; + using FF = typename Params::FF; using Sponge = FieldSponge>; From 13807f1c78ce886227d163171dc5bc3f0a7befab Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 5 Jan 2024 01:15:17 +0000 Subject: [PATCH 26/38] circleci fix --- .../cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp index 41588e9ce4c..dd93eba1089 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp @@ -5,7 +5,7 @@ namespace crypto { * @brief Hashes a vector of field elements */ template -Poseidon2::FF Poseidon2::hash(const std::vector::FF>& input) +typename Poseidon2::FF Poseidon2::hash(const std::vector::FF>& input) { auto input_span = input; return Sponge::hash_fixed_length(input_span); @@ -15,7 +15,8 @@ Poseidon2::FF Poseidon2::hash(const std::vector Poseidon2::FF Poseidon2::hash_buffer(const std::vector& input) +template +typename Poseidon2::FF Poseidon2::hash_buffer(const std::vector& input) { const size_t num_bytes = input.size(); const size_t bytes_per_element = 31; From 7dbb45ccc23df455b260cae245abe16ec81f9661 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 5 Jan 2024 21:31:51 +0000 Subject: [PATCH 27/38] adding comments, refactoring to source file --- .../poseidon2/poseidon2_permutation.hpp | 11 +- .../hash/poseidon2/poseidon2_permutation.cpp | 208 ++++++++++++++++++ .../hash/poseidon2/poseidon2_permutation.hpp | 197 +++-------------- 3 files changed, 244 insertions(+), 172 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2_permutation.hpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2_permutation.hpp index 9e3931cdac3..4f0794b893c 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2_permutation.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2_permutation.hpp @@ -7,7 +7,6 @@ #include #include #include -#include namespace crypto { @@ -123,6 +122,13 @@ template class Poseidon2Permutation { } } + /** + * @brief Native form of Poseidon2 permutation from https://eprint.iacr.org/2023/323. + * @details The permutation consists of one initial linear layer, then a set of external rounds, a set of internal + * rounds, and a set of external rounds. + * @param input + * @return constexpr State + */ static constexpr State permutation(const State& input) { // deep copy @@ -131,6 +137,7 @@ template class Poseidon2Permutation { // Apply 1st linear layer matrix_multiplication_external(current_state); + // First set of external rounds constexpr size_t rounds_f_beginning = rounds_f / 2; for (size_t i = 0; i < rounds_f_beginning; ++i) { add_round_constants(current_state, round_constants[i]); @@ -138,6 +145,7 @@ template class Poseidon2Permutation { matrix_multiplication_external(current_state); } + // Internal rounds const size_t p_end = rounds_f_beginning + rounds_p; for (size_t i = rounds_f_beginning; i < p_end; ++i) { current_state[0] += round_constants[i][0]; @@ -145,6 +153,7 @@ template class Poseidon2Permutation { matrix_multiplication_internal(current_state); } + // Remaining external rounds for (size_t i = p_end; i < NUM_ROUNDS; ++i) { add_round_constants(current_state, round_constants[i]); apply_sbox(current_state); diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp new file mode 100644 index 00000000000..e0035bcc4f0 --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp @@ -0,0 +1,208 @@ +#include "poseidon2_permutation.hpp" + +#include "barretenberg/proof_system/arithmetization/gate_data.hpp" +#include "barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.hpp" + +namespace proof_system::plonk::stdlib { + +/** + * @brief Circuit form of Poseidon2 permutation from https://eprint.iacr.org/2023/323. + * @details The permutation consists of one initial linear layer, then a set of external rounds, a set of internal + * rounds, and a set of external rounds. + * @param builder + * @param input + * @return State + */ +template +Poseidon2Permutation::State Poseidon2Permutation::permutation( + Builder* builder, const Poseidon2Permutation::State& input) +{ + // deep copy + State current_state(input); + NativeState current_native_state; + for (size_t i = 0; i < t; ++i) { + current_native_state[i] = current_state[i].get_value(); + } + + // Apply 1st linear layer + NativePermutation::matrix_multiplication_external(current_native_state); + initial_external_matrix_multiplication(builder, current_state); + + // First set of external rounds + constexpr size_t rounds_f_beginning = rounds_f / 2; + for (size_t i = 0; i < rounds_f_beginning; ++i) { + poseidon2_external_gate_ in{ current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index, + i }; + builder->create_poseidon2_external_gate(in); + // calculate the new witnesses + NativePermutation::add_round_constants(current_native_state, round_constants[i]); + NativePermutation::apply_sbox(current_native_state); + NativePermutation::matrix_multiplication_external(current_native_state); + for (size_t j = 0; j < t; ++j) { + current_state[j] = witness_t(builder, current_native_state[j]); + } + } + + // Internal rounds + const size_t p_end = rounds_f_beginning + rounds_p; + for (size_t i = rounds_f_beginning; i < p_end; ++i) { + poseidon2_internal_gate_ in{ current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index, + i }; + builder->create_poseidon2_internal_gate(in); + current_native_state[0] += round_constants[i][0]; + NativePermutation::apply_single_sbox(current_native_state[0]); + NativePermutation::matrix_multiplication_internal(current_native_state); + for (size_t j = 0; j < t; ++j) { + current_state[j] = witness_t(builder, current_native_state[j]); + } + } + + // Remaining external rounds + for (size_t i = p_end; i < NUM_ROUNDS; ++i) { + poseidon2_external_gate_ in{ current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index, + i }; + builder->create_poseidon2_external_gate(in); + // calculate the new witnesses + NativePermutation::add_round_constants(current_native_state, round_constants[i]); + NativePermutation::apply_sbox(current_native_state); + NativePermutation::matrix_multiplication_external(current_native_state); + for (size_t j = 0; j < t; ++j) { + current_state[j] = witness_t(builder, current_native_state[j]); + } + } + // need to add an extra row here to ensure that things check out, more details found in poseidon2_end_gate_ + // definition + poseidon2_end_gate_ in{ + current_state[0].witness_index, + current_state[1].witness_index, + current_state[2].witness_index, + current_state[3].witness_index, + }; + builder->create_poseidon2_end_gate(in); + return current_state; +} + +/** + * @brief Separate function to do just the first linear layer (equivalent to external matrix mul). + * @details We use 6 arithmetic gates to implement: + * gate 1: Compute tmp1 = state[0] + state[1] + 2 * state[3] + * gate 2: Compute tmp2 = 2 * state[1] + state[2] + state[3] + * gate 3: Compute v2 = 4 * state[0] + 4 * state[1] + tmp2 + * gate 4: Compute v1 = v2 + tmp1 + * gate 5: Compute v4 = tmp1 + 4 * state[2] + 4 * state[3] + * gate 6: Compute v3 = v4 + tmp2 + * output state is [v1, v2, v3, v4] + * @param builder + * @param state + */ +template +void Poseidon2Permutation::initial_external_matrix_multiplication( + Builder* builder, Poseidon2Permutation::State& state) +{ + // create the 6 gates for the initial matrix multiplication + // gate 1: Compute tmp1 = state[0] + state[1] + 2 * state[3] + field_t tmp1 = + witness_t(builder, state[0].get_value() + state[1].get_value() + FF(2) * state[3].get_value()); + builder->create_big_add_gate({ + .a = state[0].witness_index, + .b = state[1].witness_index, + .c = state[3].witness_index, + .d = tmp1.witness_index, + .a_scaling = 1, + .b_scaling = 1, + .c_scaling = 2, + .d_scaling = -1, + .const_scaling = 0, + }); + + // gate 2: Compute tmp2 = 2 * state[1] + state[2] + state[3] + field_t tmp2 = + witness_t(builder, FF(2) * state[1].get_value() + state[2].get_value() + state[3].get_value()); + builder->create_big_add_gate({ + .a = state[1].witness_index, + .b = state[2].witness_index, + .c = state[3].witness_index, + .d = tmp2.witness_index, + .a_scaling = 2, + .b_scaling = 1, + .c_scaling = 1, + .d_scaling = -1, + .const_scaling = 0, + }); + + // gate 3: Compute v2 = 4 * state[0] + 4 * state[1] + tmp2 + field_t v2 = + witness_t(builder, FF(4) * state[0].get_value() + FF(4) * state[1].get_value() + tmp2.get_value()); + builder->create_big_add_gate({ + .a = state[0].witness_index, + .b = state[1].witness_index, + .c = tmp2.witness_index, + .d = v2.witness_index, + .a_scaling = 4, + .b_scaling = 4, + .c_scaling = 1, + .d_scaling = -1, + .const_scaling = 0, + }); + + // gate 4: Compute v1 = v2 + tmp1 + field_t v1 = witness_t(builder, v2.get_value() + tmp1.get_value()); + builder->create_big_add_gate({ + .a = v2.witness_index, + .b = tmp1.witness_index, + .c = v1.witness_index, + .d = builder->zero_idx, + .a_scaling = 1, + .b_scaling = 1, + .c_scaling = -1, + .d_scaling = 0, + .const_scaling = 0, + }); + + // gate 5: Compute v4 = tmp1 + 4 * state[2] + 4 * state[3] + field_t v4 = + witness_t(builder, tmp1.get_value() + FF(4) * state[2].get_value() + FF(4) * state[3].get_value()); + builder->create_big_add_gate({ + .a = tmp1.witness_index, + .b = state[2].witness_index, + .c = state[3].witness_index, + .d = v4.witness_index, + .a_scaling = 1, + .b_scaling = 4, + .c_scaling = 4, + .d_scaling = -1, + .const_scaling = 0, + }); + + // gate 6: Compute v3 = v4 + tmp2 + field_t v3 = witness_t(builder, v4.get_value() + tmp2.get_value()); + builder->create_big_add_gate({ + .a = v4.witness_index, + .b = tmp2.witness_index, + .c = v3.witness_index, + .d = builder->zero_idx, + .a_scaling = 1, + .b_scaling = 1, + .c_scaling = -1, + .d_scaling = 0, + .const_scaling = 0, + }); + + state[0] = v1; + state[1] = v2; + state[2] = v3; + state[3] = v4; +} + +template class Poseidon2Permutation; + +} // namespace proof_system::plonk::stdlib \ No newline at end of file diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp index adbbfcd88f5..08391b7dafe 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.hpp @@ -4,7 +4,6 @@ #include #include "barretenberg/crypto/poseidon2/poseidon2_permutation.hpp" -#include "barretenberg/proof_system/arithmetization/gate_data.hpp" #include "barretenberg/stdlib/primitives/field/field.hpp" namespace proof_system::plonk::stdlib { @@ -37,176 +36,32 @@ template class Poseidon2Permutation { using RoundConstantsContainer = std::array; static constexpr RoundConstantsContainer round_constants = Params::round_constants; - static State permutation(Builder* builder, const State& input) - { - // deep copy - State current_state(input); - NativeState current_native_state; - for (size_t i = 0; i < t; ++i) { - current_native_state[i] = current_state[i].get_value(); - } - - // Apply 1st linear layer - NativePermutation::matrix_multiplication_external(current_native_state); - initial_external_matrix_multiplication(builder, current_state); - - constexpr size_t rounds_f_beginning = rounds_f / 2; - for (size_t i = 0; i < rounds_f_beginning; ++i) { - poseidon2_external_gate_ in{ current_state[0].witness_index, - current_state[1].witness_index, - current_state[2].witness_index, - current_state[3].witness_index, - i }; - builder->create_poseidon2_external_gate(in); - // calculate the new witnesses - NativePermutation::add_round_constants(current_native_state, round_constants[i]); - NativePermutation::apply_sbox(current_native_state); - NativePermutation::matrix_multiplication_external(current_native_state); - for (size_t j = 0; j < t; ++j) { - current_state[j] = witness_t(builder, current_native_state[j]); - } - } - - const size_t p_end = rounds_f_beginning + rounds_p; - for (size_t i = rounds_f_beginning; i < p_end; ++i) { - poseidon2_internal_gate_ in{ current_state[0].witness_index, - current_state[1].witness_index, - current_state[2].witness_index, - current_state[3].witness_index, - i }; - builder->create_poseidon2_internal_gate(in); - current_native_state[0] += round_constants[i][0]; - NativePermutation::apply_single_sbox(current_native_state[0]); - NativePermutation::matrix_multiplication_internal(current_native_state); - for (size_t j = 0; j < t; ++j) { - current_state[j] = witness_t(builder, current_native_state[j]); - } - } - - for (size_t i = p_end; i < NUM_ROUNDS; ++i) { - poseidon2_external_gate_ in{ current_state[0].witness_index, - current_state[1].witness_index, - current_state[2].witness_index, - current_state[3].witness_index, - i }; - builder->create_poseidon2_external_gate(in); - // calculate the new witnesses - NativePermutation::add_round_constants(current_native_state, round_constants[i]); - NativePermutation::apply_sbox(current_native_state); - NativePermutation::matrix_multiplication_external(current_native_state); - for (size_t j = 0; j < t; ++j) { - current_state[j] = witness_t(builder, current_native_state[j]); - } - } - // need to add an extra row here to ensure that things check out - poseidon2_end_gate_ in{ - current_state[0].witness_index, - current_state[1].witness_index, - current_state[2].witness_index, - current_state[3].witness_index, - }; - builder->create_poseidon2_end_gate(in); - return current_state; - } - - static void initial_external_matrix_multiplication(Builder* builder, State& state) - { - // create the 6 gates for the initial matrix multiplication - // gate 1: Compute tmp1 = state[0] + state[1] + 2 * state[3] - FF tmp1 = state[0].get_value() + state[1].get_value() + FF(2) * state[3].get_value(); - uint32_t tmp1_idx = builder->add_variable(tmp1); - - builder->create_big_add_gate({ - .a = state[0].witness_index, - .b = state[1].witness_index, - .c = state[3].witness_index, - .d = tmp1_idx, - .a_scaling = 1, - .b_scaling = 1, - .c_scaling = 2, - .d_scaling = -1, - .const_scaling = 0, - }); - - // gate 2: Compute tmp2 = 2 * state[1] + state[2] + state[3] - FF tmp2 = FF(2) * state[1].get_value() + state[2].get_value() + state[3].get_value(); - uint32_t tmp2_idx = builder->add_variable(tmp2); - builder->create_big_add_gate({ - .a = state[1].witness_index, - .b = state[2].witness_index, - .c = state[3].witness_index, - .d = tmp2_idx, - .a_scaling = 2, - .b_scaling = 1, - .c_scaling = 1, - .d_scaling = -1, - .const_scaling = 0, - }); - - // gate 3: Compute v2 = 4 * state[0] + 4 * state[1] + tmp2 - FF v2 = FF(4) * state[0].get_value() + FF(4) * state[1].get_value() + tmp2; - uint32_t v2_idx = builder->add_variable(v2); - builder->create_big_add_gate({ - .a = state[0].witness_index, - .b = state[1].witness_index, - .c = tmp2_idx, - .d = v2_idx, - .a_scaling = 4, - .b_scaling = 4, - .c_scaling = 1, - .d_scaling = -1, - .const_scaling = 0, - }); - - // gate 4: Compute v1 = v2 + tmp1 - FF v1 = v2 + tmp1; - uint32_t v1_idx = builder->add_variable(v1); - builder->create_big_add_gate({ - .a = v2_idx, - .b = tmp1_idx, - .c = v1_idx, - .d = builder->zero_idx, - .a_scaling = 1, - .b_scaling = 1, - .c_scaling = -1, - .d_scaling = 0, - .const_scaling = 0, - }); - - // gate 5: Compute v4 = tmp1 + 4 * state[2] + 4 * state[3] - FF v4 = tmp1 + FF(4) * state[2].get_value() + FF(4) * state[3].get_value(); - uint32_t v4_idx = builder->add_variable(v4); - builder->create_big_add_gate({ - .a = tmp1_idx, - .b = state[2].witness_index, - .c = state[3].witness_index, - .d = v4_idx, - .a_scaling = 1, - .b_scaling = 4, - .c_scaling = 4, - .d_scaling = -1, - .const_scaling = 0, - }); + /** + * @brief Circuit form of Poseidon2 permutation from https://eprint.iacr.org/2023/323. + * @details The permutation consists of one initial linear layer, then a set of external rounds, a set of internal + * rounds, and a set of external rounds. + * @param builder + * @param input + * @return State + */ + static State permutation(Builder* builder, const State& input); + + /** + * @brief Separate function to do just the first linear layer (equivalent to external matrix mul). + * @details We use 6 arithmetic gates to implement: + * gate 1: Compute tmp1 = state[0] + state[1] + 2 * state[3] + * gate 2: Compute tmp2 = 2 * state[1] + state[2] + state[3] + * gate 3: Compute v2 = 4 * state[0] + 4 * state[1] + tmp2 + * gate 4: Compute v1 = v2 + tmp1 + * gate 5: Compute v4 = tmp1 + 4 * state[2] + 4 * state[3] + * gate 6: Compute v3 = v4 + tmp2 + * output state is [v1, v2, v3, v4] + * @param builder + * @param state + */ + static void initial_external_matrix_multiplication(Builder* builder, State& state); +}; - // gate 6: Compute v3 = v4 + tmp2 - FF v3 = v4 + tmp2; - uint32_t v3_idx = builder->add_variable(v3); - builder->create_big_add_gate({ - .a = v4_idx, - .b = tmp2_idx, - .c = v3_idx, - .d = builder->zero_idx, - .a_scaling = 1, - .b_scaling = 1, - .c_scaling = -1, - .d_scaling = 0, - .const_scaling = 0, - }); +extern template class Poseidon2Permutation; - state[0] = field_t::from_witness_index(builder, v1_idx); - state[1] = field_t::from_witness_index(builder, v2_idx); - state[2] = field_t::from_witness_index(builder, v3_idx); - state[3] = field_t::from_witness_index(builder, v4_idx); - } -}; } // namespace proof_system::plonk::stdlib \ No newline at end of file From 8b259966b55af3c688e87bf919ca3ccd498a1c0d Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Fri, 5 Jan 2024 22:39:03 +0000 Subject: [PATCH 28/38] stupid ci fix --- .../stdlib/hash/poseidon2/poseidon2_permutation.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp index e0035bcc4f0..fc8a8cd300d 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2_permutation.cpp @@ -14,8 +14,8 @@ namespace proof_system::plonk::stdlib { * @return State */ template -Poseidon2Permutation::State Poseidon2Permutation::permutation( - Builder* builder, const Poseidon2Permutation::State& input) +typename Poseidon2Permutation::State Poseidon2Permutation::permutation( + Builder* builder, const typename Poseidon2Permutation::State& input) { // deep copy State current_state(input); @@ -106,7 +106,7 @@ Poseidon2Permutation::State Poseidon2Permutation void Poseidon2Permutation::initial_external_matrix_multiplication( - Builder* builder, Poseidon2Permutation::State& state) + Builder* builder, typename Poseidon2Permutation::State& state) { // create the 6 gates for the initial matrix multiplication // gate 1: Compute tmp1 = state[0] + state[1] + 2 * state[3] From 6f04eb06056557e34d92d4bcd3b2f5944e281b98 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Mon, 8 Jan 2024 21:18:14 +0000 Subject: [PATCH 29/38] compile fix --- .../goblin_ultra_circuit_builder.cpp | 42 +++++++++---------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp index b501d1f6f31..29126cb8c8e 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp @@ -310,31 +310,31 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseid /** * @brief Poseidon2 end round gate, needed because poseidon2 rounds compare with shifted wires - * @details Poseidon2 rounds need to be a block of 65 rows, since the result of applying a round of Poseidon2 is stored - * in the next row (the shifted row). As a result, we need this end row to compare with the result from the 64th round - * of Poseidon2. Note that it does not activate any selectors since it only serves as a comparison through the shifted - * wires. + * @details The Poseidon2 permutation needs to be a block of 65 rows, since the result of applying a round of Poseidon2 + * is stored in the next row (the shifted row). As a result, we need this end row to compare with the result from the + * 64th round of Poseidon2. Note that it does not activate any selectors since it only serves as a comparison through + * the shifted wires. */ template void GoblinUltraCircuitBuilder_::create_poseidon2_end_gate(const poseidon2_end_gate_& in) { - this->w_l.emplace_back(in.a); - this->w_r.emplace_back(in.b); - this->w_o.emplace_back(in.c); - this->w_4.emplace_back(in.d); - this->q_m.emplace_back(0); - this->q_1.emplace_back(0); - this->q_2.emplace_back(0); - this->q_3.emplace_back(0); - this->q_c.emplace_back(0); - this->q_arith.emplace_back(0); - this->q_4.emplace_back(0); - this->q_sort.emplace_back(0); - this->q_lookup_type.emplace_back(0); - this->q_elliptic.emplace_back(0); - this->q_aux.emplace_back(0); + this->w_l().emplace_back(in.a); + this->w_r().emplace_back(in.b); + this->w_o().emplace_back(in.c); + this->w_4().emplace_back(in.d); + this->q_m().emplace_back(0); + this->q_1().emplace_back(0); + this->q_2().emplace_back(0); + this->q_3().emplace_back(0); + this->q_c().emplace_back(0); + this->q_arith().emplace_back(0); + this->q_4().emplace_back(0); + this->q_sort().emplace_back(0); + this->q_lookup_type().emplace_back(0); + this->q_elliptic().emplace_back(0); + this->q_aux().emplace_back(0); this->q_busread().emplace_back(0); - this->q_poseidon2_external.emplace_back(0); - this->q_poseidon2_internal.emplace_back(0); + this->q_poseidon2_external().emplace_back(0); + this->q_poseidon2_internal().emplace_back(0); ++this->num_gates; } From ff22a5f625cf4f0c6a00f9ad9c36ce580dafd821 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Mon, 8 Jan 2024 22:09:47 +0000 Subject: [PATCH 30/38] minor update, comments --- .../barretenberg/crypto/pedersen_hash/pedersen.cpp | 12 +++++------- .../src/barretenberg/crypto/poseidon2/poseidon2.cpp | 12 +++++------- .../src/barretenberg/crypto/poseidon2/poseidon2.hpp | 1 + .../barretenberg/stdlib/hash/poseidon2/poseidon2.hpp | 1 + 4 files changed, 12 insertions(+), 14 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.cpp b/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.cpp index f0f03378e80..9e702eccb2f 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/pedersen_hash/pedersen.cpp @@ -30,16 +30,14 @@ std::vector pedersen_hash_base::convert_buffer }; std::vector elements; - for (size_t i = 0; i < num_elements; ++i) { - size_t bytes_to_slice = 0; - if (i == num_elements - 1) { - bytes_to_slice = num_bytes - (i * bytes_per_element); - } else { - bytes_to_slice = bytes_per_element; - } + for (size_t i = 0; i < num_elements - 1; ++i) { + size_t bytes_to_slice = bytes_per_element; Fq element = slice(input, i * bytes_per_element, bytes_to_slice); elements.emplace_back(element); } + size_t bytes_to_slice = num_bytes - ((num_elements - 1) * bytes_per_element); + Fq element = slice(input, (num_elements - 1) * bytes_per_element, bytes_to_slice); + elements.emplace_back(element); return elements; } diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp index dd93eba1089..ad96dc31271 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.cpp @@ -32,16 +32,14 @@ typename Poseidon2::FF Poseidon2::hash_buffer(const std::vector< }; std::vector converted; - for (size_t i = 0; i < num_elements; ++i) { - size_t bytes_to_slice = 0; - if (i == num_elements - 1) { - bytes_to_slice = num_bytes - (i * bytes_per_element); - } else { - bytes_to_slice = bytes_per_element; - } + for (size_t i = 0; i < num_elements - 1; ++i) { + size_t bytes_to_slice = bytes_per_element; FF element = slice(input, i * bytes_per_element, bytes_to_slice); converted.emplace_back(element); } + size_t bytes_to_slice = num_bytes - ((num_elements - 1) * bytes_per_element); + FF element = slice(input, (num_elements - 1) * bytes_per_element, bytes_to_slice); + converted.emplace_back(element); return hash(converted); } diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp index 01600012449..6969c680e17 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.hpp @@ -10,6 +10,7 @@ template class Poseidon2 { public: using FF = typename Params::FF; + // We choose our rate to be t-1 and capacity to be 1. using Sponge = FieldSponge>; /** diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp index b6f7c7a3421..fcfb93f91d2 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.hpp @@ -22,6 +22,7 @@ template class poseidon2 { using bool_ct = stdlib::bool_t; using Params = crypto::Poseidon2Bn254ScalarFieldParams; using Permutation = Poseidon2Permutation; + // We choose our rate to be t-1 and capacity to be 1. using Sponge = FieldSponge; public: From 2419db5641681f54934de90076c48ed45c21566b Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Mon, 8 Jan 2024 22:14:21 +0000 Subject: [PATCH 31/38] small comment update --- .../circuit_builder/goblin_ultra_circuit_builder.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp index 29126cb8c8e..c8368f4c7e2 100644 --- a/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp +++ b/barretenberg/cpp/src/barretenberg/proof_system/circuit_builder/goblin_ultra_circuit_builder.cpp @@ -310,10 +310,10 @@ void GoblinUltraCircuitBuilder_::create_poseidon2_internal_gate(const poseid /** * @brief Poseidon2 end round gate, needed because poseidon2 rounds compare with shifted wires - * @details The Poseidon2 permutation needs to be a block of 65 rows, since the result of applying a round of Poseidon2 - * is stored in the next row (the shifted row). As a result, we need this end row to compare with the result from the - * 64th round of Poseidon2. Note that it does not activate any selectors since it only serves as a comparison through - * the shifted wires. + * @details The Poseidon2 permutation is 64 rounds, but needs to be a block of 65 rows, since the result of applying a + * round of Poseidon2 is stored in the next row (the shifted row). As a result, we need this end row to compare with the + * result from the 64th round of Poseidon2. Note that it does not activate any selectors since it only serves as a + * comparison through the shifted wires. */ template void GoblinUltraCircuitBuilder_::create_poseidon2_end_gate(const poseidon2_end_gate_& in) { From aeaf1a1abc33e2687a99f1c28dc99269a5cce6f5 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Tue, 9 Jan 2024 19:38:23 +0000 Subject: [PATCH 32/38] revamped poseidon2 stdlib tests --- .../stdlib/hash/poseidon2/poseidon2.test.cpp | 233 +++++------------- 1 file changed, 55 insertions(+), 178 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp index 381e9d27c33..797cec6669c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/poseidon2/poseidon2.test.cpp @@ -22,99 +22,52 @@ template class StdlibPoseidon2 : public testing::Test { using native_poseidon2 = crypto::Poseidon2; public: - static void test_poseidon2() + /** + * @brief Call poseidon2 on a vector of inputs + * + * @param num_inputs + */ + static void test_hash(size_t num_inputs) { + using field_ct = stdlib::field_t; + using witness_ct = stdlib::witness_t; + auto builder = Builder(); - Builder builder; + std::vector inputs; + std::vector inputs_native; - fr left_in = fr::random_element(); - fr right_in = fr::random_element(); - - // ensure left has skew 1, right has skew 0 - if ((left_in.from_montgomery_form().data[0] & 1) == 1) { - left_in += fr::one(); - } - if ((right_in.from_montgomery_form().data[0] & 1) == 0) { - right_in += fr::one(); + for (size_t i = 0; i < num_inputs; ++i) { + const auto element = fr::random_element(&engine); + inputs_native.emplace_back(element); + inputs.emplace_back(field_ct(witness_ct(&builder, element))); } - fr_ct left = public_witness_ct(&builder, left_in); - fr_ct right = witness_ct(&builder, right_in); - - builder.fix_witness(left.witness_index, left.get_value()); - builder.fix_witness(right.witness_index, right.get_value()); - - fr_ct out = poseidon2::hash(builder, { left, right }); - - info("num gates = ", builder.get_num_gates()); - - bool result = builder.check_circuit(); - EXPECT_EQ(result, true); - - fr hash_native = native_poseidon2::hash({ left.get_value(), right.get_value() }); - EXPECT_EQ(out.get_value(), hash_native); - } - - static void test_poseidon2_edge_cases() - { - Builder builder; - - fr zero_fr = fr::zero(); - fr one_fr = fr::one(); - fr r_minus_one_fr = fr::modulus - 1; - fr r_minus_two_fr = fr::modulus - 2; - fr r_fr = fr::modulus; - - fr_ct zero = witness_ct(&builder, zero_fr); - fr_ct one = witness_ct(&builder, one_fr); - fr_ct r_minus_one = witness_ct(&builder, r_minus_one_fr); - fr_ct r_minus_two = witness_ct(&builder, r_minus_two_fr); - fr_ct r = witness_ct(&builder, r_fr); + auto result = stdlib::poseidon2::hash(builder, inputs); + auto expected = crypto::Poseidon2::hash(inputs_native); - fr_ct out_1_with_zero = poseidon2::hash(builder, { zero, one }); - fr_ct out_1_with_r = poseidon2::hash(builder, { r, one }); - fr_ct out_2 = poseidon2::hash(builder, { r_minus_one, r_minus_two }); - fr_ct out_with_zero = poseidon2::hash(builder, { out_1_with_zero, out_2 }); - fr_ct out_with_r = poseidon2::hash(builder, { out_1_with_r, out_2 }); - - info("num gates = ", builder.get_num_gates()); - - bool result = builder.check_circuit(); - EXPECT_EQ(result, true); - - EXPECT_EQ(bool(out_1_with_zero.get_value() == out_1_with_r.get_value()), true); - - fr hash_native_1_with_zero = native_poseidon2::hash({ zero.get_value(), one.get_value() }); - fr hash_native_1_with_r = native_poseidon2::hash({ r.get_value(), one.get_value() }); - fr hash_native_2 = native_poseidon2::hash({ r_minus_one.get_value(), r_minus_two.get_value() }); - fr hash_native_with_zero = native_poseidon2::hash({ out_1_with_zero.get_value(), out_2.get_value() }); - fr hash_native_with_r = native_poseidon2::hash({ out_1_with_r.get_value(), out_2.get_value() }); + EXPECT_EQ(result.get_value(), expected); - EXPECT_EQ(out_1_with_zero.get_value(), hash_native_1_with_zero); - EXPECT_EQ(out_1_with_r.get_value(), hash_native_1_with_r); - EXPECT_EQ(out_2.get_value(), hash_native_2); - EXPECT_EQ(out_with_zero.get_value(), hash_native_with_zero); - EXPECT_EQ(out_with_r.get_value(), hash_native_with_r); - EXPECT_EQ(hash_native_with_zero, hash_native_with_r); + bool proof_result = builder.check_circuit(); + EXPECT_EQ(proof_result, true); } - static void test_poseidon2_large() + /** + * @brief Call poseidon2 on two inputs repeatedly. + * + * @param num_inputs + */ + static void test_hash_repeated_pairs(size_t num_inputs) { Builder builder; fr left_in = fr::random_element(); fr right_in = fr::random_element(); - // ensure left has skew 1, right has skew 0 - if ((left_in.from_montgomery_form().data[0] & 1) == 1) { - left_in += fr::one(); - } - if ((right_in.from_montgomery_form().data[0] & 1) == 0) { - right_in += fr::one(); - } + fr_ct left = witness_ct(&builder, left_in); fr_ct right = witness_ct(&builder, right_in); - for (size_t i = 0; i < 256; ++i) { + // num_inputs - 1 iterations since the first hash hashes two elements + for (size_t i = 0; i < num_inputs - 1; ++i) { left = poseidon2::hash(builder, { left, right }); } @@ -125,11 +78,13 @@ template class StdlibPoseidon2 : public testing::Test { bool result = builder.check_circuit(); EXPECT_EQ(result, true); } - - static void test_hash_byte_array() + /** + * @brief Call poseidon2 hash_buffer on a vector of bytes + * + * @param num_input_bytes + */ + static void test_hash_byte_array(size_t num_input_bytes) { - const size_t num_input_bytes = 351; - Builder builder; std::vector input; @@ -151,67 +106,16 @@ template class StdlibPoseidon2 : public testing::Test { EXPECT_EQ(proof_result, true); } - static void test_multi_hash() - { - Builder builder; - - for (size_t i = 0; i < 7; ++i) { - std::vector inputs; - inputs.push_back(barretenberg::fr::random_element()); - inputs.push_back(barretenberg::fr::random_element()); - inputs.push_back(barretenberg::fr::random_element()); - inputs.push_back(barretenberg::fr::random_element()); - - if (i == 1) { - inputs[0] = barretenberg::fr(0); - } - if (i == 2) { - inputs[1] = barretenberg::fr(0); - inputs[2] = barretenberg::fr(0); - } - if (i == 3) { - inputs[3] = barretenberg::fr(0); - } - if (i == 4) { - inputs[0] = barretenberg::fr(0); - inputs[3] = barretenberg::fr(0); - } - if (i == 5) { - inputs[0] = barretenberg::fr(0); - inputs[1] = barretenberg::fr(0); - inputs[2] = barretenberg::fr(0); - inputs[3] = barretenberg::fr(0); - } - if (i == 6) { - inputs[1] = barretenberg::fr(1); - } - std::vector witnesses; - for (auto input : inputs) { - witnesses.push_back(witness_ct(&builder, input)); - } - - barretenberg::fr expected = native_poseidon2::hash(inputs); - - fr_ct result = poseidon2::hash(builder, witnesses); - EXPECT_EQ(result.get_value(), expected); - } - - info("num gates = ", builder.get_num_gates()); - - bool proof_result = builder.check_circuit(); - EXPECT_EQ(proof_result, true); - } - - static void test_hash_eight() + static void test_hash_zeros(size_t num_inputs) { Builder builder; std::vector inputs; - inputs.reserve(8); + inputs.reserve(num_inputs); std::vector> witness_inputs; - for (size_t i = 0; i < 8; ++i) { - inputs.emplace_back(barretenberg::fr::random_element()); + for (size_t i = 0; i < num_inputs; ++i) { + inputs.emplace_back(0); witness_inputs.emplace_back(witness_ct(&builder, inputs[i])); } @@ -248,64 +152,37 @@ using CircuitTypes = testing::Types; TYPED_TEST_SUITE(StdlibPoseidon2, CircuitTypes); -TYPED_TEST(StdlibPoseidon2, TestHash) +TYPED_TEST(StdlibPoseidon2, TestHashZeros) { - using Builder = TypeParam; - using field_ct = stdlib::field_t; - using witness_ct = stdlib::witness_t; - auto builder = Builder(); - - const size_t num_inputs = 10; - - std::vector inputs; - std::vector inputs_native; - - for (size_t i = 0; i < num_inputs; ++i) { - const auto element = fr::random_element(&engine); - inputs_native.emplace_back(element); - inputs.emplace_back(field_ct(witness_ct(&builder, element))); - } - - auto result = stdlib::poseidon2::hash(builder, inputs); - auto expected = crypto::Poseidon2::hash(inputs_native); - - EXPECT_EQ(result.get_value(), expected); - - bool proof_result = builder.check_circuit(); - EXPECT_EQ(proof_result, true); -} - -TYPED_TEST(StdlibPoseidon2, Small) -{ - TestFixture::test_poseidon2(); + TestFixture::test_hash_zeros(8); }; -TYPED_TEST(StdlibPoseidon2, EdgeCases) +TYPED_TEST(StdlibPoseidon2, TestHashSmall) { - TestFixture::test_poseidon2_edge_cases(); -}; + TestFixture::test_hash(10); +} -HEAVY_TYPED_TEST(StdlibPoseidon2, Large) +TYPED_TEST(StdlibPoseidon2, TestHashLarge) { - TestFixture::test_poseidon2_large(); -}; + TestFixture::test_hash(1000); +} -TYPED_TEST(StdlibPoseidon2, HashByteArray) +TYPED_TEST(StdlibPoseidon2, TestHashRepeatedPairs) { - TestFixture::test_hash_byte_array(); -}; + TestFixture::test_hash_repeated_pairs(256); +} -TYPED_TEST(StdlibPoseidon2, MultiHash) +TYPED_TEST(StdlibPoseidon2, TestHashByteArraySmall) { - TestFixture::test_multi_hash(); + TestFixture::test_hash_byte_array(351); }; -TYPED_TEST(StdlibPoseidon2, HashEight) +TYPED_TEST(StdlibPoseidon2, TestHashByteArrayLarge) { - TestFixture::test_hash_eight(); + TestFixture::test_hash_byte_array(31000); }; -TYPED_TEST(StdlibPoseidon2, HashConstants) +TYPED_TEST(StdlibPoseidon2, TestHashConstants) { TestFixture::test_hash_constants(); }; From 6b67f1199b954bec75d4b8c5a0fbe20a7338c3e5 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Thu, 11 Jan 2024 22:11:11 +0000 Subject: [PATCH 33/38] fixed hash consistency test --- .../cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp index 2081d531730..afcf08f97cb 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp @@ -42,7 +42,7 @@ TEST(Poseidon2, ConsistencyCheck) std::vector input{ a, b, c, d }; auto result = crypto::Poseidon2::hash(input); - barretenberg::fr expected(std::string("0x150c19ae11b3290c137c7a4d760d9482a6581d731535f560c3601d6a766b0937")); + barretenberg::fr expected(std::string("0x2f43a0f83b51a6f5fc839dea0ecec74947637802a579fa9841930a25a0bcec11")); EXPECT_EQ(result, expected); } From e9fd7da0dc5e305ecd012b073f3bb8216b2feb57 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Thu, 11 Jan 2024 22:11:49 +0000 Subject: [PATCH 34/38] updated tests to include hash_buffer --- .../crypto/poseidon2/poseidon2.test.cpp | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp index afcf08f97cb..9649f757728 100644 --- a/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp +++ b/barretenberg/cpp/src/barretenberg/crypto/poseidon2/poseidon2.test.cpp @@ -10,7 +10,7 @@ auto& engine = numeric::random::get_debug_engine(); } namespace poseidon2_tests { -TEST(Poseidon2, BasicTests) +TEST(Poseidon2, HashBasicTests) { barretenberg::fr a = barretenberg::fr::random_element(&engine); @@ -32,7 +32,7 @@ TEST(Poseidon2, BasicTests) // N.B. these hardcoded values were extracted from the algorithm being tested. These are NOT independent test vectors! // TODO(@zac-williamson #3132): find independent test vectors we can compare against! (very hard to find given // flexibility of Poseidon's parametrisation) -TEST(Poseidon2, ConsistencyCheck) +TEST(Poseidon2, HashConsistencyCheck) { barretenberg::fr a(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); barretenberg::fr b(std::string("9a807b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); @@ -46,4 +46,20 @@ TEST(Poseidon2, ConsistencyCheck) EXPECT_EQ(result, expected); } + +TEST(Poseidon2, HashBufferConsistencyCheck) +{ + // 31 byte inputs because hash_buffer slicing is only injective with 31 bytes, as it slices 31 bytes for each field + // element + barretenberg::fr a(std::string("00000b615c4d3e2fa0b1c2d3e4f56789fedcba9876543210abcdef0123456789")); + + auto input_vec = to_buffer(a); // takes field element and converts it to 32 bytes + input_vec.erase(input_vec.begin()); // erase first byte since we want 31 bytes + std::vector input{ a }; + auto expected = crypto::Poseidon2::hash(input); + + barretenberg::fr result = crypto::Poseidon2::hash_buffer(input_vec); + + EXPECT_EQ(result, expected); +} } // namespace poseidon2_tests \ No newline at end of file From 2c66d1fc4a68002bc63c5dbcfb569f4fa49e24a2 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Thu, 11 Jan 2024 22:13:02 +0000 Subject: [PATCH 35/38] added poseidon2 tests to bb-tests --- barretenberg/cpp/scripts/bb-tests.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/barretenberg/cpp/scripts/bb-tests.sh b/barretenberg/cpp/scripts/bb-tests.sh index 934817d08a2..a4ba5b39417 100755 --- a/barretenberg/cpp/scripts/bb-tests.sh +++ b/barretenberg/cpp/scripts/bb-tests.sh @@ -18,6 +18,7 @@ TESTS=( crypto_ecdsa_tests crypto_pedersen_commitment_tests crypto_pedersen_hash_tests + crypto_poseidon2_tests crypto_schnorr_tests crypto_sha256_tests dsl_tests From 4b7d151a7de36a0b06fb707b3a42a53245a3c7dd Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Thu, 11 Jan 2024 22:17:47 +0000 Subject: [PATCH 36/38] added poseidon2 to stdlib tests --- barretenberg/cpp/scripts/stdlib-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/barretenberg/cpp/scripts/stdlib-tests b/barretenberg/cpp/scripts/stdlib-tests index 4f61b0c2f19..823141aab9d 100644 --- a/barretenberg/cpp/scripts/stdlib-tests +++ b/barretenberg/cpp/scripts/stdlib-tests @@ -5,5 +5,6 @@ stdlib_blake3s_tests stdlib_ecdsa_tests stdlib_merkle_tree_tests stdlib_pedersen_commitment_tests +stdlib_poseidon2_tests stdlib_schnorr_tests stdlib_sha256_tests \ No newline at end of file From af5e01727d70ac059f72aedd7e5e2a81e30fd0c7 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Thu, 11 Jan 2024 22:35:14 +0000 Subject: [PATCH 37/38] added missing stdlib pedersen hash tests --- barretenberg/cpp/scripts/stdlib-tests | 1 + 1 file changed, 1 insertion(+) diff --git a/barretenberg/cpp/scripts/stdlib-tests b/barretenberg/cpp/scripts/stdlib-tests index 823141aab9d..6cb94611294 100644 --- a/barretenberg/cpp/scripts/stdlib-tests +++ b/barretenberg/cpp/scripts/stdlib-tests @@ -5,6 +5,7 @@ stdlib_blake3s_tests stdlib_ecdsa_tests stdlib_merkle_tree_tests stdlib_pedersen_commitment_tests +stdlib_pedersen_hash_tests stdlib_poseidon2_tests stdlib_schnorr_tests stdlib_sha256_tests \ No newline at end of file From 8aa065f5c975ee4c24f047a6a75cb6bf85f1a211 Mon Sep 17 00:00:00 2001 From: lucasxia01 Date: Thu, 11 Jan 2024 22:40:35 +0000 Subject: [PATCH 38/38] undo weird merge? update to circuit/ files --- .../abis/private_circuit_public_inputs.hpp | 8 ++++---- circuits/cpp/src/aztec3/constants.hpp | 16 +++++++++------- 2 files changed, 13 insertions(+), 11 deletions(-) diff --git a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp index 8ba64767668..c10e84c6d17 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp +++ b/circuits/cpp/src/aztec3/circuits/abis/private_circuit_public_inputs.hpp @@ -76,10 +76,10 @@ template class PrivateCircuitPublicInputs { { return call_context == other.call_context && args_hash == other.args_hash && return_values == other.return_values && read_requests == other.read_requests && - new_commitments == other.new_commitments && new_nullifiers == other.new_nullifiers && - nullified_commitments == other.nullified_commitments && private_call_stack == other.private_call_stack && - public_call_stack == other.public_call_stack && new_l2_to_l1_msgs == other.new_l2_to_l1_msgs && - encrypted_logs_hash == other.encrypted_logs_hash && + new_commitments == other.new_commitments && + new_nullifiers == other.new_nullifiers && nullified_commitments == other.nullified_commitments && + private_call_stack == other.private_call_stack && public_call_stack == other.public_call_stack && + new_l2_to_l1_msgs == other.new_l2_to_l1_msgs && encrypted_logs_hash == other.encrypted_logs_hash && unencrypted_logs_hash == other.unencrypted_logs_hash && encrypted_log_preimages_length == other.encrypted_log_preimages_length && unencrypted_log_preimages_length == other.unencrypted_log_preimages_length && diff --git a/circuits/cpp/src/aztec3/constants.hpp b/circuits/cpp/src/aztec3/constants.hpp index e0395aefe28..d2c444ac1b3 100644 --- a/circuits/cpp/src/aztec3/constants.hpp +++ b/circuits/cpp/src/aztec3/constants.hpp @@ -321,16 +321,18 @@ constexpr size_t CONTRACT_DEPLOYMENT_DATA_LENGTH = 6; // should change this constant as well as the offsets in private_call_stack_item.nr constexpr size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_LENGTH = CALL_CONTEXT_LENGTH + 1 // +1 for args_hash - + RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + - 2 * MAX_NEW_NULLIFIERS_PER_CALL + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + - MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + NUM_FIELDS_PER_SHA256 + 2 // + 2 for logs preimage lengths - + BLOCK_HEADER_LENGTH + CONTRACT_DEPLOYMENT_DATA_LENGTH + 2; // + 2 for chain_id and version + + RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL + + MAX_NEW_COMMITMENTS_PER_CALL + 2 * MAX_NEW_NULLIFIERS_PER_CALL + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + + NUM_FIELDS_PER_SHA256 + 2 // + 2 for logs preimage lengths + + BLOCK_HEADER_LENGTH + CONTRACT_DEPLOYMENT_DATA_LENGTH + 2; // + 2 for chain_id and version constexpr size_t PRIVATE_CIRCUIT_PUBLIC_INPUTS_HASH_INPUT_LENGTH = 1 + 1 // call_context_hash + args_hash - + RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL + MAX_NEW_COMMITMENTS_PER_CALL + - 2 * MAX_NEW_NULLIFIERS_PER_CALL + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + - MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + NUM_FIELDS_PER_SHA256 + 2 // + 2 for logs preimage lengths + + RETURN_VALUES_LENGTH + MAX_READ_REQUESTS_PER_CALL + + MAX_NEW_COMMITMENTS_PER_CALL + 2 * MAX_NEW_NULLIFIERS_PER_CALL + MAX_PRIVATE_CALL_STACK_LENGTH_PER_CALL + + MAX_PUBLIC_CALL_STACK_LENGTH_PER_CALL + MAX_NEW_L2_TO_L1_MSGS_PER_CALL + NUM_FIELDS_PER_SHA256 + + NUM_FIELDS_PER_SHA256 + 2 // + 2 for logs preimage lengths + BLOCK_HEADER_LENGTH + 3; // + 3 for contract_deployment_data.hash(), chain_id, version constexpr size_t CONTRACT_STORAGE_UPDATE_REQUEST_LENGTH = 3;