From f50b180379ac90d782aba3472708f8cef122c25b Mon Sep 17 00:00:00 2001 From: Tom French <15848336+TomAFrench@users.noreply.github.com> Date: Tue, 16 Apr 2024 15:15:22 +0100 Subject: [PATCH] feat!: Use fixed size arrays in black box functions where sizes are known (#5620) This PR enforces the sizes of inputs/outputs of blackbox functions to remove some runtime checks and allocations. --------- Co-authored-by: guipublic Co-authored-by: vezenovm --- avm-transpiler/Cargo.lock | 10 ++ .../dsl/acir_format/acir_format.test.cpp | 4 +- .../dsl/acir_format/blake2s_constraint.hpp | 2 +- .../dsl/acir_format/blake3_constraint.hpp | 2 +- .../dsl/acir_format/ecdsa_secp256k1.cpp | 65 ++------ .../dsl/acir_format/ecdsa_secp256k1.hpp | 56 ++++++- .../dsl/acir_format/ecdsa_secp256k1.test.cpp | 18 +-- .../dsl/acir_format/ecdsa_secp256r1.cpp | 22 +-- .../dsl/acir_format/ecdsa_secp256r1.hpp | 8 +- .../dsl/acir_format/ecdsa_secp256r1.test.cpp | 18 +-- .../dsl/acir_format/keccak_constraint.hpp | 6 +- .../dsl/acir_format/schnorr_verify.cpp | 2 +- .../dsl/acir_format/schnorr_verify.hpp | 2 +- .../dsl/acir_format/serde/acir.hpp | 36 ++--- .../dsl/acir_format/sha256_constraint.hpp | 8 +- .../acir_format/sha256_constraint.test.cpp | 12 +- noir/noir-repo/Cargo.lock | 10 ++ noir/noir-repo/acvm-repo/acir/Cargo.toml | 1 + .../noir-repo/acvm-repo/acir/codegen/acir.cpp | 36 ++--- .../acvm-repo/acir/src/circuit/mod.rs | 83 ++++------ .../opcodes/black_box_function_call.rs | 143 +++++++++++++++--- .../acir/tests/test_program_serialization.rs | 41 ++--- .../acvm-repo/acvm/src/pwg/blackbox/hash.rs | 68 +++------ .../acvm-repo/acvm/src/pwg/blackbox/mod.rs | 53 ++----- .../acvm/src/pwg/blackbox/signature/ecdsa.rs | 73 ++------- .../acvm/src/pwg/blackbox/signature/mod.rs | 15 ++ .../src/pwg/blackbox/signature/schnorr.rs | 7 +- .../acvm_js/test/shared/schnorr_verify.ts | 24 +-- .../src/curve_specific_solver.rs | 4 +- .../bn254_blackbox_solver/src/lib.rs | 2 +- .../acvm-repo/brillig_vm/src/black_box.rs | 3 +- .../ssa/acir_gen/acir_ir/generated_acir.rs | 92 ++++++++--- noir/noir-repo/tooling/lsp/src/solver.rs | 2 +- 33 files changed, 497 insertions(+), 431 deletions(-) diff --git a/avm-transpiler/Cargo.lock b/avm-transpiler/Cargo.lock index ff3702060f5..b99f5b35be6 100644 --- a/avm-transpiler/Cargo.lock +++ b/avm-transpiler/Cargo.lock @@ -12,6 +12,7 @@ dependencies = [ "brillig", "flate2", "serde", + "serde-big-array", "thiserror", ] @@ -1494,6 +1495,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde_derive" version = "1.0.196" 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 5d2fae4d988..49af9f200d4 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 @@ -196,7 +196,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifyPass) }); } - std::vector signature(64); + std::array signature; for (uint32_t i = 0, value = 12; i < 64; i++, value++) { signature[i] = value; range_constraints.push_back(RangeConstraint{ @@ -289,7 +289,7 @@ TEST_F(AcirFormatTests, TestSchnorrVerifySmallRange) }); } - std::vector signature(64); + std::array signature; for (uint32_t i = 0, value = 12; i < 64; i++, value++) { signature[i] = value; range_constraints.push_back(RangeConstraint{ diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake2s_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake2s_constraint.hpp index a4bf7983e47..cf55b5fb7e7 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake2s_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake2s_constraint.hpp @@ -17,7 +17,7 @@ struct Blake2sInput { struct Blake2sConstraint { std::vector inputs; - std::vector result; + std::array result; // For serialization, update with any new fields MSGPACK_FIELDS(inputs, result); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.hpp index 2fe421fb16c..c2d1ecafde7 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/blake3_constraint.hpp @@ -17,7 +17,7 @@ struct Blake3Input { struct Blake3Constraint { std::vector inputs; - std::vector result; + std::array result; // For serialization, update with any new fields MSGPACK_FIELDS(inputs, result); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp index 863c4f7b067..c402c94a954 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.cpp @@ -5,44 +5,6 @@ namespace acir_format { using namespace bb::plonk; -template -crypto::ecdsa_signature ecdsa_convert_signature(Builder& builder, std::vector signature) -{ - - crypto::ecdsa_signature signature_cr; - - // Get the witness assignment for each witness index - // Write the witness assignment to the byte_array - - for (unsigned int i = 0; i < 32; i++) { - auto witness_index = signature[i]; - - std::vector fr_bytes(sizeof(fr)); - - fr value = builder.get_variable(witness_index); - - fr::serialize_to_buffer(value, &fr_bytes[0]); - - signature_cr.r[i] = fr_bytes.back(); - } - - for (unsigned int i = 32; i < 64; i++) { - auto witness_index = signature[i]; - - std::vector fr_bytes(sizeof(fr)); - - fr value = builder.get_variable(witness_index); - - fr::serialize_to_buffer(value, &fr_bytes[0]); - - signature_cr.s[i - 32] = fr_bytes.back(); - } - - signature_cr.v = 27; - - return signature_cr; -} - template secp256k1_ct::g1_ct ecdsa_convert_inputs(Builder* ctx, const secp256k1::g1::affine_element& input) { @@ -63,9 +25,9 @@ secp256k1_ct::g1_ct ecdsa_convert_inputs(Builder* ctx, const secp256k1::g1::affi // vector of bytes here, assumes that the witness indices point to a field element which can be represented // with just a byte. // notice that this function truncates each field_element to a byte -template -bb::stdlib::byte_array ecdsa_vector_of_bytes_to_byte_array(Builder& builder, - std::vector vector_of_bytes) +template +bb::stdlib::byte_array ecdsa_array_of_bytes_to_byte_array(Builder& builder, + std::array vector_of_bytes) { using byte_array_ct = bb::stdlib::byte_array; using field_ct = bb::stdlib::field_t; @@ -106,9 +68,9 @@ void create_ecdsa_k1_verify_constraints(Builder& builder, auto new_sig = ecdsa_convert_signature(builder, input.signature); - byte_array_ct message = ecdsa_vector_of_bytes_to_byte_array(builder, input.hashed_message); - auto pub_key_x_byte_arr = ecdsa_vector_of_bytes_to_byte_array(builder, input.pub_x_indices); - auto pub_key_y_byte_arr = ecdsa_vector_of_bytes_to_byte_array(builder, input.pub_y_indices); + byte_array_ct message = ecdsa_array_of_bytes_to_byte_array(builder, input.hashed_message); + auto pub_key_x_byte_arr = ecdsa_array_of_bytes_to_byte_array(builder, input.pub_x_indices); + auto pub_key_y_byte_arr = ecdsa_array_of_bytes_to_byte_array(builder, input.pub_y_indices); auto pub_key_x_fq = typename secp256k1_ct::fq_ct(pub_key_x_byte_arr); auto pub_key_y_fq = typename secp256k1_ct::fq_ct(pub_key_y_byte_arr); @@ -153,11 +115,10 @@ void create_ecdsa_k1_verify_constraints(Builder& builder, template void dummy_ecdsa_constraint(Builder& builder, EcdsaSecp256k1Constraint const& input) { - std::vector pub_x_indices_; - std::vector pub_y_indices_; - std::vector signature_; - std::vector message_indices_; - signature_.resize(64); + std::array pub_x_indices_; + std::array pub_y_indices_; + std::array signature_; + std::array message_indices_; // Create a valid signature with a valid public key crypto::ecdsa_key_pair account; @@ -179,9 +140,9 @@ template void dummy_ecdsa_constraint(Builder& builder, EcdsaS uint32_t y_wit = builder.add_variable(pub_y_value.slice(248 - i * 8, 256 - i * 8)); uint32_t r_wit = builder.add_variable(signature.r[i]); uint32_t s_wit = builder.add_variable(signature.s[i]); - message_indices_.emplace_back(m_wit); - pub_x_indices_.emplace_back(x_wit); - pub_y_indices_.emplace_back(y_wit); + message_indices_[i] = m_wit; + pub_x_indices_[i] = x_wit; + pub_y_indices_[i] = y_wit; signature_[i] = r_wit; signature_[i + 32] = s_wit; } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp index 7dd69f6af90..d5eb6e2df85 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256k1.hpp @@ -8,19 +8,19 @@ namespace acir_format { struct EcdsaSecp256k1Constraint { // This is the byte representation of the hashed message. - std::vector hashed_message; + std::array hashed_message; // This is the computed signature // - std::vector signature; + std::array signature; // This is the supposed public key which signed the // message, giving rise to the signature. // Since Fr does not have enough bits to represent // the prime field in secp256k1, a byte array is used. // Can also use low and hi where lo=128 bits - std::vector pub_x_indices; - std::vector pub_y_indices; + std::array pub_x_indices; + std::array pub_y_indices; // This is the result of verifying the signature uint32_t result; @@ -37,11 +37,51 @@ void create_ecdsa_k1_verify_constraints(Builder& builder, template void dummy_ecdsa_constraint(Builder& builder, EcdsaSecp256k1Constraint const& input); -template -crypto::ecdsa_signature ecdsa_convert_signature(Builder& builder, std::vector signature); witness_ct ecdsa_index_to_witness(Builder& builder, uint32_t index); +template +bb::stdlib::byte_array ecdsa_array_of_bytes_to_byte_array(Builder& builder, + std::array vector_of_bytes); + +// We have the implementation of this template in the header as this method is used +// by other ecdsa constraints over different curves (e.g. secp256r1). +// gcc needs to be able to see the implementation order to generate code for +// all Builder specializations (e.g. bb::Goblin::Builder vs. bb::UltraCircuitBuilder) template -bb::stdlib::byte_array ecdsa_vector_of_bytes_to_byte_array(Builder& builder, - std::vector vector_of_bytes); +crypto::ecdsa_signature ecdsa_convert_signature(Builder& builder, std::array signature) +{ + + crypto::ecdsa_signature signature_cr; + + // Get the witness assignment for each witness index + // Write the witness assignment to the byte_array + + for (unsigned int i = 0; i < 32; i++) { + auto witness_index = signature[i]; + + std::vector fr_bytes(sizeof(fr)); + + fr value = builder.get_variable(witness_index); + + fr::serialize_to_buffer(value, &fr_bytes[0]); + + signature_cr.r[i] = fr_bytes.back(); + } + + for (unsigned int i = 32; i < 64; i++) { + auto witness_index = signature[i]; + + std::vector fr_bytes(sizeof(fr)); + + fr value = builder.get_variable(witness_index); + + fr::serialize_to_buffer(value, &fr_bytes[0]); + + signature_cr.s[i - 32] = fr_bytes.back(); + } + + signature_cr.v = 27; + + return signature_cr; +} } // namespace acir_format 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 1986460b53c..3e686b4f11c 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 @@ -37,35 +37,35 @@ size_t generate_ecdsa_constraint(EcdsaSecp256k1Constraint& ecdsa_constraint, Wit uint256_t pub_x_value = account.public_key.x; uint256_t pub_y_value = account.public_key.y; - std::vector message_in; - std::vector pub_x_indices_in; - std::vector pub_y_indices_in; - std::vector signature_in; + std::array message_in; + std::array pub_x_indices_in; + std::array pub_y_indices_in; + std::array signature_in; size_t offset = 0; for (size_t i = 0; i < hashed_message.size(); ++i) { - message_in.emplace_back(i + offset); + message_in[i] = static_cast(i + offset); const auto byte = static_cast(hashed_message[i]); witness_values.emplace_back(byte); } offset += message_in.size(); for (size_t i = 0; i < 32; ++i) { - pub_x_indices_in.emplace_back(i + offset); + pub_x_indices_in[i] = static_cast(i + offset); witness_values.emplace_back(pub_x_value.slice(248 - i * 8, 256 - i * 8)); } offset += pub_x_indices_in.size(); for (size_t i = 0; i < 32; ++i) { - pub_y_indices_in.emplace_back(i + offset); + pub_y_indices_in[i] = static_cast(i + offset); witness_values.emplace_back(pub_y_value.slice(248 - i * 8, 256 - i * 8)); } offset += pub_y_indices_in.size(); for (size_t i = 0; i < 32; ++i) { - signature_in.emplace_back(i + offset); + signature_in[i] = static_cast(i + offset); witness_values.emplace_back(signature.r[i]); } offset += signature.r.size(); for (size_t i = 0; i < 32; ++i) { - signature_in.emplace_back(i + offset); + signature_in[i + 32] = static_cast(i + offset); witness_values.emplace_back(signature.s[i]); } offset += signature.s.size(); diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp index 7ac18687808..9554c269d5f 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.cpp @@ -33,6 +33,7 @@ void create_ecdsa_r1_verify_constraints(Builder& builder, using secp256r1_ct = bb::stdlib::secp256r1; using bool_ct = bb::stdlib::bool_t; using field_ct = bb::stdlib::field_t; + using byte_array_ct = bb::stdlib::byte_array; if (has_valid_witness_assignments == false) { dummy_ecdsa_constraint(builder, input); @@ -40,9 +41,9 @@ void create_ecdsa_r1_verify_constraints(Builder& builder, auto new_sig = ecdsa_convert_signature(builder, input.signature); - auto message = ecdsa_vector_of_bytes_to_byte_array(builder, input.hashed_message); - auto pub_key_x_byte_arr = ecdsa_vector_of_bytes_to_byte_array(builder, input.pub_x_indices); - auto pub_key_y_byte_arr = ecdsa_vector_of_bytes_to_byte_array(builder, input.pub_y_indices); + byte_array_ct message = ecdsa_array_of_bytes_to_byte_array(builder, input.hashed_message); + auto pub_key_x_byte_arr = ecdsa_array_of_bytes_to_byte_array(builder, input.pub_x_indices); + auto pub_key_y_byte_arr = ecdsa_array_of_bytes_to_byte_array(builder, input.pub_y_indices); auto pub_key_x_fq = typename secp256r1_ct::fq_ct(pub_key_x_byte_arr); auto pub_key_y_fq = typename secp256r1_ct::fq_ct(pub_key_y_byte_arr); @@ -87,11 +88,10 @@ void create_ecdsa_r1_verify_constraints(Builder& builder, template void dummy_ecdsa_constraint(Builder& builder, EcdsaSecp256r1Constraint const& input) { - std::vector pub_x_indices_; - std::vector pub_y_indices_; - std::vector signature_; - std::vector message_indices_; - signature_.resize(64); + std::array pub_x_indices_; + std::array pub_y_indices_; + std::array signature_; + std::array message_indices_; // Create a valid signature with a valid public key std::string message_string = "Instructions unclear, ask again later."; @@ -121,9 +121,9 @@ template void dummy_ecdsa_constraint(Builder& builder, EcdsaS uint32_t y_wit = builder.add_variable(pub_y_value.slice(248 - i * 8, 256 - i * 8)); uint32_t r_wit = builder.add_variable(signature.r[i]); uint32_t s_wit = builder.add_variable(signature.s[i]); - message_indices_.emplace_back(m_wit); - pub_x_indices_.emplace_back(x_wit); - pub_y_indices_.emplace_back(y_wit); + message_indices_[i] = m_wit; + pub_x_indices_[i] = x_wit; + pub_y_indices_[i] = y_wit; signature_[i] = r_wit; signature_[i + 32] = s_wit; } diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.hpp index 1f5972ba609..701a0e23c41 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/ecdsa_secp256r1.hpp @@ -6,22 +6,22 @@ namespace acir_format { struct EcdsaSecp256r1Constraint { // This is the byte representation of the hashed message. - std::vector hashed_message; + std::array hashed_message; // This is the supposed public key which signed the // message, giving rise to the signature. // Since Fr does not have enough bits to represent // the prime field in secp256r1, a byte array is used. // Can also use low and hi where lo=128 bits - std::vector pub_x_indices; - std::vector pub_y_indices; + std::array pub_x_indices; + std::array pub_y_indices; // This is the result of verifying the signature uint32_t result; // This is the computed signature // - std::vector signature; + std::array signature; friend bool operator==(EcdsaSecp256r1Constraint const& lhs, EcdsaSecp256r1Constraint const& rhs) = default; }; 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 462172d3c4e..885bbe44f87 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 @@ -22,35 +22,35 @@ size_t generate_r1_constraints(EcdsaSecp256r1Constraint& ecdsa_r1_constraint, ecdsa_signature signature) { - std::vector message_in; - std::vector pub_x_indices_in; - std::vector pub_y_indices_in; - std::vector signature_in; + std::array message_in; + std::array pub_x_indices_in; + std::array pub_y_indices_in; + std::array signature_in; size_t offset = 0; for (size_t i = 0; i < hashed_message.size(); ++i) { - message_in.emplace_back(i + offset); + message_in[i] = static_cast(i + offset); const auto byte = static_cast(hashed_message[i]); witness_values.emplace_back(byte); } offset += message_in.size(); for (size_t i = 0; i < 32; ++i) { - pub_x_indices_in.emplace_back(i + offset); + pub_x_indices_in[i] = static_cast(i + offset); witness_values.emplace_back(pub_x_value.slice(248 - i * 8, 256 - i * 8)); } offset += pub_x_indices_in.size(); for (size_t i = 0; i < 32; ++i) { - pub_y_indices_in.emplace_back(i + offset); + pub_y_indices_in[i] = static_cast(i + offset); witness_values.emplace_back(pub_y_value.slice(248 - i * 8, 256 - i * 8)); } offset += pub_y_indices_in.size(); for (size_t i = 0; i < 32; ++i) { - signature_in.emplace_back(i + offset); + signature_in[i] = static_cast(i + offset); witness_values.emplace_back(signature.r[i]); } offset += signature.r.size(); for (size_t i = 0; i < 32; ++i) { - signature_in.emplace_back(i + offset); + signature_in[i + 32] = static_cast(i + offset); witness_values.emplace_back(signature.s[i]); } offset += signature.s.size(); 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 6ce3ccdc5f2..14139cba419 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/keccak_constraint.hpp @@ -16,8 +16,8 @@ struct HashInput { }; struct Keccakf1600 { - std::vector state; - std::vector result; + std::array state; + std::array result; // For serialization, update with any new fields MSGPACK_FIELDS(state, result); @@ -26,7 +26,7 @@ struct Keccakf1600 { struct KeccakConstraint { std::vector inputs; - std::vector result; + std::array result; uint32_t var_message_size; // For serialization, update with any new fields diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/schnorr_verify.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/schnorr_verify.cpp index b4d7f4737d5..bcb6e026490 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/schnorr_verify.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/schnorr_verify.cpp @@ -7,7 +7,7 @@ namespace acir_format { using namespace bb::stdlib; template -crypto::schnorr_signature convert_signature(Builder& builder, std::vector signature) +crypto::schnorr_signature convert_signature(Builder& builder, std::array signature) { crypto::schnorr_signature signature_cr; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/schnorr_verify.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/schnorr_verify.hpp index a22c2abb567..a7dbc2b0344 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/schnorr_verify.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/schnorr_verify.hpp @@ -20,7 +20,7 @@ struct SchnorrConstraint { // This is the computed signature // - std::vector signature; + std::array signature; friend bool operator==(SchnorrConstraint const& lhs, SchnorrConstraint const& rhs) = default; }; 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 1711c1ed8f7..5fd06543467 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -54,7 +54,7 @@ struct BlackBoxFuncCall { struct SHA256 { std::vector inputs; - std::vector outputs; + std::array outputs; friend bool operator==(const SHA256&, const SHA256&); std::vector bincodeSerialize() const; @@ -63,7 +63,7 @@ struct BlackBoxFuncCall { struct Blake2s { std::vector inputs; - std::vector outputs; + std::array outputs; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -72,7 +72,7 @@ struct BlackBoxFuncCall { struct Blake3 { std::vector inputs; - std::vector outputs; + std::array outputs; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; @@ -82,7 +82,7 @@ struct BlackBoxFuncCall { struct SchnorrVerify { Program::FunctionInput public_key_x; Program::FunctionInput public_key_y; - std::vector signature; + std::array signature; std::vector message; Program::Witness output; @@ -112,10 +112,10 @@ struct BlackBoxFuncCall { }; struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; + std::array public_key_x; + std::array public_key_y; + std::array signature; + std::array hashed_message; Program::Witness output; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); @@ -124,10 +124,10 @@ struct BlackBoxFuncCall { }; struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; + std::array public_key_x; + std::array public_key_y; + std::array signature; + std::array hashed_message; Program::Witness output; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); @@ -160,7 +160,7 @@ struct BlackBoxFuncCall { struct Keccak256 { std::vector inputs; Program::FunctionInput var_message_size; - std::vector outputs; + std::array outputs; friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; @@ -168,8 +168,8 @@ struct BlackBoxFuncCall { }; struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + std::array inputs; + std::array outputs; friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; @@ -257,9 +257,9 @@ struct BlackBoxFuncCall { }; struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; + std::array inputs; + std::array hash_values; + std::array outputs; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.hpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.hpp index 0c36058393a..560f8e915d2 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.hpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.hpp @@ -17,7 +17,7 @@ struct Sha256Input { struct Sha256Constraint { std::vector inputs; - std::vector result; + std::array result; friend bool operator==(Sha256Constraint const& lhs, Sha256Constraint const& rhs) = default; // for serialization, update with any new fields @@ -25,9 +25,9 @@ struct Sha256Constraint { }; struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector result; + std::array inputs; + std::array hash_values; + std::array result; friend bool operator==(Sha256Compression const& lhs, Sha256Compression const& rhs) = default; // for serialization, update with any new fields diff --git a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp index 8e770aa4f40..14283314ddb 100644 --- a/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp +++ b/barretenberg/cpp/src/barretenberg/dsl/acir_format/sha256_constraint.test.cpp @@ -17,13 +17,13 @@ class Sha256Tests : public ::testing::Test { TEST_F(Sha256Tests, TestSha256Compression) { - std::vector inputs; - for (uint32_t i = 1; i < 17; ++i) { - inputs.push_back({ .witness = i, .num_bits = 32 }); + std::array inputs; + for (size_t i = 0; i < 16; ++i) { + inputs[i] = { .witness = static_cast(i + 1), .num_bits = 32 }; } - std::vector hash_values; - for (uint32_t i = 17; i < 25; ++i) { - hash_values.push_back({ .witness = i, .num_bits = 32 }); + std::array hash_values; + for (size_t i = 0; i < 8; ++i) { + hash_values[i] = { .witness = static_cast(i + 17), .num_bits = 32 }; } Sha256Compression sha256_compression{ .inputs = inputs, diff --git a/noir/noir-repo/Cargo.lock b/noir/noir-repo/Cargo.lock index e62f966b8fd..ee7d1d7d024 100644 --- a/noir/noir-repo/Cargo.lock +++ b/noir/noir-repo/Cargo.lock @@ -13,6 +13,7 @@ dependencies = [ "flate2", "fxhash", "serde", + "serde-big-array", "serde-generate", "serde-reflection", "serde_json", @@ -4297,6 +4298,15 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + [[package]] name = "serde-generate" version = "0.25.1" diff --git a/noir/noir-repo/acvm-repo/acir/Cargo.toml b/noir/noir-repo/acvm-repo/acir/Cargo.toml index 99095ad3f61..4fae9ea20ff 100644 --- a/noir/noir-repo/acvm-repo/acir/Cargo.toml +++ b/noir/noir-repo/acvm-repo/acir/Cargo.toml @@ -20,6 +20,7 @@ thiserror.workspace = true flate2.workspace = true bincode.workspace = true base64.workspace = true +serde-big-array = "0.5.1" [dev-dependencies] serde_json = "1.0" diff --git a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp index 9e1011b2109..6c7bd347e5d 100644 --- a/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp +++ b/noir/noir-repo/acvm-repo/acir/codegen/acir.cpp @@ -54,7 +54,7 @@ namespace Program { struct SHA256 { std::vector inputs; - std::vector outputs; + std::array outputs; friend bool operator==(const SHA256&, const SHA256&); std::vector bincodeSerialize() const; @@ -63,7 +63,7 @@ namespace Program { struct Blake2s { std::vector inputs; - std::vector outputs; + std::array outputs; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -72,7 +72,7 @@ namespace Program { struct Blake3 { std::vector inputs; - std::vector outputs; + std::array outputs; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; @@ -82,7 +82,7 @@ namespace Program { struct SchnorrVerify { Program::FunctionInput public_key_x; Program::FunctionInput public_key_y; - std::vector signature; + std::array signature; std::vector message; Program::Witness output; @@ -112,10 +112,10 @@ namespace Program { }; struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; + std::array public_key_x; + std::array public_key_y; + std::array signature; + std::array hashed_message; Program::Witness output; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); @@ -124,10 +124,10 @@ namespace Program { }; struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; + std::array public_key_x; + std::array public_key_y; + std::array signature; + std::array hashed_message; Program::Witness output; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); @@ -160,7 +160,7 @@ namespace Program { struct Keccak256 { std::vector inputs; Program::FunctionInput var_message_size; - std::vector outputs; + std::array outputs; friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; @@ -168,8 +168,8 @@ namespace Program { }; struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + std::array inputs; + std::array outputs; friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; @@ -257,9 +257,9 @@ namespace Program { }; struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; + std::array inputs; + std::array hash_values; + std::array outputs; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; diff --git a/noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs index 27d8a392c81..0c79cfdb815 100644 --- a/noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs +++ b/noir/noir-repo/acvm-repo/acir/src/circuit/mod.rs @@ -317,61 +317,31 @@ mod tests { }) } 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), - ], + let inputs: Box<[FunctionInput; 25]> = Box::new(std::array::from_fn(|i| FunctionInput { + witness: Witness(i as u32 + 1), + num_bits: 8, + })); + let outputs: Box<[Witness; 25]> = Box::new(std::array::from_fn(|i| Witness(i as u32 + 26))); + + Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Keccakf1600 { inputs, outputs }) + } + fn schnorr_verify_opcode() -> Opcode { + let public_key_x = + FunctionInput { witness: Witness(1), num_bits: FieldElement::max_num_bits() }; + let public_key_y = + FunctionInput { witness: Witness(2), num_bits: FieldElement::max_num_bits() }; + let signature: Box<[FunctionInput; 64]> = Box::new(std::array::from_fn(|i| { + FunctionInput { witness: Witness(i as u32 + 3), num_bits: 8 } + })); + let message: Vec = vec![FunctionInput { witness: Witness(67), num_bits: 8 }]; + let output = Witness(68); + + Opcode::BlackBoxFuncCall(BlackBoxFuncCall::SchnorrVerify { + public_key_x, + public_key_y, + signature, + message, + output, }) } @@ -380,7 +350,7 @@ mod tests { let circuit = Circuit { current_witness_index: 5, expression_width: ExpressionWidth::Unbounded, - opcodes: vec![and_opcode(), range_opcode()], + opcodes: vec![and_opcode(), range_opcode(), schnorr_verify_opcode()], private_parameters: BTreeSet::new(), public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(12)])), return_values: PublicInputs(BTreeSet::from_iter(vec![Witness(4), Witness(12)])), @@ -413,6 +383,7 @@ mod tests { range_opcode(), and_opcode(), keccakf1600_opcode(), + schnorr_verify_opcode(), ], private_parameters: BTreeSet::new(), public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2)])), diff --git a/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index d9089578739..405cd0cef00 100644 --- a/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/noir/noir-repo/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -1,6 +1,6 @@ use crate::native_types::Witness; use crate::BlackBoxFunc; -use serde::{Deserialize, Serialize}; +use serde::{Deserialize, Deserializer, Serialize, Serializer}; // Note: Some functions will not use all of the witness // So we need to supply how many bits of the witness is needed @@ -27,20 +27,24 @@ pub enum BlackBoxFuncCall { }, SHA256 { inputs: Vec, - outputs: Vec, + outputs: Box<[Witness; 32]>, }, Blake2s { inputs: Vec, - outputs: Vec, + outputs: Box<[Witness; 32]>, }, Blake3 { inputs: Vec, - outputs: Vec, + outputs: Box<[Witness; 32]>, }, SchnorrVerify { public_key_x: FunctionInput, public_key_y: FunctionInput, - signature: Vec, + #[serde( + serialize_with = "serialize_big_array", + deserialize_with = "deserialize_big_array_into_box" + )] + signature: Box<[FunctionInput; 64]>, message: Vec, output: Witness, }, @@ -55,17 +59,25 @@ pub enum BlackBoxFuncCall { output: Witness, }, EcdsaSecp256k1 { - public_key_x: Vec, - public_key_y: Vec, - signature: Vec, - hashed_message: Vec, + public_key_x: Box<[FunctionInput; 32]>, + public_key_y: Box<[FunctionInput; 32]>, + #[serde( + serialize_with = "serialize_big_array", + deserialize_with = "deserialize_big_array_into_box" + )] + signature: Box<[FunctionInput; 64]>, + hashed_message: Box<[FunctionInput; 32]>, output: Witness, }, EcdsaSecp256r1 { - public_key_x: Vec, - public_key_y: Vec, - signature: Vec, - hashed_message: Vec, + public_key_x: Box<[FunctionInput; 32]>, + public_key_y: Box<[FunctionInput; 32]>, + #[serde( + serialize_with = "serialize_big_array", + deserialize_with = "deserialize_big_array_into_box" + )] + signature: Box<[FunctionInput; 64]>, + hashed_message: Box<[FunctionInput; 32]>, output: Witness, }, FixedBaseScalarMul { @@ -87,11 +99,11 @@ pub enum BlackBoxFuncCall { /// is more than the number of bytes in the input, /// then an error is returned. var_message_size: FunctionInput, - outputs: Vec, + outputs: Box<[Witness; 32]>, }, Keccakf1600 { - inputs: Vec, - outputs: Vec, + inputs: Box<[FunctionInput; 25]>, + outputs: Box<[Witness; 25]>, }, RecursiveAggregation { verification_key: Vec, @@ -154,11 +166,11 @@ pub enum BlackBoxFuncCall { /// * `outputs` - result of the input compressed into 256 bits Sha256Compression { /// 512 bits of the input message, represented by 16 u32s - inputs: Vec, + inputs: Box<[FunctionInput; 16]>, /// Vector of 8 u32s used to compress the input - hash_values: Vec, + hash_values: Box<[FunctionInput; 8]>, /// Output of the compression, represented by 8 u32s - outputs: Vec, + outputs: Box<[Witness; 8]>, }, } @@ -201,13 +213,15 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::SHA256 { inputs, .. } | BlackBoxFuncCall::Blake2s { inputs, .. } | BlackBoxFuncCall::Blake3 { inputs, .. } - | BlackBoxFuncCall::Keccakf1600 { inputs, .. } | BlackBoxFuncCall::PedersenCommitment { inputs, .. } | BlackBoxFuncCall::PedersenHash { inputs, .. } | BlackBoxFuncCall::BigIntFromLeBytes { inputs, .. } | BlackBoxFuncCall::Poseidon2Permutation { inputs, .. } => inputs.to_vec(), + + BlackBoxFuncCall::Keccakf1600 { inputs, .. } => inputs.to_vec(), + BlackBoxFuncCall::Sha256Compression { inputs, hash_values, .. } => { - inputs.iter().chain(hash_values).copied().collect() + inputs.iter().chain(hash_values.as_ref()).copied().collect() } BlackBoxFuncCall::AND { lhs, rhs, .. } | BlackBoxFuncCall::XOR { lhs, rhs, .. } => { vec![*lhs, *rhs] @@ -300,10 +314,14 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::SHA256 { outputs, .. } | BlackBoxFuncCall::Blake2s { outputs, .. } | BlackBoxFuncCall::Blake3 { outputs, .. } - | BlackBoxFuncCall::Keccakf1600 { outputs, .. } - | BlackBoxFuncCall::Keccak256 { outputs, .. } - | BlackBoxFuncCall::Poseidon2Permutation { outputs, .. } - | BlackBoxFuncCall::Sha256Compression { outputs, .. } => outputs.to_vec(), + | BlackBoxFuncCall::Keccak256 { outputs, .. } => outputs.to_vec(), + + BlackBoxFuncCall::Keccakf1600 { outputs, .. } => outputs.to_vec(), + + BlackBoxFuncCall::Sha256Compression { outputs, .. } => outputs.to_vec(), + + BlackBoxFuncCall::Poseidon2Permutation { outputs, .. } => outputs.to_vec(), + BlackBoxFuncCall::AND { output, .. } | BlackBoxFuncCall::XOR { output, .. } | BlackBoxFuncCall::SchnorrVerify { output, .. } @@ -422,3 +440,78 @@ impl std::fmt::Debug for BlackBoxFuncCall { std::fmt::Display::fmt(self, f) } } + +fn serialize_big_array(big_array: &[FunctionInput; 64], s: S) -> Result +where + S: Serializer, +{ + use serde_big_array::BigArray; + + (*big_array).serialize(s) +} + +fn deserialize_big_array_into_box<'de, D>( + deserializer: D, +) -> Result, D::Error> +where + D: Deserializer<'de>, +{ + use serde_big_array::BigArray; + + let big_array: [FunctionInput; 64] = BigArray::deserialize(deserializer)?; + Ok(Box::new(big_array)) +} + +#[cfg(test)] +mod tests { + + use crate::{circuit::Opcode, native_types::Witness}; + use acir_field::FieldElement; + + use super::{BlackBoxFuncCall, FunctionInput}; + + fn keccakf1600_opcode() -> Opcode { + let inputs: Box<[FunctionInput; 25]> = Box::new(std::array::from_fn(|i| FunctionInput { + witness: Witness(i as u32 + 1), + num_bits: 8, + })); + let outputs: Box<[Witness; 25]> = Box::new(std::array::from_fn(|i| Witness(i as u32 + 26))); + + Opcode::BlackBoxFuncCall(BlackBoxFuncCall::Keccakf1600 { inputs, outputs }) + } + fn schnorr_verify_opcode() -> Opcode { + let public_key_x = + FunctionInput { witness: Witness(1), num_bits: FieldElement::max_num_bits() }; + let public_key_y = + FunctionInput { witness: Witness(2), num_bits: FieldElement::max_num_bits() }; + let signature: Box<[FunctionInput; 64]> = Box::new(std::array::from_fn(|i| { + FunctionInput { witness: Witness(i as u32 + 3), num_bits: 8 } + })); + let message: Vec = vec![FunctionInput { witness: Witness(67), num_bits: 8 }]; + let output = Witness(68); + + Opcode::BlackBoxFuncCall(BlackBoxFuncCall::SchnorrVerify { + public_key_x, + public_key_y, + signature, + message, + output, + }) + } + + #[test] + fn keccakf1600_serialization_roundtrip() { + let opcode = keccakf1600_opcode(); + let buf = bincode::serialize(&opcode).unwrap(); + let recovered_opcode = bincode::deserialize(&buf).unwrap(); + assert_eq!(opcode, recovered_opcode); + } + + #[test] + fn schnorr_serialization_roundtrip() { + let opcode = schnorr_verify_opcode(); + let buf = bincode::serialize(&opcode).unwrap(); + let recovered_opcode = bincode::deserialize(&buf).unwrap(); + assert_eq!(opcode, recovered_opcode); + } +} diff --git a/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs index 3f392be9fe9..fb924a7437d 100644 --- a/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs +++ b/noir/noir-repo/acvm-repo/acir/tests/test_program_serialization.rs @@ -119,8 +119,11 @@ fn schnorr_verify_circuit() { FunctionInput { witness: Witness(1), num_bits: FieldElement::max_num_bits() }; let public_key_y = FunctionInput { witness: Witness(2), num_bits: FieldElement::max_num_bits() }; - let signature = - (3..(3 + 64)).map(|i| FunctionInput { witness: Witness(i), num_bits: 8 }).collect(); + let signature: [FunctionInput; 64] = (3..(3 + 64)) + .map(|i| FunctionInput { witness: Witness(i), num_bits: 8 }) + .collect::>() + .try_into() + .unwrap(); let message = ((3 + 64)..(3 + 64 + 10)) .map(|i| FunctionInput { witness: Witness(i), num_bits: 8 }) .collect(); @@ -130,7 +133,7 @@ fn schnorr_verify_circuit() { let schnorr = Opcode::BlackBoxFuncCall(BlackBoxFuncCall::SchnorrVerify { public_key_x, public_key_y, - signature, + signature: Box::new(signature), message, output, }); @@ -147,22 +150,22 @@ fn schnorr_verify_circuit() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 210, 135, 74, 66, 1, 24, 134, 97, 219, 123, 239, - 189, 247, 222, 187, 108, 153, 153, 221, 69, 247, 127, 9, 145, 31, 62, 130, 29, 56, 60, 133, - 32, 242, 127, 111, 75, 161, 254, 252, 212, 222, 22, 127, 199, 78, 254, 214, 222, 86, 22, - 125, 222, 86, 123, 187, 107, 111, 59, 59, 216, 201, 46, 54, 222, 30, 246, 178, 143, 253, - 28, 224, 32, 135, 56, 204, 17, 142, 114, 140, 227, 156, 224, 36, 167, 56, 205, 25, 206, - 114, 142, 243, 92, 224, 34, 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184, - 205, 29, 238, 114, 143, 251, 60, 224, 33, 143, 120, 204, 19, 158, 242, 140, 231, 188, 224, - 37, 175, 120, 205, 27, 222, 242, 142, 247, 124, 224, 35, 159, 88, 228, 51, 95, 154, 118, - 204, 243, 234, 255, 55, 190, 179, 196, 15, 150, 249, 201, 10, 191, 88, 229, 183, 239, 173, - 50, 253, 165, 189, 244, 150, 214, 210, 89, 26, 107, 244, 213, 227, 183, 164, 167, 180, 148, - 142, 210, 80, 250, 73, 59, 233, 38, 205, 164, 151, 180, 146, 78, 210, 72, 250, 72, 27, 233, - 34, 77, 164, 135, 180, 144, 14, 210, 64, 246, 95, 46, 212, 119, 207, 230, 217, 59, 91, 103, - 231, 108, 156, 125, 183, 237, 186, 107, 207, 125, 59, 30, 218, 239, 216, 110, 167, 246, 58, - 183, 211, 165, 125, 174, 237, 114, 107, 143, 123, 59, 60, 186, 127, 209, 221, 95, 220, 249, - 205, 125, 75, 238, 90, 118, 207, 138, 59, 54, 110, 214, 184, 91, 161, 233, 158, 255, 158, - 63, 46, 139, 64, 203, 241, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 210, 85, 78, 67, 81, 24, 133, 209, 226, 238, 238, + 238, 238, 238, 165, 148, 82, 102, 193, 252, 135, 64, 232, 78, 87, 147, 114, 147, 147, 5, + 47, 132, 252, 251, 107, 41, 212, 191, 159, 218, 107, 241, 115, 236, 228, 111, 237, 181, + 178, 173, 246, 186, 107, 175, 157, 29, 236, 100, 23, 27, 175, 135, 189, 236, 99, 63, 7, 56, + 200, 33, 14, 115, 132, 163, 28, 227, 56, 39, 56, 201, 41, 78, 115, 134, 179, 156, 227, 60, + 23, 184, 200, 37, 46, 115, 133, 171, 92, 227, 58, 55, 184, 201, 45, 110, 115, 135, 187, + 220, 227, 62, 15, 120, 200, 35, 30, 243, 132, 167, 60, 227, 57, 47, 120, 201, 43, 94, 243, + 134, 183, 188, 227, 61, 31, 248, 200, 39, 62, 243, 133, 175, 77, 59, 230, 123, 243, 123, + 145, 239, 44, 241, 131, 101, 126, 178, 194, 47, 86, 249, 237, 239, 86, 153, 238, 210, 92, + 122, 75, 107, 233, 44, 141, 53, 250, 234, 241, 191, 164, 167, 180, 148, 142, 210, 80, 250, + 73, 59, 233, 38, 205, 164, 151, 180, 146, 78, 210, 72, 250, 72, 27, 233, 34, 77, 164, 135, + 180, 144, 14, 210, 64, 246, 95, 46, 212, 119, 207, 230, 217, 59, 91, 103, 231, 108, 156, + 125, 183, 237, 186, 107, 207, 125, 59, 30, 218, 239, 216, 110, 167, 246, 58, 183, 211, 165, + 125, 174, 237, 114, 107, 143, 123, 59, 60, 186, 255, 179, 187, 191, 186, 115, 209, 125, 75, + 238, 90, 118, 207, 138, 59, 54, 110, 214, 184, 91, 161, 233, 158, 255, 190, 63, 165, 188, + 93, 151, 233, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/hash.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/hash.rs index 24c835a636a..caa09ea8973 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/hash.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/hash.rs @@ -1,7 +1,7 @@ use acir::{ circuit::opcodes::FunctionInput, native_types::{Witness, WitnessMap}, - BlackBoxFunc, FieldElement, + FieldElement, }; use acvm_blackbox_solver::{sha256compression, BlackBoxFunctionSolver, BlackBoxResolutionError}; @@ -14,22 +14,13 @@ pub(super) fn solve_generic_256_hash_opcode( initial_witness: &mut WitnessMap, inputs: &[FunctionInput], var_message_size: Option<&FunctionInput>, - outputs: &[Witness], + outputs: &[Witness; 32], hash_function: fn(data: &[u8]) -> Result<[u8; 32], BlackBoxResolutionError>, - black_box_func: BlackBoxFunc, ) -> Result<(), OpcodeResolutionError> { let message_input = get_hash_input(initial_witness, inputs, var_message_size)?; let digest: [u8; 32] = hash_function(&message_input)?; - let outputs: [Witness; 32] = outputs.try_into().map_err(|_| { - OpcodeResolutionError::BlackBoxFunctionFailed( - black_box_func, - format!("Expected 32 outputs but encountered {}", outputs.len()), - ) - })?; - write_digest_to_outputs(initial_witness, outputs, digest)?; - - Ok(()) + write_digest_to_outputs(initial_witness, outputs, digest) } /// Reads the hash function input from a [`WitnessMap`]. @@ -73,7 +64,7 @@ fn get_hash_input( /// Writes a `digest` to the [`WitnessMap`] at witness indices `outputs`. fn write_digest_to_outputs( initial_witness: &mut WitnessMap, - outputs: [Witness; 32], + outputs: &[Witness; 32], digest: [u8; 32], ) -> Result<(), OpcodeResolutionError> { for (output_witness, value) in outputs.iter().zip(digest.into_iter()) { @@ -87,44 +78,29 @@ fn write_digest_to_outputs( Ok(()) } +fn to_u32_array( + initial_witness: &WitnessMap, + inputs: &[FunctionInput; N], +) -> Result<[u32; N], OpcodeResolutionError> { + let mut result = [0; N]; + for (it, input) in result.iter_mut().zip(inputs) { + let witness_value = witness_to_value(initial_witness, input.witness)?; + *it = witness_value.to_u128() as u32; + } + Ok(result) +} + pub(crate) fn solve_sha_256_permutation_opcode( initial_witness: &mut WitnessMap, - inputs: &[FunctionInput], - hash_values: &[FunctionInput], - outputs: &[Witness], - black_box_func: BlackBoxFunc, + inputs: &[FunctionInput; 16], + hash_values: &[FunctionInput; 8], + outputs: &[Witness; 8], ) -> Result<(), OpcodeResolutionError> { - let mut message = [0; 16]; - if inputs.len() != 16 { - return Err(OpcodeResolutionError::BlackBoxFunctionFailed( - black_box_func, - format!("Expected 16 inputs but encountered {}", &message.len()), - )); - } - for (i, input) in inputs.iter().enumerate() { - let value = witness_to_value(initial_witness, input.witness)?; - message[i] = value.to_u128() as u32; - } - - if hash_values.len() != 8 { - return Err(OpcodeResolutionError::BlackBoxFunctionFailed( - black_box_func, - format!("Expected 8 values but encountered {}", hash_values.len()), - )); - } - let mut state = [0; 8]; - for (i, hash) in hash_values.iter().enumerate() { - let value = witness_to_value(initial_witness, hash.witness)?; - state[i] = value.to_u128() as u32; - } + let message = to_u32_array(initial_witness, inputs)?; + let mut state = to_u32_array(initial_witness, hash_values)?; sha256compression(&mut state, &message); - let outputs: [Witness; 8] = outputs.try_into().map_err(|_| { - OpcodeResolutionError::BlackBoxFunctionFailed( - black_box_func, - format!("Expected 8 outputs but encountered {}", outputs.len()), - ) - })?; + for (output_witness, value) in outputs.iter().zip(state.into_iter()) { insert_value(output_witness, FieldElement::from(value as u128), initial_witness)?; } diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs index e7ed402a8eb..26d1a3c8f86 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -71,30 +71,16 @@ pub(crate) fn solve( BlackBoxFuncCall::AND { lhs, rhs, output } => and(initial_witness, lhs, rhs, output), BlackBoxFuncCall::XOR { lhs, rhs, output } => xor(initial_witness, lhs, rhs, output), BlackBoxFuncCall::RANGE { input } => solve_range_opcode(initial_witness, input), - BlackBoxFuncCall::SHA256 { inputs, outputs } => solve_generic_256_hash_opcode( - initial_witness, - inputs, - None, - outputs, - sha256, - bb_func.get_black_box_func(), - ), - BlackBoxFuncCall::Blake2s { inputs, outputs } => solve_generic_256_hash_opcode( - initial_witness, - inputs, - None, - outputs, - 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::SHA256 { inputs, outputs } => { + solve_generic_256_hash_opcode(initial_witness, inputs, None, outputs, sha256) + } + BlackBoxFuncCall::Blake2s { inputs, outputs } => { + solve_generic_256_hash_opcode(initial_witness, inputs, None, outputs, blake2s) + } + BlackBoxFuncCall::Blake3 { inputs, outputs } => { + solve_generic_256_hash_opcode(initial_witness, inputs, None, outputs, blake3) + } + BlackBoxFuncCall::Keccak256 { inputs, var_message_size, outputs } => { solve_generic_256_hash_opcode( initial_witness, @@ -102,18 +88,17 @@ pub(crate) fn solve( Some(var_message_size), outputs, keccak256, - bb_func.get_black_box_func(), ) } BlackBoxFuncCall::Keccakf1600 { inputs, outputs } => { let mut state = [0; 25]; - for (i, input) in inputs.iter().enumerate() { + for (it, input) in state.iter_mut().zip(inputs.as_ref()) { 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(); + *it = lane.unwrap(); } let output_state = keccakf1600(state)?; for (output_witness, value) in outputs.iter().zip(output_state.into_iter()) { @@ -132,7 +117,7 @@ pub(crate) fn solve( initial_witness, *public_key_x, *public_key_y, - signature, + signature.as_ref(), message, *output, ), @@ -153,7 +138,7 @@ pub(crate) fn solve( public_key_x, public_key_y, signature, - message, + message.as_ref(), *output, ), BlackBoxFuncCall::EcdsaSecp256r1 { @@ -167,7 +152,7 @@ pub(crate) fn solve( public_key_x, public_key_y, signature, - message, + message.as_ref(), *output, ), BlackBoxFuncCall::FixedBaseScalarMul { low, high, outputs } => { @@ -199,13 +184,7 @@ pub(crate) fn solve( bigint_solver.bigint_to_bytes(*input, outputs, initial_witness) } BlackBoxFuncCall::Sha256Compression { inputs, hash_values, outputs } => { - solve_sha_256_permutation_opcode( - initial_witness, - inputs, - hash_values, - outputs, - bb_func.get_black_box_func(), - ) + solve_sha_256_permutation_opcode(initial_witness, inputs, hash_values, outputs) } BlackBoxFuncCall::Poseidon2Permutation { inputs, outputs, len } => { solve_poseidon2_permutation_opcode(backend, initial_witness, inputs, outputs, *len) diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs index 8f0df8378ad..b113c801251 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/ecdsa.rs @@ -7,85 +7,42 @@ use acvm_blackbox_solver::{ecdsa_secp256k1_verify, ecdsa_secp256r1_verify}; use crate::{pwg::insert_value, OpcodeResolutionError}; -use super::to_u8_vec; +use super::{to_u8_array, to_u8_vec}; pub(crate) fn secp256k1_prehashed( initial_witness: &mut WitnessMap, - public_key_x_inputs: &[FunctionInput], - public_key_y_inputs: &[FunctionInput], - signature_inputs: &[FunctionInput], + public_key_x_inputs: &[FunctionInput; 32], + public_key_y_inputs: &[FunctionInput; 32], + signature_inputs: &[FunctionInput; 64], hashed_message_inputs: &[FunctionInput], output: Witness, ) -> Result<(), OpcodeResolutionError> { let hashed_message = to_u8_vec(initial_witness, hashed_message_inputs)?; - // These errors should never be emitted in practice as they would imply malformed ACIR generation. - let pub_key_x: [u8; 32] = - to_u8_vec(initial_witness, public_key_x_inputs)?.try_into().map_err(|_| { - OpcodeResolutionError::BlackBoxFunctionFailed( - acir::BlackBoxFunc::EcdsaSecp256k1, - format!("expected pubkey_x size 32 but received {}", public_key_x_inputs.len()), - ) - })?; - - let pub_key_y: [u8; 32] = - to_u8_vec(initial_witness, public_key_y_inputs)?.try_into().map_err(|_| { - OpcodeResolutionError::BlackBoxFunctionFailed( - acir::BlackBoxFunc::EcdsaSecp256k1, - format!("expected pubkey_y size 32 but received {}", public_key_y_inputs.len()), - ) - })?; - - let signature: [u8; 64] = - to_u8_vec(initial_witness, signature_inputs)?.try_into().map_err(|_| { - OpcodeResolutionError::BlackBoxFunctionFailed( - acir::BlackBoxFunc::EcdsaSecp256k1, - format!("expected signature size 64 but received {}", signature_inputs.len()), - ) - })?; + let pub_key_x: [u8; 32] = to_u8_array(initial_witness, public_key_x_inputs)?; + let pub_key_y: [u8; 32] = to_u8_array(initial_witness, public_key_y_inputs)?; + let signature: [u8; 64] = to_u8_array(initial_witness, signature_inputs)?; let is_valid = ecdsa_secp256k1_verify(&hashed_message, &pub_key_x, &pub_key_y, &signature)?; - insert_value(&output, FieldElement::from(is_valid), initial_witness)?; - Ok(()) + insert_value(&output, FieldElement::from(is_valid), initial_witness) } pub(crate) fn secp256r1_prehashed( initial_witness: &mut WitnessMap, - public_key_x_inputs: &[FunctionInput], - public_key_y_inputs: &[FunctionInput], - signature_inputs: &[FunctionInput], + public_key_x_inputs: &[FunctionInput; 32], + public_key_y_inputs: &[FunctionInput; 32], + signature_inputs: &[FunctionInput; 64], hashed_message_inputs: &[FunctionInput], output: Witness, ) -> Result<(), OpcodeResolutionError> { let hashed_message = to_u8_vec(initial_witness, hashed_message_inputs)?; - let pub_key_x: [u8; 32] = - to_u8_vec(initial_witness, public_key_x_inputs)?.try_into().map_err(|_| { - OpcodeResolutionError::BlackBoxFunctionFailed( - acir::BlackBoxFunc::EcdsaSecp256r1, - format!("expected pubkey_x size 32 but received {}", public_key_x_inputs.len()), - ) - })?; - - let pub_key_y: [u8; 32] = - to_u8_vec(initial_witness, public_key_y_inputs)?.try_into().map_err(|_| { - OpcodeResolutionError::BlackBoxFunctionFailed( - acir::BlackBoxFunc::EcdsaSecp256r1, - format!("expected pubkey_y size 32 but received {}", public_key_y_inputs.len()), - ) - })?; - - let signature: [u8; 64] = - to_u8_vec(initial_witness, signature_inputs)?.try_into().map_err(|_| { - OpcodeResolutionError::BlackBoxFunctionFailed( - acir::BlackBoxFunc::EcdsaSecp256r1, - format!("expected signature size 64 but received {}", signature_inputs.len()), - ) - })?; + let pub_key_x: [u8; 32] = to_u8_array(initial_witness, public_key_x_inputs)?; + let pub_key_y: [u8; 32] = to_u8_array(initial_witness, public_key_y_inputs)?; + let signature: [u8; 64] = to_u8_array(initial_witness, signature_inputs)?; let is_valid = ecdsa_secp256r1_verify(&hashed_message, &pub_key_x, &pub_key_y, &signature)?; - insert_value(&output, FieldElement::from(is_valid), initial_witness)?; - Ok(()) + insert_value(&output, FieldElement::from(is_valid), initial_witness) } diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs index 0e28a63ff68..bd223ecd0c9 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/mod.rs @@ -2,6 +2,21 @@ use acir::{circuit::opcodes::FunctionInput, native_types::WitnessMap}; use crate::pwg::{witness_to_value, OpcodeResolutionError}; +fn to_u8_array( + initial_witness: &WitnessMap, + inputs: &[FunctionInput; N], +) -> Result<[u8; N], OpcodeResolutionError> { + let mut result = [0; N]; + for (it, input) in result.iter_mut().zip(inputs) { + let witness_value_bytes = witness_to_value(initial_witness, input.witness)?.to_be_bytes(); + let byte = witness_value_bytes + .last() + .expect("Field element must be represented by non-zero amount of bytes"); + *it = *byte; + } + Ok(result) +} + fn to_u8_vec( initial_witness: &WitnessMap, inputs: &[FunctionInput], diff --git a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs index 7f5381cee91..3d0216fa217 100644 --- a/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs +++ b/noir/noir-repo/acvm-repo/acvm/src/pwg/blackbox/signature/schnorr.rs @@ -1,4 +1,4 @@ -use super::to_u8_vec; +use super::{to_u8_array, to_u8_vec}; use crate::{ pwg::{insert_value, witness_to_value, OpcodeResolutionError}, BlackBoxFunctionSolver, @@ -15,15 +15,14 @@ pub(crate) fn schnorr_verify( initial_witness: &mut WitnessMap, public_key_x: FunctionInput, public_key_y: FunctionInput, - signature: &[FunctionInput], + signature: &[FunctionInput; 64], message: &[FunctionInput], output: Witness, ) -> Result<(), OpcodeResolutionError> { let public_key_x: &FieldElement = witness_to_value(initial_witness, public_key_x.witness)?; let public_key_y: &FieldElement = witness_to_value(initial_witness, public_key_y.witness)?; - let signature = to_u8_vec(initial_witness, signature)?; - + let signature = to_u8_array(initial_witness, signature)?; let message = to_u8_vec(initial_witness, message)?; let valid_signature = diff --git a/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts b/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts index 0aef82bc8e9..a207aa12b2c 100644 --- a/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts +++ b/noir/noir-repo/acvm-repo/acvm_js/test/shared/schnorr_verify.ts @@ -1,17 +1,17 @@ // See `schnorr_verify_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 210, 135, 74, 66, 1, 24, 134, 97, 219, 123, 239, 189, 247, 222, 187, 108, 153, - 153, 221, 69, 247, 127, 9, 145, 31, 62, 130, 29, 56, 60, 133, 32, 242, 127, 111, 75, 161, 254, 252, 212, 222, 22, 127, - 199, 78, 254, 214, 222, 86, 22, 125, 222, 86, 123, 187, 107, 111, 59, 59, 216, 201, 46, 54, 222, 30, 246, 178, 143, - 253, 28, 224, 32, 135, 56, 204, 17, 142, 114, 140, 227, 156, 224, 36, 167, 56, 205, 25, 206, 114, 142, 243, 92, 224, - 34, 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184, 205, 29, 238, 114, 143, 251, 60, 224, 33, 143, 120, - 204, 19, 158, 242, 140, 231, 188, 224, 37, 175, 120, 205, 27, 222, 242, 142, 247, 124, 224, 35, 159, 88, 228, 51, 95, - 154, 118, 204, 243, 234, 255, 55, 190, 179, 196, 15, 150, 249, 201, 10, 191, 88, 229, 183, 239, 173, 50, 253, 165, - 189, 244, 150, 214, 210, 89, 26, 107, 244, 213, 227, 183, 164, 167, 180, 148, 142, 210, 80, 250, 73, 59, 233, 38, 205, - 164, 151, 180, 146, 78, 210, 72, 250, 72, 27, 233, 34, 77, 164, 135, 180, 144, 14, 210, 64, 246, 95, 46, 212, 119, - 207, 230, 217, 59, 91, 103, 231, 108, 156, 125, 183, 237, 186, 107, 207, 125, 59, 30, 218, 239, 216, 110, 167, 246, - 58, 183, 211, 165, 125, 174, 237, 114, 107, 143, 123, 59, 60, 186, 127, 209, 221, 95, 220, 249, 205, 125, 75, 238, 90, - 118, 207, 138, 59, 54, 110, 214, 184, 91, 161, 233, 158, 255, 158, 63, 46, 139, 64, 203, 241, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 85, 210, 85, 78, 67, 81, 24, 133, 209, 226, 238, 238, 238, 238, 238, 165, 148, 82, + 102, 193, 252, 135, 64, 232, 78, 87, 147, 114, 147, 147, 5, 47, 132, 252, 251, 107, 41, 212, 191, 159, 218, 107, 241, + 115, 236, 228, 111, 237, 181, 178, 173, 246, 186, 107, 175, 157, 29, 236, 100, 23, 27, 175, 135, 189, 236, 99, 63, 7, + 56, 200, 33, 14, 115, 132, 163, 28, 227, 56, 39, 56, 201, 41, 78, 115, 134, 179, 156, 227, 60, 23, 184, 200, 37, 46, + 115, 133, 171, 92, 227, 58, 55, 184, 201, 45, 110, 115, 135, 187, 220, 227, 62, 15, 120, 200, 35, 30, 243, 132, 167, + 60, 227, 57, 47, 120, 201, 43, 94, 243, 134, 183, 188, 227, 61, 31, 248, 200, 39, 62, 243, 133, 175, 77, 59, 230, 123, + 243, 123, 145, 239, 44, 241, 131, 101, 126, 178, 194, 47, 86, 249, 237, 239, 86, 153, 238, 210, 92, 122, 75, 107, 233, + 44, 141, 53, 250, 234, 241, 191, 164, 167, 180, 148, 142, 210, 80, 250, 73, 59, 233, 38, 205, 164, 151, 180, 146, 78, + 210, 72, 250, 72, 27, 233, 34, 77, 164, 135, 180, 144, 14, 210, 64, 246, 95, 46, 212, 119, 207, 230, 217, 59, 91, 103, + 231, 108, 156, 125, 183, 237, 186, 107, 207, 125, 59, 30, 218, 239, 216, 110, 167, 246, 58, 183, 211, 165, 125, 174, + 237, 114, 107, 143, 123, 59, 60, 186, 255, 179, 187, 191, 186, 115, 209, 125, 75, 238, 90, 118, 207, 138, 59, 54, 110, + 214, 184, 91, 161, 233, 158, 255, 190, 63, 165, 188, 93, 151, 233, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/noir/noir-repo/acvm-repo/blackbox_solver/src/curve_specific_solver.rs b/noir/noir-repo/acvm-repo/blackbox_solver/src/curve_specific_solver.rs index f0ab4561229..fab67467d9a 100644 --- a/noir/noir-repo/acvm-repo/blackbox_solver/src/curve_specific_solver.rs +++ b/noir/noir-repo/acvm-repo/blackbox_solver/src/curve_specific_solver.rs @@ -11,7 +11,7 @@ pub trait BlackBoxFunctionSolver { &self, public_key_x: &FieldElement, public_key_y: &FieldElement, - signature: &[u8], + signature: &[u8; 64], message: &[u8], ) -> Result; fn pedersen_commitment( @@ -59,7 +59,7 @@ impl BlackBoxFunctionSolver for StubbedBlackBoxSolver { &self, _public_key_x: &FieldElement, _public_key_y: &FieldElement, - _signature: &[u8], + _signature: &[u8; 64], _message: &[u8], ) -> Result { Err(Self::fail(BlackBoxFunc::SchnorrVerify)) diff --git a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs index 231594170e3..f7c303888e8 100644 --- a/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs +++ b/noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs @@ -52,7 +52,7 @@ impl BlackBoxFunctionSolver for Bn254BlackBoxSolver { &self, public_key_x: &FieldElement, public_key_y: &FieldElement, - signature: &[u8], + signature: &[u8; 64], message: &[u8], ) -> Result { let pub_key_bytes: Vec = diff --git a/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs b/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs index 73981fb0625..2857e27f1af 100644 --- a/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs +++ b/noir/noir-repo/acvm-repo/brillig_vm/src/black_box.rs @@ -127,7 +127,8 @@ pub(crate) fn evaluate_black_box( let public_key_x = memory.read(*public_key_x).try_into().unwrap(); let public_key_y = memory.read(*public_key_y).try_into().unwrap(); let message: Vec = to_u8_vec(read_heap_vector(memory, message)); - let signature: Vec = to_u8_vec(read_heap_vector(memory, signature)); + let signature: [u8; 64] = + to_u8_vec(read_heap_vector(memory, signature)).try_into().unwrap(); let verified = solver.schnorr_verify(&public_key_x, &public_key_y, &signature, &message)?; memory.write(*result, verified.into()); diff --git a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index ba4e03bff95..e16eb2172be 100644 --- a/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/noir/noir-repo/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -167,17 +167,27 @@ impl GeneratedAcir { BlackBoxFuncCall::XOR { lhs: inputs[0][0], rhs: inputs[1][0], output: outputs[0] } } BlackBoxFunc::RANGE => BlackBoxFuncCall::RANGE { input: inputs[0][0] }, - BlackBoxFunc::SHA256 => BlackBoxFuncCall::SHA256 { inputs: inputs[0].clone(), outputs }, - BlackBoxFunc::Blake2s => { - BlackBoxFuncCall::Blake2s { inputs: inputs[0].clone(), outputs } - } - BlackBoxFunc::Blake3 => BlackBoxFuncCall::Blake3 { inputs: inputs[0].clone(), outputs }, + BlackBoxFunc::SHA256 => BlackBoxFuncCall::SHA256 { + inputs: inputs[0].clone(), + outputs: outputs.try_into().expect("Compiler should generate correct size outputs"), + }, + BlackBoxFunc::Blake2s => BlackBoxFuncCall::Blake2s { + inputs: inputs[0].clone(), + outputs: outputs.try_into().expect("Compiler should generate correct size outputs"), + }, + BlackBoxFunc::Blake3 => BlackBoxFuncCall::Blake3 { + inputs: inputs[0].clone(), + outputs: outputs.try_into().expect("Compiler should generate correct size outputs"), + }, BlackBoxFunc::SchnorrVerify => { BlackBoxFuncCall::SchnorrVerify { public_key_x: inputs[0][0], public_key_y: inputs[1][0], // Schnorr signature is an r & s, 32 bytes each - signature: inputs[2].clone(), + signature: inputs[2] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), message: inputs[3].clone(), output: outputs[0], } @@ -195,24 +205,48 @@ impl GeneratedAcir { BlackBoxFunc::EcdsaSecp256k1 => { BlackBoxFuncCall::EcdsaSecp256k1 { // 32 bytes for each public key co-ordinate - public_key_x: inputs[0].clone(), - public_key_y: inputs[1].clone(), + public_key_x: inputs[0] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + public_key_y: inputs[1] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), // (r,s) are both 32 bytes each, so signature // takes up 64 bytes - signature: inputs[2].clone(), - hashed_message: inputs[3].clone(), + signature: inputs[2] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + hashed_message: inputs[3] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), output: outputs[0], } } BlackBoxFunc::EcdsaSecp256r1 => { BlackBoxFuncCall::EcdsaSecp256r1 { // 32 bytes for each public key co-ordinate - public_key_x: inputs[0].clone(), - public_key_y: inputs[1].clone(), + public_key_x: inputs[0] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + public_key_y: inputs[1] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), // (r,s) are both 32 bytes each, so signature // takes up 64 bytes - signature: inputs[2].clone(), - hashed_message: inputs[3].clone(), + signature: inputs[2] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + hashed_message: inputs[3] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), output: outputs[0], } } @@ -240,11 +274,21 @@ impl GeneratedAcir { } }; - BlackBoxFuncCall::Keccak256 { inputs: inputs[0].clone(), var_message_size, outputs } - } - BlackBoxFunc::Keccakf1600 => { - BlackBoxFuncCall::Keccakf1600 { inputs: inputs[0].clone(), outputs } + BlackBoxFuncCall::Keccak256 { + inputs: inputs[0].clone(), + var_message_size, + outputs: outputs + .try_into() + .expect("Compiler should generate correct size outputs"), + } } + BlackBoxFunc::Keccakf1600 => BlackBoxFuncCall::Keccakf1600 { + inputs: inputs[0] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + outputs: outputs.try_into().expect("Compiler should generate correct size outputs"), + }, BlackBoxFunc::RecursiveAggregation => BlackBoxFuncCall::RecursiveAggregation { verification_key: inputs[0].clone(), proof: inputs[1].clone(), @@ -286,9 +330,15 @@ impl GeneratedAcir { len: constant_inputs[0].to_u128() as u32, }, BlackBoxFunc::Sha256Compression => BlackBoxFuncCall::Sha256Compression { - inputs: inputs[0].clone(), - hash_values: inputs[1].clone(), - outputs, + inputs: inputs[0] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + hash_values: inputs[1] + .clone() + .try_into() + .expect("Compiler should generate correct size inputs"), + outputs: outputs.try_into().expect("Compiler should generate correct size outputs"), }, }; diff --git a/noir/noir-repo/tooling/lsp/src/solver.rs b/noir/noir-repo/tooling/lsp/src/solver.rs index d0acbf1aec5..0fea9b16b54 100644 --- a/noir/noir-repo/tooling/lsp/src/solver.rs +++ b/noir/noir-repo/tooling/lsp/src/solver.rs @@ -10,7 +10,7 @@ impl BlackBoxFunctionSolver for WrapperSolver { &self, public_key_x: &acvm::FieldElement, public_key_y: &acvm::FieldElement, - signature: &[u8], + signature: &[u8; 64], message: &[u8], ) -> Result { self.0.schnorr_verify(public_key_x, public_key_y, signature, message)