From d2ae2cd529b0ef132c0b6c7c35938066c89d809c Mon Sep 17 00:00:00 2001 From: kevaundray Date: Mon, 8 Jan 2024 16:38:13 +0000 Subject: [PATCH] feat!: Noir development branch (serialization changes) (#3858) The report gates diff workflow relies on a compiled from source version of Noir which uses a released version of bb. If any changes are made to bb, it is not reflected in the compiled version of Noir. This can lead to failures if the serialization is changed for example. Since report-gates-diff is a github actions workflow, it doesn't have access the compiled bb binary in CCI. We don't want to recompile it on bb as that would take upwards of half an hour. So that we don't block Noir related PRs that have been reviewed, this branch will be used to merge in the breaking changes to serialization until the issue with reports gate diff has been fixed. # Checklist: Remove the checklist to signal you've completed it. Enable auto-merge if the PR is ready to merge. - [ ] If the pull request requires a cryptography review (e.g. cryptographic algorithm implementations) I have added the 'crypto' tag. - [ ] I have reviewed my diff in github, line by line and removed unexpected formatting changes, testing logs, or commented-out code. - [ ] Every change is related to the PR description. - [ ] I have [linked](https://docs.github.com/en/issues/tracking-your-work-with-issues/linking-a-pull-request-to-an-issue) this pull request to relevant issues (if any exist). --------- Co-authored-by: guipublic Co-authored-by: guipublic <47281315+guipublic@users.noreply.github.com> Co-authored-by: Tom French <15848336+TomAFrench@users.noreply.github.com> --- barretenberg/cpp/src/barretenberg/bb/main.cpp | 2 +- .../dsl/acir_format/acir_format.cpp | 8 ++ .../dsl/acir_format/acir_format.hpp | 5 + .../dsl/acir_format/acir_format.test.cpp | 54 ++++++++ .../acir_format/acir_to_constraint_buf.hpp | 17 +++ .../dsl/acir_format/blake3_constraint.cpp | 44 ++++++ .../dsl/acir_format/blake3_constraint.hpp | 29 ++++ .../dsl/acir_format/block_constraint.test.cpp | 2 + .../dsl/acir_format/ecdsa_secp256k1.test.cpp | 6 + .../dsl/acir_format/ecdsa_secp256r1.test.cpp | 8 ++ .../dsl/acir_format/keccak_constraint.cpp | 28 ++++ .../dsl/acir_format/keccak_constraint.hpp | 10 ++ .../acir_format/recursion_constraint.test.cpp | 4 + .../dsl/acir_format/serde/acir.hpp | 124 +++++++++++++++++ .../stdlib/hash/keccak/keccak.cpp | 127 ++++++++++++++++++ .../stdlib/hash/keccak/keccak.hpp | 11 ++ .../stdlib/hash/keccak/keccak.test.cpp | 43 ++++++ noir/Cargo.lock | 26 ++++ noir/acvm-repo/acir/codegen/acir.cpp | 102 +++++++++++++- .../acir/src/circuit/black_box_functions.rs | 8 ++ noir/acvm-repo/acir/src/circuit/mod.rs | 59 ++++++++ .../opcodes/black_box_function_call.rs | 14 ++ .../acvm/src/compiler/transformers/mod.rs | 4 +- noir/acvm-repo/acvm/src/pwg/blackbox/hash.rs | 79 +++++++++++ noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs | 30 ++++- noir/acvm-repo/blackbox_solver/Cargo.toml | 1 + noir/acvm-repo/blackbox_solver/src/lib.rs | 4 + .../ssa/acir_gen/acir_ir/generated_acir.rs | 13 +- .../src/ssa/ir/instruction/call.rs | 2 + noir/noir_stdlib/src/hash.nr | 3 + .../execution_success/blake3/Nargo.toml | 7 + .../execution_success/blake3/Prover.toml | 37 +++++ .../execution_success/blake3/src/main.nr | 6 + .../mock_backend/src/info_cmd.rs | 1 + .../src/__snapshots__/index.test.ts.snap | 4 +- 35 files changed, 913 insertions(+), 9 deletions(-) create mode 100644 barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.cpp create mode 100644 barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.hpp create mode 100644 noir/test_programs/execution_success/blake3/Nargo.toml create mode 100644 noir/test_programs/execution_success/blake3/Prover.toml create mode 100644 noir/test_programs/execution_success/blake3/src/main.nr diff --git a/barretenberg/cpp/src/barretenberg/bb/main.cpp b/barretenberg/cpp/src/barretenberg/bb/main.cpp index df046160069..f3af328e910 100644 --- a/barretenberg/cpp/src/barretenberg/bb/main.cpp +++ b/barretenberg/cpp/src/barretenberg/bb/main.cpp @@ -397,7 +397,7 @@ void acvm_info(const std::string& output_path) "width" : 3 }, "opcodes_supported" : ["arithmetic", "directive", "brillig", "memory_init", "memory_op"], - "black_box_functions_supported" : ["and", "xor", "range", "sha256", "blake2s", "keccak256", "schnorr_verify", "pedersen", "pedersen_hash", "ecdsa_secp256k1", "ecdsa_secp256r1", "fixed_base_scalar_mul", "recursive_aggregation"] + "black_box_functions_supported" : ["and", "xor", "range", "sha256", "blake2s", "keccak256", "keccak_f1600", "schnorr_verify", "pedersen", "pedersen_hash", "ecdsa_secp256k1", "ecdsa_secp256r1", "fixed_base_scalar_mul", "recursive_aggregation"] })"; size_t length = strlen(jsonData); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp index 516fa1aaa89..912c23e77df 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.cpp @@ -119,6 +119,11 @@ void build_constraints(Builder& builder, acir_format const& constraint_system, b create_blake2s_constraints(builder, constraint); } + // Add blake3 constraints + for (const auto& constraint : constraint_system.blake3_constraints) { + create_blake3_constraints(builder, constraint); + } + // Add keccak constraints for (const auto& constraint : constraint_system.keccak_constraints) { create_keccak_constraints(builder, constraint); @@ -126,6 +131,9 @@ void build_constraints(Builder& builder, acir_format const& constraint_system, b for (const auto& constraint : constraint_system.keccak_var_constraints) { create_keccak_var_constraints(builder, constraint); } + for (const auto& constraint : constraint_system.keccak_permutations) { + create_keccak_permutations(builder, constraint); + } // Add pedersen constraints for (const auto& constraint : constraint_system.pedersen_constraints) { diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp index 1f00b202b9f..a2f198e2f7f 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.hpp @@ -3,6 +3,7 @@ #include "barretenberg/dsl/types.hpp" #include "barretenberg/serialize/msgpack.hpp" #include "blake2s_constraint.hpp" +#include "blake3_constraint.hpp" #include "block_constraint.hpp" #include "ecdsa_secp256k1.hpp" #include "ecdsa_secp256r1.hpp" @@ -30,8 +31,10 @@ struct acir_format { std::vector ecdsa_k1_constraints; std::vector ecdsa_r1_constraints; std::vector blake2s_constraints; + std::vector blake3_constraints; std::vector keccak_constraints; std::vector keccak_var_constraints; + std::vector keccak_permutations; std::vector pedersen_constraints; std::vector pedersen_hash_constraints; std::vector fixed_base_scalar_mul_constraints; @@ -55,8 +58,10 @@ struct acir_format { ecdsa_k1_constraints, ecdsa_r1_constraints, blake2s_constraints, + blake3_constraints, keccak_constraints, keccak_var_constraints, + keccak_permutations, pedersen_constraints, pedersen_hash_constraints, fixed_base_scalar_mul_constraints, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp index a4f64e0791c..4b6fdcd52a5 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_format.test.cpp @@ -37,8 +37,10 @@ TEST_F(AcirFormatTests, TestASingleConstraintNoPubInputs) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -143,8 +145,10 @@ TEST_F(AcirFormatTests, TestLogicGateFromNoirCircuit) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -207,8 +211,10 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -294,8 +300,10 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -400,8 +408,10 @@ TEST_F(AcirFormatTests, TestVarKeccak) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = { keccak }, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -419,4 +429,48 @@ TEST_F(AcirFormatTests, TestVarKeccak) EXPECT_EQ(verifier.verify_proof(proof), true); } +TEST_F(AcirFormatTests, TestKeccakPermutation) +{ + Keccakf1600 + keccak_permutation{ + .state = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 }, + .result = { 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, + 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50 }, + }; + + acir_format constraint_system{ .varnum = 51, + .public_inputs = {}, + .logic_constraints = {}, + .range_constraints = {}, + .sha256_constraints = {}, + .schnorr_constraints = {}, + .ecdsa_k1_constraints = {}, + .ecdsa_r1_constraints = {}, + .blake2s_constraints = {}, + .blake3_constraints = {}, + .keccak_constraints = {}, + .keccak_var_constraints = {}, + .keccak_permutations = { keccak_permutation }, + .pedersen_constraints = {}, + .pedersen_hash_constraints = {}, + .fixed_base_scalar_mul_constraints = {}, + .recursion_constraints = {}, + .constraints = {}, + .block_constraints = {} }; + + WitnessVector witness{ 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, + 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, + 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50 }; + + auto builder = create_circuit_with_witness(constraint_system, witness); + + auto composer = Composer(); + auto prover = composer.create_ultra_with_keccak_prover(builder); + auto proof = prover.construct_proof(); + + auto verifier = composer.create_ultra_with_keccak_verifier(builder); + + EXPECT_EQ(verifier.verify_proof(proof), true); +} + } // namespace acir_format::tests diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp index 123c52a27a3..9b6b36d7e06 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp @@ -3,6 +3,7 @@ #include "barretenberg/common/container.hpp" #include "barretenberg/common/throw_or_abort.hpp" #include "barretenberg/dsl/acir_format/blake2s_constraint.hpp" +#include "barretenberg/dsl/acir_format/blake3_constraint.hpp" #include "barretenberg/dsl/acir_format/block_constraint.hpp" #include "barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp" #include "barretenberg/dsl/acir_format/keccak_constraint.hpp" @@ -113,6 +114,17 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, aci }), .result = map(arg.outputs, [](auto& e) { return e.value; }), }); + } else if constexpr (std::is_same_v) { + af.blake3_constraints.push_back(Blake3Constraint{ + .inputs = map(arg.inputs, + [](auto& e) { + return Blake3Input{ + .witness = e.witness.value, + .num_bits = e.num_bits, + }; + }), + .result = map(arg.outputs, [](auto& e) { return e.value; }), + }); } else if constexpr (std::is_same_v) { af.schnorr_constraints.push_back(SchnorrConstraint{ .message = map(arg.message, [](auto& e) { return e.witness.value; }), @@ -180,6 +192,11 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, aci .result = map(arg.outputs, [](auto& e) { return e.value; }), .var_message_size = arg.var_message_size.witness.value, }); + } else if constexpr (std::is_same_v) { + af.keccak_permutations.push_back(Keccakf1600{ + .state = map(arg.inputs, [](auto& e) { return e.witness.value; }), + .result = map(arg.outputs, [](auto& e) { return e.value; }), + }); } else if constexpr (std::is_same_v) { auto c = RecursionConstraint{ .key = map(arg.verification_key, [](auto& e) { return e.witness.value; }), diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.cpp new file mode 100644 index 00000000000..7348ee25d0d --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.cpp @@ -0,0 +1,44 @@ +#include "blake3_constraint.hpp" +#include "round.hpp" + +namespace acir_format { + +template void create_blake3_constraints(Builder& builder, const Blake3Constraint& constraint) +{ + using byte_array_ct = proof_system::plonk::stdlib::byte_array; + using field_ct = proof_system::plonk::stdlib::field_t; + + // Create byte array struct + byte_array_ct arr(&builder); + + // Get the witness assignment for each witness index + // Write the witness assignment to the byte_array + for (const auto& witness_index_num_bits : constraint.inputs) { + auto witness_index = witness_index_num_bits.witness; + auto num_bits = witness_index_num_bits.num_bits; + + // XXX: The implementation requires us to truncate the element to the nearest byte and not bit + auto num_bytes = round_to_nearest_byte(num_bits); + + field_ct element = field_ct::from_witness_index(&builder, witness_index); + byte_array_ct element_bytes(element, num_bytes); + + arr.write(element_bytes); + } + + byte_array_ct output_bytes = proof_system::plonk::stdlib::blake3s(arr); + + // Convert byte array to vector of field_t + auto bytes = output_bytes.bytes(); + + for (size_t i = 0; i < bytes.size(); ++i) { + builder.assert_equal(bytes[i].normalize().witness_index, constraint.result[i]); + } +} + +template void create_blake3_constraints(UltraCircuitBuilder& builder, + const Blake3Constraint& constraint); +template void create_blake3_constraints(GoblinUltraCircuitBuilder& builder, + const Blake3Constraint& constraint); + +} // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.hpp new file mode 100644 index 00000000000..2fe421fb16c --- /dev/null +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.hpp @@ -0,0 +1,29 @@ +#pragma once +#include "barretenberg/dsl/types.hpp" +#include "barretenberg/serialize/msgpack.hpp" +#include +#include + +namespace acir_format { + +struct Blake3Input { + uint32_t witness; + uint32_t num_bits; + + // For serialization, update with any new fields + MSGPACK_FIELDS(witness, num_bits); + friend bool operator==(Blake3Input const& lhs, Blake3Input const& rhs) = default; +}; + +struct Blake3Constraint { + std::vector inputs; + std::vector result; + + // For serialization, update with any new fields + MSGPACK_FIELDS(inputs, result); + friend bool operator==(Blake3Constraint const& lhs, Blake3Constraint const& rhs) = default; +}; + +template void create_blake3_constraints(Builder& builder, const Blake3Constraint& constraint); + +} // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp index a20de2c75db..0473907838a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/block_constraint.test.cpp @@ -118,8 +118,10 @@ TEST_F(UltraPlonkRAM, TestBlockConstraint) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp index 9bcbc89ec87..4dfdff06fb2 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.test.cpp @@ -97,8 +97,10 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintSucceed) .ecdsa_k1_constraints = { ecdsa_k1_constraint }, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -137,8 +139,10 @@ TEST_F(ECDSASecp256k1, TestECDSACompilesForVerifier) .ecdsa_k1_constraints = { ecdsa_k1_constraint }, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -172,8 +176,10 @@ TEST_F(ECDSASecp256k1, TestECDSAConstraintFail) .ecdsa_k1_constraints = { ecdsa_k1_constraint }, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp index 5d26a4b7a37..deb95e656b5 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.test.cpp @@ -131,8 +131,10 @@ TEST(ECDSASecp256r1, test_hardcoded) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = { ecdsa_r1_constraint }, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -172,8 +174,10 @@ TEST(ECDSASecp256r1, TestECDSAConstraintSucceed) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = { ecdsa_r1_constraint }, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -211,8 +215,10 @@ TEST(ECDSASecp256r1, TestECDSACompilesForVerifier) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = { ecdsa_r1_constraint }, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -245,8 +251,10 @@ TEST(ECDSASecp256r1, TestECDSAConstraintFail) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = { ecdsa_r1_constraint }, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.cpp index 46745de023c..bd26897dbad 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.cpp @@ -1,5 +1,6 @@ #include "keccak_constraint.hpp" #include "barretenberg/stdlib/hash/keccak/keccak.hpp" +#include "barretenberg/stdlib/primitives/circuit_builders/circuit_builders_fwd.hpp" #include "round.hpp" namespace acir_format { @@ -73,13 +74,40 @@ template void create_keccak_var_constraints(Builder& builder, } } +template void create_keccak_permutations(Builder& builder, const Keccakf1600& constraint) +{ + using field_ct = proof_system::plonk::stdlib::field_t; + + // Create the array containing the permuted state + std::array::NUM_KECCAK_LANES> state; + + // Get the witness assignment for each witness index + // Write the witness assignment to the byte_array + for (size_t i = 0; i < constraint.state.size(); ++i) { + info(constraint.state[i]); + state[i] = field_ct::from_witness_index(&builder, constraint.state[i]); + } + + std::array output_state = + proof_system::plonk::stdlib::keccak::permutation_opcode(state, &builder); + + for (size_t i = 0; i < output_state.size(); ++i) { + builder.assert_equal(output_state[i].normalize().witness_index, constraint.result[i]); + } +} template void create_keccak_constraints(UltraCircuitBuilder& builder, const KeccakConstraint& constraint); template void create_keccak_var_constraints(UltraCircuitBuilder& builder, const KeccakVarConstraint& constraint); +template void create_keccak_permutations(UltraCircuitBuilder& builder, + const Keccakf1600& constraint); + template void create_keccak_constraints(GoblinUltraCircuitBuilder& builder, const KeccakConstraint& constraint); template void create_keccak_var_constraints(GoblinUltraCircuitBuilder& builder, const KeccakVarConstraint& constraint); +template void create_keccak_permutations(GoblinUltraCircuitBuilder& builder, + const Keccakf1600& constraint); + } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.hpp index 25259e1e941..4524e35862b 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.hpp @@ -15,6 +15,15 @@ struct HashInput { friend bool operator==(HashInput const& lhs, HashInput const& rhs) = default; }; +struct Keccakf1600 { + std::vector state; + std::vector result; + + // For serialization, update with any new fields + MSGPACK_FIELDS(state, result); + friend bool operator==(Keccakf1600 const& lhs, Keccakf1600 const& rhs) = default; +}; + struct KeccakConstraint { std::vector inputs; std::vector result; @@ -36,5 +45,6 @@ struct KeccakVarConstraint { template void create_keccak_constraints(Builder& builder, const KeccakConstraint& constraint); template void create_keccak_var_constraints(Builder& builder, const KeccakVarConstraint& constraint); +template void create_keccak_permutations(Builder& builder, const Keccakf1600& constraint); } // namespace acir_format diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp index c4decf04a3a..63a60cda21a 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/recursion_constraint.test.cpp @@ -90,8 +90,10 @@ Builder create_inner_circuit() .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, @@ -247,8 +249,10 @@ Builder create_outer_circuit(std::vector& inner_circuits) .ecdsa_k1_constraints = {}, .ecdsa_r1_constraints = {}, .blake2s_constraints = {}, + .blake3_constraints = {}, .keccak_constraints = {}, .keccak_var_constraints = {}, + .keccak_permutations = {}, .pedersen_constraints = {}, .pedersen_hash_constraints = {}, .fixed_base_scalar_mul_constraints = {}, diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index 2d124e2a7b2..4aa912073c8 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -70,6 +70,15 @@ struct BlackBoxFuncCall { static Blake2s bincodeDeserialize(std::vector); }; + struct Blake3 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Blake3&, const Blake3&); + std::vector bincodeSerialize() const; + static Blake3 bincodeDeserialize(std::vector); + }; + struct SchnorrVerify { Circuit::FunctionInput public_key_x; Circuit::FunctionInput public_key_y; @@ -155,6 +164,15 @@ struct BlackBoxFuncCall { static Keccak256VariableLength bincodeDeserialize(std::vector); }; + struct Keccakf1600 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Keccakf1600&, const Keccakf1600&); + std::vector bincodeSerialize() const; + static Keccakf1600 bincodeDeserialize(std::vector); + }; + struct RecursiveAggregation { std::vector verification_key; std::vector proof; @@ -173,6 +191,7 @@ struct BlackBoxFuncCall { RANGE, SHA256, Blake2s, + Blake3, SchnorrVerify, PedersenCommitment, PedersenHash, @@ -181,6 +200,7 @@ struct BlackBoxFuncCall { FixedBaseScalarMul, Keccak256, Keccak256VariableLength, + Keccakf1600, RecursiveAggregation> value; @@ -2035,6 +2055,58 @@ Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable BlackBoxFuncCall::Blake3::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BlackBoxFuncCall::Blake3 BlackBoxFuncCall::Blake3::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake3& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Circuit::BlackBoxFuncCall::Blake3 serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Circuit::BlackBoxFuncCall::Blake3 obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + inline bool operator==(const BlackBoxFuncCall::SchnorrVerify& lhs, const BlackBoxFuncCall::SchnorrVerify& rhs) { if (!(lhs.public_key_x == rhs.public_key_x)) { @@ -2520,6 +2592,58 @@ Circuit::BlackBoxFuncCall::Keccak256VariableLength serde::Deserializable< namespace Circuit { +inline bool operator==(const BlackBoxFuncCall::Keccakf1600& lhs, const BlackBoxFuncCall::Keccakf1600& rhs) +{ + if (!(lhs.inputs == rhs.inputs)) { + return false; + } + if (!(lhs.outputs == rhs.outputs)) { + return false; + } + return true; +} + +inline std::vector BlackBoxFuncCall::Keccakf1600::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline BlackBoxFuncCall::Keccakf1600 BlackBoxFuncCall::Keccakf1600::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize( + const Circuit::BlackBoxFuncCall::Keccakf1600& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Circuit::BlackBoxFuncCall::Keccakf1600 serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Circuit::BlackBoxFuncCall::Keccakf1600 obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + inline bool operator==(const BlackBoxFuncCall::RecursiveAggregation& lhs, const BlackBoxFuncCall::RecursiveAggregation& rhs) { diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.cpp index 2ff044e13fe..bbc2159c756 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.cpp @@ -1,6 +1,7 @@ #include "keccak.hpp" #include "barretenberg/common/constexpr_utils.hpp" #include "barretenberg/numeric/bitop/sparse_form.hpp" +#include "barretenberg/stdlib/primitives/logic/logic.hpp" #include "barretenberg/stdlib/primitives/uint/uint.hpp" namespace proof_system::plonk { namespace stdlib { @@ -721,6 +722,92 @@ std::vector> keccak::format_input_lanes(byte_array_ct& return lanes; } +// Returns the keccak f1600 permutation of the input state +// We first convert the state into 'extended' representation, along with the 'twisted' state +// and then we call keccakf1600() with this keccak 'internal state' +// Finally, we convert back the state from the extented representation +template +std::array, keccak::NUM_KECCAK_LANES> keccak::permutation_opcode( + std::array, NUM_KECCAK_LANES> state, Builder* ctx) +{ + std::vector> converted_buffer(NUM_KECCAK_LANES); + std::vector> msb_buffer(NUM_KECCAK_LANES); + // populate keccak_state, convert our 64-bit lanes into an extended base-11 representation + keccak_state internal; + internal.context = ctx; + for (size_t i = 0; i < state.size(); ++i) { + const auto accumulators = plookup_read::get_lookup_accumulators(KECCAK_FORMAT_INPUT, state[i]); + internal.state[i] = accumulators[ColumnIdx::C2][0]; + internal.state_msb[i] = accumulators[ColumnIdx::C3][accumulators[ColumnIdx::C3].size() - 1]; + } + compute_twisted_state(internal); + keccakf1600(internal); + // we convert back to the normal lanes + return extended_2_normal(internal); +} + +// This function is similar to sponge_absorb() +// but it uses permutation_opcode() instead of calling directly keccakf1600(). +// As a result, this function is less efficient and should only be used to test permutation_opcode() +template +void keccak::sponge_absorb_with_permutation_opcode(keccak_state& internal, + std::vector>& input_buffer, + const size_t input_size) +{ + // populate keccak_state + const size_t num_blocks = input_size / (BLOCK_SIZE / 8); + for (size_t i = 0; i < num_blocks; ++i) { + if (i == 0) { + for (size_t j = 0; j < LIMBS_PER_BLOCK; ++j) { + internal.state[j] = input_buffer[j]; + } + for (size_t j = LIMBS_PER_BLOCK; j < NUM_KECCAK_LANES; ++j) { + internal.state[j] = witness_ct::create_constant_witness(internal.context, 0); + } + } else { + for (size_t j = 0; j < LIMBS_PER_BLOCK; ++j) { + internal.state[j] = stdlib::logic::create_logic_constraint( + internal.state[j], input_buffer[i * LIMBS_PER_BLOCK + j], 64, true); + } + } + internal.state = permutation_opcode(internal.state, internal.context); + } +} + +// This function computes the keccak hash, like the hash() function +// but it uses permutation_opcode() instead of calling directly keccakf1600(). +// As a result, this function is less efficient and should only be used to test permutation_opcode() +template +stdlib::byte_array keccak::hash_using_permutation_opcode(byte_array_ct& input, + const uint32_ct& num_bytes) +{ + auto ctx = input.get_context(); + + ASSERT(uint256_t(num_bytes.get_value()) == input.size()); + + if (ctx == nullptr) { + // if buffer is constant compute hash and return w/o creating constraints + byte_array_ct output(nullptr, 32); + const std::vector result = hash_native(input.get_value()); + for (size_t i = 0; i < 32; ++i) { + output.set_byte(i, result[i]); + } + return output; + } + + // convert the input byte array into 64-bit keccak lanes (+ apply padding) + auto formatted_slices = format_input_lanes(input, num_bytes); + + keccak_state internal; + internal.context = ctx; + uint32_ct num_blocks_with_data = (num_bytes + BLOCK_SIZE) / BLOCK_SIZE; + sponge_absorb_with_permutation_opcode(internal, formatted_slices, formatted_slices.size()); + + auto result = sponge_squeeze_for_permutation_opcode(internal.state, ctx); + + return result; +} + template stdlib::byte_array keccak::hash(byte_array_ct& input, const uint32_ct& num_bytes) { @@ -762,6 +849,46 @@ stdlib::byte_array keccak::hash(byte_array_ct& input, const ui return result; } +// Convert the 'extended' representation of the internal Keccak state into the usual array of 64 bits lanes +template +std::array, keccak::NUM_KECCAK_LANES> keccak::extended_2_normal( + keccak_state& internal) +{ + std::array, NUM_KECCAK_LANES> conversion; + + // Each hash limb represents a little-endian integer. Need to reverse bytes before we write into the output array + for (size_t i = 0; i < internal.state.size(); ++i) { + field_ct output_limb = plookup_read::read_from_1_to_2_table(KECCAK_FORMAT_OUTPUT, internal.state[i]); + conversion[i] = output_limb; + } + + return conversion; +} + +// This function is the same as sponge_squeeze, except that it does not convert +// from extended representation and assumes the input has already being converted +template +stdlib::byte_array keccak::sponge_squeeze_for_permutation_opcode( + std::array, NUM_KECCAK_LANES> lanes, Builder* context) +{ + byte_array_ct result(context); + + // Each hash limb represents a little-endian integer. Need to reverse bytes before we write into the output array + for (size_t i = 0; i < 4; ++i) { + byte_array_ct limb_bytes(lanes[i], 8); + byte_array_ct little_endian_limb_bytes(context, 8); + little_endian_limb_bytes.set_byte(0, limb_bytes[7]); + little_endian_limb_bytes.set_byte(1, limb_bytes[6]); + little_endian_limb_bytes.set_byte(2, limb_bytes[5]); + little_endian_limb_bytes.set_byte(3, limb_bytes[4]); + little_endian_limb_bytes.set_byte(4, limb_bytes[3]); + little_endian_limb_bytes.set_byte(5, limb_bytes[2]); + little_endian_limb_bytes.set_byte(6, limb_bytes[1]); + little_endian_limb_bytes.set_byte(7, limb_bytes[0]); + result.write(little_endian_limb_bytes); + } + return result; +} INSTANTIATE_STDLIB_ULTRA_TYPE(keccak) } // namespace stdlib } // namespace proof_system::plonk diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.hpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.hpp index 1790040731e..5719938ebad 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.hpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.hpp @@ -189,6 +189,17 @@ template class keccak { memcpy((void*)&output[0], (void*)&hash_result.word64s[0], 32); return output; } + + // exposing keccak f1600 permutation + static byte_array_ct hash_using_permutation_opcode(byte_array_ct& input, const uint32_ct& num_bytes); + static std::array permutation_opcode(std::array state, + Builder* context); + static void sponge_absorb_with_permutation_opcode(keccak_state& internal, + std::vector& input_buffer, + const size_t input_size); + static std::array extended_2_normal(keccak_state& internal); + static byte_array_ct sponge_squeeze_for_permutation_opcode(std::array lanes, + Builder* context); }; EXTERN_STDLIB_ULTRA_TYPE(keccak) diff --git a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp index dd5ab49884e..852488f5a6c 100644 --- a/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp +++ b/barretenberg/cpp/src/barretenberg/stdlib/hash/keccak/keccak.test.cpp @@ -269,3 +269,46 @@ TEST(stdlib_keccak, test_variable_length_nonzero_input_greater_than_byte_array_s bool proof_result = builder.check_circuit(); EXPECT_EQ(proof_result, true); } + +TEST(stdlib_keccak, test_permutation_opcode_single_block) +{ + Builder builder = Builder(); + std::string input = "abcdefghijklmnopqrstuvwxyz0123456789abcdefghijklmnopqrstuvwxyz01"; + std::vector input_v(input.begin(), input.end()); + + byte_array input_arr(&builder, input_v); + byte_array output = + stdlib::keccak::hash_using_permutation_opcode(input_arr, static_cast(input.size())); + + std::vector expected = stdlib::keccak::hash_native(input_v); + + EXPECT_EQ(output.get_value(), expected); + + builder.print_num_gates(); + + bool proof_result = builder.check_circuit(); + EXPECT_EQ(proof_result, true); +} + +TEST(stdlib_keccak, test_permutation_opcode_double_block) +{ + Builder builder = Builder(); + std::string input = ""; + for (size_t i = 0; i < 200; ++i) { + input += "a"; + } + std::vector input_v(input.begin(), input.end()); + + byte_array input_arr(&builder, input_v); + byte_array output = + stdlib::keccak::hash_using_permutation_opcode(input_arr, static_cast(input.size())); + + std::vector expected = stdlib::keccak::hash_native(input_v); + + EXPECT_EQ(output.get_value(), expected); + + builder.print_num_gates(); + + bool proof_result = builder.check_circuit(); + EXPECT_EQ(proof_result, true); +} diff --git a/noir/Cargo.lock b/noir/Cargo.lock index f1fb11aea6a..82d4030f100 100644 --- a/noir/Cargo.lock +++ b/noir/Cargo.lock @@ -58,6 +58,7 @@ version = "0.38.0" dependencies = [ "acir", "blake2", + "blake3", "k256", "p256", "sha2", @@ -344,6 +345,12 @@ dependencies = [ "rand", ] +[[package]] +name = "arrayref" +version = "0.3.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6b4930d2cb77ce62f89ee5d5289b4ac049559b1c45539271f5ed4fdc7db34545" + [[package]] name = "arrayvec" version = "0.7.4" @@ -575,6 +582,19 @@ dependencies = [ "digest", ] +[[package]] +name = "blake3" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0231f06152bf547e9c2b5194f247cd97aacf6dcd8b15d8e5ec0663f64580da87" +dependencies = [ + "arrayref", + "arrayvec", + "cc", + "cfg-if", + "constant_time_eq", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -963,6 +983,12 @@ dependencies = [ "unicode-xid", ] +[[package]] +name = "constant_time_eq" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7144d30dcf0fafbce74250a3963025d8d52177934239851c917d29f1df280c2" + [[package]] name = "core-foundation-sys" version = "0.8.4" diff --git a/noir/acvm-repo/acir/codegen/acir.cpp b/noir/acvm-repo/acir/codegen/acir.cpp index 18532940752..27dc427227f 100644 --- a/noir/acvm-repo/acir/codegen/acir.cpp +++ b/noir/acvm-repo/acir/codegen/acir.cpp @@ -70,6 +70,15 @@ namespace Circuit { static Blake2s bincodeDeserialize(std::vector); }; + struct Blake3 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Blake3&, const Blake3&); + std::vector bincodeSerialize() const; + static Blake3 bincodeDeserialize(std::vector); + }; + struct SchnorrVerify { Circuit::FunctionInput public_key_x; Circuit::FunctionInput public_key_y; @@ -155,6 +164,15 @@ namespace Circuit { static Keccak256VariableLength bincodeDeserialize(std::vector); }; + struct Keccakf1600 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Keccakf1600&, const Keccakf1600&); + std::vector bincodeSerialize() const; + static Keccakf1600 bincodeDeserialize(std::vector); + }; + struct RecursiveAggregation { std::vector verification_key; std::vector proof; @@ -168,7 +186,7 @@ namespace Circuit { static RecursiveAggregation bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; @@ -1821,6 +1839,47 @@ Circuit::BlackBoxFuncCall::Blake2s serde::Deserializable BlackBoxFuncCall::Blake3::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxFuncCall::Blake3 BlackBoxFuncCall::Blake3::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Blake3 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Circuit::BlackBoxFuncCall::Blake3 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::Blake3 obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const BlackBoxFuncCall::SchnorrVerify &lhs, const BlackBoxFuncCall::SchnorrVerify &rhs) { @@ -2188,6 +2247,47 @@ Circuit::BlackBoxFuncCall::Keccak256VariableLength serde::Deserializable BlackBoxFuncCall::Keccakf1600::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BlackBoxFuncCall::Keccakf1600 BlackBoxFuncCall::Keccakf1600::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::Keccakf1600 &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.outputs, serializer); +} + +template <> +template +Circuit::BlackBoxFuncCall::Keccakf1600 serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::Keccakf1600 obj; + obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.outputs = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const BlackBoxFuncCall::RecursiveAggregation &lhs, const BlackBoxFuncCall::RecursiveAggregation &rhs) { diff --git a/noir/acvm-repo/acir/src/circuit/black_box_functions.rs b/noir/acvm-repo/acir/src/circuit/black_box_functions.rs index b2dcbd73ef6..6e45a9a2c21 100644 --- a/noir/acvm-repo/acir/src/circuit/black_box_functions.rs +++ b/noir/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -19,6 +19,8 @@ pub enum BlackBoxFunc { SHA256, /// Calculates the Blake2s hash of the inputs. Blake2s, + /// Calculates the Blake3 hash of the inputs. + Blake3, /// Verifies a Schnorr signature over a curve which is "pairing friendly" with the curve on which the ACIR circuit is defined. /// /// The exact curve which this signature uses will vary based on the curve being used by ACIR. @@ -38,6 +40,8 @@ pub enum BlackBoxFunc { FixedBaseScalarMul, /// Calculates the Keccak256 hash of the inputs. Keccak256, + /// Keccak Permutation function of 1600 width + Keccakf1600, /// Compute a recursive aggregation object when verifying a proof inside another circuit. /// This outputted aggregation object will then be either checked in a top-level verifier or aggregated upon again. RecursiveAggregation, @@ -55,6 +59,7 @@ impl BlackBoxFunc { BlackBoxFunc::SHA256 => "sha256", BlackBoxFunc::SchnorrVerify => "schnorr_verify", BlackBoxFunc::Blake2s => "blake2s", + BlackBoxFunc::Blake3 => "blake3", BlackBoxFunc::PedersenCommitment => "pedersen_commitment", BlackBoxFunc::PedersenHash => "pedersen_hash", BlackBoxFunc::EcdsaSecp256k1 => "ecdsa_secp256k1", @@ -63,6 +68,7 @@ impl BlackBoxFunc { BlackBoxFunc::XOR => "xor", BlackBoxFunc::RANGE => "range", BlackBoxFunc::Keccak256 => "keccak256", + BlackBoxFunc::Keccakf1600 => "keccak_f1600", BlackBoxFunc::RecursiveAggregation => "recursive_aggregation", BlackBoxFunc::EcdsaSecp256r1 => "ecdsa_secp256r1", } @@ -72,6 +78,7 @@ impl BlackBoxFunc { "sha256" => Some(BlackBoxFunc::SHA256), "schnorr_verify" => Some(BlackBoxFunc::SchnorrVerify), "blake2s" => Some(BlackBoxFunc::Blake2s), + "blake3" => Some(BlackBoxFunc::Blake3), "pedersen_commitment" => Some(BlackBoxFunc::PedersenCommitment), "pedersen_hash" => Some(BlackBoxFunc::PedersenHash), "ecdsa_secp256k1" => Some(BlackBoxFunc::EcdsaSecp256k1), @@ -81,6 +88,7 @@ impl BlackBoxFunc { "xor" => Some(BlackBoxFunc::XOR), "range" => Some(BlackBoxFunc::RANGE), "keccak256" => Some(BlackBoxFunc::Keccak256), + "keccakf1600" => Some(BlackBoxFunc::Keccakf1600), "recursive_aggregation" => Some(BlackBoxFunc::RecursiveAggregation), _ => None, } diff --git a/noir/acvm-repo/acir/src/circuit/mod.rs b/noir/acvm-repo/acir/src/circuit/mod.rs index 99ab389e31e..e42bebc52ac 100644 --- a/noir/acvm-repo/acir/src/circuit/mod.rs +++ b/noir/acvm-repo/acir/src/circuit/mod.rs @@ -250,6 +250,64 @@ mod tests { input: FunctionInput { witness: Witness(1), num_bits: 8 }, }) } + fn keccakf1600_opcode() -> Opcode { + Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Keccakf1600 { + inputs: vec![ + FunctionInput { witness: Witness(1), num_bits: 64 }, + FunctionInput { witness: Witness(2), num_bits: 64 }, + FunctionInput { witness: Witness(3), num_bits: 64 }, + FunctionInput { witness: Witness(4), num_bits: 64 }, + FunctionInput { witness: Witness(5), num_bits: 64 }, + FunctionInput { witness: Witness(6), num_bits: 64 }, + FunctionInput { witness: Witness(7), num_bits: 64 }, + FunctionInput { witness: Witness(8), num_bits: 64 }, + FunctionInput { witness: Witness(9), num_bits: 64 }, + FunctionInput { witness: Witness(10), num_bits: 64 }, + FunctionInput { witness: Witness(11), num_bits: 64 }, + FunctionInput { witness: Witness(12), num_bits: 64 }, + FunctionInput { witness: Witness(13), num_bits: 64 }, + FunctionInput { witness: Witness(14), num_bits: 64 }, + FunctionInput { witness: Witness(15), num_bits: 64 }, + FunctionInput { witness: Witness(16), num_bits: 64 }, + FunctionInput { witness: Witness(17), num_bits: 64 }, + FunctionInput { witness: Witness(18), num_bits: 64 }, + FunctionInput { witness: Witness(19), num_bits: 64 }, + FunctionInput { witness: Witness(20), num_bits: 64 }, + FunctionInput { witness: Witness(21), num_bits: 64 }, + FunctionInput { witness: Witness(22), num_bits: 64 }, + FunctionInput { witness: Witness(23), num_bits: 64 }, + FunctionInput { witness: Witness(24), num_bits: 64 }, + FunctionInput { witness: Witness(25), num_bits: 64 }, + ], + outputs: vec![ + Witness(26), + Witness(27), + Witness(28), + Witness(29), + Witness(30), + Witness(31), + Witness(32), + Witness(33), + Witness(34), + Witness(35), + Witness(36), + Witness(37), + Witness(38), + Witness(39), + Witness(40), + Witness(41), + Witness(42), + Witness(43), + Witness(44), + Witness(45), + Witness(46), + Witness(47), + Witness(48), + Witness(49), + Witness(50), + ], + }) + } #[test] fn serialization_roundtrip() { @@ -284,6 +342,7 @@ mod tests { }), range_opcode(), and_opcode(), + keccakf1600_opcode(), ], private_parameters: BTreeSet::new(), public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])), diff --git a/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index ded3b0898a0..fea12f9c08a 100644 --- a/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/noir/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -39,6 +39,10 @@ pub enum BlackBoxFuncCall { inputs: Vec, outputs: Vec, }, + Blake3 { + inputs: Vec, + outputs: Vec, + }, SchnorrVerify { public_key_x: FunctionInput, public_key_y: FunctionInput, @@ -88,6 +92,10 @@ pub enum BlackBoxFuncCall { var_message_size: FunctionInput, outputs: Vec, }, + Keccakf1600 { + inputs: Vec, + outputs: Vec, + }, RecursiveAggregation { verification_key: Vec, proof: Vec, @@ -121,6 +129,7 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::RANGE { .. } => BlackBoxFunc::RANGE, BlackBoxFuncCall::SHA256 { .. } => BlackBoxFunc::SHA256, BlackBoxFuncCall::Blake2s { .. } => BlackBoxFunc::Blake2s, + BlackBoxFuncCall::Blake3 { .. } => BlackBoxFunc::Blake3, BlackBoxFuncCall::SchnorrVerify { .. } => BlackBoxFunc::SchnorrVerify, BlackBoxFuncCall::PedersenCommitment { .. } => BlackBoxFunc::PedersenCommitment, BlackBoxFuncCall::PedersenHash { .. } => BlackBoxFunc::PedersenHash, @@ -129,6 +138,7 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::FixedBaseScalarMul { .. } => BlackBoxFunc::FixedBaseScalarMul, BlackBoxFuncCall::Keccak256 { .. } => BlackBoxFunc::Keccak256, BlackBoxFuncCall::Keccak256VariableLength { .. } => BlackBoxFunc::Keccak256, + BlackBoxFuncCall::Keccakf1600 { .. } => BlackBoxFunc::Keccakf1600, BlackBoxFuncCall::RecursiveAggregation { .. } => BlackBoxFunc::RecursiveAggregation, } } @@ -141,7 +151,9 @@ impl BlackBoxFuncCall { match self { BlackBoxFuncCall::SHA256 { inputs, .. } | BlackBoxFuncCall::Blake2s { inputs, .. } + | BlackBoxFuncCall::Blake3 { inputs, .. } | BlackBoxFuncCall::Keccak256 { inputs, .. } + | BlackBoxFuncCall::Keccakf1600 { inputs, .. } | BlackBoxFuncCall::PedersenCommitment { inputs, .. } | BlackBoxFuncCall::PedersenHash { inputs, .. } => inputs.to_vec(), BlackBoxFuncCall::AND { lhs, rhs, .. } | BlackBoxFuncCall::XOR { lhs, rhs, .. } => { @@ -230,7 +242,9 @@ impl BlackBoxFuncCall { match self { BlackBoxFuncCall::SHA256 { outputs, .. } | BlackBoxFuncCall::Blake2s { outputs, .. } + | BlackBoxFuncCall::Blake3 { outputs, .. } | BlackBoxFuncCall::Keccak256 { outputs, .. } + | BlackBoxFuncCall::Keccakf1600 { outputs, .. } | BlackBoxFuncCall::RecursiveAggregation { output_aggregation_object: outputs, .. } => outputs.to_vec(), diff --git a/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs b/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs index 664e0f9ac9a..003124f8b63 100644 --- a/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/noir/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -112,11 +112,13 @@ pub(super) fn transform_internal( outputs, .. } + | acir::circuit::opcodes::BlackBoxFuncCall::Keccakf1600 { outputs, .. } | acir::circuit::opcodes::BlackBoxFuncCall::RecursiveAggregation { output_aggregation_object: outputs, .. } - | acir::circuit::opcodes::BlackBoxFuncCall::Blake2s { outputs, .. } => { + | acir::circuit::opcodes::BlackBoxFuncCall::Blake2s { outputs, .. } + | acir::circuit::opcodes::BlackBoxFuncCall::Blake3 { outputs, .. } => { for witness in outputs { transformer.mark_solvable(*witness); } diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/hash.rs b/noir/acvm-repo/acvm/src/pwg/blackbox/hash.rs index 1ada397fc59..bbf7dd43bd9 100644 --- a/noir/acvm-repo/acvm/src/pwg/blackbox/hash.rs +++ b/noir/acvm-repo/acvm/src/pwg/blackbox/hash.rs @@ -86,3 +86,82 @@ fn write_digest_to_outputs( Ok(()) } + +const ROUNDS: usize = 24; + +const RC: [u64; ROUNDS] = [ + 1u64, + 0x8082u64, + 0x800000000000808au64, + 0x8000000080008000u64, + 0x808bu64, + 0x80000001u64, + 0x8000000080008081u64, + 0x8000000000008009u64, + 0x8au64, + 0x88u64, + 0x80008009u64, + 0x8000000au64, + 0x8000808bu64, + 0x800000000000008bu64, + 0x8000000000008089u64, + 0x8000000000008003u64, + 0x8000000000008002u64, + 0x8000000000000080u64, + 0x800au64, + 0x800000008000000au64, + 0x8000000080008081u64, + 0x8000000000008080u64, + 0x80000001u64, + 0x8000000080008008u64, +]; + +const RHO: [u32; 24] = + [1, 3, 6, 10, 15, 21, 28, 36, 45, 55, 2, 14, 27, 41, 56, 8, 25, 43, 62, 18, 39, 61, 20, 44]; + +const PI: [usize; 24] = + [10, 7, 11, 17, 18, 3, 5, 16, 8, 21, 24, 4, 15, 23, 19, 13, 12, 2, 20, 14, 22, 9, 6, 1]; + +const KECCAK_LANES: usize = 25; + +pub(crate) fn keccakf1600(state: &mut [u64; KECCAK_LANES]) { + for rc in RC { + let mut array: [u64; 5] = [0; 5]; + + // Theta + for x in 0..5 { + for y_count in 0..5 { + let y = y_count * 5; + array[x] ^= state[x + y]; + } + } + + for x in 0..5 { + for y_count in 0..5 { + let y = y_count * 5; + state[y + x] ^= array[(x + 4) % 5] ^ array[(x + 1) % 5].rotate_left(1); + } + } + + // Rho and pi + let mut last = state[1]; + for x in 0..24 { + array[0] = state[PI[x]]; + state[PI[x]] = last.rotate_left(RHO[x]); + last = array[0]; + } + + // Chi + for y_step in 0..5 { + let y = y_step * 5; + array[..5].copy_from_slice(&state[y..(5 + y)]); + + for x in 0..5 { + state[y + x] = array[x] ^ ((!array[(x + 1) % 5]) & (array[(x + 2) % 5])); + } + } + + // Iota + state[0] ^= rc; + } +} diff --git a/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs index ad15b121383..c36596235a2 100644 --- a/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/noir/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -3,12 +3,12 @@ use acir::{ native_types::{Witness, WitnessMap}, FieldElement, }; -use acvm_blackbox_solver::{blake2s, keccak256, sha256}; +use acvm_blackbox_solver::{blake2s, blake3, keccak256, sha256}; -use self::pedersen::pedersen_hash; +use self::{hash::keccakf1600, pedersen::pedersen_hash}; use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError}; -use crate::BlackBoxFunctionSolver; +use crate::{pwg::witness_to_value, BlackBoxFunctionSolver}; mod fixed_base_scalar_mul; mod hash; @@ -83,6 +83,14 @@ pub(crate) fn solve( blake2s, bb_func.get_black_box_func(), ), + BlackBoxFuncCall::Blake3 { inputs, outputs } => solve_generic_256_hash_opcode( + initial_witness, + inputs, + None, + outputs, + blake3, + bb_func.get_black_box_func(), + ), BlackBoxFuncCall::Keccak256 { inputs, outputs } => solve_generic_256_hash_opcode( initial_witness, inputs, @@ -101,6 +109,22 @@ pub(crate) fn solve( bb_func.get_black_box_func(), ) } + BlackBoxFuncCall::Keccakf1600 { inputs, outputs } => { + let mut state = [0; 25]; + for (i, input) in inputs.iter().enumerate() { + let witness = input.witness; + let num_bits = input.num_bits as usize; + assert_eq!(num_bits, 64); + let witness_assignment = witness_to_value(initial_witness, witness)?; + let lane = witness_assignment.try_to_u64(); + state[i] = lane.unwrap(); + } + keccakf1600(&mut state); + for (output_witness, value) in outputs.iter().zip(state.into_iter()) { + insert_value(output_witness, FieldElement::from(value as u128), initial_witness)?; + } + Ok(()) + } BlackBoxFuncCall::SchnorrVerify { public_key_x, public_key_y, diff --git a/noir/acvm-repo/blackbox_solver/Cargo.toml b/noir/acvm-repo/blackbox_solver/Cargo.toml index be2a58417f4..258321d8ef4 100644 --- a/noir/acvm-repo/blackbox_solver/Cargo.toml +++ b/noir/acvm-repo/blackbox_solver/Cargo.toml @@ -17,6 +17,7 @@ acir.workspace = true thiserror.workspace = true blake2 = "0.10.6" +blake3 = "1.5.0" sha2 = "0.10.6" sha3 = "0.10.6" k256 = { version = "0.11.0", features = [ diff --git a/noir/acvm-repo/blackbox_solver/src/lib.rs b/noir/acvm-repo/blackbox_solver/src/lib.rs index cf2cf295f7a..ede648ef75e 100644 --- a/noir/acvm-repo/blackbox_solver/src/lib.rs +++ b/noir/acvm-repo/blackbox_solver/src/lib.rs @@ -59,6 +59,10 @@ pub fn blake2s(inputs: &[u8]) -> Result<[u8; 32], BlackBoxResolutionError> { .map_err(|err| BlackBoxResolutionError::Failed(BlackBoxFunc::Blake2s, err)) } +pub fn blake3(inputs: &[u8]) -> Result<[u8; 32], BlackBoxResolutionError> { + Ok(blake3::hash(inputs).into()) +} + pub fn keccak256(inputs: &[u8]) -> Result<[u8; 32], BlackBoxResolutionError> { generic_hash_256::(inputs) .map_err(|err| BlackBoxResolutionError::Failed(BlackBoxFunc::Keccak256, err)) diff --git a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index bd8271260af..c9f7ee51e97 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -155,6 +155,7 @@ impl GeneratedAcir { BlackBoxFunc::Blake2s => { BlackBoxFuncCall::Blake2s { inputs: inputs[0].clone(), outputs } } + BlackBoxFunc::Blake3 => BlackBoxFuncCall::Blake3 { inputs: inputs[0].clone(), outputs }, BlackBoxFunc::SchnorrVerify => { BlackBoxFuncCall::SchnorrVerify { public_key_x: inputs[0][0], @@ -222,6 +223,9 @@ impl GeneratedAcir { outputs, } } + BlackBoxFunc::Keccakf1600 => { + BlackBoxFuncCall::Keccakf1600 { inputs: inputs[0].clone(), outputs } + } BlackBoxFunc::RecursiveAggregation => { let has_previous_aggregation = self.opcodes.iter().any(|op| { matches!( @@ -569,9 +573,12 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { BlackBoxFunc::Keccak256 | BlackBoxFunc::SHA256 | BlackBoxFunc::Blake2s + | BlackBoxFunc::Blake3 | BlackBoxFunc::PedersenCommitment | BlackBoxFunc::PedersenHash => None, + BlackBoxFunc::Keccakf1600 => Some(25), + // Can only apply a range constraint to one // witness at a time. BlackBoxFunc::RANGE => Some(1), @@ -597,7 +604,11 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { // or the operation. BlackBoxFunc::AND | BlackBoxFunc::XOR => Some(1), // 32 byte hash algorithms - BlackBoxFunc::Keccak256 | BlackBoxFunc::SHA256 | BlackBoxFunc::Blake2s => Some(32), + BlackBoxFunc::Keccak256 + | BlackBoxFunc::SHA256 + | BlackBoxFunc::Blake2s + | BlackBoxFunc::Blake3 => Some(32), + BlackBoxFunc::Keccakf1600 => Some(25), // Pedersen commitment returns a point BlackBoxFunc::PedersenCommitment => Some(2), // Pedersen hash returns a field diff --git a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index cada0b97f93..f77e84d99e0 100644 --- a/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/noir/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -374,6 +374,8 @@ fn simplify_black_box_func( match bb_func { BlackBoxFunc::SHA256 => simplify_hash(dfg, arguments, acvm::blackbox_solver::sha256), BlackBoxFunc::Blake2s => simplify_hash(dfg, arguments, acvm::blackbox_solver::blake2s), + BlackBoxFunc::Blake3 => simplify_hash(dfg, arguments, acvm::blackbox_solver::blake3), + BlackBoxFunc::Keccakf1600 => SimplifyResult::None, //TODO(Guillaume) BlackBoxFunc::Keccak256 => { match (dfg.get_array_constant(arguments[0]), dfg.get_numeric_constant(arguments[1])) { (Some((input, _)), Some(num_bytes)) if array_is_constant(dfg, &input) => { diff --git a/noir/noir_stdlib/src/hash.nr b/noir/noir_stdlib/src/hash.nr index ad7e4f2e28f..5933209d9bc 100644 --- a/noir/noir_stdlib/src/hash.nr +++ b/noir/noir_stdlib/src/hash.nr @@ -7,6 +7,9 @@ pub fn sha256(_input: [u8; N]) -> [u8; 32] {} #[foreign(blake2s)] pub fn blake2s(_input: [u8; N]) -> [u8; 32] {} +#[foreign(blake3)] +pub fn blake3(_input: [u8; N]) -> [u8; 32] {} + struct PedersenPoint { x : Field, y : Field, diff --git a/noir/test_programs/execution_success/blake3/Nargo.toml b/noir/test_programs/execution_success/blake3/Nargo.toml new file mode 100644 index 00000000000..29f6ad5f11c --- /dev/null +++ b/noir/test_programs/execution_success/blake3/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "blake3" +type = "bin" +authors = [""] +compiler_version = ">=0.22.0" + +[dependencies] \ No newline at end of file diff --git a/noir/test_programs/execution_success/blake3/Prover.toml b/noir/test_programs/execution_success/blake3/Prover.toml new file mode 100644 index 00000000000..c807701479b --- /dev/null +++ b/noir/test_programs/execution_success/blake3/Prover.toml @@ -0,0 +1,37 @@ +# hello as bytes +# https://connor4312.github.io/blake3/index.html +x = [104, 101, 108, 108, 111] +result = [ + 0xea, + 0x8f, + 0x16, + 0x3d, + 0xb3, + 0x86, + 0x82, + 0x92, + 0x5e, + 0x44, + 0x91, + 0xc5, + 0xe5, + 0x8d, + 0x4b, + 0xb3, + 0x50, + 0x6e, + 0xf8, + 0xc1, + 0x4e, + 0xb7, + 0x8a, + 0x86, + 0xe9, + 0x08, + 0xc5, + 0x62, + 0x4a, + 0x67, + 0x20, + 0x0f, +] diff --git a/noir/test_programs/execution_success/blake3/src/main.nr b/noir/test_programs/execution_success/blake3/src/main.nr new file mode 100644 index 00000000000..3bfea6c5f95 --- /dev/null +++ b/noir/test_programs/execution_success/blake3/src/main.nr @@ -0,0 +1,6 @@ +use dep::std; + +fn main(x: [u8; 5], result: [u8; 32]) { + let digest = std::hash::blake3(x); + assert(digest == result); +} diff --git a/noir/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs b/noir/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs index 09c9596fb5a..fd8cf602125 100644 --- a/noir/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs +++ b/noir/tooling/backend_interface/test-binaries/mock_backend/src/info_cmd.rs @@ -14,6 +14,7 @@ const INFO_RESPONSE: &str = r#"{ "range", "sha256", "blake2s", + "blake3", "keccak256", "schnorr_verify", "pedersen", diff --git a/yarn-project/noir-compiler/src/__snapshots__/index.test.ts.snap b/yarn-project/noir-compiler/src/__snapshots__/index.test.ts.snap index 1a99b10fe69..a68f82ec125 100644 --- a/yarn-project/noir-compiler/src/__snapshots__/index.test.ts.snap +++ b/yarn-project/noir-compiler/src/__snapshots__/index.test.ts.snap @@ -7,7 +7,7 @@ exports[`noir-compiler using nargo compiles the test contract 1`] = ` "events": [], "functions": [ { - "bytecode": "H4sIAAAAAAAA/62QUQqEMAxEY7ew10maxCZ/e5Ut1vufQFRsoX7rQJiZnyG8CAABLk3HfZv3vrX8gbt6/zXHZ6Lpxa0wbDHOIjWnSkx/TF5MUbTMRkZquiRjriaWvXhGJ+FKqzqvbSy+9xeOXHsOA/+TaRwY7+UbOCacAQAA", + "bytecode": "H4sIAAAAAAAA/62QQQ6EMAwDQ7eHfU7SJDS57Ve2ovz/BQgQrVTOYCmyfbGiiQAQ4NJ03Ld571vLH7ir919zfCaaXtwKwxbjLFJzqsT0x+TFFEXLbGSkpksy5mpi2YtndBKutKrz2sbie3/hyLXnMPA/mcaB8Q4eX+1anAEAAA==", "functionType": "secret", "isInternal": false, "name": "constructor", @@ -205,7 +205,7 @@ exports[`noir-compiler using wasm binary compiles the test contract 1`] = ` "events": [], "functions": [ { - "bytecode": "H4sIAAAAAAAA/62QUQqEMAxEY7ew10maxCZ/e5Ut1vufQFRsoX7rQJiZnyG8CAABLk3HfZv3vrX8gbt6/zXHZ6Lpxa0wbDHOIjWnSkx/TF5MUbTMRkZquiRjriaWvXhGJ+FKqzqvbSy+9xeOXHsOA/+TaRwY7+UbOCacAQAA", + "bytecode": "H4sIAAAAAAAA/62QQQ6EMAwDQ7eHfU7SJDS57Ve2ovz/BQgQrVTOYCmyfbGiiQAQ4NJ03Ld571vLH7ir919zfCaaXtwKwxbjLFJzqsT0x+TFFEXLbGSkpksy5mpi2YtndBKutKrz2sbie3/hyLXnMPA/mcaB8Q4eX+1anAEAAA==", "functionType": "secret", "isInternal": false, "name": "constructor",