diff --git a/.aztec-sync-commit b/.aztec-sync-commit index 258eb260471..b47eb7bdaec 100644 --- a/.aztec-sync-commit +++ b/.aztec-sync-commit @@ -1 +1 @@ -670af8a158633d106a3f1df82dbd28ef9a9e4ceb +ab0c80d7493e6bdbc58dcd517b248de6ddd6fd67 diff --git a/Cargo.lock b/Cargo.lock index 8be1d274678..a24908fd2e6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -71,7 +71,6 @@ dependencies = [ "p256", "proptest", "sha2", - "sha3", "thiserror", ] diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index 70ad596a93a..637ac2ce201 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -145,12 +145,6 @@ namespace Program { struct IntegerBitSize { - struct U0 { - friend bool operator==(const U0&, const U0&); - std::vector bincodeSerialize() const; - static U0 bincodeDeserialize(std::vector); - }; - struct U1 { friend bool operator==(const U1&, const U1&); std::vector bincodeSerialize() const; @@ -187,7 +181,7 @@ namespace Program { static U128 bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const IntegerBitSize&, const IntegerBitSize&); std::vector bincodeSerialize() const; @@ -218,7 +212,24 @@ namespace Program { }; struct MemoryAddress { - uint64_t value; + + struct Direct { + uint64_t value; + + friend bool operator==(const Direct&, const Direct&); + std::vector bincodeSerialize() const; + static Direct bincodeDeserialize(std::vector); + }; + + struct Relative { + uint64_t value; + + friend bool operator==(const Relative&, const Relative&); + std::vector bincodeSerialize() const; + static Relative bincodeDeserialize(std::vector); + }; + + std::variant value; friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; @@ -274,15 +285,6 @@ namespace Program { static Blake3 bincodeDeserialize(std::vector); }; - struct Keccak256 { - Program::HeapVector message; - Program::HeapArray output; - - friend bool operator==(const Keccak256&, const Keccak256&); - std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); - }; - struct Keccakf1600 { Program::HeapVector message; Program::HeapArray output; @@ -328,26 +330,6 @@ namespace Program { static SchnorrVerify bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - Program::HeapVector inputs; - Program::MemoryAddress domain_separator; - Program::HeapArray output; - - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); - std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); - }; - - struct PedersenHash { - Program::HeapVector inputs; - Program::MemoryAddress domain_separator; - Program::MemoryAddress output; - - friend bool operator==(const PedersenHash&, const PedersenHash&); - std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); - }; - struct MultiScalarMul { Program::HeapVector points; Program::HeapVector scalars; @@ -462,7 +444,7 @@ namespace Program { static ToRadix bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; @@ -848,26 +830,6 @@ namespace Program { static SchnorrVerify bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - std::vector inputs; - uint32_t domain_separator; - std::array outputs; - - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); - std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); - }; - - struct PedersenHash { - std::vector inputs; - uint32_t domain_separator; - Program::Witness output; - - friend bool operator==(const PedersenHash&, const PedersenHash&); - std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); - }; - struct EcdsaSecp256k1 { std::array public_key_x; std::array public_key_y; @@ -912,16 +874,6 @@ namespace Program { static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - struct Keccak256 { - std::vector inputs; - Program::FunctionInput var_message_size; - std::array outputs; - - friend bool operator==(const Keccak256&, const Keccak256&); - std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); - }; - struct Keccakf1600 { std::array inputs; std::array outputs; @@ -1022,7 +974,7 @@ namespace Program { static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; @@ -2744,94 +2696,6 @@ Program::BlackBoxFuncCall::SchnorrVerify serde::Deserializable BlackBoxFuncCall::PedersenCommitment::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline BlackBoxFuncCall::PedersenCommitment BlackBoxFuncCall::PedersenCommitment::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 Program - -template <> -template -void serde::Serializable::serialize(const Program::BlackBoxFuncCall::PedersenCommitment &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); - serde::Serializable::serialize(obj.outputs, serializer); -} - -template <> -template -Program::BlackBoxFuncCall::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BlackBoxFuncCall::PedersenCommitment obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); - return obj; -} - -namespace Program { - - inline bool operator==(const BlackBoxFuncCall::PedersenHash &lhs, const BlackBoxFuncCall::PedersenHash &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } - return true; - } - - inline std::vector BlackBoxFuncCall::PedersenHash::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline BlackBoxFuncCall::PedersenHash BlackBoxFuncCall::PedersenHash::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 Program - -template <> -template -void serde::Serializable::serialize(const Program::BlackBoxFuncCall::PedersenHash &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); - serde::Serializable::serialize(obj.output, serializer); -} - -template <> -template -Program::BlackBoxFuncCall::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BlackBoxFuncCall::PedersenHash obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); - return obj; -} - namespace Program { inline bool operator==(const BlackBoxFuncCall::EcdsaSecp256k1 &lhs, const BlackBoxFuncCall::EcdsaSecp256k1 &rhs) { @@ -3020,50 +2884,6 @@ Program::BlackBoxFuncCall::EmbeddedCurveAdd serde::Deserializable BlackBoxFuncCall::Keccak256::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline BlackBoxFuncCall::Keccak256 BlackBoxFuncCall::Keccak256::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 Program - -template <> -template -void serde::Serializable::serialize(const Program::BlackBoxFuncCall::Keccak256 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.var_message_size, serializer); - serde::Serializable::serialize(obj.outputs, serializer); -} - -template <> -template -Program::BlackBoxFuncCall::Keccak256 serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BlackBoxFuncCall::Keccak256 obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.var_message_size = serde::Deserializable::deserialize(deserializer); - obj.outputs = serde::Deserializable::deserialize(deserializer); - return obj; -} - namespace Program { inline bool operator==(const BlackBoxFuncCall::Keccakf1600 &lhs, const BlackBoxFuncCall::Keccakf1600 &rhs) { @@ -3675,47 +3495,6 @@ Program::BlackBoxOp::Blake3 serde::Deserializable:: return obj; } -namespace Program { - - inline bool operator==(const BlackBoxOp::Keccak256 &lhs, const BlackBoxOp::Keccak256 &rhs) { - if (!(lhs.message == rhs.message)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } - return true; - } - - inline std::vector BlackBoxOp::Keccak256::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline BlackBoxOp::Keccak256 BlackBoxOp::Keccak256::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 Program - -template <> -template -void serde::Serializable::serialize(const Program::BlackBoxOp::Keccak256 &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.message, serializer); - serde::Serializable::serialize(obj.output, serializer); -} - -template <> -template -Program::BlackBoxOp::Keccak256 serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BlackBoxOp::Keccak256 obj; - obj.message = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); - return obj; -} - namespace Program { inline bool operator==(const BlackBoxOp::Keccakf1600 &lhs, const BlackBoxOp::Keccakf1600 &rhs) { @@ -3907,94 +3686,6 @@ Program::BlackBoxOp::SchnorrVerify serde::Deserializable BlackBoxOp::PedersenCommitment::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline BlackBoxOp::PedersenCommitment BlackBoxOp::PedersenCommitment::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 Program - -template <> -template -void serde::Serializable::serialize(const Program::BlackBoxOp::PedersenCommitment &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); - serde::Serializable::serialize(obj.output, serializer); -} - -template <> -template -Program::BlackBoxOp::PedersenCommitment serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BlackBoxOp::PedersenCommitment obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); - return obj; -} - -namespace Program { - - inline bool operator==(const BlackBoxOp::PedersenHash &lhs, const BlackBoxOp::PedersenHash &rhs) { - if (!(lhs.inputs == rhs.inputs)) { return false; } - if (!(lhs.domain_separator == rhs.domain_separator)) { return false; } - if (!(lhs.output == rhs.output)) { return false; } - return true; - } - - inline std::vector BlackBoxOp::PedersenHash::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline BlackBoxOp::PedersenHash BlackBoxOp::PedersenHash::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 Program - -template <> -template -void serde::Serializable::serialize(const Program::BlackBoxOp::PedersenHash &obj, Serializer &serializer) { - serde::Serializable::serialize(obj.inputs, serializer); - serde::Serializable::serialize(obj.domain_separator, serializer); - serde::Serializable::serialize(obj.output, serializer); -} - -template <> -template -Program::BlackBoxOp::PedersenHash serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BlackBoxOp::PedersenHash obj; - obj.inputs = serde::Deserializable::deserialize(deserializer); - obj.domain_separator = serde::Deserializable::deserialize(deserializer); - obj.output = serde::Deserializable::deserialize(deserializer); - return obj; -} - namespace Program { inline bool operator==(const BlackBoxOp::MultiScalarMul &lhs, const BlackBoxOp::MultiScalarMul &rhs) { @@ -6772,41 +6463,6 @@ Program::IntegerBitSize serde::Deserializable::deserial return obj; } -namespace Program { - - inline bool operator==(const IntegerBitSize::U0 &lhs, const IntegerBitSize::U0 &rhs) { - return true; - } - - inline std::vector IntegerBitSize::U0::bincodeSerialize() const { - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); - } - - inline IntegerBitSize::U0 IntegerBitSize::U0::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 Program - -template <> -template -void serde::Serializable::serialize(const Program::IntegerBitSize::U0 &obj, Serializer &serializer) { -} - -template <> -template -Program::IntegerBitSize::U0 serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::IntegerBitSize::U0 obj; - return obj; -} - namespace Program { inline bool operator==(const IntegerBitSize::U1 &lhs, const IntegerBitSize::U1 &rhs) { @@ -7107,6 +6763,82 @@ Program::MemoryAddress serde::Deserializable::deserializ return obj; } +namespace Program { + + inline bool operator==(const MemoryAddress::Direct &lhs, const MemoryAddress::Direct &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector MemoryAddress::Direct::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline MemoryAddress::Direct MemoryAddress::Direct::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 Program + +template <> +template +void serde::Serializable::serialize(const Program::MemoryAddress::Direct &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::MemoryAddress::Direct serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::MemoryAddress::Direct obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + + inline bool operator==(const MemoryAddress::Relative &lhs, const MemoryAddress::Relative &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector MemoryAddress::Relative::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline MemoryAddress::Relative MemoryAddress::Relative::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 Program + +template <> +template +void serde::Serializable::serialize(const Program::MemoryAddress::Relative &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::MemoryAddress::Relative serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::MemoryAddress::Relative obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Program { inline bool operator==(const Opcode &lhs, const Opcode &rhs) { diff --git a/acvm-repo/acir/src/circuit/black_box_functions.rs b/acvm-repo/acir/src/circuit/black_box_functions.rs index 5c07a61af7e..2e5a94f1c50 100644 --- a/acvm-repo/acir/src/circuit/black_box_functions.rs +++ b/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -76,10 +76,6 @@ pub enum BlackBoxFunc { /// /// [grumpkin]: https://hackmd.io/@aztec-network/ByzgNxBfd#2-Grumpkin---A-curve-on-top-of-BN-254-for-SNARK-efficient-group-operations SchnorrVerify, - /// Will be deprecated - PedersenCommitment, - /// Will be deprecated - PedersenHash, /// Verifies a ECDSA signature over the secp256k1 curve. /// - inputs: /// - x coordinate of public key as 32 bytes @@ -117,11 +113,6 @@ pub enum BlackBoxFunc { /// scalar $a$: `a=low+high*2^{128}`, with `low, high < 2^{128}` MultiScalarMul, - /// Computes the Keccak-256 (Ethereum version) of the inputs. - /// - inputs: Vector of bytes (witness, 8) - /// - outputs: Array of 32 bytes (witness, 8) - Keccak256, - /// Keccak Permutation function of width 1600 /// - inputs: An array of 25 64-bit Keccak lanes that represent a keccak sponge of 1600 bits /// - outputs: The result of a keccak f1600 permutation on the input state. Also an array of 25 Keccak lanes. @@ -216,7 +207,6 @@ impl BlackBoxFunc { BlackBoxFunc::AND => "and", BlackBoxFunc::XOR => "xor", BlackBoxFunc::RANGE => "range", - BlackBoxFunc::Keccak256 => "keccak256", BlackBoxFunc::Keccakf1600 => "keccakf1600", BlackBoxFunc::RecursiveAggregation => "recursive_aggregation", BlackBoxFunc::EcdsaSecp256r1 => "ecdsa_secp256r1", @@ -228,8 +218,6 @@ impl BlackBoxFunc { BlackBoxFunc::BigIntToLeBytes => "bigint_to_le_bytes", BlackBoxFunc::Poseidon2Permutation => "poseidon2_permutation", BlackBoxFunc::Sha256Compression => "sha256_compression", - BlackBoxFunc::PedersenCommitment => "pedersen_commitment", - BlackBoxFunc::PedersenHash => "pedersen_hash", } } @@ -246,7 +234,6 @@ impl BlackBoxFunc { "and" => Some(BlackBoxFunc::AND), "xor" => Some(BlackBoxFunc::XOR), "range" => Some(BlackBoxFunc::RANGE), - "keccak256" => Some(BlackBoxFunc::Keccak256), "keccakf1600" => Some(BlackBoxFunc::Keccakf1600), "recursive_aggregation" => Some(BlackBoxFunc::RecursiveAggregation), "bigint_add" => Some(BlackBoxFunc::BigIntAdd), @@ -257,8 +244,6 @@ impl BlackBoxFunc { "bigint_to_le_bytes" => Some(BlackBoxFunc::BigIntToLeBytes), "poseidon2_permutation" => Some(BlackBoxFunc::Poseidon2Permutation), "sha256_compression" => Some(BlackBoxFunc::Sha256Compression), - "pedersen_commitment" => Some(BlackBoxFunc::PedersenCommitment), - "pedersen_hash" => Some(BlackBoxFunc::PedersenHash), _ => None, } } diff --git a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index 8bb9a680ea9..e06286d179e 100644 --- a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -117,18 +117,6 @@ pub enum BlackBoxFuncCall { message: Vec>, output: Witness, }, - /// Will be deprecated - PedersenCommitment { - inputs: Vec>, - domain_separator: u32, - outputs: (Witness, Witness), - }, - /// Will be deprecated - PedersenHash { - inputs: Vec>, - domain_separator: u32, - output: Witness, - }, EcdsaSecp256k1 { public_key_x: Box<[FunctionInput; 32]>, public_key_y: Box<[FunctionInput; 32]>, @@ -161,15 +149,6 @@ pub enum BlackBoxFuncCall { input2: Box<[FunctionInput; 3]>, outputs: (Witness, Witness, Witness), }, - Keccak256 { - inputs: Vec>, - /// This is the number of bytes to take - /// from the input. Note: if `var_message_size` - /// is more than the number of bytes in the input, - /// then an error is returned. - var_message_size: FunctionInput, - outputs: Box<[Witness; 32]>, - }, Keccakf1600 { inputs: Box<[FunctionInput; 25]>, outputs: Box<[Witness; 25]>, @@ -258,7 +237,6 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::EcdsaSecp256r1 { .. } => BlackBoxFunc::EcdsaSecp256r1, BlackBoxFuncCall::MultiScalarMul { .. } => BlackBoxFunc::MultiScalarMul, BlackBoxFuncCall::EmbeddedCurveAdd { .. } => BlackBoxFunc::EmbeddedCurveAdd, - BlackBoxFuncCall::Keccak256 { .. } => BlackBoxFunc::Keccak256, BlackBoxFuncCall::Keccakf1600 { .. } => BlackBoxFunc::Keccakf1600, BlackBoxFuncCall::RecursiveAggregation { .. } => BlackBoxFunc::RecursiveAggregation, BlackBoxFuncCall::BigIntAdd { .. } => BlackBoxFunc::BigIntAdd, @@ -269,8 +247,6 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::BigIntToLeBytes { .. } => BlackBoxFunc::BigIntToLeBytes, BlackBoxFuncCall::Poseidon2Permutation { .. } => BlackBoxFunc::Poseidon2Permutation, BlackBoxFuncCall::Sha256Compression { .. } => BlackBoxFunc::Sha256Compression, - BlackBoxFuncCall::PedersenCommitment { .. } => BlackBoxFunc::PedersenCommitment, - BlackBoxFuncCall::PedersenHash { .. } => BlackBoxFunc::PedersenHash, } } @@ -284,8 +260,6 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::Blake2s { inputs, .. } | BlackBoxFuncCall::Blake3 { inputs, .. } | BlackBoxFuncCall::BigIntFromLeBytes { inputs, .. } - | BlackBoxFuncCall::PedersenCommitment { inputs, .. } - | BlackBoxFuncCall::PedersenHash { inputs, .. } | BlackBoxFuncCall::Poseidon2Permutation { inputs, .. } => inputs.to_vec(), BlackBoxFuncCall::Keccakf1600 { inputs, .. } => inputs.to_vec(), @@ -365,11 +339,6 @@ impl BlackBoxFuncCall { inputs.extend(hashed_message.iter().copied()); inputs } - BlackBoxFuncCall::Keccak256 { inputs, var_message_size, .. } => { - let mut inputs = inputs.clone(); - inputs.push(*var_message_size); - inputs - } BlackBoxFuncCall::RecursiveAggregation { verification_key: key, proof, @@ -390,8 +359,7 @@ impl BlackBoxFuncCall { pub fn get_outputs_vec(&self) -> Vec { match self { BlackBoxFuncCall::Blake2s { outputs, .. } - | BlackBoxFuncCall::Blake3 { outputs, .. } - | BlackBoxFuncCall::Keccak256 { outputs, .. } => outputs.to_vec(), + | BlackBoxFuncCall::Blake3 { outputs, .. } => outputs.to_vec(), BlackBoxFuncCall::Keccakf1600 { outputs, .. } => outputs.to_vec(), @@ -404,9 +372,7 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::XOR { output, .. } | BlackBoxFuncCall::SchnorrVerify { output, .. } | BlackBoxFuncCall::EcdsaSecp256k1 { output, .. } - | BlackBoxFuncCall::PedersenHash { output, .. } | BlackBoxFuncCall::EcdsaSecp256r1 { output, .. } => vec![*output], - BlackBoxFuncCall::PedersenCommitment { outputs, .. } => vec![outputs.0, outputs.1], BlackBoxFuncCall::MultiScalarMul { outputs, .. } | BlackBoxFuncCall::EmbeddedCurveAdd { outputs, .. } => { vec![outputs.0, outputs.1, outputs.2] @@ -479,14 +445,6 @@ fn get_outputs_string(outputs: &[Witness]) -> String { impl std::fmt::Display for BlackBoxFuncCall { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - BlackBoxFuncCall::PedersenCommitment { .. } => { - return write!(f, "BLACKBOX::Deprecated") - } - BlackBoxFuncCall::PedersenHash { .. } => return write!(f, "BLACKBOX::Deprecated"), - _ => (), - } - let uppercase_name = self.name().to_uppercase(); write!(f, "BLACKBOX::{uppercase_name} ")?; // INPUTS diff --git a/acvm-repo/acir/src/lib.rs b/acvm-repo/acir/src/lib.rs index 36331427b9f..f8a31439127 100644 --- a/acvm-repo/acir/src/lib.rs +++ b/acvm-repo/acir/src/lib.rs @@ -35,7 +35,7 @@ mod reflection { use acir_field::FieldElement; use brillig::{ BinaryFieldOp, BinaryIntOp, BitSize, BlackBoxOp, HeapValueType, IntegerBitSize, - Opcode as BrilligOpcode, ValueOrArray, + MemoryAddress, Opcode as BrilligOpcode, ValueOrArray, }; use serde_reflection::{Tracer, TracerConfig}; @@ -84,6 +84,7 @@ mod reflection { tracer.trace_simple_type::>().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); let registry = tracer.registry().unwrap(); diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index 6bf5afe52d9..a915cb95d07 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -91,10 +91,10 @@ fn multi_scalar_mul_circuit() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 141, 11, 10, 0, 32, 8, 67, 43, 181, 15, 221, 255, - 186, 145, 210, 130, 149, 240, 112, 234, 212, 156, 78, 12, 39, 67, 71, 158, 142, 80, 29, 44, - 228, 66, 90, 168, 119, 189, 74, 115, 131, 174, 78, 115, 58, 124, 70, 254, 130, 59, 74, 253, - 68, 255, 255, 221, 39, 54, 29, 134, 27, 102, 193, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 77, 9, 14, 0, 32, 8, 202, 171, 227, 255, 255, 109, + 217, 162, 141, 114, 99, 2, 162, 74, 57, 53, 18, 2, 46, 208, 70, 122, 99, 162, 43, 113, 35, + 239, 102, 157, 230, 1, 94, 19, 45, 209, 145, 11, 202, 43, 238, 56, 249, 133, 254, 255, 187, + 79, 45, 204, 84, 220, 246, 193, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -165,25 +165,25 @@ fn simple_brillig_foreign_call() { let brillig_bytecode = BrilligBytecode { bytecode: vec![ brillig::Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(1_usize), }, brillig::Opcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0_usize), }, brillig::Opcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, brillig::Opcode::ForeignCall { function: "invert".into(), - destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(0))], destination_value_types: vec![HeapValueType::field()], - inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(0))], input_value_types: vec![HeapValueType::field()], }, brillig::Opcode::Stop { return_data_offset: 0, return_data_size: 1 }, @@ -214,12 +214,12 @@ fn simple_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 81, 73, 10, 192, 48, 8, 140, 165, 91, 160, 183, - 126, 196, 254, 160, 159, 233, 161, 151, 30, 74, 200, 251, 19, 136, 130, 132, 196, 75, 28, - 16, 199, 17, 212, 65, 112, 5, 123, 14, 32, 190, 80, 230, 90, 130, 181, 155, 50, 142, 225, - 2, 187, 89, 40, 239, 157, 106, 2, 82, 116, 138, 51, 118, 239, 171, 222, 108, 232, 218, 139, - 125, 198, 179, 113, 83, 188, 29, 57, 86, 226, 239, 23, 159, 63, 104, 63, 238, 213, 45, 237, - 108, 244, 18, 195, 174, 252, 193, 92, 2, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 79, 73, 10, 128, 48, 12, 204, 40, 46, 5, 111, 126, + 36, 254, 192, 207, 120, 240, 226, 65, 196, 247, 91, 48, 129, 80, 218, 122, 48, 3, 33, 147, + 9, 89, 6, 244, 98, 140, 1, 225, 157, 100, 173, 45, 84, 91, 37, 243, 63, 44, 240, 219, 197, + 246, 223, 38, 37, 176, 34, 85, 156, 169, 251, 144, 233, 183, 142, 206, 67, 114, 215, 121, + 63, 15, 84, 135, 222, 157, 98, 244, 194, 247, 227, 222, 206, 11, 31, 19, 165, 186, 164, + 207, 153, 222, 3, 91, 101, 84, 220, 120, 2, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -242,55 +242,61 @@ fn complex_brillig_foreign_call() { let brillig_bytecode = BrilligBytecode { bytecode: vec![ brillig::Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(3_usize), }, brillig::Opcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0_usize), }, brillig::Opcode::CalldataCopy { - destination_address: MemoryAddress(32), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(32), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, brillig::Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), value: FieldElement::from(32_usize), bit_size: BitSize::Integer(IntegerBitSize::U32), }, brillig::Opcode::Const { - destination: MemoryAddress(3), + destination: MemoryAddress::direct(3), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(1_usize), }, brillig::Opcode::Const { - destination: MemoryAddress(4), + destination: MemoryAddress::direct(4), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(3_usize), }, brillig::Opcode::CalldataCopy { - destination_address: MemoryAddress(1), - size_address: MemoryAddress(3), - offset_address: MemoryAddress(4), + destination_address: MemoryAddress::direct(1), + size_address: MemoryAddress::direct(3), + offset_address: MemoryAddress::direct(4), }, // Oracles are named 'foreign calls' in brillig brillig::Opcode::ForeignCall { function: "complex".into(), inputs: vec![ - ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), - ValueOrArray::MemoryAddress(MemoryAddress::from(1)), + ValueOrArray::HeapArray(HeapArray { + pointer: MemoryAddress::direct(0), + size: 3, + }), + ValueOrArray::MemoryAddress(MemoryAddress::direct(1)), ], input_value_types: vec![ HeapValueType::Array { size: 3, value_types: vec![HeapValueType::field()] }, HeapValueType::field(), ], destinations: vec![ - ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), - ValueOrArray::MemoryAddress(MemoryAddress::from(35)), - ValueOrArray::MemoryAddress(MemoryAddress::from(36)), + ValueOrArray::HeapArray(HeapArray { + pointer: MemoryAddress::direct(0), + size: 3, + }), + ValueOrArray::MemoryAddress(MemoryAddress::direct(35)), + ValueOrArray::MemoryAddress(MemoryAddress::direct(36)), ], destination_value_types: vec![ HeapValueType::Array { size: 3, value_types: vec![HeapValueType::field()] }, @@ -338,17 +344,17 @@ fn complex_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 85, 81, 14, 194, 48, 8, 133, 118, 186, 53, 241, - 207, 11, 152, 232, 1, 58, 189, 128, 119, 49, 254, 105, 244, 211, 227, 59, 50, 154, 49, 214, - 100, 31, 163, 201, 246, 146, 133, 174, 5, 10, 15, 72, 17, 122, 52, 221, 135, 188, 222, 177, - 116, 44, 105, 223, 195, 24, 73, 247, 206, 50, 46, 67, 139, 118, 190, 98, 169, 24, 221, 6, - 98, 244, 5, 98, 4, 81, 255, 21, 214, 219, 178, 46, 166, 252, 249, 204, 252, 84, 208, 207, - 215, 158, 255, 107, 150, 141, 38, 154, 140, 28, 76, 7, 111, 132, 212, 61, 65, 201, 116, 86, - 217, 101, 115, 11, 226, 62, 99, 223, 145, 88, 56, 205, 228, 102, 127, 239, 53, 6, 69, 184, - 97, 78, 109, 96, 127, 37, 106, 81, 11, 126, 100, 103, 17, 14, 48, 116, 213, 227, 243, 254, - 190, 158, 63, 175, 40, 149, 102, 132, 179, 88, 95, 212, 57, 42, 59, 109, 43, 33, 31, 140, - 156, 46, 102, 244, 230, 124, 31, 97, 104, 141, 244, 48, 253, 1, 180, 46, 168, 159, 181, 6, - 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 85, 93, 10, 194, 48, 12, 78, 155, 233, 54, 240, + 205, 11, 8, 122, 128, 76, 47, 176, 187, 136, 111, 138, 62, 122, 124, 45, 75, 88, 23, 139, + 19, 76, 64, 63, 24, 89, 75, 242, 229, 159, 6, 24, 208, 60, 191, 192, 255, 11, 150, 145, + 101, 186, 71, 152, 66, 116, 123, 150, 244, 29, 186, 96, 199, 69, 94, 49, 198, 63, 136, 17, + 29, 98, 132, 172, 255, 63, 216, 111, 203, 190, 152, 214, 15, 11, 251, 83, 193, 176, 95, 75, + 62, 215, 44, 27, 93, 232, 100, 20, 225, 117, 241, 38, 144, 233, 105, 149, 4, 229, 185, 183, + 201, 232, 208, 42, 191, 198, 252, 36, 213, 216, 192, 103, 249, 250, 228, 185, 39, 225, 71, + 23, 126, 234, 132, 191, 114, 234, 83, 173, 234, 149, 231, 146, 251, 93, 193, 56, 129, 199, + 235, 229, 118, 62, 221, 177, 96, 170, 205, 19, 182, 234, 188, 43, 148, 108, 142, 67, 144, + 63, 52, 239, 244, 67, 65, 127, 206, 102, 13, 227, 56, 201, 195, 246, 0, 155, 0, 46, 128, + 245, 6, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm-repo/acvm/src/pwg/blackbox/hash.rs b/acvm-repo/acvm/src/pwg/blackbox/hash.rs index f177cd071d0..7476b0dc2dc 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/hash.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/hash.rs @@ -49,7 +49,7 @@ fn get_hash_input( // in the message, then we error. if num_bytes_to_take > message_input.len() { return Err(OpcodeResolutionError::BlackBoxFunctionFailed( - acir::BlackBoxFunc::Keccak256, + acir::BlackBoxFunc::Blake2s, format!("the number of bytes to take from the message is more than the number of bytes in the message. {} > {}", num_bytes_to_take, message_input.len()), )); } diff --git a/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/acvm-repo/acvm/src/pwg/blackbox/mod.rs index 1cca14cc680..c3b1627ba65 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -3,7 +3,7 @@ use acir::{ native_types::{Witness, WitnessMap}, AcirField, }; -use acvm_blackbox_solver::{blake2s, blake3, keccak256, keccakf1600}; +use acvm_blackbox_solver::{blake2s, blake3, keccakf1600}; use self::{ aes128::solve_aes128_encryption_opcode, bigint::AcvmBigIntSolver, @@ -18,7 +18,6 @@ pub(crate) mod bigint; mod embedded_curve_ops; mod hash; mod logic; -mod pedersen; mod range; mod signature; pub(crate) mod utils; @@ -27,7 +26,6 @@ use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul}; // Hash functions should eventually be exposed for external consumers. use hash::{solve_generic_256_hash_opcode, solve_sha_256_permutation_opcode}; use logic::{and, xor}; -use pedersen::{pedersen, pedersen_hash}; pub(crate) use range::solve_range_opcode; use signature::{ ecdsa::{secp256k1_prehashed, secp256r1_prehashed}, @@ -90,16 +88,6 @@ pub(crate) fn solve( 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, - inputs, - Some(var_message_size), - outputs, - keccak256, - ) - } BlackBoxFuncCall::Keccakf1600 { inputs, outputs } => { let mut state = [0; 25]; for (it, input) in state.iter_mut().zip(inputs.as_ref()) { @@ -130,12 +118,6 @@ pub(crate) fn solve( message, *output, ), - BlackBoxFuncCall::PedersenCommitment { inputs, domain_separator, outputs } => { - pedersen(backend, initial_witness, inputs, *domain_separator, *outputs) - } - BlackBoxFuncCall::PedersenHash { inputs, domain_separator, output } => { - pedersen_hash(backend, initial_witness, inputs, *domain_separator, *output) - } BlackBoxFuncCall::EcdsaSecp256k1 { public_key_x, public_key_y, diff --git a/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs b/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs deleted file mode 100644 index 654814bf92d..00000000000 --- a/acvm-repo/acvm/src/pwg/blackbox/pedersen.rs +++ /dev/null @@ -1,47 +0,0 @@ -use acir::{ - circuit::opcodes::FunctionInput, - native_types::{Witness, WitnessMap}, - AcirField, -}; - -use crate::{ - pwg::{input_to_value, insert_value, OpcodeResolutionError}, - BlackBoxFunctionSolver, -}; - -pub(super) fn pedersen( - backend: &impl BlackBoxFunctionSolver, - initial_witness: &mut WitnessMap, - inputs: &[FunctionInput], - domain_separator: u32, - outputs: (Witness, Witness), -) -> Result<(), OpcodeResolutionError> { - let scalars: Result, _> = - inputs.iter().map(|input| input_to_value(initial_witness, *input, false)).collect(); - let scalars: Vec<_> = scalars?.into_iter().collect(); - - let (res_x, res_y) = backend.pedersen_commitment(&scalars, domain_separator)?; - - insert_value(&outputs.0, res_x, initial_witness)?; - insert_value(&outputs.1, res_y, initial_witness)?; - - Ok(()) -} - -pub(super) fn pedersen_hash( - backend: &impl BlackBoxFunctionSolver, - initial_witness: &mut WitnessMap, - inputs: &[FunctionInput], - domain_separator: u32, - output: Witness, -) -> Result<(), OpcodeResolutionError> { - let scalars: Result, _> = - inputs.iter().map(|input| input_to_value(initial_witness, *input, false)).collect(); - let scalars: Vec<_> = scalars?.into_iter().collect(); - - let res = backend.pedersen_hash(&scalars, domain_separator)?; - - insert_value(&output, res, initial_witness)?; - - Ok(()) -} diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 6ad52999820..efa8de289e5 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -79,9 +79,9 @@ fn inversion_brillig_oracle_equivalence() { let equal_opcode = BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Equals, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(2), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(1), + destination: MemoryAddress::direct(2), }; let opcodes = vec![ @@ -125,27 +125,27 @@ fn inversion_brillig_oracle_equivalence() { let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(2u64), }, BrilligOpcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, equal_opcode, // Oracles are named 'foreign calls' in brillig BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(1))], destination_value_types: vec![HeapValueType::field()], - inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(0))], input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 3 }, @@ -218,9 +218,9 @@ fn double_inversion_brillig_oracle() { let equal_opcode = BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Equals, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(4), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(1), + destination: MemoryAddress::direct(4), }; let opcodes = vec![ @@ -271,34 +271,34 @@ fn double_inversion_brillig_oracle() { let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(3u64), }, BrilligOpcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, equal_opcode, // Oracles are named 'foreign calls' in brillig BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(1))], destination_value_types: vec![HeapValueType::field()], - inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(0))], input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(3))], destination_value_types: vec![HeapValueType::field()], - inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(2))], input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 5 }, @@ -389,32 +389,32 @@ fn oracle_dependent_execution() { let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(3u64), }, BrilligOpcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, // Oracles are named 'foreign calls' in brillig BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(1))], destination_value_types: vec![HeapValueType::field()], - inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(0))], input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(3))], destination_value_types: vec![HeapValueType::field()], - inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(2))], input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 4 }, @@ -522,35 +522,35 @@ fn brillig_oracle_predicate() { let equal_opcode = BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Equals, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(2), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(1), + destination: MemoryAddress::direct(2), }; let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(2u64), }, BrilligOpcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, equal_opcode, // Oracles are named 'foreign calls' in brillig BrilligOpcode::ForeignCall { function: "invert".into(), - destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(1))], destination_value_types: vec![HeapValueType::field()], - inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(0))], input_value_types: vec![HeapValueType::field()], }, ], @@ -649,23 +649,23 @@ fn unsatisfied_opcode_resolved_brillig() { let w_result = Witness(6); let calldata_copy_opcode = BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }; let equal_opcode = BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Equals, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(2), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(1), + destination: MemoryAddress::direct(2), }; // Jump pass the trap if the values are equal, else // jump to the trap let location_of_stop = 3; let jmp_if_opcode = - BrilligOpcode::JumpIf { condition: MemoryAddress::from(2), location: location_of_stop }; + BrilligOpcode::JumpIf { condition: MemoryAddress::direct(2), location: location_of_stop }; let trap_opcode = BrilligOpcode::Trap { revert_data: HeapArray::default() }; let stop_opcode = BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }; @@ -673,12 +673,12 @@ fn unsatisfied_opcode_resolved_brillig() { let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(2u64), }, BrilligOpcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, @@ -1099,45 +1099,6 @@ fn blake3_op( }) } -// variable inputs -// 32 outputs -fn keccak256_op( - function_inputs_and_outputs: (Vec>, Vec), -) -> Result, OpcodeResolutionError> { - let (function_inputs, outputs) = function_inputs_and_outputs; - let function_inputs_len = function_inputs.len(); - Ok(BlackBoxFuncCall::Keccak256 { - inputs: function_inputs, - var_message_size: FunctionInput::constant( - function_inputs_len.into(), - FieldElement::max_num_bits(), - )?, - outputs: outputs.try_into().expect("Keccak256 returns 32 outputs"), - }) -} - -// var_message_size is the number of bytes to take -// from the input. Note: if `var_message_size` -// is more than the number of bytes in the input, -// then an error is returned. -// -// variable inputs -// 32 outputs -fn keccak256_invalid_message_size_op( - function_inputs_and_outputs: (Vec>, Vec), -) -> Result, OpcodeResolutionError> { - let (function_inputs, outputs) = function_inputs_and_outputs; - let function_inputs_len = function_inputs.len(); - Ok(BlackBoxFuncCall::Keccak256 { - inputs: function_inputs, - var_message_size: FunctionInput::constant( - (function_inputs_len - 1).into(), - FieldElement::max_num_bits(), - )?, - outputs: outputs.try_into().expect("Keccak256 returns 32 outputs"), - }) -} - // 25 inputs // 25 outputs fn keccakf1600_op( @@ -1489,19 +1450,6 @@ fn blake3_zeros() { assert_eq!(results, Ok(expected_results)); } -#[test] -fn keccak256_zeros() { - let results = solve_array_input_blackbox_call(vec![], 32, None, keccak256_op); - let expected_results: Vec<_> = vec![ - 197, 210, 70, 1, 134, 247, 35, 60, 146, 126, 125, 178, 220, 199, 3, 192, 229, 0, 182, 83, - 202, 130, 39, 59, 123, 250, 216, 4, 93, 133, 164, 112, - ] - .into_iter() - .map(|x: u128| FieldElement::from(x)) - .collect(); - assert_eq!(results, Ok(expected_results)); -} - #[test] fn keccakf1600_zeros() { let results = solve_array_input_blackbox_call( @@ -1642,24 +1590,6 @@ proptest! { prop_assert!(result, "{}", message); } - #[test] - fn keccak256_injective(inputs_distinct_inputs in any_distinct_inputs(Some(8), 0, 32)) { - let (inputs, distinct_inputs) = inputs_distinct_inputs; - let (result, message) = prop_assert_injective(inputs, distinct_inputs, 32, Some(8), keccak256_op); - prop_assert!(result, "{}", message); - } - - // TODO(https://github.com/noir-lang/noir/issues/5689): doesn't fail with a user error - // The test failing with "not injective" demonstrates that it returns constant output instead - // of failing with a user error. - #[test] - #[should_panic(expected = "Test failed: not injective")] - fn keccak256_invalid_message_size_fails(inputs_distinct_inputs in any_distinct_inputs(Some(8), 0, 32)) { - let (inputs, distinct_inputs) = inputs_distinct_inputs; - let (result, message) = prop_assert_injective(inputs, distinct_inputs, 32, Some(8), keccak256_invalid_message_size_op); - prop_assert!(result, "{}", message); - } - #[test] fn keccakf1600_injective(inputs_distinct_inputs in any_distinct_inputs(Some(8), 25, 25)) { let (inputs, distinct_inputs) = inputs_distinct_inputs; diff --git a/acvm-repo/acvm_js/src/black_box_solvers.rs b/acvm-repo/acvm_js/src/black_box_solvers.rs index 6046d52943c..0e35851ee78 100644 --- a/acvm-repo/acvm_js/src/black_box_solvers.rs +++ b/acvm-repo/acvm_js/src/black_box_solvers.rs @@ -37,12 +37,6 @@ pub fn blake2s256(inputs: &[u8]) -> Vec { acvm::blackbox_solver::blake2s(inputs).unwrap().into() } -/// Calculates the Keccak256 hash of the input bytes -#[wasm_bindgen] -pub fn keccak256(inputs: &[u8]) -> Vec { - acvm::blackbox_solver::keccak256(inputs).unwrap().into() -} - /// Verifies a ECDSA signature over the secp256k1 curve. #[wasm_bindgen] pub fn ecdsa_secp256k1_verify( diff --git a/acvm-repo/acvm_js/src/lib.rs b/acvm-repo/acvm_js/src/lib.rs index 8fe64afbba9..e2468e6d939 100644 --- a/acvm-repo/acvm_js/src/lib.rs +++ b/acvm-repo/acvm_js/src/lib.rs @@ -17,8 +17,7 @@ mod logging; mod public_witness; pub use black_box_solvers::{ - and, blake2s256, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, sha256_compression, - xor, + and, blake2s256, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, sha256_compression, xor, }; pub use build_info::build_info; pub use compression::{ diff --git a/acvm-repo/acvm_js/test/browser/black_box_solvers.test.ts b/acvm-repo/acvm_js/test/browser/black_box_solvers.test.ts index 9dc5be2c682..b99fe9e3d88 100644 --- a/acvm-repo/acvm_js/test/browser/black_box_solvers.test.ts +++ b/acvm-repo/acvm_js/test/browser/black_box_solvers.test.ts @@ -4,7 +4,6 @@ import initACVM, { blake2s256, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, - keccak256, sha256_compression, xor, } from '@noir-lang/acvm_js'; @@ -51,16 +50,6 @@ it('successfully calculates the blake2s256 hash', async () => { } }); -it('successfully calculates the keccak256 hash', async () => { - const { keccak256_test_cases } = await import('../shared/black_box_solvers'); - - for (const testCase of keccak256_test_cases) { - const [preimage, expectedResult] = testCase; - const hash = keccak256(preimage); - hash.forEach((value, index) => expect(value).to.be.eq(expectedResult.at(index))); - } -}); - it('successfully verifies secp256k1 ECDSA signatures', async () => { const { ecdsa_secp256k1_test_cases } = await import('../shared/black_box_solvers'); diff --git a/acvm-repo/acvm_js/test/node/black_box_solvers.test.ts b/acvm-repo/acvm_js/test/node/black_box_solvers.test.ts index fc998ced5a5..74553f6b692 100644 --- a/acvm-repo/acvm_js/test/node/black_box_solvers.test.ts +++ b/acvm-repo/acvm_js/test/node/black_box_solvers.test.ts @@ -4,7 +4,6 @@ import { blake2s256, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, - keccak256, sha256_compression, xor, } from '@noir-lang/acvm_js'; @@ -47,28 +46,6 @@ it('successfully calculates the blake2s256 hash', async () => { } }); -it('successfully calculates the keccak256 hash', async () => { - const { keccak256_test_cases } = await import('../shared/black_box_solvers'); - - for (const testCase of keccak256_test_cases) { - const [preimage, expectedResult] = testCase; - const hash = keccak256(preimage); - hash.forEach((value, index) => expect(value).to.be.eq(expectedResult.at(index))); - } -}); - -// it("successfully calculates the hash_to_field_128_security field", async () => { -// const { hash_to_field_128_security_test_cases } = await import( -// "../shared/black_box_solvers" -// ); - -// for (const testCase of hash_to_field_128_security_test_cases) { -// const [preimage, expectedResult] = testCase; -// const hashField = hash_to_field_128_security(preimage); -// expect(hashField).to.be.eq(expectedResult); -// } -// }); - it('successfully verifies secp256k1 ECDSA signatures', async () => { const { ecdsa_secp256k1_test_cases } = await import('../shared/black_box_solvers'); diff --git a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts index 60e4c8d5829..8eb7b7d5059 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,14 +2,14 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `complex_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 85, 81, 14, 194, 48, 8, 133, 118, 186, 53, 241, 207, 11, 152, 232, 1, 58, 189, - 128, 119, 49, 254, 105, 244, 211, 227, 59, 50, 154, 49, 214, 100, 31, 163, 201, 246, 146, 133, 174, 5, 10, 15, 72, 17, - 122, 52, 221, 135, 188, 222, 177, 116, 44, 105, 223, 195, 24, 73, 247, 206, 50, 46, 67, 139, 118, 190, 98, 169, 24, - 221, 6, 98, 244, 5, 98, 4, 81, 255, 21, 214, 219, 178, 46, 166, 252, 249, 204, 252, 84, 208, 207, 215, 158, 255, 107, - 150, 141, 38, 154, 140, 28, 76, 7, 111, 132, 212, 61, 65, 201, 116, 86, 217, 101, 115, 11, 226, 62, 99, 223, 145, 88, - 56, 205, 228, 102, 127, 239, 53, 6, 69, 184, 97, 78, 109, 96, 127, 37, 106, 81, 11, 126, 100, 103, 17, 14, 48, 116, - 213, 227, 243, 254, 190, 158, 63, 175, 40, 149, 102, 132, 179, 88, 95, 212, 57, 42, 59, 109, 43, 33, 31, 140, 156, 46, - 102, 244, 230, 124, 31, 97, 104, 141, 244, 48, 253, 1, 180, 46, 168, 159, 181, 6, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 85, 93, 10, 194, 48, 12, 78, 155, 233, 54, 240, 205, 11, 8, 122, 128, 76, 47, + 176, 187, 136, 111, 138, 62, 122, 124, 45, 75, 88, 23, 139, 19, 76, 64, 63, 24, 89, 75, 242, 229, 159, 6, 24, 208, 60, + 191, 192, 255, 11, 150, 145, 101, 186, 71, 152, 66, 116, 123, 150, 244, 29, 186, 96, 199, 69, 94, 49, 198, 63, 136, + 17, 29, 98, 132, 172, 255, 63, 216, 111, 203, 190, 152, 214, 15, 11, 251, 83, 193, 176, 95, 75, 62, 215, 44, 27, 93, + 232, 100, 20, 225, 117, 241, 38, 144, 233, 105, 149, 4, 229, 185, 183, 201, 232, 208, 42, 191, 198, 252, 36, 213, 216, + 192, 103, 249, 250, 228, 185, 39, 225, 71, 23, 126, 234, 132, 191, 114, 234, 83, 173, 234, 149, 231, 146, 251, 93, + 193, 56, 129, 199, 235, 229, 118, 62, 221, 177, 96, 170, 205, 19, 182, 234, 188, 43, 148, 108, 142, 67, 144, 63, 52, + 239, 244, 67, 65, 127, 206, 102, 13, 227, 56, 201, 195, 246, 0, 155, 0, 46, 128, 245, 6, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/acvm-repo/acvm_js/test/shared/foreign_call.ts b/acvm-repo/acvm_js/test/shared/foreign_call.ts index 9bf57535c87..dc3c6f23f6f 100644 --- a/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,11 +2,11 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 81, 73, 10, 192, 48, 8, 140, 165, 91, 160, 183, 126, 196, 254, 160, 159, 233, - 161, 151, 30, 74, 200, 251, 19, 136, 130, 132, 196, 75, 28, 16, 199, 17, 212, 65, 112, 5, 123, 14, 32, 190, 80, 230, - 90, 130, 181, 155, 50, 142, 225, 2, 187, 89, 40, 239, 157, 106, 2, 82, 116, 138, 51, 118, 239, 171, 222, 108, 232, - 218, 139, 125, 198, 179, 113, 83, 188, 29, 57, 86, 226, 239, 23, 159, 63, 104, 63, 238, 213, 45, 237, 108, 244, 18, - 195, 174, 252, 193, 92, 2, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 79, 73, 10, 128, 48, 12, 204, 40, 46, 5, 111, 126, 36, 254, 192, 207, 120, + 240, 226, 65, 196, 247, 91, 48, 129, 80, 218, 122, 48, 3, 33, 147, 9, 89, 6, 244, 98, 140, 1, 225, 157, 100, 173, 45, + 84, 91, 37, 243, 63, 44, 240, 219, 197, 246, 223, 38, 37, 176, 34, 85, 156, 169, 251, 144, 233, 183, 142, 206, 67, + 114, 215, 121, 63, 15, 84, 135, 222, 157, 98, 244, 194, 247, 227, 222, 206, 11, 31, 19, 165, 186, 164, 207, 153, 222, + 3, 91, 101, 84, 220, 120, 2, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts b/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts index f23847a75fc..239d5473606 100644 --- a/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts +++ b/acvm-repo/acvm_js/test/shared/multi_scalar_mul.ts @@ -1,8 +1,8 @@ // See `multi_scalar_mul_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, 93, 141, 11, 10, 0, 32, 8, 67, 43, 181, 15, 221, 255, 186, 145, 210, 130, 149, 240, - 112, 234, 212, 156, 78, 12, 39, 67, 71, 158, 142, 80, 29, 44, 228, 66, 90, 168, 119, 189, 74, 115, 131, 174, 78, 115, - 58, 124, 70, 254, 130, 59, 74, 253, 68, 255, 255, 221, 39, 54, 29, 134, 27, 102, 193, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 77, 9, 14, 0, 32, 8, 202, 171, 227, 255, 255, 109, 217, 162, 141, 114, 99, 2, + 162, 74, 57, 53, 18, 2, 46, 208, 70, 122, 99, 162, 43, 113, 35, 239, 102, 157, 230, 1, 94, 19, 45, 209, 145, 11, 202, + 43, 238, 56, 249, 133, 254, 255, 187, 79, 45, 204, 84, 220, 246, 193, 0, 0, 0, ]); export const initialWitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/acvm-repo/blackbox_solver/Cargo.toml b/acvm-repo/blackbox_solver/Cargo.toml index b57c9356198..d99240c5a24 100644 --- a/acvm-repo/blackbox_solver/Cargo.toml +++ b/acvm-repo/blackbox_solver/Cargo.toml @@ -23,7 +23,6 @@ num-bigint = "0.4" blake2 = "0.10.6" blake3 = "1.5.0" sha2.workspace = true -sha3.workspace = true keccak = "0.1.4" k256 = { version = "0.11.0", features = [ "ecdsa", diff --git a/acvm-repo/blackbox_solver/src/curve_specific_solver.rs b/acvm-repo/blackbox_solver/src/curve_specific_solver.rs index f729a5033fb..869017f52ee 100644 --- a/acvm-repo/blackbox_solver/src/curve_specific_solver.rs +++ b/acvm-repo/blackbox_solver/src/curve_specific_solver.rs @@ -14,16 +14,6 @@ pub trait BlackBoxFunctionSolver { signature: &[u8; 64], message: &[u8], ) -> Result; - fn pedersen_commitment( - &self, - inputs: &[F], - domain_separator: u32, - ) -> Result<(F, F), BlackBoxResolutionError>; - fn pedersen_hash( - &self, - inputs: &[F], - domain_separator: u32, - ) -> Result; fn multi_scalar_mul( &self, points: &[F], @@ -67,21 +57,6 @@ impl BlackBoxFunctionSolver for StubbedBlackBoxSolver { ) -> Result { Err(Self::fail(BlackBoxFunc::SchnorrVerify)) } - fn pedersen_commitment( - &self, - _inputs: &[F], - _domain_separator: u32, - ) -> Result<(F, F), BlackBoxResolutionError> { - Err(Self::fail(BlackBoxFunc::PedersenCommitment)) - } - fn pedersen_hash( - &self, - _inputs: &[F], - _domain_separator: u32, - ) -> Result { - Err(Self::fail(BlackBoxFunc::PedersenHash)) - } - fn multi_scalar_mul( &self, _points: &[F], diff --git a/acvm-repo/blackbox_solver/src/hash.rs b/acvm-repo/blackbox_solver/src/hash.rs index af503117466..660a1fb0e5d 100644 --- a/acvm-repo/blackbox_solver/src/hash.rs +++ b/acvm-repo/blackbox_solver/src/hash.rs @@ -1,7 +1,6 @@ use acir::BlackBoxFunc; use blake2::digest::generic_array::GenericArray; use blake2::{Blake2s256, Digest}; -use sha3::Keccak256; use crate::BlackBoxResolutionError; @@ -22,11 +21,6 @@ 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)) -} - pub fn sha256_compression(state: &mut [u32; 8], msg_blocks: &[u32; 16]) { let mut blocks = [0_u8; 64]; for (i, block) in msg_blocks.iter().enumerate() { diff --git a/acvm-repo/blackbox_solver/src/lib.rs b/acvm-repo/blackbox_solver/src/lib.rs index 87ca539f435..d8f926fcb4b 100644 --- a/acvm-repo/blackbox_solver/src/lib.rs +++ b/acvm-repo/blackbox_solver/src/lib.rs @@ -5,7 +5,7 @@ //! This crate provides the implementation of BlackBox functions of ACIR and Brillig. //! For functions that are backend-dependent, it provides a Trait [BlackBoxFunctionSolver] that must be implemented by the backend. -//! For functions that have a reference implementation, such as [keccak256], this crate exports the reference implementation directly. +//! For functions that have a reference implementation, such as [keccakf1600], this crate exports the reference implementation directly. use acir::BlackBoxFunc; use thiserror::Error; @@ -21,7 +21,7 @@ pub use aes128::aes128_encrypt; pub use bigint::BigIntSolver; pub use curve_specific_solver::{BlackBoxFunctionSolver, StubbedBlackBoxSolver}; pub use ecdsa::{ecdsa_secp256k1_verify, ecdsa_secp256r1_verify}; -pub use hash::{blake2s, blake3, keccak256, keccakf1600, sha256_compression}; +pub use hash::{blake2s, blake3, keccakf1600, sha256_compression}; pub use logic::{bit_and, bit_xor}; #[derive(Clone, PartialEq, Eq, Debug, Error)] diff --git a/acvm-repo/bn254_blackbox_solver/src/lib.rs b/acvm-repo/bn254_blackbox_solver/src/lib.rs index 952c4498d84..d74c17a52b5 100644 --- a/acvm-repo/bn254_blackbox_solver/src/lib.rs +++ b/acvm-repo/bn254_blackbox_solver/src/lib.rs @@ -10,7 +10,6 @@ mod pedersen; mod poseidon2; mod schnorr; -use ark_ec::AffineRepr; pub use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul}; pub use generator::generators::derive_generators; pub use poseidon2::{ @@ -44,33 +43,6 @@ impl BlackBoxFunctionSolver for Bn254BlackBoxSolver { )) } - fn pedersen_commitment( - &self, - inputs: &[FieldElement], - domain_separator: u32, - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - let inputs: Vec = inputs.iter().map(|input| input.into_repr()).collect(); - let result = pedersen::commitment::commit_native_with_index(&inputs, domain_separator); - let result = if let Some((x, y)) = result.xy() { - (FieldElement::from_repr(*x), FieldElement::from_repr(*y)) - } else { - (FieldElement::from(0_u128), FieldElement::from(0_u128)) - }; - - Ok(result) - } - - fn pedersen_hash( - &self, - inputs: &[FieldElement], - domain_separator: u32, - ) -> Result { - let inputs: Vec = inputs.iter().map(|input| input.into_repr()).collect(); - let result = pedersen::hash::hash_with_index(&inputs, domain_separator); - let result = FieldElement::from_repr(result); - Ok(result) - } - fn multi_scalar_mul( &self, points: &[FieldElement], diff --git a/acvm-repo/brillig/src/black_box.rs b/acvm-repo/brillig/src/black_box.rs index 534ef7d318e..b61c2272587 100644 --- a/acvm-repo/brillig/src/black_box.rs +++ b/acvm-repo/brillig/src/black_box.rs @@ -22,11 +22,6 @@ pub enum BlackBoxOp { message: HeapVector, output: HeapArray, }, - /// Calculates the Keccak256 hash of the inputs. - Keccak256 { - message: HeapVector, - output: HeapArray, - }, /// Keccak Permutation function of 1600 width Keccakf1600 { message: HeapVector, @@ -56,18 +51,6 @@ pub enum BlackBoxOp { signature: HeapVector, result: MemoryAddress, }, - /// Will be deprecated - PedersenCommitment { - inputs: HeapVector, - domain_separator: MemoryAddress, - output: HeapArray, - }, - /// Will be deprecated - PedersenHash { - inputs: HeapVector, - domain_separator: MemoryAddress, - output: MemoryAddress, - }, /// Performs multi scalar multiplication over the embedded curve. MultiScalarMul { points: HeapVector, diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index 45df2aca2d8..69ca9ed379a 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -5,18 +5,53 @@ use serde::{Deserialize, Serialize}; pub type Label = usize; #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)] -pub struct MemoryAddress(pub usize); +pub enum MemoryAddress { + Direct(usize), + Relative(usize), +} /// `MemoryAddress` refers to the index in VM memory. impl MemoryAddress { + pub fn direct(address: usize) -> Self { + MemoryAddress::Direct(address) + } + pub fn relative(offset: usize) -> Self { + MemoryAddress::Relative(offset) + } + + pub fn unwrap_direct(self) -> usize { + match self { + MemoryAddress::Direct(address) => address, + MemoryAddress::Relative(_) => panic!("Expected direct memory address"), + } + } + + pub fn unwrap_relative(self) -> usize { + match self { + MemoryAddress::Direct(_) => panic!("Expected relative memory address"), + MemoryAddress::Relative(offset) => offset, + } + } + pub fn to_usize(self) -> usize { - self.0 + match self { + MemoryAddress::Direct(address) => address, + MemoryAddress::Relative(offset) => offset, + } + } + + pub fn is_relative(&self) -> bool { + match self { + MemoryAddress::Relative(_) => true, + MemoryAddress::Direct(_) => false, + } } -} -impl From for MemoryAddress { - fn from(value: usize) -> Self { - MemoryAddress(value) + pub fn offset(&self, amount: usize) -> Self { + match self { + MemoryAddress::Direct(address) => MemoryAddress::Direct(address + amount), + MemoryAddress::Relative(offset) => MemoryAddress::Relative(offset + amount), + } } } @@ -54,7 +89,7 @@ pub struct HeapArray { impl Default for HeapArray { fn default() -> Self { - Self { pointer: MemoryAddress(0), size: 0 } + Self { pointer: MemoryAddress::direct(0), size: 0 } } } @@ -67,7 +102,6 @@ pub struct HeapVector { #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord)] pub enum IntegerBitSize { - U0, // Uninitialized U1, U8, U16, @@ -79,7 +113,6 @@ pub enum IntegerBitSize { impl From for u32 { fn from(bit_size: IntegerBitSize) -> u32 { match bit_size { - IntegerBitSize::U0 => 0, IntegerBitSize::U1 => 1, IntegerBitSize::U8 => 8, IntegerBitSize::U16 => 16, @@ -95,7 +128,6 @@ impl TryFrom for IntegerBitSize { fn try_from(value: u32) -> Result { match value { - 0 => Ok(IntegerBitSize::U0), 1 => Ok(IntegerBitSize::U1), 8 => Ok(IntegerBitSize::U8), 16 => Ok(IntegerBitSize::U16), @@ -110,7 +142,6 @@ impl TryFrom for IntegerBitSize { impl std::fmt::Display for IntegerBitSize { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { match self { - IntegerBitSize::U0 => write!(f, "null"), IntegerBitSize::U1 => write!(f, "bool"), IntegerBitSize::U8 => write!(f, "u8"), IntegerBitSize::U16 => write!(f, "u16"), diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index 56f715c13a9..4201d2ddba2 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -2,8 +2,8 @@ use acir::brillig::{BlackBoxOp, HeapArray, HeapVector, IntegerBitSize}; use acir::{AcirField, BlackBoxFunc}; use acvm_blackbox_solver::BigIntSolver; use acvm_blackbox_solver::{ - aes128_encrypt, blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccak256, - keccakf1600, sha256_compression, BlackBoxFunctionSolver, BlackBoxResolutionError, + aes128_encrypt, blake2s, blake3, ecdsa_secp256k1_verify, ecdsa_secp256r1_verify, keccakf1600, + sha256_compression, BlackBoxFunctionSolver, BlackBoxResolutionError, }; use num_bigint::BigUint; use num_traits::Zero; @@ -77,12 +77,6 @@ pub(crate) fn evaluate_black_box memory.write_slice(memory.read_ref(output.pointer), &to_value_vec(&bytes)); Ok(()) } - BlackBoxOp::Keccak256 { message, output } => { - let message = to_u8_vec(read_heap_vector(memory, message)); - let bytes = keccak256(message.as_slice())?; - memory.write_slice(memory.read_ref(output.pointer), &to_value_vec(&bytes)); - Ok(()) - } BlackBoxOp::Keccakf1600 { message, output } => { let state_vec: Vec = read_heap_vector(memory, message) .iter() @@ -227,41 +221,6 @@ pub(crate) fn evaluate_black_box ); Ok(()) } - BlackBoxOp::PedersenCommitment { inputs, domain_separator, output } => { - let inputs: Vec = read_heap_vector(memory, inputs) - .iter() - .map(|x| *x.extract_field().unwrap()) - .collect(); - let domain_separator: u32 = - memory.read(*domain_separator).try_into().map_err(|_| { - BlackBoxResolutionError::Failed( - BlackBoxFunc::PedersenCommitment, - "Invalid separator length".to_string(), - ) - })?; - let (x, y) = solver.pedersen_commitment(&inputs, domain_separator)?; - memory.write_slice( - memory.read_ref(output.pointer), - &[MemoryValue::new_field(x), MemoryValue::new_field(y)], - ); - Ok(()) - } - BlackBoxOp::PedersenHash { inputs, domain_separator, output } => { - let inputs: Vec = read_heap_vector(memory, inputs) - .iter() - .map(|x| *x.extract_field().unwrap()) - .collect(); - let domain_separator: u32 = - memory.read(*domain_separator).try_into().map_err(|_| { - BlackBoxResolutionError::Failed( - BlackBoxFunc::PedersenCommitment, - "Invalid separator length".to_string(), - ) - })?; - let hash = solver.pedersen_hash(&inputs, domain_separator)?; - memory.write(*output, MemoryValue::new_field(hash)); - Ok(()) - } BlackBoxOp::BigIntAdd { lhs, rhs, output } => { let lhs = memory.read(*lhs).try_into().unwrap(); let rhs = memory.read(*rhs).try_into().unwrap(); @@ -447,7 +406,6 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { BlackBoxOp::AES128Encrypt { .. } => BlackBoxFunc::AES128Encrypt, BlackBoxOp::Blake2s { .. } => BlackBoxFunc::Blake2s, BlackBoxOp::Blake3 { .. } => BlackBoxFunc::Blake3, - BlackBoxOp::Keccak256 { .. } => BlackBoxFunc::Keccak256, BlackBoxOp::Keccakf1600 { .. } => BlackBoxFunc::Keccakf1600, BlackBoxOp::EcdsaSecp256k1 { .. } => BlackBoxFunc::EcdsaSecp256k1, BlackBoxOp::EcdsaSecp256r1 { .. } => BlackBoxFunc::EcdsaSecp256r1, @@ -463,7 +421,5 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { BlackBoxOp::Poseidon2Permutation { .. } => BlackBoxFunc::Poseidon2Permutation, BlackBoxOp::Sha256Compression { .. } => BlackBoxFunc::Sha256Compression, BlackBoxOp::ToRadix { .. } => unreachable!("ToRadix is not an ACIR BlackBoxFunc"), - BlackBoxOp::PedersenCommitment { .. } => BlackBoxFunc::PedersenCommitment, - BlackBoxOp::PedersenHash { .. } => BlackBoxFunc::PedersenHash, } } diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 07d0ea02ad4..1e5ad84eb8f 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -185,7 +185,7 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { } pub fn write_memory_at(&mut self, ptr: usize, value: MemoryValue) { - self.memory.write(MemoryAddress(ptr), value); + self.memory.write(MemoryAddress::direct(ptr), value); } /// Returns the VM's current call stack, including the actual program @@ -315,7 +315,10 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { } Opcode::Trap { revert_data } => { if revert_data.size > 0 { - self.trap(self.memory.read_ref(revert_data.pointer).0, revert_data.size) + self.trap( + self.memory.read_ref(revert_data.pointer).unwrap_direct(), + revert_data.size, + ) } else { self.trap(0, 0) } @@ -437,6 +440,7 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { size: usize, value_types: &[HeapValueType], ) -> Vec> { + assert!(!start.is_relative(), "read_slice_of_values_from_memory requires direct addresses"); if HeapValueType::all_simple(value_types) { self.memory.read_slice(start, size).to_vec() } else { @@ -449,20 +453,25 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { (0..size) .zip(value_types.iter().cycle()) .flat_map(|(i, value_type)| { - let value_address: MemoryAddress = (start.to_usize() + i).into(); + let value_address = start.offset(i); match value_type { HeapValueType::Simple(_) => { vec![self.memory.read(value_address)] } HeapValueType::Array { value_types, size } => { let array_address = self.memory.read_ref(value_address); - let items_start = MemoryAddress(array_address.to_usize() + 1); - self.read_slice_of_values_from_memory(items_start, *size, value_types) + + self.read_slice_of_values_from_memory( + array_address.offset(1), + *size, + value_types, + ) } HeapValueType::Vector { value_types } => { let vector_address = self.memory.read_ref(value_address); - let size_address = MemoryAddress(vector_address.to_usize() + 1); - let items_start = MemoryAddress(vector_address.to_usize() + 2); + let size_address = + MemoryAddress::direct(vector_address.unwrap_direct() + 1); + let items_start = vector_address.offset(2); let vector_size = self.memory.read(size_address).to_usize(); self.read_slice_of_values_from_memory( items_start, @@ -630,13 +639,17 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { values: &Vec, values_idx: &mut usize, value_type: &HeapValueType, - ) -> Result { + ) -> Result<(), String> { + assert!( + !destination.is_relative(), + "write_slice_of_values_to_memory requires direct addresses" + ); let mut current_pointer = destination; match value_type { HeapValueType::Simple(bit_size) => { self.write_value_to_memory(destination, &values[*values_idx], *bit_size)?; *values_idx += 1; - Ok(MemoryAddress(destination.to_usize() + 1)) + Ok(()) } HeapValueType::Array { value_types, size } => { for _ in 0..*size { @@ -649,18 +662,17 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { *len, )?; *values_idx += 1; - current_pointer = MemoryAddress(current_pointer.to_usize() + 1); + current_pointer = current_pointer.offset(1); } HeapValueType::Array { .. } => { - let destination = - MemoryAddress(self.memory.read_ref(current_pointer).0 + 1); + let destination = self.memory.read_ref(current_pointer).offset(1); self.write_slice_of_values_to_memory( destination, values, values_idx, typ, )?; - current_pointer = MemoryAddress(current_pointer.to_usize() + 1); + current_pointer = current_pointer.offset(1); } HeapValueType::Vector { .. } => { return Err(format!( @@ -671,7 +683,7 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { } } } - Ok(current_pointer) + Ok(()) } HeapValueType::Vector { .. } => { Err(format!("Unsupported returned type in foreign calls {:?}", value_type)) @@ -795,7 +807,7 @@ mod tests { let calldata = vec![]; let opcodes = [Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(27u128), }]; @@ -809,7 +821,7 @@ mod tests { // The address at index `2` should have the value of 3 since we had an // add opcode let VM { memory, .. } = vm; - let output_value = memory.read(MemoryAddress::from(0)); + let output_value = memory.read(MemoryAddress::direct(0)); assert_eq!(output_value.to_field(), FieldElement::from(27u128)); } @@ -820,31 +832,31 @@ mod tests { let lhs = { calldata.push(2u128.into()); - MemoryAddress::from(calldata.len() - 1) + MemoryAddress::direct(calldata.len() - 1) }; let rhs = { calldata.push(2u128.into()); - MemoryAddress::from(calldata.len() - 1) + MemoryAddress::direct(calldata.len() - 1) }; - let destination = MemoryAddress::from(calldata.len()); + let destination = MemoryAddress::direct(calldata.len()); let opcodes = vec![ Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(2u64), }, Opcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, Opcode::BinaryFieldOp { destination, op: BinaryFieldOp::Equals, lhs, rhs }, Opcode::Jump { location: 5 }, @@ -878,34 +890,34 @@ mod tests { let opcodes = vec![ Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(2u64), }, Opcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, Opcode::Jump { location: 5 }, Opcode::Trap { revert_data: HeapArray::default() }, Opcode::BinaryFieldOp { op: BinaryFieldOp::Equals, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(2), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(1), + destination: MemoryAddress::direct(2), }, - Opcode::JumpIfNot { condition: MemoryAddress::from(2), location: 4 }, + Opcode::JumpIfNot { condition: MemoryAddress::direct(2), location: 4 }, Opcode::BinaryFieldOp { op: BinaryFieldOp::Add, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(2), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(1), + destination: MemoryAddress::direct(2), }, ]; @@ -922,7 +934,7 @@ mod tests { let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let output_cmp_value = vm.memory.read(MemoryAddress::from(2)); + let output_cmp_value = vm.memory.read(MemoryAddress::direct(2)); assert_eq!(output_cmp_value.to_field(), false.into()); let status = vm.process_opcode(); @@ -939,7 +951,7 @@ mod tests { // The address at index `2` should have not changed as we jumped over the add opcode let VM { memory, .. } = vm; - let output_value = memory.read(MemoryAddress::from(2)); + let output_value = memory.read(MemoryAddress::direct(2)); assert_eq!(output_value.to_field(), false.into()); } @@ -949,23 +961,23 @@ mod tests { let opcodes = &[ Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(1u64), }, Opcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, Opcode::Cast { - destination: MemoryAddress::from(1), - source: MemoryAddress::from(0), + destination: MemoryAddress::direct(1), + source: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U8), }, Opcode::Stop { return_data_offset: 1, return_data_size: 1 }, @@ -985,7 +997,7 @@ mod tests { let VM { memory, .. } = vm; - let casted_value = memory.read(MemoryAddress::from(1)); + let casted_value = memory.read(MemoryAddress::direct(1)); assert_eq!(casted_value.to_field(), (2_u128.pow(8) - 1).into()); } @@ -995,28 +1007,28 @@ mod tests { let opcodes = &[ Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(1u64), }, Opcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, Opcode::Cast { - destination: MemoryAddress::from(1), - source: MemoryAddress::from(0), + destination: MemoryAddress::direct(1), + source: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U128), }, Opcode::Not { - destination: MemoryAddress::from(1), - source: MemoryAddress::from(1), + destination: MemoryAddress::direct(1), + source: MemoryAddress::direct(1), bit_size: IntegerBitSize::U128, }, Opcode::Stop { return_data_offset: 1, return_data_size: 1 }, @@ -1039,7 +1051,7 @@ mod tests { let VM { memory, .. } = vm; let (negated_value, _) = memory - .read(MemoryAddress::from(1)) + .read(MemoryAddress::direct(1)) .extract_integer() .expect("Expected integer as the output of Not"); assert_eq!(negated_value, !1_u128); @@ -1051,21 +1063,21 @@ mod tests { let opcodes = &[ Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(3u64), }, Opcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, - Opcode::Mov { destination: MemoryAddress::from(2), source: MemoryAddress::from(0) }, + Opcode::Mov { destination: MemoryAddress::direct(2), source: MemoryAddress::direct(0) }, ]; let mut vm = VM::new(calldata, opcodes, vec![], &StubbedBlackBoxSolver); @@ -1081,10 +1093,10 @@ mod tests { let VM { memory, .. } = vm; - let destination_value = memory.read(MemoryAddress::from(2)); + let destination_value = memory.read(MemoryAddress::direct(2)); assert_eq!(destination_value.to_field(), (1u128).into()); - let source_value = memory.read(MemoryAddress::from(0)); + let source_value = memory.read(MemoryAddress::direct(0)); assert_eq!(source_value.to_field(), (1u128).into()); } @@ -1095,41 +1107,41 @@ mod tests { let opcodes = &[ Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(4u64), }, Opcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, Opcode::Cast { - destination: MemoryAddress::from(0), - source: MemoryAddress::from(0), + destination: MemoryAddress::direct(0), + source: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U1), }, Opcode::Cast { - destination: MemoryAddress::from(1), - source: MemoryAddress::from(1), + destination: MemoryAddress::direct(1), + source: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U1), }, Opcode::ConditionalMov { - destination: MemoryAddress(4), // Sets 3_u128 to memory address 4 - source_a: MemoryAddress(2), - source_b: MemoryAddress(3), - condition: MemoryAddress(0), + destination: MemoryAddress::direct(4), // Sets 3_u128 to memory address 4 + source_a: MemoryAddress::direct(2), + source_b: MemoryAddress::direct(3), + condition: MemoryAddress::direct(0), }, Opcode::ConditionalMov { - destination: MemoryAddress(5), // Sets 2_u128 to memory address 5 - source_a: MemoryAddress(2), - source_b: MemoryAddress(3), - condition: MemoryAddress(1), + destination: MemoryAddress::direct(5), // Sets 2_u128 to memory address 5 + source_a: MemoryAddress::direct(2), + source_b: MemoryAddress::direct(3), + condition: MemoryAddress::direct(1), }, ]; let mut vm = VM::new(calldata, opcodes, vec![], &StubbedBlackBoxSolver); @@ -1151,10 +1163,10 @@ mod tests { let VM { memory, .. } = vm; - let destination_value = memory.read(MemoryAddress::from(4)); + let destination_value = memory.read(MemoryAddress::direct(4)); assert_eq!(destination_value.to_field(), (3_u128).into()); - let source_value = memory.read(MemoryAddress::from(5)); + let source_value = memory.read(MemoryAddress::direct(5)); assert_eq!(source_value.to_field(), (2_u128).into()); } @@ -1167,26 +1179,26 @@ mod tests { let calldata_copy_opcodes = vec![ Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(5u64), }, Opcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, ]; let cast_opcodes: Vec<_> = (0..calldata_size) .map(|index| Opcode::Cast { - destination: MemoryAddress::from(index), - source: MemoryAddress::from(index), + destination: MemoryAddress::direct(index), + source: MemoryAddress::direct(index), bit_size: BitSize::Integer(bit_size), }) .collect(); @@ -1194,33 +1206,33 @@ mod tests { let equal_opcode = Opcode::BinaryIntOp { bit_size, op: BinaryIntOp::Equals, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(2), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(1), + destination: MemoryAddress::direct(2), }; let not_equal_opcode = Opcode::BinaryIntOp { bit_size, op: BinaryIntOp::Equals, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(3), - destination: MemoryAddress::from(2), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(3), + destination: MemoryAddress::direct(2), }; let less_than_opcode = Opcode::BinaryIntOp { bit_size, op: BinaryIntOp::LessThan, - lhs: MemoryAddress::from(3), - rhs: MemoryAddress::from(4), - destination: MemoryAddress::from(2), + lhs: MemoryAddress::direct(3), + rhs: MemoryAddress::direct(4), + destination: MemoryAddress::direct(2), }; let less_than_equal_opcode = Opcode::BinaryIntOp { bit_size, op: BinaryIntOp::LessThanEquals, - lhs: MemoryAddress::from(3), - rhs: MemoryAddress::from(4), - destination: MemoryAddress::from(2), + lhs: MemoryAddress::direct(3), + rhs: MemoryAddress::direct(4), + destination: MemoryAddress::direct(2), }; let opcodes: Vec<_> = calldata_copy_opcodes @@ -1247,25 +1259,25 @@ mod tests { let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let output_eq_value = vm.memory.read(MemoryAddress::from(2)); + let output_eq_value = vm.memory.read(MemoryAddress::direct(2)); assert_eq!(output_eq_value, true.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let output_neq_value = vm.memory.read(MemoryAddress::from(2)); + let output_neq_value = vm.memory.read(MemoryAddress::direct(2)); assert_eq!(output_neq_value, false.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::InProgress); - let lt_value = vm.memory.read(MemoryAddress::from(2)); + let lt_value = vm.memory.read(MemoryAddress::direct(2)); assert_eq!(lt_value, true.into()); let status = vm.process_opcode(); assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); - let lte_value = vm.memory.read(MemoryAddress::from(2)); + let lte_value = vm.memory.read(MemoryAddress::direct(2)); assert_eq!(lte_value, true.into()); } @@ -1281,10 +1293,10 @@ mod tests { fn brillig_write_memory(item_count: usize) -> Vec> { let integer_bit_size = MEMORY_ADDRESSING_BIT_SIZE; let bit_size = BitSize::Integer(integer_bit_size); - let r_i = MemoryAddress::from(0); - let r_len = MemoryAddress::from(1); - let r_tmp = MemoryAddress::from(2); - let r_pointer = MemoryAddress::from(3); + let r_i = MemoryAddress::direct(0); + let r_len = MemoryAddress::direct(1); + let r_tmp = MemoryAddress::direct(2); + let r_pointer = MemoryAddress::direct(3); let start: [Opcode; 3] = [ // i = 0 @@ -1346,12 +1358,12 @@ mod tests { fn iconst_opcode() { let opcodes = &[ Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), value: FieldElement::from(8_usize), }, Opcode::IndirectConst { - destination_pointer: MemoryAddress(0), + destination_pointer: MemoryAddress::direct(0), bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), value: FieldElement::from(27_usize), }, @@ -1366,7 +1378,7 @@ mod tests { let VM { memory, .. } = vm; - let destination_value = memory.read(MemoryAddress::from(8)); + let destination_value = memory.read(MemoryAddress::direct(8)); assert_eq!(destination_value.to_field(), (27_usize).into()); } @@ -1382,11 +1394,11 @@ mod tests { /// } fn brillig_sum_memory(memory: Vec) -> FieldElement { let bit_size = IntegerBitSize::U32; - let r_i = MemoryAddress::from(0); - let r_len = MemoryAddress::from(1); - let r_sum = MemoryAddress::from(2); - let r_tmp = MemoryAddress::from(3); - let r_pointer = MemoryAddress::from(4); + let r_i = MemoryAddress::direct(0); + let r_len = MemoryAddress::direct(1); + let r_sum = MemoryAddress::direct(2); + let r_tmp = MemoryAddress::direct(3); + let r_pointer = MemoryAddress::direct(4); let start = [ // sum = 0 @@ -1410,19 +1422,19 @@ mod tests { bit_size: BitSize::Integer(bit_size), }, Opcode::Const { - destination: MemoryAddress(100), + destination: MemoryAddress::direct(100), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(memory.len() as u32), }, Opcode::Const { - destination: MemoryAddress(101), + destination: MemoryAddress::direct(101), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(5), - size_address: MemoryAddress(100), - offset_address: MemoryAddress(101), + destination_address: MemoryAddress::direct(5), + size_address: MemoryAddress::direct(100), + offset_address: MemoryAddress::direct(101), }, ]; let loop_body = [ @@ -1501,10 +1513,10 @@ mod tests { fn brillig_recursive_write_memory(size: usize) -> Vec> { let integer_bit_size = MEMORY_ADDRESSING_BIT_SIZE; let bit_size = BitSize::Integer(integer_bit_size); - let r_i = MemoryAddress::from(0); - let r_len = MemoryAddress::from(1); - let r_tmp = MemoryAddress::from(2); - let r_pointer = MemoryAddress::from(3); + let r_i = MemoryAddress::direct(0); + let r_len = MemoryAddress::direct(1); + let r_tmp = MemoryAddress::direct(2); + let r_pointer = MemoryAddress::direct(3); let start: [Opcode; 5] = [ // i = 0 @@ -1598,8 +1610,8 @@ mod tests { #[test] fn foreign_call_opcode_simple_result() { - let r_input = MemoryAddress::from(0); - let r_result = MemoryAddress::from(1); + let r_input = MemoryAddress::direct(0); + let r_result = MemoryAddress::direct(1); let double_program = vec![ // Load input address with value 5 @@ -1654,8 +1666,8 @@ mod tests { #[test] fn foreign_call_opcode_memory_result() { - let r_input = MemoryAddress::from(0); - let r_output = MemoryAddress::from(1); + let r_input = MemoryAddress::direct(0); + let r_output = MemoryAddress::direct(1); // Define a simple 2x2 matrix in memory let initial_matrix: Vec = @@ -1667,19 +1679,19 @@ mod tests { let invert_program = vec![ Opcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(initial_matrix.len() as u32), }, Opcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(2), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(2), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, // input = 0 Opcode::Const { @@ -1736,7 +1748,7 @@ mod tests { assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); // Check result in memory - let result_values = vm.memory.read_slice(MemoryAddress(2), 4).to_vec(); + let result_values = vm.memory.read_slice(MemoryAddress::direct(2), 4).to_vec(); assert_eq!( result_values.into_iter().map(|mem_value| mem_value.to_field()).collect::>(), expected_result @@ -1749,11 +1761,11 @@ mod tests { /// Calling a simple foreign call function that takes any string input, concatenates it with itself, and reverses the concatenation #[test] fn foreign_call_opcode_vector_input_and_output() { - let r_input_pointer = MemoryAddress::from(0); - let r_input_size = MemoryAddress::from(1); + let r_input_pointer = MemoryAddress::direct(0); + let r_input_size = MemoryAddress::direct(1); // We need to pass a location of appropriate size - let r_output_pointer = MemoryAddress::from(2); - let r_output_size = MemoryAddress::from(3); + let r_output_pointer = MemoryAddress::direct(2); + let r_output_size = MemoryAddress::direct(3); // Our first string to use the identity function with let input_string: Vec = @@ -1767,19 +1779,19 @@ mod tests { // First call: let string_double_program = vec![ Opcode::Const { - destination: MemoryAddress(100), + destination: MemoryAddress::direct(100), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(input_string.len() as u32), }, Opcode::Const { - destination: MemoryAddress(101), + destination: MemoryAddress::direct(101), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(4), - size_address: MemoryAddress(100), - offset_address: MemoryAddress(101), + destination_address: MemoryAddress::direct(4), + size_address: MemoryAddress::direct(100), + offset_address: MemoryAddress::direct(101), }, // input_pointer = 4 Opcode::Const { @@ -1850,7 +1862,7 @@ mod tests { // Check result in memory let result_values: Vec<_> = vm .memory - .read_slice(MemoryAddress(4 + input_string.len()), output_string.len()) + .read_slice(MemoryAddress::direct(4 + input_string.len()), output_string.len()) .iter() .map(|mem_val| mem_val.clone().to_field()) .collect(); @@ -1862,8 +1874,8 @@ mod tests { #[test] fn foreign_call_opcode_memory_alloc_result() { - let r_input = MemoryAddress::from(0); - let r_output = MemoryAddress::from(1); + let r_input = MemoryAddress::direct(0); + let r_output = MemoryAddress::direct(1); // Define a simple 2x2 matrix in memory let initial_matrix: Vec = @@ -1875,19 +1887,19 @@ mod tests { let invert_program = vec![ Opcode::Const { - destination: MemoryAddress(100), + destination: MemoryAddress::direct(100), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(initial_matrix.len() as u32), }, Opcode::Const { - destination: MemoryAddress(101), + destination: MemoryAddress::direct(101), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(2), - size_address: MemoryAddress(100), - offset_address: MemoryAddress(101), + destination_address: MemoryAddress::direct(2), + size_address: MemoryAddress::direct(100), + offset_address: MemoryAddress::direct(101), }, // input = 0 Opcode::Const { @@ -1946,7 +1958,7 @@ mod tests { // Check initial memory still in place let initial_values: Vec<_> = vm .memory - .read_slice(MemoryAddress(2), 4) + .read_slice(MemoryAddress::direct(2), 4) .iter() .map(|mem_val| mem_val.clone().to_field()) .collect(); @@ -1955,7 +1967,7 @@ mod tests { // Check result in memory let result_values: Vec<_> = vm .memory - .read_slice(MemoryAddress(6), 4) + .read_slice(MemoryAddress::direct(6), 4) .iter() .map(|mem_val| mem_val.clone().to_field()) .collect(); @@ -1967,9 +1979,9 @@ mod tests { #[test] fn foreign_call_opcode_multiple_array_inputs_result() { - let r_input_a = MemoryAddress::from(0); - let r_input_b = MemoryAddress::from(1); - let r_output = MemoryAddress::from(2); + let r_input_a = MemoryAddress::direct(0); + let r_input_b = MemoryAddress::direct(1); + let r_output = MemoryAddress::direct(2); // Define a simple 2x2 matrix in memory let matrix_a: Vec = @@ -1984,19 +1996,19 @@ mod tests { let matrix_mul_program = vec![ Opcode::Const { - destination: MemoryAddress(100), + destination: MemoryAddress::direct(100), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(matrix_a.len() + matrix_b.len()), }, Opcode::Const { - destination: MemoryAddress(101), + destination: MemoryAddress::direct(101), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(3), - size_address: MemoryAddress(100), - offset_address: MemoryAddress(101), + destination_address: MemoryAddress::direct(3), + size_address: MemoryAddress::direct(100), + offset_address: MemoryAddress::direct(101), }, // input = 3 Opcode::Const { @@ -2068,7 +2080,7 @@ mod tests { // Check result in memory let result_values: Vec<_> = vm .memory - .read_slice(MemoryAddress(0), 4) + .read_slice(MemoryAddress::direct(0), 4) .iter() .map(|mem_val| mem_val.clone().to_field()) .collect(); @@ -2135,30 +2147,30 @@ mod tests { // memory address of the end of the above data structures let r_ptr = memory.len(); - let r_input = MemoryAddress::from(r_ptr); - let r_output = MemoryAddress::from(r_ptr + 1); + let r_input = MemoryAddress::direct(r_ptr); + let r_output = MemoryAddress::direct(r_ptr + 1); let program: Vec<_> = vec![ Opcode::Const { - destination: MemoryAddress(100), + destination: MemoryAddress::direct(100), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(memory.len()), }, Opcode::Const { - destination: MemoryAddress(101), + destination: MemoryAddress::direct(101), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, Opcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(100), - offset_address: MemoryAddress(101), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(100), + offset_address: MemoryAddress::direct(101), }, ] .into_iter() .chain(memory.iter().enumerate().map(|(index, mem_value)| Opcode::Cast { - destination: MemoryAddress(index), - source: MemoryAddress(index), + destination: MemoryAddress::direct(index), + source: MemoryAddress::direct(index), bit_size: mem_value.bit_size(), })) .chain(vec![ @@ -2227,4 +2239,49 @@ mod tests { // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); } + + #[test] + fn relative_addressing() { + let calldata = vec![]; + let bit_size = BitSize::Integer(IntegerBitSize::U32); + let value = FieldElement::from(3u128); + + let opcodes = [ + Opcode::Const { + destination: MemoryAddress::direct(0), + bit_size, + value: FieldElement::from(27u128), + }, + Opcode::Const { + destination: MemoryAddress::relative(1), // Resolved address 28 value 3 + bit_size, + value, + }, + Opcode::Const { + destination: MemoryAddress::direct(1), // Address 1 value 3 + bit_size, + value, + }, + Opcode::BinaryIntOp { + destination: MemoryAddress::direct(1), + op: BinaryIntOp::Equals, + bit_size: IntegerBitSize::U32, + lhs: MemoryAddress::direct(1), + rhs: MemoryAddress::direct(28), + }, + ]; + + let mut vm = VM::new(calldata, &opcodes, vec![], &StubbedBlackBoxSolver); + + vm.process_opcode(); + vm.process_opcode(); + vm.process_opcode(); + let status = vm.process_opcode(); + assert_eq!(status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); + + let VM { memory, .. } = vm; + let output_value = memory.read(MemoryAddress::direct(1)); + + assert_eq!(output_value.to_field(), FieldElement::from(1u128)); + } } diff --git a/acvm-repo/brillig_vm/src/memory.rs b/acvm-repo/brillig_vm/src/memory.rs index ef1e0301387..2bf45f77b54 100644 --- a/acvm-repo/brillig_vm/src/memory.rs +++ b/acvm-repo/brillig_vm/src/memory.rs @@ -136,7 +136,7 @@ impl std::fmt::Display for MemoryValue { impl Default for MemoryValue { fn default() -> Self { - MemoryValue::new_integer(0, IntegerBitSize::U0) + MemoryValue::new_field(F::zero()) } } @@ -233,13 +233,25 @@ pub struct Memory { } impl Memory { - /// Gets the value at pointer - pub fn read(&self, ptr: MemoryAddress) -> MemoryValue { - self.inner.get(ptr.to_usize()).copied().unwrap_or_default() + fn get_stack_pointer(&self) -> usize { + self.read(MemoryAddress::Direct(0)).to_usize() + } + + fn resolve(&self, address: MemoryAddress) -> usize { + match address { + MemoryAddress::Direct(address) => address, + MemoryAddress::Relative(offset) => self.get_stack_pointer() + offset, + } + } + + /// Gets the value at address + pub fn read(&self, address: MemoryAddress) -> MemoryValue { + let resolved_addr = self.resolve(address); + self.inner.get(resolved_addr).copied().unwrap_or_default() } pub fn read_ref(&self, ptr: MemoryAddress) -> MemoryAddress { - MemoryAddress(self.read(ptr).to_usize()) + MemoryAddress::direct(self.read(ptr).to_usize()) } pub fn read_slice(&self, addr: MemoryAddress, len: usize) -> &[MemoryValue] { @@ -249,13 +261,15 @@ impl Memory { if len == 0 { return &[]; } - &self.inner[addr.to_usize()..(addr.to_usize() + len)] + let resolved_addr = self.resolve(addr); + &self.inner[resolved_addr..(resolved_addr + len)] } - /// Sets the value at pointer `ptr` to `value` - pub fn write(&mut self, ptr: MemoryAddress, value: MemoryValue) { - self.resize_to_fit(ptr.to_usize() + 1); - self.inner[ptr.to_usize()] = value; + /// Sets the value at `address` to `value` + pub fn write(&mut self, address: MemoryAddress, value: MemoryValue) { + let resolved_ptr = self.resolve(address); + self.resize_to_fit(resolved_ptr + 1); + self.inner[resolved_ptr] = value; } fn resize_to_fit(&mut self, size: usize) { @@ -265,10 +279,11 @@ impl Memory { self.inner.resize(new_size, MemoryValue::default()); } - /// Sets the values after pointer `ptr` to `values` - pub fn write_slice(&mut self, ptr: MemoryAddress, values: &[MemoryValue]) { - self.resize_to_fit(ptr.to_usize() + values.len()); - self.inner[ptr.to_usize()..(ptr.to_usize() + values.len())].copy_from_slice(values); + /// Sets the values after `address` to `values` + pub fn write_slice(&mut self, address: MemoryAddress, values: &[MemoryValue]) { + let resolved_address = self.resolve(address); + self.resize_to_fit(resolved_address + values.len()); + self.inner[resolved_address..(resolved_address + values.len())].copy_from_slice(values); } /// Returns the values of the memory diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index f7270a6e4ed..c4e2491a5fe 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -125,6 +125,12 @@ pub struct CompileOptions { /// This check should always be run on production code. #[arg(long)] pub skip_underconstrained_check: bool, + + /// Setting to decide on an inlining strategy for brillig functions. + /// A more aggressive inliner should generate larger programs but more optimized + /// A less aggressive inliner should generate smaller programs + #[arg(long, hide = true, allow_hyphen_values = true, default_value_t = i64::MAX)] + pub inliner_aggressiveness: i64, } pub fn parse_expression_width(input: &str) -> Result { @@ -449,14 +455,12 @@ fn compile_contract_inner( .attributes .secondary .iter() - .filter_map(|attr| { - if let SecondaryAttribute::Tag(attribute) = attr { - Some(&attribute.contents) - } else { - None + .filter_map(|attr| match attr { + SecondaryAttribute::Tag(attribute) | SecondaryAttribute::Meta(attribute) => { + Some(attribute.contents.clone()) } + _ => None, }) - .cloned() .collect(); functions.push(ContractFunction { @@ -585,6 +589,7 @@ pub fn compile_no_check( }, emit_ssa: if options.emit_ssa { Some(context.package_build_path.clone()) } else { None }, skip_underconstrained_check: options.skip_underconstrained_check, + inliner_aggressiveness: options.inliner_aggressiveness, }; let SsaProgramArtifact { program, debug, warnings, names, brillig_names, error_types, .. } = diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen.rs index 628ec9657f2..313fd65a197 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen.rs @@ -27,6 +27,8 @@ pub(crate) fn convert_ssa_function( brillig_context.enter_context(Label::function(func.id())); + brillig_context.call_check_max_stack_depth_procedure(); + for block in function_context.blocks.clone() { BrilligBlock::compile(&mut function_context, &mut brillig_context, block, &func.dfg); } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 889af07fbef..10c0e8b8e8c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -7,9 +7,7 @@ use acvm::{ }; use crate::brillig::brillig_ir::{ - brillig_variable::{BrilligVariable, SingleAddrVariable}, - debug_show::DebugToString, - registers::RegisterAllocator, + brillig_variable::BrilligVariable, debug_show::DebugToString, registers::RegisterAllocator, BrilligBinaryOp, BrilligContext, }; @@ -61,33 +59,6 @@ pub(crate) fn convert_black_box_call { - if let ( - [message, BrilligVariable::SingleAddr(message_size)], - [BrilligVariable::BrilligArray(result_array)], - ) = (function_arguments, function_results) - { - let message_vector = convert_array_or_vector(brillig_context, *message, bb_func); - let output_heap_array = - brillig_context.codegen_brillig_array_to_heap_array(*result_array); - - // Message_size is not usize - brillig_context.cast_instruction( - SingleAddrVariable::new_usize(message_vector.size), - *message_size, - ); - - brillig_context.black_box_op_instruction(BlackBoxOp::Keccak256 { - message: message_vector, - output: output_heap_array, - }); - - brillig_context.deallocate_heap_vector(message_vector); - brillig_context.deallocate_heap_array(output_heap_array); - } else { - unreachable!("ICE: Keccak256 expects message, message size and result array") - } - } BlackBoxFunc::Keccakf1600 => { if let ([message], [BrilligVariable::BrilligArray(result_array)]) = (function_arguments, function_results) @@ -170,42 +141,6 @@ pub(crate) fn convert_black_box_call { - if let ( - [message, BrilligVariable::SingleAddr(domain_separator)], - [BrilligVariable::BrilligArray(result_array)], - ) = (function_arguments, function_results) - { - let inputs = convert_array_or_vector(brillig_context, *message, bb_func); - let output = brillig_context.codegen_brillig_array_to_heap_array(*result_array); - brillig_context.black_box_op_instruction(BlackBoxOp::PedersenCommitment { - inputs, - domain_separator: domain_separator.address, - output, - }); - brillig_context.deallocate_heap_vector(inputs); - brillig_context.deallocate_heap_array(output); - } else { - unreachable!("ICE: Pedersen expects one array argument, a register for the domain separator, and one array result") - } - } - BlackBoxFunc::PedersenHash => { - if let ( - [message, BrilligVariable::SingleAddr(domain_separator)], - [BrilligVariable::SingleAddr(result)], - ) = (function_arguments, function_results) - { - let inputs = convert_array_or_vector(brillig_context, *message, bb_func); - brillig_context.black_box_op_instruction(BlackBoxOp::PedersenHash { - inputs, - domain_separator: domain_separator.address, - output: result.address, - }); - brillig_context.deallocate_heap_vector(inputs); - } else { - unreachable!("ICE: Pedersen hash expects one array argument, a register for the domain separator, and one register result") - } - } BlackBoxFunc::SchnorrVerify => { if let ( [BrilligVariable::SingleAddr(public_key_x), BrilligVariable::SingleAddr(public_key_y), signature, message], diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index e764c81b023..deaae6a05cc 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -783,26 +783,9 @@ impl<'block> BrilligBlock<'block> { dfg: &DataFlowGraph, result_ids: &[ValueId], ) { - // Convert the arguments to registers casting those to the types of the receiving function - let argument_registers: Vec = arguments - .iter() - .map(|argument_id| self.convert_ssa_value(*argument_id, dfg).extract_register()) - .collect(); - - let variables_to_save = self.variables.get_available_variables(self.function_context); - - let saved_registers = self - .brillig_context - .codegen_pre_call_save_registers_prep_args(&argument_registers, &variables_to_save); - - // Call instruction, which will interpret above registers 0..num args - self.brillig_context.add_external_call_instruction(func_id); - - // Important: resolve after pre_call_save_registers_prep_args - // This ensures we don't save the results to registers unnecessarily. - - // Allocate the registers for the variables where we are assigning the returns - let variables_assigned_to = vecmap(result_ids, |result_id| { + let argument_variables = + vecmap(arguments, |argument_id| self.convert_ssa_value(*argument_id, dfg)); + let return_variables = vecmap(result_ids, |result_id| { self.variables.define_variable( self.function_context, self.brillig_context, @@ -810,26 +793,7 @@ impl<'block> BrilligBlock<'block> { dfg, ) }); - - // Collect the registers that should have been returned - let returned_registers: Vec = variables_assigned_to - .iter() - .map(|returned_variable| returned_variable.extract_register()) - .collect(); - - assert!( - !saved_registers.iter().any(|x| returned_registers.contains(x)), - "should not save registers used as function results" - ); - - // puts the returns into the returned_registers and restores saved_registers - self.brillig_context - .codegen_post_call_prep_returns_load_registers(&returned_registers, &saved_registers); - - // Reset the register state to the one needed to hold the current available variables - let variables = self.variables.get_available_variables(self.function_context); - let registers = variables.into_iter().map(|variable| variable.extract_register()).collect(); - self.brillig_context.set_allocated_registers(registers); + self.brillig_context.codegen_call(func_id, &argument_variables, &return_variables); } fn validate_array_index( @@ -1310,12 +1274,13 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.binary_instruction(zero, num, twos_complement, BrilligBinaryOp::Sub); // absolute_value = result_is_negative ? twos_complement : num - self.brillig_context.conditional_mov_instruction( - absolute_value.address, - result_is_negative.address, - twos_complement.address, - num.address, - ); + self.brillig_context.codegen_branch(result_is_negative.address, |ctx, is_negative| { + if is_negative { + ctx.mov_instruction(absolute_value.address, twos_complement.address); + } else { + ctx.mov_instruction(absolute_value.address, num.address); + } + }); self.brillig_context.deallocate_single_addr(zero); self.brillig_context.deallocate_single_addr(max_positive); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index faf4242a9ca..f066d967e0d 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -14,29 +14,29 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { // The input argument, ie the value that will be inverted. // We store the result in this register too. - let input = MemoryAddress::from(0); - let one_const = MemoryAddress::from(1); - let zero_const = MemoryAddress::from(2); - let input_is_zero = MemoryAddress::from(3); + let input = MemoryAddress::direct(0); + let one_const = MemoryAddress::direct(1); + let zero_const = MemoryAddress::direct(2); + let input_is_zero = MemoryAddress::direct(3); // Location of the stop opcode let stop_location = 8; GeneratedBrillig { byte_code: vec![ BrilligOpcode::Const { - destination: MemoryAddress(20), + destination: MemoryAddress::direct(20), bit_size: BitSize::Integer(IntegerBitSize::U32), value: F::from(1_usize), }, BrilligOpcode::Const { - destination: MemoryAddress::from(21), + destination: MemoryAddress::direct(21), bit_size: BitSize::Integer(IntegerBitSize::U32), value: F::from(0_usize), }, BrilligOpcode::CalldataCopy { destination_address: input, - size_address: MemoryAddress::from(20), - offset_address: MemoryAddress::from(21), + size_address: MemoryAddress::direct(20), + offset_address: MemoryAddress::direct(21), }, // Put value zero in register (2) BrilligOpcode::Const { @@ -89,46 +89,46 @@ pub(crate) fn directive_quotient() -> GeneratedBrillig { GeneratedBrillig { byte_code: vec![ BrilligOpcode::Const { - destination: MemoryAddress::from(10), + destination: MemoryAddress::direct(10), bit_size: BitSize::Integer(IntegerBitSize::U32), value: F::from(2_usize), }, BrilligOpcode::Const { - destination: MemoryAddress::from(11), + destination: MemoryAddress::direct(11), bit_size: BitSize::Integer(IntegerBitSize::U32), value: F::from(0_usize), }, BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress::from(0), - size_address: MemoryAddress::from(10), - offset_address: MemoryAddress::from(11), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(10), + offset_address: MemoryAddress::direct(11), }, // No cast, since calldata is typed as field by default //q = a/b is set into register (2) BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::IntegerDiv, // We want integer division, not field division! - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(2), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(1), + destination: MemoryAddress::direct(2), }, //(1)= q*b BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Mul, - lhs: MemoryAddress::from(2), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(1), + lhs: MemoryAddress::direct(2), + rhs: MemoryAddress::direct(1), + destination: MemoryAddress::direct(1), }, //(1) = a-q*b BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Sub, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(1), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(1), + destination: MemoryAddress::direct(1), }, //(0) = q BrilligOpcode::Mov { - destination: MemoryAddress::from(0), - source: MemoryAddress::from(2), + destination: MemoryAddress::direct(0), + source: MemoryAddress::direct(2), }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 2 }, ], diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 85db1bd8b96..76e35395dd6 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -162,6 +162,7 @@ mod tests { use std::vec; use acvm::FieldElement; + use noirc_frontend::monomorphization::ast::InlineType; use crate::brillig::brillig_gen::brillig_block::BrilligBlock; use crate::brillig::brillig_gen::brillig_block_variables::BlockVariables; @@ -182,7 +183,7 @@ mod tests { fn create_test_environment() -> (Ssa, FunctionContext, BrilligContext) { let mut builder = FunctionBuilder::new("main".to_string(), Id::test_new(0)); - builder.set_runtime(RuntimeType::Brillig); + builder.set_runtime(RuntimeType::Brillig(InlineType::default())); let ssa = builder.finish(); let mut brillig_context = create_context(ssa.main_id); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/variable_liveness.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/variable_liveness.rs index 92595292bf0..a18461bc0cd 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/variable_liveness.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/variable_liveness.rs @@ -341,6 +341,7 @@ impl VariableLiveness { #[cfg(test)] mod test { use fxhash::FxHashSet; + use noirc_frontend::monomorphization::ast::InlineType; use crate::brillig::brillig_gen::constant_allocation::ConstantAllocation; use crate::brillig::brillig_gen::variable_liveness::VariableLiveness; @@ -373,7 +374,7 @@ mod test { let main_id = Id::test_new(1); let mut builder = FunctionBuilder::new("main".into(), main_id); - builder.set_runtime(RuntimeType::Brillig); + builder.set_runtime(RuntimeType::Brillig(InlineType::default())); let b1 = builder.insert_block(); let b2 = builder.insert_block(); @@ -483,7 +484,7 @@ mod test { let main_id = Id::test_new(1); let mut builder = FunctionBuilder::new("main".into(), main_id); - builder.set_runtime(RuntimeType::Brillig); + builder.set_runtime(RuntimeType::Brillig(InlineType::default())); let b1 = builder.insert_block(); let b2 = builder.insert_block(); @@ -622,7 +623,7 @@ mod test { let main_id = Id::test_new(1); let mut builder = FunctionBuilder::new("main".into(), main_id); - builder.set_runtime(RuntimeType::Brillig); + builder.set_runtime(RuntimeType::Brillig(InlineType::default())); let v0 = builder.add_parameter(Type::bool()); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index d8065294b0c..4964ff27f60 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -43,19 +43,17 @@ pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 32; // Registers reserved in runtime for special purposes. pub(crate) enum ReservedRegisters { + /// This register stores the stack pointer. All relative memory addresses are relative to this pointer. + StackPointer = 0, /// This register stores the free memory pointer. Allocations must be done after this pointer. - FreeMemoryPointer = 0, - /// This register stores the previous stack pointer. The registers of the caller are stored here. - PreviousStackPointer = 1, + FreeMemoryPointer = 1, /// This register stores a 1_usize constant. UsizeOne = 2, } impl ReservedRegisters { - /// The number of reserved registers. - /// - /// This is used to offset the general registers - /// which should not overwrite the special register + /// The number of reserved registers. These are allocated in the first memory positions. + /// The stack should start after the reserved registers. const NUM_RESERVED_REGISTERS: usize = 3; /// Returns the length of the reserved registers @@ -63,19 +61,16 @@ impl ReservedRegisters { Self::NUM_RESERVED_REGISTERS } - /// Returns the free memory pointer register. This will get used to allocate memory in runtime. - pub(crate) fn free_memory_pointer() -> MemoryAddress { - MemoryAddress::from(ReservedRegisters::FreeMemoryPointer as usize) + pub(crate) fn stack_pointer() -> MemoryAddress { + MemoryAddress::direct(ReservedRegisters::StackPointer as usize) } - /// Returns the previous stack pointer register. This will be used to restore the registers after a fn call. - pub(crate) fn previous_stack_pointer() -> MemoryAddress { - MemoryAddress::from(ReservedRegisters::PreviousStackPointer as usize) + pub(crate) fn free_memory_pointer() -> MemoryAddress { + MemoryAddress::direct(ReservedRegisters::FreeMemoryPointer as usize) } - /// Returns the usize one register. This will be used to perform arithmetic operations. pub(crate) fn usize_one() -> MemoryAddress { - MemoryAddress::from(ReservedRegisters::UsizeOne as usize) + MemoryAddress::direct(ReservedRegisters::UsizeOne as usize) } } @@ -178,20 +173,6 @@ pub(crate) mod tests { ) -> Result { Ok(true) } - fn pedersen_commitment( - &self, - _inputs: &[FieldElement], - _domain_separator: u32, - ) -> Result<(FieldElement, FieldElement), BlackBoxResolutionError> { - Ok((2_u128.into(), 3_u128.into())) - } - fn pedersen_hash( - &self, - _inputs: &[FieldElement], - _domain_separator: u32, - ) -> Result { - Ok(6_u128.into()) - } fn multi_scalar_mul( &self, _points: &[FieldElement], @@ -279,10 +260,10 @@ pub(crate) mod tests { let r_stack = ReservedRegisters::free_memory_pointer(); // Start stack pointer at 0 context.usize_const_instruction(r_stack, FieldElement::from(ReservedRegisters::len() + 3)); - let r_input_size = MemoryAddress::from(ReservedRegisters::len()); - let r_array_ptr = MemoryAddress::from(ReservedRegisters::len() + 1); - let r_output_size = MemoryAddress::from(ReservedRegisters::len() + 2); - let r_equality = MemoryAddress::from(ReservedRegisters::len() + 3); + let r_input_size = MemoryAddress::direct(ReservedRegisters::len()); + let r_array_ptr = MemoryAddress::direct(ReservedRegisters::len() + 1); + let r_output_size = MemoryAddress::direct(ReservedRegisters::len() + 2); + let r_equality = MemoryAddress::direct(ReservedRegisters::len() + 3); context.usize_const_instruction(r_input_size, FieldElement::from(12_usize)); // copy our stack frame to r_array_ptr context.mov_instruction(r_array_ptr, r_stack); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs index 185a6a08a04..777acfc4da3 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_calls.rs @@ -1,105 +1,78 @@ use acvm::{acir::brillig::MemoryAddress, AcirField}; +use crate::ssa::ir::function::FunctionId; + use super::{ - brillig_variable::BrilligVariable, debug_show::DebugToString, registers::RegisterAllocator, + brillig_variable::{BrilligVariable, SingleAddrVariable}, + debug_show::DebugToString, + registers::{RegisterAllocator, Stack}, BrilligBinaryOp, BrilligContext, ReservedRegisters, }; -impl BrilligContext { - /// Saves all of the registers that have been used up until this point. - fn codegen_save_registers_of_vars(&mut self, vars: &[BrilligVariable]) -> Vec { - // Save all of the used registers at this point in memory - // because the function call will/may overwrite them. - // - // Note that here it is important that the stack pointer register is at register 0, - // as after the first register save we add to the pointer. - let mut used_registers: Vec<_> = vars.iter().map(|var| var.extract_register()).collect(); - - // Also dump the previous stack pointer - used_registers.push(ReservedRegisters::previous_stack_pointer()); - for register in used_registers.iter() { - self.store_instruction(ReservedRegisters::free_memory_pointer(), *register); - // Add one to our stack pointer - self.codegen_usize_op_in_place( - ReservedRegisters::free_memory_pointer(), - BrilligBinaryOp::Add, - 1, +impl BrilligContext { + pub(crate) fn codegen_call( + &mut self, + func_id: FunctionId, + arguments: &[BrilligVariable], + returns: &[BrilligVariable], + ) { + let stack_size_register = SingleAddrVariable::new_usize(self.allocate_register()); + let previous_stack_pointer = self.registers.empty_stack_start(); + let stack_size = previous_stack_pointer.unwrap_relative(); + // Write the stack size + self.const_instruction(stack_size_register, stack_size.into()); + // Pass the previous stack pointer + self.mov_instruction(previous_stack_pointer, ReservedRegisters::stack_pointer()); + // Pass the arguments + let mut current_argument_location = stack_size + 1; + for item in arguments { + self.mov_instruction( + MemoryAddress::relative(current_argument_location), + item.extract_register(), ); + current_argument_location += 1; } - - // Store the location of our registers in the previous stack pointer - self.mov_instruction( - ReservedRegisters::previous_stack_pointer(), - ReservedRegisters::free_memory_pointer(), + // Increment the stack pointer + self.memory_op_instruction( + ReservedRegisters::stack_pointer(), + stack_size_register.address, + ReservedRegisters::stack_pointer(), + BrilligBinaryOp::Add, ); - used_registers - } - /// Loads all of the registers that have been save by save_all_used_registers. - fn codegen_load_all_saved_registers(&mut self, used_registers: &[MemoryAddress]) { - // Load all of the used registers that we saved. - // We do all the reverse operations of save_all_used_registers. - // Iterate our registers in reverse - let iterator_register = self.allocate_register(); - self.mov_instruction(iterator_register, ReservedRegisters::previous_stack_pointer()); + self.add_external_call_instruction(func_id); + + // Restore the stack pointer + self.mov_instruction(ReservedRegisters::stack_pointer(), MemoryAddress::relative(0)); - for register in used_registers.iter().rev() { - // Subtract one from our stack pointer - self.codegen_usize_op_in_place(iterator_register, BrilligBinaryOp::Sub, 1); - self.load_instruction(*register, iterator_register); + // Move the return values back + let mut current_return_location = stack_size + 1; + for item in returns { + self.mov_instruction( + item.extract_register(), + MemoryAddress::relative(current_return_location), + ); + current_return_location += 1; } + self.deallocate_single_addr(stack_size_register); } - // Used before a call instruction. - // Save all the registers we have used to the stack. - // Move argument values to the front of the register indices. - pub(crate) fn codegen_pre_call_save_registers_prep_args( - &mut self, - arguments: &[MemoryAddress], - variables_to_save: &[BrilligVariable], - ) -> Vec { - // Save all the registers we have used to the stack. - let saved_registers = self.codegen_save_registers_of_vars(variables_to_save); + /// Codegens a return from the current function. + pub(crate) fn codegen_return(&mut self, return_registers: &[MemoryAddress]) { + let mut sources = Vec::with_capacity(return_registers.len()); + let mut destinations = Vec::with_capacity(return_registers.len()); - // Move argument values to the front of the registers - // - // This means that the arguments will be in the first `n` registers after - // the number of reserved registers. - let (sources, destinations): (Vec<_>, Vec<_>) = arguments - .iter() - .enumerate() - .map(|(i, argument)| (*argument, self.stack_register(i))) - .unzip(); + for (destination_index, return_register) in return_registers.iter().enumerate() { + // In case we have fewer return registers than indices to write to, ensure we've allocated this register + let destination_register = MemoryAddress::relative(Stack::start() + destination_index); + self.registers.ensure_register_is_allocated(destination_register); + sources.push(*return_register); + destinations.push(destination_register); + } destinations .iter() .for_each(|destination| self.registers.ensure_register_is_allocated(*destination)); self.codegen_mov_registers_to_registers(sources, destinations); - saved_registers - } - - // Used after a call instruction. - // Move return values to the front of the register indices. - // Load all the registers we have previous saved in save_registers_prep_args. - pub(crate) fn codegen_post_call_prep_returns_load_registers( - &mut self, - result_registers: &[MemoryAddress], - saved_registers: &[MemoryAddress], - ) { - // Allocate our result registers and write into them - // We assume the return values of our call are held in 0..num results register indices - let (sources, destinations): (Vec<_>, Vec<_>) = result_registers - .iter() - .enumerate() - .map(|(i, result_register)| (self.stack_register(i), *result_register)) - .unzip(); - sources.iter().for_each(|source| self.registers.ensure_register_is_allocated(*source)); - self.codegen_mov_registers_to_registers(sources, destinations); - - // Restore all the same registers we have, in exact reverse order. - // Note that we have allocated some registers above, which we will not be handling here, - // only restoring registers that were used prior to the call finishing. - // After the call instruction, the stack frame pointer should be back to where we left off, - // so we do our instructions in reverse order. - self.codegen_load_all_saved_registers(saved_registers); + self.stop_instruction(); } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs index e5b57293d1e..c305d8c78f3 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_control_flow.rs @@ -7,7 +7,7 @@ use super::{ artifact::BrilligParameter, brillig_variable::{BrilligArray, BrilligVariable, SingleAddrVariable}, debug_show::DebugToString, - registers::{RegisterAllocator, Stack}, + registers::RegisterAllocator, BrilligBinaryOp, BrilligContext, ReservedRegisters, }; @@ -349,32 +349,3 @@ impl BrilligContext< } } } - -impl BrilligContext { - /// Codegens a return from the current function. - /// - /// For Brillig, the return is implicit, since there is no explicit return instruction. - /// The caller will take `N` values from the Register starting at register index 0. - /// `N` indicates the number of return values expected. - /// - /// Brillig does not have an explicit return instruction, so this - /// method will move all register values to the first `N` values in - /// the VM. - pub(crate) fn codegen_return(&mut self, return_registers: &[MemoryAddress]) { - let mut sources = Vec::with_capacity(return_registers.len()); - let mut destinations = Vec::with_capacity(return_registers.len()); - - for (destination_index, return_register) in return_registers.iter().enumerate() { - // In case we have fewer return registers than indices to write to, ensure we've allocated this register - let destination_register = MemoryAddress(Stack::start() + destination_index); - self.registers.ensure_register_is_allocated(destination_register); - sources.push(*return_register); - destinations.push(destination_register); - } - destinations - .iter() - .for_each(|destination| self.registers.ensure_register_is_allocated(*destination)); - self.codegen_mov_registers_to_registers(sources, destinations); - self.stop_instruction(); - } -} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs index b7b25c6db49..a0e2a500e20 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_stack.rs @@ -140,7 +140,9 @@ mod tests { movements: Vec<(usize, usize)>, ) -> HashMap> { movements.into_iter().fold(HashMap::default(), |mut map, (source, destination)| { - map.entry(MemoryAddress(source)).or_default().insert(MemoryAddress(destination)); + map.entry(MemoryAddress::relative(source)) + .or_default() + .insert(MemoryAddress::relative(destination)); map }) } @@ -190,9 +192,12 @@ mod tests { fn movements_to_source_and_destinations( movements: Vec<(usize, usize)>, ) -> (Vec, Vec) { - let sources = movements.iter().map(|(source, _)| MemoryAddress::from(*source)).collect(); - let destinations = - movements.iter().map(|(_, destination)| MemoryAddress::from(*destination)).collect(); + let sources = + movements.iter().map(|(source, _)| MemoryAddress::relative(*source)).collect(); + let destinations = movements + .iter() + .map(|(_, destination)| MemoryAddress::relative(*destination)) + .collect(); (sources, destinations) } @@ -223,10 +228,22 @@ mod tests { assert_eq!( opcodes, vec![ - Opcode::Mov { destination: MemoryAddress(14), source: MemoryAddress(13) }, - Opcode::Mov { destination: MemoryAddress(13), source: MemoryAddress(12) }, - Opcode::Mov { destination: MemoryAddress(12), source: MemoryAddress(11) }, - Opcode::Mov { destination: MemoryAddress(11), source: MemoryAddress(10) }, + Opcode::Mov { + destination: MemoryAddress::relative(14), + source: MemoryAddress::relative(13) + }, + Opcode::Mov { + destination: MemoryAddress::relative(13), + source: MemoryAddress::relative(12) + }, + Opcode::Mov { + destination: MemoryAddress::relative(12), + source: MemoryAddress::relative(11) + }, + Opcode::Mov { + destination: MemoryAddress::relative(11), + source: MemoryAddress::relative(10) + }, ] ); } @@ -241,8 +258,14 @@ mod tests { assert_eq!( opcodes, vec![ - Opcode::Mov { destination: MemoryAddress(12), source: MemoryAddress(11) }, - Opcode::Mov { destination: MemoryAddress(11), source: MemoryAddress(10) }, + Opcode::Mov { + destination: MemoryAddress::relative(12), + source: MemoryAddress::relative(11) + }, + Opcode::Mov { + destination: MemoryAddress::relative(11), + source: MemoryAddress::relative(10) + }, ] ); } @@ -258,11 +281,26 @@ mod tests { assert_eq!( opcodes, vec![ - Opcode::Mov { destination: MemoryAddress(3), source: MemoryAddress(10) }, - Opcode::Mov { destination: MemoryAddress(10), source: MemoryAddress(13) }, - Opcode::Mov { destination: MemoryAddress(13), source: MemoryAddress(12) }, - Opcode::Mov { destination: MemoryAddress(12), source: MemoryAddress(11) }, - Opcode::Mov { destination: MemoryAddress(11), source: MemoryAddress(3) } + Opcode::Mov { + destination: MemoryAddress::relative(1), + source: MemoryAddress::relative(10) + }, + Opcode::Mov { + destination: MemoryAddress::relative(10), + source: MemoryAddress::relative(13) + }, + Opcode::Mov { + destination: MemoryAddress::relative(13), + source: MemoryAddress::relative(12) + }, + Opcode::Mov { + destination: MemoryAddress::relative(12), + source: MemoryAddress::relative(11) + }, + Opcode::Mov { + destination: MemoryAddress::relative(11), + source: MemoryAddress::relative(1) + } ] ); } @@ -278,12 +316,30 @@ mod tests { assert_eq!( opcodes, vec![ - Opcode::Mov { destination: MemoryAddress(3), source: MemoryAddress(10) }, // Temporary - Opcode::Mov { destination: MemoryAddress(14), source: MemoryAddress(13) }, // Branch - Opcode::Mov { destination: MemoryAddress(10), source: MemoryAddress(12) }, // Loop - Opcode::Mov { destination: MemoryAddress(12), source: MemoryAddress(11) }, // Loop - Opcode::Mov { destination: MemoryAddress(13), source: MemoryAddress(3) }, // Finish branch - Opcode::Mov { destination: MemoryAddress(11), source: MemoryAddress(3) } // Finish loop + Opcode::Mov { + destination: MemoryAddress::relative(1), + source: MemoryAddress::relative(10) + }, // Temporary + Opcode::Mov { + destination: MemoryAddress::relative(10), + source: MemoryAddress::relative(12) + }, // Branch + Opcode::Mov { + destination: MemoryAddress::relative(12), + source: MemoryAddress::relative(11) + }, // Loop + Opcode::Mov { + destination: MemoryAddress::relative(14), + source: MemoryAddress::relative(13) + }, // Loop + Opcode::Mov { + destination: MemoryAddress::relative(11), + source: MemoryAddress::relative(1) + }, // Finish branch + Opcode::Mov { + destination: MemoryAddress::relative(13), + source: MemoryAddress::relative(1) + } // Finish loop ] ); } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 08e6c18182b..7597da2be05 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -28,10 +28,13 @@ impl DebugToString for MemoryAddress { fn debug_to_string(&self) -> String { if *self == ReservedRegisters::free_memory_pointer() { "FreeMem".into() - } else if *self == ReservedRegisters::previous_stack_pointer() { - "PrevStack".into() + } else if *self == ReservedRegisters::stack_pointer() { + "StackPointer".into() } else { - format!("R{}", self.to_usize()) + match self { + MemoryAddress::Direct(address) => format!("M{}", address), + MemoryAddress::Relative(offset) => format!("S{}", offset), + } } } } @@ -123,24 +126,6 @@ impl DebugShow { debug_println!(self.enable_debug_trace, " MOV {}, {}", destination, source); } - /// Emits a conditional `mov` instruction. - pub(crate) fn conditional_mov_instruction( - &self, - destination: MemoryAddress, - condition: MemoryAddress, - source_a: MemoryAddress, - source_b: MemoryAddress, - ) { - debug_println!( - self.enable_debug_trace, - " CMOV {} = {}? {} : {}", - destination, - condition, - source_a, - source_b - ); - } - /// Emits a `cast` instruction. pub(crate) fn cast_instruction( &self, @@ -285,9 +270,6 @@ impl DebugShow { outputs ); } - BlackBoxOp::Keccak256 { message, output } => { - debug_println!(self.enable_debug_trace, " KECCAK256 {} -> {}", message, output); - } BlackBoxOp::Keccakf1600 { message, output } => { debug_println!(self.enable_debug_trace, " KECCAKF1600 {} -> {}", message, output); } @@ -353,24 +335,6 @@ impl DebugShow { result ); } - BlackBoxOp::PedersenCommitment { inputs, domain_separator, output } => { - debug_println!( - self.enable_debug_trace, - " PEDERSEN {} {} -> {}", - inputs, - domain_separator, - output - ); - } - BlackBoxOp::PedersenHash { inputs, domain_separator, output } => { - debug_println!( - self.enable_debug_trace, - " PEDERSEN_HASH {} {} -> {}", - inputs, - domain_separator, - output - ); - } BlackBoxOp::SchnorrVerify { public_key_x, public_key_y, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index ff9b5ea67eb..75d91716c23 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -9,7 +9,8 @@ use super::{ }; use acvm::acir::{brillig::MemoryAddress, AcirField}; -pub(crate) const MAX_STACK_SIZE: usize = 2048; +pub(crate) const MAX_STACK_SIZE: usize = 16 * MAX_STACK_FRAME_SIZE; +pub(crate) const MAX_STACK_FRAME_SIZE: usize = 2048; pub(crate) const MAX_SCRATCH_SPACE: usize = 64; impl BrilligContext { @@ -57,12 +58,18 @@ impl BrilligContext { 1_usize.into(), ); - // Set initial value of stack pointer: calldata_start_offset + calldata_size + return_data_size + // Set initial value of free memory pointer: calldata_start_offset + calldata_size + return_data_size self.const_instruction( SingleAddrVariable::new_usize(ReservedRegisters::free_memory_pointer()), (Self::calldata_start_offset() + calldata_size + return_data_size).into(), ); + // Set initial value of stack pointer: ReservedRegisters.len() + self.const_instruction( + SingleAddrVariable::new_usize(ReservedRegisters::stack_pointer()), + ReservedRegisters::len().into(), + ); + // Copy calldata self.copy_and_cast_calldata(arguments); @@ -74,7 +81,7 @@ impl BrilligContext { (BrilligVariable::SingleAddr(single_address), BrilligParameter::SingleAddr(_)) => { self.mov_instruction( single_address.address, - MemoryAddress(current_calldata_pointer), + MemoryAddress::direct(current_calldata_pointer), ); current_calldata_pointer += 1; } @@ -142,7 +149,7 @@ impl BrilligContext { fn copy_and_cast_calldata(&mut self, arguments: &[BrilligParameter]) { let calldata_size = Self::flattened_tuple_size(arguments); self.calldata_copy_instruction( - MemoryAddress(Self::calldata_start_offset()), + MemoryAddress::direct(Self::calldata_start_offset()), calldata_size, 0, ); @@ -162,10 +169,12 @@ impl BrilligContext { if bit_size < F::max_num_bits() { self.cast_instruction( SingleAddrVariable::new( - MemoryAddress(Self::calldata_start_offset() + i), + MemoryAddress::direct(Self::calldata_start_offset() + i), bit_size, ), - SingleAddrVariable::new_field(MemoryAddress(Self::calldata_start_offset() + i)), + SingleAddrVariable::new_field(MemoryAddress::direct( + Self::calldata_start_offset() + i, + )), ); } } @@ -325,7 +334,7 @@ impl BrilligContext { match return_param { BrilligParameter::SingleAddr(_) => { self.mov_instruction( - MemoryAddress(return_data_index), + MemoryAddress::direct(return_data_index), returned_variable.extract_single_addr().address, ); return_data_index += 1; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs index f196552b768..1ac672687f3 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -327,25 +327,6 @@ impl BrilligContext< self.push_opcode(BrilligOpcode::Mov { destination, source }); } - /// Emits a conditional `mov` instruction. - /// - /// Copies the value at `source` into `destination` - pub(crate) fn conditional_mov_instruction( - &mut self, - destination: MemoryAddress, - condition: MemoryAddress, - source_a: MemoryAddress, - source_b: MemoryAddress, - ) { - self.debug_show.conditional_mov_instruction(destination, condition, source_a, source_b); - self.push_opcode(BrilligOpcode::ConditionalMov { - destination, - source_a, - source_b, - condition, - }); - } - /// Cast truncates the value to the given bit size and converts the type of the value in memory to that bit size. pub(crate) fn cast_instruction( &mut self, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_copy.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_copy.rs index 5b97bbc8f7a..67f7cf2dc34 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_copy.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_copy.rs @@ -18,9 +18,9 @@ impl BrilligContext< source_array: BrilligArray, destination_array: BrilligArray, ) { - let source_array_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let source_array_memory_size_arg = MemoryAddress::from(ScratchSpace::start() + 1); - let new_array_pointer_return = MemoryAddress::from(ScratchSpace::start() + 2); + let source_array_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let source_array_memory_size_arg = MemoryAddress::direct(ScratchSpace::start() + 1); + let new_array_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 2); self.mov_instruction(source_array_pointer_arg, source_array.pointer); self.usize_const_instruction(source_array_memory_size_arg, (source_array.size + 1).into()); @@ -34,9 +34,9 @@ impl BrilligContext< pub(super) fn compile_array_copy_procedure( brillig_context: &mut BrilligContext, ) { - let source_array_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let source_array_memory_size_arg = MemoryAddress::from(ScratchSpace::start() + 1); - let new_array_pointer_return = MemoryAddress::from(ScratchSpace::start() + 2); + let source_array_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let source_array_memory_size_arg = MemoryAddress::direct(ScratchSpace::start() + 1); + let new_array_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 2); brillig_context.set_allocated_registers(vec![ source_array_pointer_arg, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_reverse.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_reverse.rs index 0d98599bf96..a5a11d61bef 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_reverse.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/array_reverse.rs @@ -15,8 +15,8 @@ impl BrilligContext< pointer: MemoryAddress, size: MemoryAddress, ) { - let source_pointer = MemoryAddress::from(ScratchSpace::start()); - let size_register = MemoryAddress::from(ScratchSpace::start() + 1); + let source_pointer = MemoryAddress::direct(ScratchSpace::start()); + let size_register = MemoryAddress::direct(ScratchSpace::start() + 1); self.mov_instruction(source_pointer, pointer); self.mov_instruction(size_register, size); @@ -28,8 +28,8 @@ impl BrilligContext< pub(super) fn compile_array_reverse_procedure( brillig_context: &mut BrilligContext, ) { - let source_pointer = MemoryAddress::from(ScratchSpace::start()); - let size_register = MemoryAddress::from(ScratchSpace::start() + 1); + let source_pointer = MemoryAddress::direct(ScratchSpace::start()); + let size_register = MemoryAddress::direct(ScratchSpace::start() + 1); brillig_context.set_allocated_registers(vec![source_pointer, size_register]); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/check_max_stack_depth.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/check_max_stack_depth.rs new file mode 100644 index 00000000000..4d5abe93420 --- /dev/null +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/check_max_stack_depth.rs @@ -0,0 +1,30 @@ +use acvm::AcirField; + +use super::ProcedureId; +use crate::brillig::brillig_ir::{ + brillig_variable::SingleAddrVariable, + debug_show::DebugToString, + entry_point::{MAX_STACK_FRAME_SIZE, MAX_STACK_SIZE}, + registers::{RegisterAllocator, ScratchSpace}, + BrilligBinaryOp, BrilligContext, ReservedRegisters, +}; + +impl BrilligContext { + pub(crate) fn call_check_max_stack_depth_procedure(&mut self) { + self.add_procedure_call_instruction(ProcedureId::CheckMaxStackDepth); + } +} + +pub(super) fn compile_check_max_stack_depth_procedure( + brillig_context: &mut BrilligContext, +) { + let in_range = SingleAddrVariable::new(brillig_context.allocate_register(), 1); + brillig_context.codegen_usize_op( + ReservedRegisters::stack_pointer(), + in_range.address, + BrilligBinaryOp::LessThan, + MAX_STACK_SIZE - MAX_STACK_FRAME_SIZE, + ); + brillig_context.codegen_constrain(in_range, Some("Stack too deep".to_string())); + brillig_context.deallocate_single_addr(in_range); +} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mem_copy.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mem_copy.rs index b4e1d37af38..cdd99542483 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mem_copy.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mem_copy.rs @@ -17,9 +17,12 @@ impl BrilligContext< destination_pointer: MemoryAddress, num_elements_variable: MemoryAddress, ) { - self.mov_instruction(MemoryAddress::from(ScratchSpace::start()), source_pointer); - self.mov_instruction(MemoryAddress::from(ScratchSpace::start() + 1), destination_pointer); - self.mov_instruction(MemoryAddress::from(ScratchSpace::start() + 2), num_elements_variable); + self.mov_instruction(MemoryAddress::direct(ScratchSpace::start()), source_pointer); + self.mov_instruction(MemoryAddress::direct(ScratchSpace::start() + 1), destination_pointer); + self.mov_instruction( + MemoryAddress::direct(ScratchSpace::start() + 2), + num_elements_variable, + ); self.add_procedure_call_instruction(ProcedureId::MemCopy); } } @@ -27,9 +30,9 @@ impl BrilligContext< pub(super) fn compile_mem_copy_procedure( brillig_context: &mut BrilligContext, ) { - let source_pointer = MemoryAddress::from(ScratchSpace::start()); - let destination_pointer = MemoryAddress::from(ScratchSpace::start() + 1); - let num_elements_variable = MemoryAddress::from(ScratchSpace::start() + 2); + let source_pointer = MemoryAddress::direct(ScratchSpace::start()); + let destination_pointer = MemoryAddress::direct(ScratchSpace::start() + 1); + let num_elements_variable = MemoryAddress::direct(ScratchSpace::start() + 2); brillig_context.set_allocated_registers(vec![ source_pointer, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs index 32fe6725e56..0ee6fe49435 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/mod.rs @@ -1,5 +1,6 @@ mod array_copy; mod array_reverse; +mod check_max_stack_depth; mod mem_copy; mod prepare_vector_insert; mod prepare_vector_push; @@ -9,6 +10,7 @@ mod vector_remove; use array_copy::compile_array_copy_procedure; use array_reverse::compile_array_reverse_procedure; +use check_max_stack_depth::compile_check_max_stack_depth_procedure; use mem_copy::compile_mem_copy_procedure; use prepare_vector_insert::compile_prepare_vector_insert_procedure; use prepare_vector_push::compile_prepare_vector_push_procedure; @@ -37,6 +39,7 @@ pub(crate) enum ProcedureId { VectorPop(bool), PrepareVectorInsert, VectorRemove, + CheckMaxStackDepth, } pub(crate) fn compile_procedure( @@ -60,6 +63,9 @@ pub(crate) fn compile_procedure( compile_prepare_vector_insert_procedure(&mut brillig_context); } ProcedureId::VectorRemove => compile_vector_remove_procedure(&mut brillig_context), + ProcedureId::CheckMaxStackDepth => { + compile_check_max_stack_depth_procedure(&mut brillig_context); + } }; brillig_context.stop_instruction(); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs index d3a6855fa0f..8dbbf80782c 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_insert.rs @@ -20,11 +20,11 @@ impl BrilligContext< write_pointer: MemoryAddress, item_count: usize, ) { - let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let index_arg = MemoryAddress::from(ScratchSpace::start() + 1); - let item_count_arg = MemoryAddress::from(ScratchSpace::start() + 2); - let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); - let write_pointer_return = MemoryAddress::from(ScratchSpace::start() + 4); + let source_vector_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let index_arg = MemoryAddress::direct(ScratchSpace::start() + 1); + let item_count_arg = MemoryAddress::direct(ScratchSpace::start() + 2); + let new_vector_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 3); + let write_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 4); self.mov_instruction(source_vector_pointer_arg, source_vector.pointer); self.mov_instruction(index_arg, index.address); @@ -40,11 +40,11 @@ impl BrilligContext< pub(super) fn compile_prepare_vector_insert_procedure( brillig_context: &mut BrilligContext, ) { - let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let index_arg = MemoryAddress::from(ScratchSpace::start() + 1); - let item_count_arg = MemoryAddress::from(ScratchSpace::start() + 2); - let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); - let write_pointer_return = MemoryAddress::from(ScratchSpace::start() + 4); + let source_vector_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let index_arg = MemoryAddress::direct(ScratchSpace::start() + 1); + let item_count_arg = MemoryAddress::direct(ScratchSpace::start() + 2); + let new_vector_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 3); + let write_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 4); brillig_context.set_allocated_registers(vec![ source_vector_pointer_arg, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs index 8af75712374..00a339ef714 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/prepare_vector_push.rs @@ -21,10 +21,10 @@ impl BrilligContext< item_push_count: usize, back: bool, ) { - let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let item_push_count_arg = MemoryAddress::from(ScratchSpace::start() + 1); - let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 2); - let write_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + let source_vector_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let item_push_count_arg = MemoryAddress::direct(ScratchSpace::start() + 1); + let new_vector_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 2); + let write_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 3); self.mov_instruction(source_vector_pointer_arg, source_vector.pointer); self.usize_const_instruction(item_push_count_arg, item_push_count.into()); @@ -40,10 +40,10 @@ pub(super) fn compile_prepare_vector_push_procedure, push_back: bool, ) { - let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let item_push_count_arg = MemoryAddress::from(ScratchSpace::start() + 1); - let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 2); - let write_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + let source_vector_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let item_push_count_arg = MemoryAddress::direct(ScratchSpace::start() + 1); + let new_vector_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 2); + let write_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 3); brillig_context.set_allocated_registers(vec![ source_vector_pointer_arg, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_copy.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_copy.rs index 87895a975f8..7695e840c0b 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_copy.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_copy.rs @@ -18,8 +18,8 @@ impl BrilligContext< source_vector: BrilligVector, destination_vector: BrilligVector, ) { - let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 1); + let source_vector_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let new_vector_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 1); self.mov_instruction(source_vector_pointer_arg, source_vector.pointer); @@ -32,8 +32,8 @@ impl BrilligContext< pub(super) fn compile_vector_copy_procedure( brillig_context: &mut BrilligContext, ) { - let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 1); + let source_vector_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let new_vector_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 1); brillig_context .set_allocated_registers(vec![source_vector_pointer_arg, new_vector_pointer_return]); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop.rs index bb14ffac6be..8fcfebb2360 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_pop.rs @@ -20,10 +20,10 @@ impl BrilligContext< item_pop_count: usize, back: bool, ) { - let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let item_pop_count_arg = MemoryAddress::from(ScratchSpace::start() + 1); - let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 2); - let read_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + let source_vector_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let item_pop_count_arg = MemoryAddress::direct(ScratchSpace::start() + 1); + let new_vector_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 2); + let read_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 3); self.mov_instruction(source_vector_pointer_arg, source_vector.pointer); self.usize_const_instruction(item_pop_count_arg, item_pop_count.into()); @@ -39,10 +39,10 @@ pub(super) fn compile_vector_pop_procedure( brillig_context: &mut BrilligContext, pop_back: bool, ) { - let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let item_pop_count_arg = MemoryAddress::from(ScratchSpace::start() + 1); - let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 2); - let read_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + let source_vector_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let item_pop_count_arg = MemoryAddress::direct(ScratchSpace::start() + 1); + let new_vector_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 2); + let read_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 3); brillig_context.set_allocated_registers(vec![ source_vector_pointer_arg, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs index d4a7217677f..b7b54f970fa 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/procedures/vector_remove.rs @@ -19,10 +19,10 @@ impl BrilligContext< index: SingleAddrVariable, item_count: usize, ) { - let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let index_arg = MemoryAddress::from(ScratchSpace::start() + 1); - let item_count_arg = MemoryAddress::from(ScratchSpace::start() + 2); - let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + let source_vector_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let index_arg = MemoryAddress::direct(ScratchSpace::start() + 1); + let item_count_arg = MemoryAddress::direct(ScratchSpace::start() + 2); + let new_vector_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 3); self.mov_instruction(source_vector_pointer_arg, source_vector.pointer); self.mov_instruction(index_arg, index.address); @@ -37,10 +37,10 @@ impl BrilligContext< pub(super) fn compile_vector_remove_procedure( brillig_context: &mut BrilligContext, ) { - let source_vector_pointer_arg = MemoryAddress::from(ScratchSpace::start()); - let index_arg = MemoryAddress::from(ScratchSpace::start() + 1); - let item_count_arg = MemoryAddress::from(ScratchSpace::start() + 2); - let new_vector_pointer_return = MemoryAddress::from(ScratchSpace::start() + 3); + let source_vector_pointer_arg = MemoryAddress::direct(ScratchSpace::start()); + let index_arg = MemoryAddress::direct(ScratchSpace::start() + 1); + let item_count_arg = MemoryAddress::direct(ScratchSpace::start() + 2); + let new_vector_pointer_return = MemoryAddress::direct(ScratchSpace::start() + 3); brillig_context.set_allocated_registers(vec![ source_vector_pointer_arg, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs index 75fb60fc9f2..dd7766f40aa 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/registers.rs @@ -1,10 +1,14 @@ +use std::collections::BTreeSet; + use acvm::acir::brillig::{HeapArray, HeapVector, MemoryAddress}; +use iter_extended::vecmap; use crate::brillig::brillig_ir::entry_point::MAX_STACK_SIZE; use super::{ - brillig_variable::SingleAddrVariable, entry_point::MAX_SCRATCH_SPACE, BrilligContext, - ReservedRegisters, + brillig_variable::SingleAddrVariable, + entry_point::{MAX_SCRATCH_SPACE, MAX_STACK_FRAME_SIZE}, + BrilligContext, ReservedRegisters, }; pub(crate) trait RegisterAllocator { @@ -34,33 +38,37 @@ impl Stack { } fn is_within_bounds(register: MemoryAddress) -> bool { - let index = register.to_usize(); - index >= Self::start() && index < Self::end() + let offset = register.unwrap_relative(); + offset >= Self::start() && offset < Self::end() + } + + pub(crate) fn empty_stack_start(&self) -> MemoryAddress { + MemoryAddress::relative(self.storage.empty_registers_start(Self::start())) } } impl RegisterAllocator for Stack { fn start() -> usize { - ReservedRegisters::len() + 1 // Previous stack pointer is the first stack item } fn end() -> usize { - ReservedRegisters::len() + MAX_STACK_SIZE + MAX_STACK_FRAME_SIZE } fn ensure_register_is_allocated(&mut self, register: MemoryAddress) { assert!(Self::is_within_bounds(register), "Register out of stack bounds"); - self.storage.ensure_register_is_allocated(register); + self.storage.ensure_register_is_allocated(register.unwrap_relative()); } fn allocate_register(&mut self) -> MemoryAddress { - let allocated = self.storage.allocate_register(); - assert!(Self::is_within_bounds(allocated), "Stack too deep"); + let allocated = MemoryAddress::relative(self.storage.allocate_register()); + assert!(Self::is_within_bounds(allocated), "Stack frame too deep"); allocated } fn deallocate_register(&mut self, register_index: MemoryAddress) { - self.storage.deallocate_register(register_index); + self.storage.deallocate_register(register_index.unwrap_relative()); } fn from_preallocated_registers(preallocated_registers: Vec) -> Self { @@ -71,7 +79,7 @@ impl RegisterAllocator for Stack { Self { storage: DeallocationListAllocator::from_preallocated_registers( Self::start(), - preallocated_registers, + vecmap(preallocated_registers, |r| r.unwrap_relative()), ), } } @@ -90,7 +98,7 @@ impl ScratchSpace { } fn is_within_bounds(register: MemoryAddress) -> bool { - let index = register.to_usize(); + let index = register.unwrap_direct(); index >= Self::start() && index < Self::end() } } @@ -106,17 +114,17 @@ impl RegisterAllocator for ScratchSpace { fn ensure_register_is_allocated(&mut self, register: MemoryAddress) { assert!(Self::is_within_bounds(register), "Register out of scratch space bounds"); - self.storage.ensure_register_is_allocated(register); + self.storage.ensure_register_is_allocated(register.unwrap_direct()); } fn allocate_register(&mut self) -> MemoryAddress { - let allocated = self.storage.allocate_register(); + let allocated = MemoryAddress::direct(self.storage.allocate_register()); assert!(Self::is_within_bounds(allocated), "Scratch space too deep"); allocated } fn deallocate_register(&mut self, register_index: MemoryAddress) { - self.storage.deallocate_register(register_index); + self.storage.deallocate_register(register_index.unwrap_direct()); } fn from_preallocated_registers(preallocated_registers: Vec) -> Self { @@ -127,7 +135,7 @@ impl RegisterAllocator for ScratchSpace { Self { storage: DeallocationListAllocator::from_preallocated_registers( Self::start(), - preallocated_registers, + vecmap(preallocated_registers, |r| r.unwrap_direct()), ), } } @@ -135,75 +143,77 @@ impl RegisterAllocator for ScratchSpace { struct DeallocationListAllocator { /// A free-list of registers that have been deallocated and can be used again. - deallocated_registers: Vec, + deallocated_registers: BTreeSet, /// A usize indicating the next un-used register. next_free_register_index: usize, } impl DeallocationListAllocator { fn new(start: usize) -> Self { - Self { deallocated_registers: Vec::new(), next_free_register_index: start } + Self { deallocated_registers: BTreeSet::new(), next_free_register_index: start } } - fn ensure_register_is_allocated(&mut self, register: MemoryAddress) { - let index = register.to_usize(); + fn ensure_register_is_allocated(&mut self, index: usize) { if index < self.next_free_register_index { // If it could be allocated, check if it's in the deallocated list and remove it from there - self.deallocated_registers.retain(|&r| r != register); + self.deallocated_registers.retain(|&r| r != index); } else { // If it couldn't yet be, expand the register space. self.next_free_register_index = index + 1; } } - fn allocate_register(&mut self) -> MemoryAddress { + fn allocate_register(&mut self) -> usize { // If we have a register in our free list of deallocated registers, // consume it first. This prioritizes reuse. - if let Some(register) = self.deallocated_registers.pop() { + if let Some(register) = self.deallocated_registers.pop_first() { return register; } // Otherwise, move to our latest register. - let register = MemoryAddress::from(self.next_free_register_index); + let register = self.next_free_register_index; self.next_free_register_index += 1; register } - fn deallocate_register(&mut self, register_index: MemoryAddress) { + fn deallocate_register(&mut self, register_index: usize) { assert!(!self.deallocated_registers.contains(®ister_index)); - self.deallocated_registers.push(register_index); + self.deallocated_registers.insert(register_index); } - fn from_preallocated_registers( - start: usize, - preallocated_registers: Vec, - ) -> Self { + fn from_preallocated_registers(start: usize, preallocated_registers: Vec) -> Self { let next_free_register_index = preallocated_registers.iter().fold( start, - |free_register_index, preallocated_register| { - if preallocated_register.to_usize() < free_register_index { + |free_register_index, &preallocated_register| { + if preallocated_register < free_register_index { free_register_index } else { - preallocated_register.to_usize() + 1 + preallocated_register + 1 } }, ); - let mut deallocated_registers = Vec::new(); + let mut deallocated_registers = BTreeSet::new(); for i in start..next_free_register_index { - if !preallocated_registers.contains(&MemoryAddress::from(i)) { - deallocated_registers.push(MemoryAddress::from(i)); + if !preallocated_registers.contains(&i) { + deallocated_registers.insert(i); } } Self { deallocated_registers, next_free_register_index } } -} -impl BrilligContext { - /// Returns the i'th register after the reserved ones - pub(crate) fn stack_register(&self, i: usize) -> MemoryAddress { - MemoryAddress::from(ReservedRegisters::NUM_RESERVED_REGISTERS + i) + fn empty_registers_start(&self, start: usize) -> usize { + let mut first_free = self.next_free_register_index; + while first_free > start { + if !self.deallocated_registers.contains(&(first_free - 1)) { + break; + } + first_free -= 1; + } + first_free } +} +impl BrilligContext { /// Allocates an unused register. pub(crate) fn allocate_register(&mut self) -> MemoryAddress { self.registers.allocate_register() @@ -232,3 +242,22 @@ impl BrilligContext { self.deallocate_register(vec.size); } } + +#[cfg(test)] +mod tests { + use crate::brillig::brillig_ir::registers::{RegisterAllocator, Stack}; + + #[test] + fn stack_should_prioritize_returning_low_registers() { + let mut stack = Stack::new(); + let one = stack.allocate_register(); + let _two = stack.allocate_register(); + let three = stack.allocate_register(); + + stack.deallocate_register(three); + stack.deallocate_register(one); + + let one_again = stack.allocate_register(); + assert_eq!(one, one_again); + } +} diff --git a/compiler/noirc_evaluator/src/brillig/mod.rs b/compiler/noirc_evaluator/src/brillig/mod.rs index 45b84f5311e..f1da76669cd 100644 --- a/compiler/noirc_evaluator/src/brillig/mod.rs +++ b/compiler/noirc_evaluator/src/brillig/mod.rs @@ -65,7 +65,9 @@ impl Ssa { let brillig_reachable_function_ids = self .functions .iter() - .filter_map(|(id, func)| (func.runtime() == RuntimeType::Brillig).then_some(*id)) + .filter_map(|(id, func)| { + matches!(func.runtime(), RuntimeType::Brillig(_)).then_some(*id) + }) .collect::>(); let mut brillig = Brillig::default(); diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index efc7c6018c1..ea41b0cfb32 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -67,6 +67,9 @@ pub struct SsaEvaluatorOptions { /// Skip the check for under constrained values pub skip_underconstrained_check: bool, + + /// The higher the value, the more inlined brillig functions will be. + pub inliner_aggressiveness: i64, } pub(crate) struct ArtifactsAndWarnings(Artifacts, Vec); @@ -94,9 +97,10 @@ pub(crate) fn optimize_into_acir( .run_pass(Ssa::remove_paired_rc, "After Removing Paired rc_inc & rc_decs:") .run_pass(Ssa::separate_runtime, "After Runtime Separation:") .run_pass(Ssa::resolve_is_unconstrained, "After Resolving IsUnconstrained:") - .run_pass(Ssa::inline_functions, "After Inlining:") + .run_pass(|ssa| ssa.inline_functions(options.inliner_aggressiveness), "After Inlining:") // Run mem2reg with the CFG separated into blocks .run_pass(Ssa::mem2reg, "After Mem2Reg:") + .run_pass(Ssa::simplify_cfg, "After Simplifying:") .run_pass(Ssa::as_slice_optimization, "After `as_slice` optimization") .try_run_pass( Ssa::evaluate_static_assert_and_assert_constant, @@ -112,7 +116,10 @@ pub(crate) fn optimize_into_acir( // Before flattening is run, we treat functions marked with the `InlineType::NoPredicates` as an entry point. // This pass must come immediately following `mem2reg` as the succeeding passes // may create an SSA which inlining fails to handle. - .run_pass(Ssa::inline_functions_with_no_predicates, "After Inlining:") + .run_pass( + |ssa| ssa.inline_functions_with_no_predicates(options.inliner_aggressiveness), + "After Inlining:", + ) .run_pass(Ssa::remove_if_else, "After Remove IfElse:") .run_pass(Ssa::fold_constants, "After Constant Folding:") .run_pass(Ssa::remove_enable_side_effects, "After EnableSideEffectsIf removal:") @@ -405,7 +412,10 @@ impl SsaBuilder { } /// Runs the given SSA pass and prints the SSA afterward if `print_ssa_passes` is true. - fn run_pass(mut self, pass: fn(Ssa) -> Ssa, msg: &str) -> Self { + fn run_pass(mut self, pass: F, msg: &str) -> Self + where + F: FnOnce(Ssa) -> Ssa, + { self.ssa = time(msg, self.print_codegen_timings, || pass(self.ssa)); self.print(msg) } diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 1069416b7b8..db08b906185 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -1286,31 +1286,6 @@ impl AcirContext { ) -> Result, RuntimeError> { // Separate out any arguments that should be constants let (constant_inputs, constant_outputs) = match name { - BlackBoxFunc::PedersenCommitment | BlackBoxFunc::PedersenHash => { - // The last argument of pedersen is the domain separator, which must be a constant - let domain_var = match inputs.pop() { - Some(domain_var) => domain_var.into_var()?, - None => { - return Err(RuntimeError::InternalError(InternalError::MissingArg { - name: "pedersen call".to_string(), - arg: "domain separator".to_string(), - call_stack: self.get_call_stack(), - })) - } - }; - - let domain_constant = match self.vars[&domain_var].as_constant() { - Some(domain_constant) => domain_constant, - None => { - return Err(RuntimeError::InternalError(InternalError::NotAConstant { - name: "domain separator".to_string(), - call_stack: self.get_call_stack(), - })) - } - }; - - (vec![*domain_constant], Vec::new()) - } BlackBoxFunc::Poseidon2Permutation => { // The last argument is the state length, which must be a constant let state_len = match inputs.pop() { diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index 21d4dfb60b8..01fcaef9042 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -225,16 +225,6 @@ impl GeneratedAcir { output: outputs[0], } } - BlackBoxFunc::PedersenCommitment => BlackBoxFuncCall::PedersenCommitment { - inputs: inputs[0].clone(), - outputs: (outputs[0], outputs[1]), - domain_separator: constant_inputs[0].to_u128() as u32, - }, - BlackBoxFunc::PedersenHash => BlackBoxFuncCall::PedersenHash { - inputs: inputs[0].clone(), - output: outputs[0], - domain_separator: constant_inputs[0].to_u128() as u32, - }, BlackBoxFunc::EcdsaSecp256k1 => { BlackBoxFuncCall::EcdsaSecp256k1 { // 32 bytes for each public key co-ordinate @@ -294,9 +284,6 @@ impl GeneratedAcir { input2: Box::new([inputs[3][0], inputs[4][0], inputs[5][0]]), outputs: (outputs[0], outputs[1], outputs[2]), }, - BlackBoxFunc::Keccak256 => { - unreachable!("unexpected BlackBox {}", func_name.to_string()) - } BlackBoxFunc::Keccakf1600 => BlackBoxFuncCall::Keccakf1600 { inputs: inputs[0] .clone() @@ -475,7 +462,7 @@ impl GeneratedAcir { /// /// This equation however falls short when `t != 0` because then `t` /// may not be `1`. If `t` is non-zero, then `y` is also non-zero due to - /// `y == 1 - t` and the equation `y * t == 0` fails. + /// `y == 1 - t` and the equation `y * t == 0` fails. /// /// To fix, we introduce another free variable called `z` and apply the following /// constraint instead: `y == 1 - t * z`. @@ -485,7 +472,7 @@ impl GeneratedAcir { /// /// We now arrive at the conclusion that when `t == 0`, `y` is `1` and when /// `t != 0`, then `y` is `0`. - /// + /// /// Bringing it all together, We introduce two variables `y` and `z`, /// With the following equations: /// - `y == 1 - tz` (`z` is a value that is chosen to be the inverse of `t` by the prover) @@ -643,12 +630,7 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { // All of the hash/cipher methods will take in a // variable number of inputs. - BlackBoxFunc::AES128Encrypt - | BlackBoxFunc::Keccak256 - | BlackBoxFunc::Blake2s - | BlackBoxFunc::Blake3 - | BlackBoxFunc::PedersenCommitment - | BlackBoxFunc::PedersenHash => None, + BlackBoxFunc::AES128Encrypt | BlackBoxFunc::Blake2s | BlackBoxFunc::Blake3 => None, BlackBoxFunc::Keccakf1600 => Some(25), // The permutation takes a fixed number of inputs, but the inputs length depends on the proving system implementation. @@ -696,7 +678,7 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { BlackBoxFunc::AND | BlackBoxFunc::XOR => Some(1), // 32 byte hash algorithms - BlackBoxFunc::Keccak256 | BlackBoxFunc::Blake2s | BlackBoxFunc::Blake3 => Some(32), + BlackBoxFunc::Blake2s | BlackBoxFunc::Blake3 => Some(32), BlackBoxFunc::Keccakf1600 => Some(25), // The permutation returns a fixed number of outputs, equals to the inputs length which depends on the proving system implementation. @@ -704,12 +686,6 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { BlackBoxFunc::Sha256Compression => Some(8), - // Pedersen commitment returns a point - BlackBoxFunc::PedersenCommitment => Some(2), - - // Pedersen hash returns a field - BlackBoxFunc::PedersenHash => Some(1), - // Can only apply a range constraint to one // witness at a time. BlackBoxFunc::RANGE => Some(0), diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index b560fafd337..a5c51392114 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -377,7 +377,7 @@ impl<'a> Context<'a> { match function.runtime() { RuntimeType::Acir(inline_type) => { match inline_type { - InlineType::Inline => { + InlineType::Inline | InlineType::InlineAlways => { if function.id() != ssa.main_id { panic!("ACIR function should have been inlined earlier if not marked otherwise"); } @@ -390,7 +390,7 @@ impl<'a> Context<'a> { // We only want to convert entry point functions. This being `main` and those marked with `InlineType::Fold` Ok(Some(self.convert_acir_main(function, ssa, brillig)?)) } - RuntimeType::Brillig => { + RuntimeType::Brillig(_) => { if function.id() == ssa.main_id { Ok(Some(self.convert_brillig_main(function, brillig)?)) } else { @@ -816,7 +816,7 @@ impl<'a> Context<'a> { self.handle_ssa_call_outputs(result_ids, output_values, dfg)?; } - RuntimeType::Brillig => { + RuntimeType::Brillig(_) => { // Check that we are not attempting to return a slice from // an unconstrained runtime to a constrained runtime for result_id in result_ids { @@ -2939,8 +2939,8 @@ mod test { fn build_basic_foo_with_return( builder: &mut FunctionBuilder, foo_id: FunctionId, - // `InlineType` can only exist on ACIR functions, so if the option is `None` we should generate a Brillig function - inline_type: Option, + brillig: bool, + inline_type: InlineType, ) { // fn foo f1 { // b0(v0: Field, v1: Field): @@ -2948,10 +2948,10 @@ mod test { // constrain v2 == u1 0 // return v0 // } - if let Some(inline_type) = inline_type { - builder.new_function("foo".into(), foo_id, inline_type); + if brillig { + builder.new_brillig_function("foo".into(), foo_id, inline_type); } else { - builder.new_brillig_function("foo".into(), foo_id); + builder.new_function("foo".into(), foo_id, inline_type); } // Set a call stack for testing whether `brillig_locations` in the `GeneratedAcir` was accurately set. builder.set_call_stack(vector![Location::dummy(), Location::dummy()]); @@ -3015,7 +3015,7 @@ mod test { builder.insert_constrain(main_call1_results[0], main_call2_results[0], None); builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, Some(inline_type)); + build_basic_foo_with_return(&mut builder, foo_id, false, inline_type); let ssa = builder.finish(); @@ -3120,7 +3120,7 @@ mod test { builder.insert_constrain(main_call1_results[0], main_call2_results[0], None); builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, Some(inline_type)); + build_basic_foo_with_return(&mut builder, foo_id, false, inline_type); let ssa = builder.finish(); @@ -3220,7 +3220,7 @@ mod test { .to_vec(); builder.terminate_with_return(vec![foo_call[0]]); - build_basic_foo_with_return(&mut builder, foo_id, Some(inline_type)); + build_basic_foo_with_return(&mut builder, foo_id, false, inline_type); let ssa = builder.finish(); @@ -3342,8 +3342,8 @@ mod test { builder.insert_call(bar, vec![main_v0, main_v1], vec![Type::field()]).to_vec(); builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, None); - build_basic_foo_with_return(&mut builder, bar_id, None); + build_basic_foo_with_return(&mut builder, foo_id, true, InlineType::default()); + build_basic_foo_with_return(&mut builder, bar_id, true, InlineType::default()); let ssa = builder.finish(); let brillig = ssa.to_brillig(false); @@ -3479,7 +3479,7 @@ mod test { builder.terminate_with_return(vec![]); - build_basic_foo_with_return(&mut builder, foo_id, None); + build_basic_foo_with_return(&mut builder, foo_id, true, InlineType::default()); let ssa = builder.finish(); // We need to generate Brillig artifacts for the regular Brillig function and pass them to the ACIR generation pass. @@ -3565,9 +3565,9 @@ mod test { builder.terminate_with_return(vec![]); // Build a Brillig function - build_basic_foo_with_return(&mut builder, foo_id, None); + build_basic_foo_with_return(&mut builder, foo_id, true, InlineType::default()); // Build an ACIR function which has the same logic as the Brillig function above - build_basic_foo_with_return(&mut builder, bar_id, Some(InlineType::Fold)); + build_basic_foo_with_return(&mut builder, bar_id, false, InlineType::Fold); let ssa = builder.finish(); // We need to generate Brillig artifacts for the regular Brillig function and pass them to the ACIR generation pass. diff --git a/compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs b/compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs index aa5f4c8df95..7bee18d24a0 100644 --- a/compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs +++ b/compiler/noirc_evaluator/src/ssa/checks/check_for_underconstrained_values.rs @@ -27,7 +27,7 @@ impl Ssa { function_to_process, &self.functions, ), - RuntimeType::Brillig => Vec::new(), + RuntimeType::Brillig(_) => Vec::new(), } }) .collect() @@ -223,7 +223,7 @@ impl Context { } }, Value::Function(callee) => match all_functions[&callee].runtime() { - RuntimeType::Brillig => { + RuntimeType::Brillig(_) => { // For calls to brillig functions we memorize the mapping of results to argument ValueId's and InstructionId's // The latter are needed to produce the callstack later for result in @@ -351,6 +351,8 @@ impl Context { } #[cfg(test)] mod test { + use noirc_frontend::monomorphization::ast::InlineType; + use crate::ssa::{ function_builder::FunctionBuilder, ir::{instruction::BinaryOp, map::Id, types::Type}, @@ -419,7 +421,7 @@ mod test { builder.insert_constrain(v5, one, None); builder.terminate_with_return(vec![]); - builder.new_brillig_function("br".into(), br_function_id); + builder.new_brillig_function("br".into(), br_function_id, InlineType::default()); let v0 = builder.add_parameter(Type::field()); let v1 = builder.add_parameter(Type::field()); let v2 = builder.insert_binary(v0, BinaryOp::Add, v1); diff --git a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs index 04d4e893bf8..f810b65d105 100644 --- a/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/function_builder/mod.rs @@ -95,8 +95,13 @@ impl FunctionBuilder { } /// Finish the current function and create a new unconstrained function. - pub(crate) fn new_brillig_function(&mut self, name: String, function_id: FunctionId) { - self.new_function_with_type(name, function_id, RuntimeType::Brillig); + pub(crate) fn new_brillig_function( + &mut self, + name: String, + function_id: FunctionId, + inline_type: InlineType, + ) { + self.new_function_with_type(name, function_id, RuntimeType::Brillig(inline_type)); } /// Consume the FunctionBuilder returning all the functions it has generated. diff --git a/compiler/noirc_evaluator/src/ssa/ir/function.rs b/compiler/noirc_evaluator/src/ssa/ir/function.rs index 1466f2e5d44..e8245ff6036 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/function.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/function.rs @@ -16,7 +16,7 @@ pub(crate) enum RuntimeType { // A noir function, to be compiled in ACIR and executed by ACVM Acir(InlineType), // Unconstrained function, to be compiled to brillig and executed by the Brillig VM - Brillig, + Brillig(InlineType), } impl RuntimeType { @@ -27,9 +27,25 @@ impl RuntimeType { pub(crate) fn is_entry_point(&self) -> bool { match self { RuntimeType::Acir(inline_type) => inline_type.is_entry_point(), - RuntimeType::Brillig => true, + RuntimeType::Brillig(_) => true, } } + + pub(crate) fn is_inline_always(&self) -> bool { + matches!( + self, + RuntimeType::Acir(InlineType::InlineAlways) + | RuntimeType::Brillig(InlineType::InlineAlways) + ) + } + + pub(crate) fn is_no_predicates(&self) -> bool { + matches!( + self, + RuntimeType::Acir(InlineType::NoPredicates) + | RuntimeType::Brillig(InlineType::NoPredicates) + ) + } } /// A function holds a list of instructions. @@ -103,7 +119,7 @@ impl Function { pub(crate) fn is_no_predicates(&self) -> bool { match self.runtime() { RuntimeType::Acir(inline_type) => matches!(inline_type, InlineType::NoPredicates), - RuntimeType::Brillig => false, + RuntimeType::Brillig(_) => false, } } @@ -177,7 +193,7 @@ impl std::fmt::Display for RuntimeType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { RuntimeType::Acir(inline_type) => write!(f, "acir({inline_type})"), - RuntimeType::Brillig => write!(f, "brillig"), + RuntimeType::Brillig(inline_type) => write!(f, "brillig({inline_type})"), } } } diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 8b540d45664..0bf7fe6a146 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -533,9 +533,6 @@ fn simplify_black_box_func( SimplifyResult::None } } - BlackBoxFunc::Keccak256 => { - unreachable!("Keccak256 should have been replaced by calls to Keccakf1600") - } BlackBoxFunc::Poseidon2Permutation => { blackbox::simplify_poseidon2_permutation(dfg, solver, arguments) } @@ -550,9 +547,7 @@ fn simplify_black_box_func( acvm::blackbox_solver::ecdsa_secp256r1_verify, ), - BlackBoxFunc::PedersenCommitment - | BlackBoxFunc::PedersenHash - | BlackBoxFunc::MultiScalarMul => SimplifyResult::None, + BlackBoxFunc::MultiScalarMul => SimplifyResult::None, BlackBoxFunc::EmbeddedCurveAdd => blackbox::simplify_ec_add(dfg, solver, arguments), BlackBoxFunc::SchnorrVerify => blackbox::simplify_schnorr_verify(dfg, solver, arguments), diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call/blackbox.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call/blackbox.rs index 7789b212e58..3881646d5e4 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call/blackbox.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call/blackbox.rs @@ -1,5 +1,3 @@ -use std::sync::Arc; - use acvm::{acir::AcirField, BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; use iter_extended::vecmap; @@ -41,13 +39,11 @@ pub(super) fn simplify_ec_add( return SimplifyResult::None; }; - let result_x = dfg.make_constant(result_x, Type::field()); - let result_y = dfg.make_constant(result_y, Type::field()); - let result_is_infinity = dfg.make_constant(result_is_infinity, Type::bool()); - - let typ = Type::Array(Arc::new(vec![Type::field()]), 3); - let result_array = - dfg.make_array(im::vector![result_x, result_y, result_is_infinity], typ); + let result_array = make_constant_array( + dfg, + vec![result_x, result_y, result_is_infinity], + Type::field(), + ); SimplifyResult::SimplifiedTo(result_array) } diff --git a/compiler/noirc_evaluator/src/ssa/opt/array_set.rs b/compiler/noirc_evaluator/src/ssa/opt/array_set.rs index b2fe137c8bc..6ae13bc085a 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/array_set.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/array_set.rs @@ -34,7 +34,8 @@ impl Function { assert_eq!(reachable_blocks.len(), 1, "Expected there to be 1 block remaining in Acir function for array_set optimization"); } - let mut context = Context::new(&self.dfg, matches!(self.runtime(), RuntimeType::Brillig)); + let mut context = + Context::new(&self.dfg, matches!(self.runtime(), RuntimeType::Brillig(_))); for block in reachable_blocks.iter() { context.analyze_last_uses(*block); @@ -180,6 +181,7 @@ mod tests { use std::sync::Arc; use im::vector; + use noirc_frontend::monomorphization::ast::InlineType; use crate::ssa::{ function_builder::FunctionBuilder, @@ -227,7 +229,7 @@ mod tests { // } let main_id = Id::test_new(0); let mut builder = FunctionBuilder::new("main".into(), main_id); - builder.set_runtime(RuntimeType::Brillig); + builder.set_runtime(RuntimeType::Brillig(InlineType::default())); let array_type = Type::Array(Arc::new(vec![Type::field()]), 5); let zero = builder.field_constant(0u128); diff --git a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs index cb455507985..984f639df00 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/flatten_cfg.rs @@ -142,7 +142,7 @@ use crate::ssa::{ basic_block::BasicBlockId, cfg::ControlFlowGraph, dfg::{CallStack, InsertInstructionResult}, - function::{Function, FunctionId}, + function::{Function, FunctionId, RuntimeType}, function_inserter::FunctionInserter, instruction::{BinaryOp, Instruction, InstructionId, Intrinsic, TerminatorInstruction}, types::Type, @@ -254,7 +254,7 @@ fn flatten_function_cfg(function: &mut Function, no_predicates: &HashMap Ssa { - Self::inline_functions_inner(self, false) + pub(crate) fn inline_functions(self, aggressiveness: i64) -> Ssa { + Self::inline_functions_inner(self, aggressiveness, false) } // Run the inlining pass where functions marked with `InlineType::NoPredicates` as not entry points - pub(crate) fn inline_functions_with_no_predicates(self) -> Ssa { - Self::inline_functions_inner(self, true) - } - - fn inline_functions_inner(mut self, inline_no_predicates_functions: bool) -> Ssa { - let recursive_functions = find_all_recursive_functions(&self); - self.functions = btree_map( - get_functions_to_inline_into(&self, inline_no_predicates_functions), - |entry_point| { - let new_function = InlineContext::new( - &self, - entry_point, - inline_no_predicates_functions, - recursive_functions.clone(), - ) - .inline_all(&self); - (entry_point, new_function) - }, - ); + pub(crate) fn inline_functions_with_no_predicates(self, aggressiveness: i64) -> Ssa { + Self::inline_functions_inner(self, aggressiveness, true) + } + + fn inline_functions_inner( + mut self, + aggressiveness: i64, + inline_no_predicates_functions: bool, + ) -> Ssa { + let inline_sources = + get_functions_to_inline_into(&self, inline_no_predicates_functions, aggressiveness); + self.functions = btree_map(&inline_sources, |entry_point| { + let new_function = InlineContext::new( + &self, + *entry_point, + inline_no_predicates_functions, + inline_sources.clone(), + ) + .inline_all(&self); + (*entry_point, new_function) + }); self } } @@ -93,8 +95,8 @@ struct InlineContext { /// the control flow graph has been flattened. inline_no_predicates_functions: bool, - // We keep track of the recursive functions in the SSA to avoid inlining them in a brillig context. - recursive_functions: BTreeSet, + // These are the functions of the program that we shouldn't inline. + functions_not_to_inline: BTreeSet, } /// The per-function inlining context contains information that is only valid for one function. @@ -129,8 +131,8 @@ struct PerFunctionContext<'function> { } /// Utility function to find out the direct calls of a function. -fn called_functions(func: &Function) -> BTreeSet { - let mut called_function_ids = BTreeSet::default(); +fn called_functions_vec(func: &Function) -> Vec { + let mut called_function_ids = Vec::new(); for block_id in func.reachable_blocks() { for instruction_id in func.dfg[block_id].instructions() { let Instruction::Call { func: called_value_id, .. } = &func.dfg[*instruction_id] else { @@ -138,7 +140,7 @@ fn called_functions(func: &Function) -> BTreeSet { }; if let Value::Function(function_id) = func.dfg[*called_value_id] { - called_function_ids.insert(function_id); + called_function_ids.push(function_id); } } } @@ -146,52 +148,32 @@ fn called_functions(func: &Function) -> BTreeSet { called_function_ids } -// Recursively explore the SSA to find the functions that end up calling themselves -fn find_recursive_functions( - ssa: &Ssa, - current_function: FunctionId, - mut explored_functions: im::HashSet, - recursive_functions: &mut BTreeSet, -) { - if explored_functions.contains(¤t_function) { - recursive_functions.insert(current_function); - return; - } - - let called_functions = called_functions(&ssa.functions[¤t_function]); - - explored_functions.insert(current_function); - - for called_function in called_functions { - find_recursive_functions( - ssa, - called_function, - explored_functions.clone(), - recursive_functions, - ); - } -} - -fn find_all_recursive_functions(ssa: &Ssa) -> BTreeSet { - let mut recursive_functions = BTreeSet::default(); - find_recursive_functions(ssa, ssa.main_id, im::HashSet::default(), &mut recursive_functions); - recursive_functions +/// Utility function to find out the deduplicated direct calls of a function. +fn called_functions(func: &Function) -> BTreeSet { + called_functions_vec(func).into_iter().collect() } /// The functions we should inline into (and that should be left in the final program) are: /// - main /// - Any Brillig function called from Acir -/// - Any Brillig recursive function (Acir recursive functions will be inlined into the main function) +/// - Some Brillig functions depending on aggressiveness and some metrics /// - Any Acir functions with a [fold inline type][InlineType::Fold], fn get_functions_to_inline_into( ssa: &Ssa, inline_no_predicates_functions: bool, + aggressiveness: i64, ) -> BTreeSet { let mut brillig_entry_points = BTreeSet::default(); let mut acir_entry_points = BTreeSet::default(); + if matches!(ssa.main().runtime(), RuntimeType::Brillig(_)) { + brillig_entry_points.insert(ssa.main_id); + } else { + acir_entry_points.insert(ssa.main_id); + } + for (func_id, function) in ssa.functions.iter() { - if function.runtime() == RuntimeType::Brillig { + if matches!(function.runtime(), RuntimeType::Brillig(_)) { continue; } @@ -203,27 +185,167 @@ fn get_functions_to_inline_into( } for called_function_id in called_functions(function) { - if ssa.functions[&called_function_id].runtime() == RuntimeType::Brillig { + if matches!(ssa.functions[&called_function_id].runtime(), RuntimeType::Brillig(_)) { brillig_entry_points.insert(called_function_id); } } } - let brillig_recursive_functions: BTreeSet<_> = find_all_recursive_functions(ssa) + let times_called = compute_times_called(ssa); + + let brillig_functions_to_retain: BTreeSet<_> = compute_functions_to_retain( + ssa, + &brillig_entry_points, + ×_called, + inline_no_predicates_functions, + aggressiveness, + ); + + acir_entry_points .into_iter() - .filter(|recursive_function_id| { - let function = &ssa.functions[&recursive_function_id]; - function.runtime() == RuntimeType::Brillig + .chain(brillig_entry_points) + .chain(brillig_functions_to_retain) + .collect() +} + +fn compute_times_called(ssa: &Ssa) -> HashMap { + ssa.functions + .iter() + .flat_map(|(_caller_id, function)| { + let called_functions_vec = called_functions_vec(function); + called_functions_vec.into_iter() }) - .collect(); + .chain(std::iter::once(ssa.main_id)) + .fold(HashMap::default(), |mut map, func_id| { + *map.entry(func_id).or_insert(0) += 1; + map + }) +} - std::iter::once(ssa.main_id) - .chain(acir_entry_points) - .chain(brillig_entry_points) - .chain(brillig_recursive_functions) +fn should_retain_recursive( + ssa: &Ssa, + func: FunctionId, + times_called: &HashMap, + should_retain_function: &mut HashMap, + mut explored_functions: im::HashSet, + inline_no_predicates_functions: bool, + aggressiveness: i64, +) { + // We have already decided on this function + if should_retain_function.get(&func).is_some() { + return; + } + // Recursive, this function won't be inlined + if explored_functions.contains(&func) { + should_retain_function.insert(func, (true, 0)); + return; + } + explored_functions.insert(func); + + // Decide on dependencies first + let called_functions = called_functions(&ssa.functions[&func]); + for function in called_functions.iter() { + should_retain_recursive( + ssa, + *function, + times_called, + should_retain_function, + explored_functions.clone(), + inline_no_predicates_functions, + aggressiveness, + ); + } + // We could have decided on this function while deciding on dependencies + // If the function is recursive + if should_retain_function.get(&func).is_some() { + return; + } + + // We'll use some heuristics to decide whether to inline or not. + // We compute the weight (roughly the number of instructions) of the function after inlining + // And the interface cost of the function (the inherent cost at the callsite, roughly the number of args and returns) + // We then can compute an approximation of the cost of inlining vs the cost of retaining the function + // We do this computation using saturating i64s to avoid overflows + let inlined_function_weights: i64 = called_functions.iter().fold(0, |acc, called_function| { + let (should_retain, weight) = should_retain_function[called_function]; + if should_retain { + acc + } else { + acc.saturating_add(weight) + } + }); + + let this_function_weight = inlined_function_weights + .saturating_add(compute_function_own_weight(&ssa.functions[&func]) as i64); + + let interface_cost = compute_function_interface_cost(&ssa.functions[&func]) as i64; + + let times_called = times_called[&func] as i64; + + let inline_cost = times_called.saturating_mul(this_function_weight); + let retain_cost = times_called.saturating_mul(interface_cost) + this_function_weight; + + let runtime = ssa.functions[&func].runtime(); + // We inline if the aggressiveness is higher than inline cost minus the retain cost + // If aggressiveness is infinite, we'll always inline + // If aggressiveness is 0, we'll inline when the inline cost is lower than the retain cost + // If aggressiveness is minus infinity, we'll never inline (other than in the mandatory cases) + let should_inline = ((inline_cost.saturating_sub(retain_cost)) < aggressiveness) + || runtime.is_inline_always() + || (runtime.is_no_predicates() && inline_no_predicates_functions); + + should_retain_function.insert(func, (!should_inline, this_function_weight)); +} + +fn compute_functions_to_retain( + ssa: &Ssa, + entry_points: &BTreeSet, + times_called: &HashMap, + inline_no_predicates_functions: bool, + aggressiveness: i64, +) -> BTreeSet { + let mut should_retain_function = HashMap::default(); + + for entry_point in entry_points.iter() { + should_retain_recursive( + ssa, + *entry_point, + times_called, + &mut should_retain_function, + im::HashSet::default(), + inline_no_predicates_functions, + aggressiveness, + ); + } + + should_retain_function + .into_iter() + .filter_map( + |(func_id, (should_retain, _))| { + if should_retain { + Some(func_id) + } else { + None + } + }, + ) .collect() } +fn compute_function_own_weight(func: &Function) -> usize { + let mut weight = 0; + for block_id in func.reachable_blocks() { + weight += func.dfg[block_id].instructions().len() + 1; // We add one for the terminator + } + // We use an approximation of the average increase in instruction ratio from SSA to Brillig + // In order to get the actual weight we'd need to codegen this function to brillig. + weight +} + +fn compute_function_interface_cost(func: &Function) -> usize { + func.parameters().len() + func.returns().len() +} + impl InlineContext { /// Create a new context object for the function inlining pass. /// This starts off with an empty mapping of instructions for main's parameters. @@ -234,7 +356,7 @@ impl InlineContext { ssa: &Ssa, entry_point: FunctionId, inline_no_predicates_functions: bool, - recursive_functions: BTreeSet, + functions_not_to_inline: BTreeSet, ) -> InlineContext { let source = &ssa.functions[&entry_point]; let mut builder = FunctionBuilder::new(source.name().to_owned(), entry_point); @@ -245,7 +367,7 @@ impl InlineContext { entry_point, call_stack: CallStack::new(), inline_no_predicates_functions, - recursive_functions, + functions_not_to_inline, } } @@ -526,8 +648,8 @@ impl<'function> PerFunctionContext<'function> { !inline_type.is_entry_point() && !preserve_function } else { // If the called function is brillig, we inline only if it's into brillig and the function is not recursive - ssa.functions[&self.context.entry_point].runtime() == RuntimeType::Brillig - && !self.context.recursive_functions.contains(&called_func_id) + matches!(ssa.functions[&self.context.entry_point].runtime(), RuntimeType::Brillig(_)) + && !self.context.functions_not_to_inline.contains(&called_func_id) } } @@ -696,9 +818,10 @@ mod test { function_builder::FunctionBuilder, ir::{ basic_block::BasicBlockId, + function::RuntimeType, instruction::{BinaryOp, Intrinsic, TerminatorInstruction}, map::Id, - types::Type, + types::{NumericType, Type}, }, }; @@ -729,7 +852,7 @@ mod test { let ssa = builder.finish(); assert_eq!(ssa.functions.len(), 2); - let inlined = ssa.inline_functions(); + let inlined = ssa.inline_functions(i64::MAX); assert_eq!(inlined.functions.len(), 1); } @@ -795,7 +918,7 @@ mod test { let ssa = builder.finish(); assert_eq!(ssa.functions.len(), 4); - let inlined = ssa.inline_functions(); + let inlined = ssa.inline_functions(i64::MAX); assert_eq!(inlined.functions.len(), 1); } @@ -869,7 +992,7 @@ mod test { // b6(): // return Field 120 // } - let inlined = ssa.inline_functions(); + let inlined = ssa.inline_functions(i64::MAX); assert_eq!(inlined.functions.len(), 1); let main = inlined.main(); @@ -952,7 +1075,7 @@ mod test { builder.switch_to_block(join_block); builder.terminate_with_return(vec![join_param]); - let ssa = builder.finish().inline_functions(); + let ssa = builder.finish().inline_functions(i64::MAX); // Expected result: // fn main f3 { // b0(v0: u1): @@ -989,7 +1112,96 @@ mod test { let ssa = builder.finish(); assert_eq!(ssa.functions.len(), 1); - let inlined = ssa.inline_functions(); + let inlined = ssa.inline_functions(i64::MAX); assert_eq!(inlined.functions.len(), 0); } + + #[test] + fn inliner_disabled() { + // brillig fn foo { + // b0(): + // v0 = call bar() + // return v0 + // } + // brillig fn bar { + // b0(): + // return 72 + // } + let foo_id = Id::test_new(0); + let mut builder = FunctionBuilder::new("foo".into(), foo_id); + builder.set_runtime(RuntimeType::Brillig(InlineType::default())); + + let bar_id = Id::test_new(1); + let bar = builder.import_function(bar_id); + let results = builder.insert_call(bar, Vec::new(), vec![Type::field()]).to_vec(); + builder.terminate_with_return(results); + + builder.new_brillig_function("bar".into(), bar_id, InlineType::default()); + let expected_return = 72u128; + let seventy_two = builder.field_constant(expected_return); + builder.terminate_with_return(vec![seventy_two]); + + let ssa = builder.finish(); + assert_eq!(ssa.functions.len(), 2); + + let inlined = ssa.inline_functions(i64::MIN); + // No inlining has happened + assert_eq!(inlined.functions.len(), 2); + } + + #[test] + fn conditional_inlining() { + // In this example we call a larger brillig function 3 times so the inliner refuses to inline the function. + // brillig fn foo { + // b0(): + // v0 = call bar() + // v1 = call bar() + // v2 = call bar() + // return v0 + // } + // brillig fn bar { + // b0(): + // jmpif 1 then: b1, else: b2 + // b1(): + // jmp b3(Field 1) + // b3(v3: Field): + // return v3 + // b2(): + // jmp b3(Field 2) + // } + let foo_id = Id::test_new(0); + let mut builder = FunctionBuilder::new("foo".into(), foo_id); + builder.set_runtime(RuntimeType::Brillig(InlineType::default())); + + let bar_id = Id::test_new(1); + let bar = builder.import_function(bar_id); + let v0 = builder.insert_call(bar, Vec::new(), vec![Type::field()]).to_vec(); + let _v1 = builder.insert_call(bar, Vec::new(), vec![Type::field()]).to_vec(); + let _v2 = builder.insert_call(bar, Vec::new(), vec![Type::field()]).to_vec(); + builder.terminate_with_return(v0); + + builder.new_brillig_function("bar".into(), bar_id, InlineType::default()); + let bar_v0 = + builder.numeric_constant(1_usize, Type::Numeric(NumericType::Unsigned { bit_size: 1 })); + let then_block = builder.insert_block(); + let else_block = builder.insert_block(); + let join_block = builder.insert_block(); + builder.terminate_with_jmpif(bar_v0, then_block, else_block); + builder.switch_to_block(then_block); + let one = builder.numeric_constant(FieldElement::one(), Type::field()); + builder.terminate_with_jmp(join_block, vec![one]); + builder.switch_to_block(else_block); + let two = builder.numeric_constant(FieldElement::from(2_u128), Type::field()); + builder.terminate_with_jmp(join_block, vec![two]); + let join_param = builder.add_block_parameter(join_block, Type::field()); + builder.switch_to_block(join_block); + builder.terminate_with_return(vec![join_param]); + + let ssa = builder.finish(); + assert_eq!(ssa.functions.len(), 2); + + let inlined = ssa.inline_functions(0); + // No inlining has happened + assert_eq!(inlined.functions.len(), 2); + } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/rc.rs b/compiler/noirc_evaluator/src/ssa/opt/rc.rs index c879f6c8fff..c3606ac4311 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/rc.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/rc.rs @@ -155,6 +155,8 @@ fn remove_instructions(to_remove: HashSet, function: &mut Functio mod test { use std::sync::Arc; + use noirc_frontend::monomorphization::ast::InlineType; + use crate::ssa::{ function_builder::FunctionBuilder, ir::{ @@ -199,7 +201,7 @@ mod test { // } let main_id = Id::test_new(0); let mut builder = FunctionBuilder::new("foo".into(), main_id); - builder.set_runtime(RuntimeType::Brillig); + builder.set_runtime(RuntimeType::Brillig(InlineType::default())); let inner_array_type = Type::Array(Arc::new(vec![Type::field()]), 2); let v0 = builder.add_parameter(inner_array_type.clone()); diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs index 4b2d753f072..6f3f2fa14b7 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_bit_shifts.rs @@ -31,7 +31,7 @@ impl Function { /// The structure of this pass is simple: /// Go through each block and re-insert all instructions. pub(crate) fn remove_bit_shifts(&mut self) { - if let RuntimeType::Brillig = self.runtime() { + if matches!(self.runtime(), RuntimeType::Brillig(_)) { return; } diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs index daae2cb08ce..222ae0aaf29 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_enable_side_effects.rs @@ -37,7 +37,7 @@ impl Ssa { impl Function { pub(crate) fn remove_enable_side_effects(&mut self) { - if matches!(self.runtime(), RuntimeType::Brillig) { + if matches!(self.runtime(), RuntimeType::Brillig(_)) { // Brillig functions do not make use of the `EnableSideEffects` instruction so are unaffected by this pass. return; } diff --git a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs index 299669b9564..bfcfada2d94 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/remove_if_else.rs @@ -3,6 +3,7 @@ use std::collections::hash_map::Entry; use acvm::{acir::AcirField, FieldElement}; use fxhash::FxHashMap as HashMap; +use crate::ssa::ir::function::RuntimeType; use crate::ssa::ir::value::ValueId; use crate::ssa::{ ir::{ @@ -37,7 +38,7 @@ impl Ssa { impl Function { pub(crate) fn remove_if_else(&mut self) { // This should match the check in flatten_cfg - if let crate::ssa::ir::function::RuntimeType::Brillig = self.runtime() { + if matches!(self.runtime(), RuntimeType::Brillig(_)) { // skip } else { Context::default().remove_if_else(self); diff --git a/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs b/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs index 1768cbddec3..3d40c88d704 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/resolve_is_unconstrained.rs @@ -48,7 +48,7 @@ impl Function { self.dfg.replace_result(instruction_id, original_return_id); let is_within_unconstrained = self.dfg.make_constant( - FieldElement::from(matches!(self.runtime(), RuntimeType::Brillig)), + FieldElement::from(matches!(self.runtime(), RuntimeType::Brillig(_))), Type::bool(), ); // Replace all uses of the original return value with the constant diff --git a/compiler/noirc_evaluator/src/ssa/opt/runtime_separation.rs b/compiler/noirc_evaluator/src/ssa/opt/runtime_separation.rs index c0c9c0a1372..5628e12b9ae 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/runtime_separation.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/runtime_separation.rs @@ -70,7 +70,7 @@ impl RuntimeSeparatorContext { processed_functions.insert((within_brillig, current_func_id)); let func = &ssa.functions[¤t_func_id]; - if func.runtime() == RuntimeType::Brillig { + if matches!(func.runtime(), RuntimeType::Brillig(_)) { within_brillig = true; } @@ -97,17 +97,20 @@ impl RuntimeSeparatorContext { fn convert_acir_functions_called_from_brillig_to_brillig(&mut self, ssa: &mut Ssa) { for acir_func_id in self.acir_functions_called_from_brillig.iter() { + let RuntimeType::Acir(inline_type) = ssa.functions[acir_func_id].runtime() else { + unreachable!("Function to transform to brillig should be ACIR") + }; let cloned_id = ssa.clone_fn(*acir_func_id); let new_func = ssa.functions.get_mut(&cloned_id).expect("Cloned function should exist in SSA"); - new_func.set_runtime(RuntimeType::Brillig); + new_func.set_runtime(RuntimeType::Brillig(inline_type)); self.mapped_functions.insert(*acir_func_id, cloned_id); } } fn replace_calls_to_mapped_functions(&self, ssa: &mut Ssa) { for (_function_id, func) in ssa.functions.iter_mut() { - if func.runtime() == RuntimeType::Brillig { + if matches!(func.runtime(), RuntimeType::Brillig(_)) { for called_func_value_id in called_functions_values(func).iter() { let Value::Function(called_func_id) = &func.dfg[*called_func_value_id] else { unreachable!("Value should be a function") @@ -207,7 +210,7 @@ mod test { // } let foo_id = Id::test_new(0); let mut builder = FunctionBuilder::new("foo".into(), foo_id); - builder.current_function.set_runtime(RuntimeType::Brillig); + builder.current_function.set_runtime(RuntimeType::Brillig(InlineType::default())); let bar_id = Id::test_new(1); let bar = builder.import_function(bar_id); @@ -239,7 +242,7 @@ mod test { // All functions should be brillig now for func in separated.functions.values() { - assert_eq!(func.runtime(), RuntimeType::Brillig); + assert_eq!(func.runtime(), RuntimeType::Brillig(InlineType::default())); } } @@ -289,7 +292,7 @@ mod test { let v1 = builder.insert_call(baz, Vec::new(), vec![Type::field()]).to_vec(); builder.terminate_with_return(vec![v0[0], v1[0]]); - builder.new_brillig_function("bar".into(), bar_id); + builder.new_brillig_function("bar".into(), bar_id, InlineType::default()); let baz = builder.import_function(baz_id); let v0 = builder.insert_call(baz, Vec::new(), vec![Type::field()]).to_vec(); builder.terminate_with_return(v0); @@ -337,12 +340,12 @@ mod test { let baz_acir = find_func_by_name(&separated, &main_calls, "baz"); assert_eq!(baz_acir.runtime(), RuntimeType::Acir(InlineType::Inline)); - assert_eq!(bar.runtime(), RuntimeType::Brillig); + assert_eq!(bar.runtime(), RuntimeType::Brillig(InlineType::default())); let bar_calls = called_functions(bar); assert_eq!(bar_calls.len(), 1); let baz_brillig = find_func_by_name(&separated, &bar_calls, "baz"); - assert_eq!(baz_brillig.runtime(), RuntimeType::Brillig); + assert_eq!(baz_brillig.runtime(), RuntimeType::Brillig(InlineType::default())); } } diff --git a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs index d6ed11ddf0e..5fe0d00c2b9 100644 --- a/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs +++ b/compiler/noirc_evaluator/src/ssa/opt/unrolling.rs @@ -114,7 +114,7 @@ impl Function { // Loop unrolling in brillig can lead to a code explosion currently. This can // also be true for ACIR, but we have no alternative to unrolling in ACIR. // Brillig also generally prefers smaller code rather than faster code. - if self.runtime() != RuntimeType::Brillig { + if !matches!(self.runtime(), RuntimeType::Brillig(_)) { errors.extend(find_all_loops(self).unroll_each_loop(self)); } } diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs index c71c3a33edf..0c6041029da 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/context.rs @@ -128,7 +128,7 @@ impl<'a> FunctionContext<'a> { ) { self.definitions.clear(); if func.unconstrained || (force_brillig_runtime && func.inline_type != InlineType::Inline) { - self.builder.new_brillig_function(func.name.clone(), id); + self.builder.new_brillig_function(func.name.clone(), id, func.inline_type); } else { self.builder.new_function(func.name.clone(), id, func.inline_type); } diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs index 2318fea8960..8bf3a740b3a 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/mod.rs @@ -58,7 +58,7 @@ pub(crate) fn generate_ssa( main.name.clone(), &main.parameters, if force_brillig_runtime || main.unconstrained { - RuntimeType::Brillig + RuntimeType::Brillig(main.inline_type) } else { RuntimeType::Acir(main.inline_type) }, diff --git a/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs b/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs index fe786da16ca..3dba6dc0a98 100644 --- a/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs +++ b/compiler/noirc_evaluator/src/ssa/ssa_gen/program.rs @@ -54,7 +54,7 @@ impl Ssa { let runtime = func.runtime(); match func.runtime() { RuntimeType::Acir(_) => runtime.is_entry_point() || func.id() == main_id, - RuntimeType::Brillig => false, + RuntimeType::Brillig(_) => false, } }) .enumerate(), diff --git a/compiler/noirc_frontend/src/ast/function.rs b/compiler/noirc_frontend/src/ast/function.rs index 4f55e4c2c76..70d2b3dbb39 100644 --- a/compiler/noirc_frontend/src/ast/function.rs +++ b/compiler/noirc_frontend/src/ast/function.rs @@ -117,6 +117,7 @@ impl From for NoirFunction { Some(FunctionAttribute::Recursive) => FunctionKind::Recursive, Some(FunctionAttribute::Fold) => FunctionKind::Normal, Some(FunctionAttribute::NoPredicates) => FunctionKind::Normal, + Some(FunctionAttribute::InlineAlways) => FunctionKind::Normal, None => FunctionKind::Normal, }; diff --git a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs index 1011d71be16..273f34a8a5e 100644 --- a/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs +++ b/compiler/noirc_frontend/src/hir/comptime/interpreter/builtin.rs @@ -134,6 +134,9 @@ impl<'local, 'context> Interpreter<'local, 'context> { "function_def_set_return_public" => { function_def_set_return_public(self, arguments, location) } + "function_def_set_return_data" => { + function_def_set_return_data(self, arguments, location) + } "function_def_set_unconstrained" => { function_def_set_unconstrained(self, arguments, location) } @@ -2252,7 +2255,10 @@ fn function_def_add_attribute( } } - if let Attribute::Secondary(SecondaryAttribute::Tag(attribute)) = attribute { + if let Attribute::Secondary( + SecondaryAttribute::Tag(attribute) | SecondaryAttribute::Meta(attribute), + ) = attribute + { let func_meta = interpreter.elaborator.interner.function_meta_mut(&func_id); func_meta.custom_attributes.push(attribute); } @@ -2525,6 +2531,23 @@ fn function_def_set_return_public( Ok(Value::Unit) } +// fn set_return_data(self) +fn function_def_set_return_data( + interpreter: &mut Interpreter, + arguments: Vec<(Value, Location)>, + location: Location, +) -> IResult { + let self_argument = check_one_argument(arguments, location)?; + + let func_id = get_function_def(self_argument)?; + check_function_not_yet_resolved(interpreter, func_id, location)?; + + let func_meta = interpreter.elaborator.interner.function_meta_mut(&func_id); + func_meta.return_visibility = Visibility::ReturnData; + + Ok(Value::Unit) +} + // fn set_unconstrained(self, value: bool) fn function_def_set_unconstrained( interpreter: &mut Interpreter, diff --git a/compiler/noirc_frontend/src/lexer/token.rs b/compiler/noirc_frontend/src/lexer/token.rs index 4037135a889..a8e463fb93b 100644 --- a/compiler/noirc_frontend/src/lexer/token.rs +++ b/compiler/noirc_frontend/src/lexer/token.rs @@ -796,6 +796,7 @@ impl Attribute { ["recursive"] => Attribute::Function(FunctionAttribute::Recursive), ["fold"] => Attribute::Function(FunctionAttribute::Fold), ["no_predicates"] => Attribute::Function(FunctionAttribute::NoPredicates), + ["inline_always"] => Attribute::Function(FunctionAttribute::InlineAlways), ["test", name] => { validate(name)?; let malformed_scope = @@ -856,6 +857,7 @@ pub enum FunctionAttribute { Recursive, Fold, NoPredicates, + InlineAlways, } impl FunctionAttribute { @@ -903,6 +905,13 @@ impl FunctionAttribute { matches!(self, FunctionAttribute::NoPredicates) } + /// Check whether we have an `inline_always` attribute + /// This is used to indicate that a function should always be inlined + /// regardless of the target runtime. + pub fn is_inline_always(&self) -> bool { + matches!(self, FunctionAttribute::InlineAlways) + } + pub fn name(&self) -> &'static str { match self { FunctionAttribute::Foreign(_) => "foreign", @@ -912,6 +921,7 @@ impl FunctionAttribute { FunctionAttribute::Recursive => "recursive", FunctionAttribute::Fold => "fold", FunctionAttribute::NoPredicates => "no_predicates", + FunctionAttribute::InlineAlways => "inline_always", } } } @@ -926,6 +936,7 @@ impl fmt::Display for FunctionAttribute { FunctionAttribute::Recursive => write!(f, "#[recursive]"), FunctionAttribute::Fold => write!(f, "#[fold]"), FunctionAttribute::NoPredicates => write!(f, "#[no_predicates]"), + FunctionAttribute::InlineAlways => write!(f, "#[inline_always]"), } } } @@ -1052,6 +1063,7 @@ impl AsRef for FunctionAttribute { FunctionAttribute::Recursive => "", FunctionAttribute::Fold => "", FunctionAttribute::NoPredicates => "", + FunctionAttribute::InlineAlways => "", } } } diff --git a/compiler/noirc_frontend/src/monomorphization/ast.rs b/compiler/noirc_frontend/src/monomorphization/ast.rs index eb6b4bf7bd4..1b4bafd9d78 100644 --- a/compiler/noirc_frontend/src/monomorphization/ast.rs +++ b/compiler/noirc_frontend/src/monomorphization/ast.rs @@ -222,6 +222,8 @@ pub enum InlineType { /// All function calls are expected to be inlined into a single ACIR. #[default] Inline, + /// Functions marked as inline always will always be inlined, even in brillig contexts. + InlineAlways, /// Functions marked as foldable will not be inlined and compiled separately into ACIR Fold, /// Functions marked to have no predicates will not be inlined in the default inlining pass @@ -239,6 +241,7 @@ impl From<&Attributes> for InlineType { match func_attribute { FunctionAttribute::Fold => InlineType::Fold, FunctionAttribute::NoPredicates => InlineType::NoPredicates, + FunctionAttribute::InlineAlways => InlineType::InlineAlways, _ => InlineType::default(), } }) @@ -249,6 +252,7 @@ impl InlineType { pub fn is_entry_point(&self) -> bool { match self { InlineType::Inline => false, + InlineType::InlineAlways => false, InlineType::Fold => true, InlineType::NoPredicates => false, } @@ -259,6 +263,7 @@ impl std::fmt::Display for InlineType { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { match self { InlineType::Inline => write!(f, "inline"), + InlineType::InlineAlways => write!(f, "inline_always"), InlineType::Fold => write!(f, "fold"), InlineType::NoPredicates => write!(f, "no_predicates"), } @@ -320,7 +325,7 @@ pub struct Program { pub main_function_signature: FunctionSignature, pub return_location: Option, pub return_visibility: Visibility, - /// Indicates to a backend whether a SNARK-friendly prover should be used. + /// Indicates to a backend whether a SNARK-friendly prover should be used. pub recursive: bool, pub debug_variables: DebugVariables, pub debug_functions: DebugFunctions, diff --git a/compiler/noirc_frontend/src/tests.rs b/compiler/noirc_frontend/src/tests.rs index b2800717d90..17acd17dcc9 100644 --- a/compiler/noirc_frontend/src/tests.rs +++ b/compiler/noirc_frontend/src/tests.rs @@ -195,7 +195,7 @@ fn check_trait_implementation_duplicate_method() { x + 2 * y } } - + fn main() { let _ = Foo { bar: 1, array: [2, 3] }; // silence Foo never constructed warning }"; @@ -644,7 +644,7 @@ fn check_impl_struct_not_trait() { Self { bar: x, array: [x,y] } } } - + fn main() { let _ = Default { x: 1, z: 1 }; // silence Default never constructed warning } @@ -1572,7 +1572,7 @@ fn struct_numeric_generic_in_function() { inner: u64 } - pub fn bar() { + pub fn bar() { let _ = Foo { inner: 1 }; // silence Foo never constructed warning } "#; @@ -2156,7 +2156,7 @@ fn numeric_generics_type_kind_mismatch() { } global M: u16 = 3; - + fn main() { let _ = bar::(); } @@ -2194,7 +2194,7 @@ fn numeric_generics_value_kind_mismatch_u32_u64() { } impl BoundedVec { - pub fn extend_from_bounded_vec(&mut self, _vec: BoundedVec) { + pub fn extend_from_bounded_vec(&mut self, _vec: BoundedVec) { // We do this to avoid an unused variable warning on `self` let _ = self.len; for _ in 0..Len { } @@ -2485,7 +2485,7 @@ fn trait_impl_where_clause_stricter_pass() { fn bad_foo() where A: OtherTrait { } } - + fn main() { let _ = Option { inner: 1 }; // silence Option never constructed warning } diff --git a/noir_stdlib/src/collections/umap.nr b/noir_stdlib/src/collections/umap.nr index 8a7e6f81103..33010e75560 100644 --- a/noir_stdlib/src/collections/umap.nr +++ b/noir_stdlib/src/collections/umap.nr @@ -21,7 +21,7 @@ pub struct UHashMap { } // Data unit in the UHashMap table. -// In case Noir adds support for enums in the future, this +// In case Noir adds support for enums in the future, this // should be refactored to have three states: // 1. (key, value) // 2. (empty) @@ -60,7 +60,7 @@ impl Slot { } // Shall not override `_key_value` with Option::none(), - // because we must be able to differentiate empty + // because we must be able to differentiate empty // and deleted slots for lookup. fn mark_deleted(&mut self) { self._is_deleted = true; @@ -68,7 +68,7 @@ impl Slot { } // While conducting lookup, we iterate attempt from 0 to N - 1 due to heuristic, -// that if we have went that far without finding desired, +// that if we have went that far without finding desired, // it is very unlikely to be after - performance will be heavily degraded. impl UHashMap { // Creates a new instance of UHashMap with specified BuildHasher. @@ -213,7 +213,7 @@ impl UHashMap { pub unconstrained fn iter_keys_mut( &mut self, f: fn(K) -> K - ) + ) where K: Eq + Hash, B: BuildHasher, @@ -307,7 +307,7 @@ impl UHashMap { result } - // Insert key-value entry. In case key was already present, value is overridden. + // Insert key-value entry. In case key was already present, value is overridden. // docs:start:insert pub unconstrained fn insert( &mut self, @@ -407,14 +407,14 @@ impl UHashMap { // Probing scheme: quadratic function. // We use 0.5 constant near variadic attempt and attempt^2 monomials. // This ensures good uniformity of distribution for table sizes - // equal to prime numbers or powers of two. + // equal to prime numbers or powers of two. fn quadratic_probe(self: Self, hash: u32, attempt: u32) -> u32 { (hash + (attempt + attempt * attempt) / 2) % self._table.len() } } -// Equality class on UHashMap has to test that they have -// equal sets of key-value entries, +// Equality class on UHashMap has to test that they have +// equal sets of key-value entries, // thus one is a subset of the other and vice versa. // docs:start:eq impl Eq for UHashMap diff --git a/noir_stdlib/src/field/bn254.nr b/noir_stdlib/src/field/bn254.nr index 532fcd59a62..9349e67aed3 100644 --- a/noir_stdlib/src/field/bn254.nr +++ b/noir_stdlib/src/field/bn254.nr @@ -70,8 +70,8 @@ fn assert_gt_limbs(a: (Field, Field), b: (Field, Field)) { let rlo = alo - blo - 1 + (borrow as Field) * TWO_POW_128; let rhi = ahi - bhi - (borrow as Field); - rlo.assert_max_bit_size(128); - rhi.assert_max_bit_size(128); + rlo.assert_max_bit_size::<128>(); + rhi.assert_max_bit_size::<128>(); } } @@ -85,8 +85,8 @@ pub fn decompose(x: Field) -> (Field, Field) { let (xlo, xhi) = decompose_hint(x); // Range check the limbs - xlo.assert_max_bit_size(128); - xhi.assert_max_bit_size(128); + xlo.assert_max_bit_size::<128>(); + xhi.assert_max_bit_size::<128>(); // Check that the decomposition is correct assert_eq(x, xlo + TWO_POW_128 * xhi); diff --git a/noir_stdlib/src/field/mod.nr b/noir_stdlib/src/field/mod.nr index 35f95541354..4a329aaeb59 100644 --- a/noir_stdlib/src/field/mod.nr +++ b/noir_stdlib/src/field/mod.nr @@ -8,11 +8,10 @@ impl Field { /// # Failures /// Causes a constraint failure for `Field` values exceeding `2^{bit_size}`. // docs:start:assert_max_bit_size - pub fn assert_max_bit_size(self, bit_size: u32) { + pub fn assert_max_bit_size(self) { // docs:end:assert_max_bit_size - crate::assert_constant(bit_size); - assert(bit_size < modulus_num_bits() as u32); - self.__assert_max_bit_size(bit_size); + assert(BIT_SIZE < modulus_num_bits() as u32); + self.__assert_max_bit_size(BIT_SIZE); } #[builtin(apply_range_constraint)] @@ -20,7 +19,7 @@ impl Field { /// Decomposes `self` into its little endian bit decomposition as a `[u1; N]` array. /// This slice will be zero padded should not all bits be necessary to represent `self`. - /// + /// /// # Failures /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not /// be able to represent the original `Field`. @@ -36,7 +35,7 @@ impl Field { /// Decomposes `self` into its big endian bit decomposition as a `[u1; N]` array. /// This array will be zero padded should not all bits be necessary to represent `self`. - /// + /// /// # Failures /// Causes a constraint failure for `Field` values exceeding `2^N` as the resulting slice will not /// be able to represent the original `Field`. @@ -118,14 +117,20 @@ impl Field { // docs:start:to_le_radix pub fn to_le_radix(self: Self, radix: u32) -> [u8; N] { - crate::assert_constant(radix); + // Brillig does not need an immediate radix + if !crate::runtime::is_unconstrained() { + crate::assert_constant(radix); + } self.__to_le_radix(radix) } // docs:end:to_le_radix // docs:start:to_be_radix pub fn to_be_radix(self: Self, radix: u32) -> [u8; N] { - crate::assert_constant(radix); + // Brillig does not need an immediate radix + if !crate::runtime::is_unconstrained() { + crate::assert_constant(radix); + } self.__to_be_radix(radix) } // docs:end:to_be_radix diff --git a/noir_stdlib/src/hash/mod.nr b/noir_stdlib/src/hash/mod.nr index e8c0ce81a16..7cd4b8e292e 100644 --- a/noir_stdlib/src/hash/mod.nr +++ b/noir_stdlib/src/hash/mod.nr @@ -32,21 +32,8 @@ pub fn pedersen_commitment(input: [Field; N]) -> EmbeddedCurvePoint pedersen_commitment_with_separator(input, 0) } -pub fn pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field { - pedersen_hash_with_separator_noir(input, separator) -} - +#[inline_always] pub fn pedersen_commitment_with_separator(input: [Field; N], separator: u32) -> EmbeddedCurvePoint { - let value = __pedersen_commitment_with_separator(input, separator); - if (value[0] == 0) & (value[1] == 0) { - EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true } - } else { - EmbeddedCurvePoint { x: value[0], y: value[1], is_infinite: false } - } -} - -#[no_predicates] -fn pedersen_commitment_with_separator_noir(input: [Field; N], separator: u32) -> EmbeddedCurvePoint { let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N]; for i in 0..N { // we use the unsafe version because the multi_scalar_mul will constrain the scalars. @@ -56,8 +43,15 @@ fn pedersen_commitment_with_separator_noir(input: [Field; N], separa multi_scalar_mul(generators, points) } +// docs:start:pedersen_hash +pub fn pedersen_hash(input: [Field; N]) -> Field +// docs:end:pedersen_hash +{ + pedersen_hash_with_separator(input, 0) +} + #[no_predicates] -fn pedersen_hash_with_separator_noir(input: [Field; N], separator: u32) -> Field { +pub fn pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field { let mut scalars: Vec = Vec::from_slice([EmbeddedCurveScalar { lo: 0, hi: 0 }; N].as_slice()); //Vec::new(); for i in 0..N { @@ -74,19 +68,6 @@ fn pedersen_hash_with_separator_noir(input: [Field; N], separator: u multi_scalar_mul_slice(vec_generators.slice, scalars.slice)[0] } -// docs:start:pedersen_hash -pub fn pedersen_hash(input: [Field; N]) -> Field -// docs:end:pedersen_hash -{ - pedersen_hash_with_separator_noir(input, 0) -} - -#[foreign(pedersen_hash)] -fn __pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field {} - -#[foreign(pedersen_commitment)] -fn __pedersen_commitment_with_separator(input: [Field; N], separator: u32) -> [Field; 2] {} - #[field(bn254)] pub fn derive_generators(domain_separator_bytes: [u8; M], starting_index: u32) -> [EmbeddedCurvePoint; N] { crate::assert_constant(domain_separator_bytes); diff --git a/noir_stdlib/src/lib.nr b/noir_stdlib/src/lib.nr index 3d1dd3e90eb..f1ef6aca83c 100644 --- a/noir_stdlib/src/lib.nr +++ b/noir_stdlib/src/lib.nr @@ -67,7 +67,9 @@ pub fn verify_proof_with_type( key_hash: Field, proof_type: u32 ) { - crate::assert_constant(proof_type); + if !crate::runtime::is_unconstrained() { + crate::assert_constant(proof_type); + } verify_proof_internal(verification_key, proof, public_inputs, key_hash, proof_type); } diff --git a/noir_stdlib/src/meta/function_def.nr b/noir_stdlib/src/meta/function_def.nr index 3c29d57e20c..11dc169b188 100644 --- a/noir_stdlib/src/meta/function_def.nr +++ b/noir_stdlib/src/meta/function_def.nr @@ -59,6 +59,9 @@ impl FunctionDefinition { pub comptime fn set_return_public(self, public: bool) {} // docs:end:set_return_public + #[builtin(function_def_set_return_data)] + comptime fn set_return_data(self) {} + #[builtin(function_def_set_unconstrained)] // docs:start:set_unconstrained pub comptime fn set_unconstrained(self, value: bool) {} diff --git a/noir_stdlib/src/uint128.nr b/noir_stdlib/src/uint128.nr index 4a035ef91ef..e4a4342c3d1 100644 --- a/noir_stdlib/src/uint128.nr +++ b/noir_stdlib/src/uint128.nr @@ -111,7 +111,7 @@ impl U128 { }) as Field } - // TODO: Replace with a faster version. + // TODO: Replace with a faster version. // A circuit that uses this function can be slow to compute // (we're doing up to 127 calls to compute the quotient) unconstrained fn unconstrained_div(self: Self, b: U128) -> (U128, U128) { @@ -141,7 +141,7 @@ impl U128 { pub fn from_integer(i: T) -> U128 { let f = crate::as_field(i); // Reject values which would overflow a u128 - f.assert_max_bit_size(128); + f.assert_max_bit_size::<128>(); let lo = f as u64 as Field; let hi = (f - lo) / pow64; U128 { lo, hi } diff --git a/scripts/install_bb.sh b/scripts/install_bb.sh index c94a1b7dff0..596f0a54ba4 100755 --- a/scripts/install_bb.sh +++ b/scripts/install_bb.sh @@ -1,6 +1,6 @@ #!/bin/bash -VERSION="0.56.0" +VERSION="0.58.0" BBUP_PATH=~/.bb/bbup diff --git a/test_programs/execution_success/check_large_field_bits/src/main.nr b/test_programs/execution_success/check_large_field_bits/src/main.nr index 1d65b342966..542a06ecb6f 100644 --- a/test_programs/execution_success/check_large_field_bits/src/main.nr +++ b/test_programs/execution_success/check_large_field_bits/src/main.nr @@ -23,7 +23,7 @@ fn main() { // 8589934594 has 34 bits assert(size == 34); - C.assert_max_bit_size(34); + C.assert_max_bit_size::<34>(); assert( C.to_be_bits() == [ diff --git a/test_programs/execution_success/inline_never_basic/Nargo.toml b/test_programs/execution_success/inline_never_basic/Nargo.toml new file mode 100644 index 00000000000..16691770d76 --- /dev/null +++ b/test_programs/execution_success/inline_never_basic/Nargo.toml @@ -0,0 +1,7 @@ +[package] +name = "inline_never_basic" +type = "bin" +authors = [""] +compiler_version = ">=0.27.0" + +[dependencies] \ No newline at end of file diff --git a/test_programs/execution_success/inline_never_basic/Prover.toml b/test_programs/execution_success/inline_never_basic/Prover.toml new file mode 100644 index 00000000000..fbe96700abe --- /dev/null +++ b/test_programs/execution_success/inline_never_basic/Prover.toml @@ -0,0 +1,2 @@ +x = "5" +y = "10" \ No newline at end of file diff --git a/test_programs/execution_success/inline_never_basic/src/main.nr b/test_programs/execution_success/inline_never_basic/src/main.nr new file mode 100644 index 00000000000..505a1641c76 --- /dev/null +++ b/test_programs/execution_success/inline_never_basic/src/main.nr @@ -0,0 +1,8 @@ +fn main(x: Field, y: pub Field) { + basic_check(x, y); +} + +#['inline(never)] +fn basic_check(x: Field, y: Field) { + assert(x != y); +} diff --git a/test_programs/execution_success/unsafe_range_constraint/src/main.nr b/test_programs/execution_success/unsafe_range_constraint/src/main.nr index ead5613bcce..ed846ec20b4 100644 --- a/test_programs/execution_success/unsafe_range_constraint/src/main.nr +++ b/test_programs/execution_success/unsafe_range_constraint/src/main.nr @@ -1,5 +1,5 @@ -// Test that we can apply a range constraint to a field using +// Test that we can apply a range constraint to a field using // a builtin. fn main(x: Field) { - x.assert_max_bit_size(48); + x.assert_max_bit_size::<48>(); } diff --git a/test_programs/noir_test_success/bounded_vec/src/main.nr b/test_programs/noir_test_success/bounded_vec/src/main.nr index 0ad5840ba32..fa2c55e6934 100644 --- a/test_programs/noir_test_success/bounded_vec/src/main.nr +++ b/test_programs/noir_test_success/bounded_vec/src/main.nr @@ -79,7 +79,7 @@ fn set_unchecked_example() { // We've now written past the end of `vec`. // As this index is still within the maximum potential length of `v`, - // it won't cause a constraint failure. + // it won't cause a constraint failure. vec.set_unchecked(2, 42); println(vec); @@ -189,13 +189,13 @@ fn test_vec_extend_from_bounded_vec() { // docs:end:bounded-vec-extend-from-bounded-vec-example } -#[test(should_fail_with="extend_from_array out of bounds")] +#[test(should_fail_with = "extend_from_array out of bounds")] fn test_vec_extend_from_array_out_of_bound() { let mut vec: BoundedVec = BoundedVec::new(); vec.extend_from_array([2, 4, 6]); } -#[test(should_fail_with="extend_from_array out of bounds")] +#[test(should_fail_with = "extend_from_array out of bounds")] fn test_vec_extend_from_array_twice_out_of_bound() { let mut vec: BoundedVec = BoundedVec::new(); vec.extend_from_array([2]); @@ -223,14 +223,14 @@ fn test_vec_get_uninitialized() { let _x = vec.get(0); } -#[test(should_fail_with="push out of bounds")] +#[test(should_fail_with = "push out of bounds")] fn test_vec_push_out_of_bound() { let mut vec: BoundedVec = BoundedVec::new(); vec.push(1); vec.push(2); } -#[test(should_fail_with="extend_from_bounded_vec out of bounds")] +#[test(should_fail_with = "extend_from_bounded_vec out of bounds")] fn test_vec_extend_from_bounded_vec_out_of_bound() { let mut vec: BoundedVec = BoundedVec::new(); @@ -240,7 +240,7 @@ fn test_vec_extend_from_bounded_vec_out_of_bound() { vec.extend_from_bounded_vec(another_vec); } -#[test(should_fail_with="extend_from_bounded_vec out of bounds")] +#[test(should_fail_with = "extend_from_bounded_vec out of bounds")] fn test_vec_extend_from_bounded_vec_twice_out_of_bound() { let mut vec: BoundedVec = BoundedVec::new(); vec.extend_from_array([1, 2]); diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index dde3fe84d88..3f64fc1acdb 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -977,22 +977,22 @@ mod tests { let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(1u64), }, BrilligOpcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, BrilligOpcode::Const { - destination: MemoryAddress::from(1), + destination: MemoryAddress::direct(1), value: fe_0, bit_size: BitSize::Integer(IntegerBitSize::U32), }, @@ -1000,7 +1000,7 @@ mod tests { function: "clear_mock".into(), destinations: vec![], destination_value_types: vec![], - inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::direct(0))], input_value_types: vec![HeapValueType::field()], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, @@ -1136,25 +1136,25 @@ mod tests { let brillig_bytecode = BrilligBytecode { bytecode: vec![ BrilligOpcode::Const { - destination: MemoryAddress(0), + destination: MemoryAddress::direct(0), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(2u64), }, BrilligOpcode::Const { - destination: MemoryAddress(1), + destination: MemoryAddress::direct(1), bit_size: BitSize::Integer(IntegerBitSize::U32), value: FieldElement::from(0u64), }, BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress(0), - size_address: MemoryAddress(0), - offset_address: MemoryAddress(1), + destination_address: MemoryAddress::direct(0), + size_address: MemoryAddress::direct(0), + offset_address: MemoryAddress::direct(1), }, BrilligOpcode::BinaryFieldOp { - destination: MemoryAddress::from(0), + destination: MemoryAddress::direct(0), op: BinaryFieldOp::Add, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), + lhs: MemoryAddress::direct(0), + rhs: MemoryAddress::direct(1), }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 1 }, ], diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index 1a7c2d6c7a8..012af0e88e8 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -1,11 +1,10 @@ use crate::context::{DebugCommandResult, DebugContext, DebugLocation}; -use acvm::acir::brillig::{BitSize, IntegerBitSize}; +use acvm::acir::brillig::BitSize; use acvm::acir::circuit::brillig::{BrilligBytecode, BrilligFunctionId}; use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap, WitnessStack}; use acvm::brillig_vm::brillig::Opcode as BrilligOpcode; -use acvm::brillig_vm::MemoryValue; use acvm::{BlackBoxFunctionSolver, FieldElement}; use nargo::NargoError; use noirc_driver::CompiledProgram; @@ -369,11 +368,7 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { return; }; - for (index, value) in memory - .iter() - .enumerate() - .filter(|(_, value)| !matches!(value, MemoryValue::Integer(_, IntegerBitSize::U0))) - { + for (index, value) in memory.iter().enumerate() { println!("{index} = {}", value); } } diff --git a/tooling/lsp/src/requests/completion/builtins.rs b/tooling/lsp/src/requests/completion/builtins.rs index cf2af4036f7..078e2faf036 100644 --- a/tooling/lsp/src/requests/completion/builtins.rs +++ b/tooling/lsp/src/requests/completion/builtins.rs @@ -109,9 +109,9 @@ impl<'a> NodeFinder<'a> { if name_matches("test", prefix) || name_matches("should_fail_with", prefix) { self.completion_items.push(snippet_completion_item( - "test(should_fail_with=\"...\")", + "test(should_fail_with = \"...\")", CompletionItemKind::METHOD, - "test(should_fail_with=\"${1:message}\")", + "test(should_fail_with = \"${1:message}\")", None, )); } diff --git a/tooling/lsp/src/solver.rs b/tooling/lsp/src/solver.rs index 9d1185e3a79..3c2d7499880 100644 --- a/tooling/lsp/src/solver.rs +++ b/tooling/lsp/src/solver.rs @@ -16,22 +16,6 @@ impl BlackBoxFunctionSolver for WrapperSolver { self.0.schnorr_verify(public_key_x, public_key_y, signature, message) } - fn pedersen_commitment( - &self, - inputs: &[acvm::FieldElement], - domain_separator: u32, - ) -> Result<(acvm::FieldElement, acvm::FieldElement), acvm::BlackBoxResolutionError> { - self.0.pedersen_commitment(inputs, domain_separator) - } - - fn pedersen_hash( - &self, - inputs: &[acvm::FieldElement], - domain_separator: u32, - ) -> Result { - self.0.pedersen_hash(inputs, domain_separator) - } - fn multi_scalar_mul( &self, points: &[acvm::FieldElement], diff --git a/tooling/nargo_fmt/tests/input/fn.nr b/tooling/nargo_fmt/tests/input/fn.nr index 8ed2c565bc4..9e19222decb 100644 --- a/tooling/nargo_fmt/tests/input/fn.nr +++ b/tooling/nargo_fmt/tests/input/fn.nr @@ -47,12 +47,12 @@ pub fn from_baz(x: [Field; crate::foo::MAGIC_NUMBER]) {} fn id< T , let I : Field > ( x : [ Field ; I ] ) -> [Field; I ] { } -fn id_two(x: [Field ; I]) -> [ Field; I] {} fn whitespace_before_generics < T > (foo: T) {} -fn more_whitespace_before_generics < +fn more_whitespace_before_generics < T > (foo: T) {} fn with_unconstrained(x: unconstrained fn() -> ()) {} @@ -70,6 +70,6 @@ unconstrained pub comptime fn two() {} // comment fn four() {} -#[test(should_fail_with="oops")] +#[test(should_fail_with = "oops")] fn five() {} diff --git a/tooling/noir_js/src/index.ts b/tooling/noir_js/src/index.ts index f3016efd032..ed0999a960c 100644 --- a/tooling/noir_js/src/index.ts +++ b/tooling/noir_js/src/index.ts @@ -2,7 +2,7 @@ import * as acvm from '@noir-lang/acvm_js'; import * as abi from '@noir-lang/noirc_abi'; import { CompiledCircuit } from '@noir-lang/types'; -export { ecdsa_secp256r1_verify, ecdsa_secp256k1_verify, keccak256, blake2s256, xor, and } from '@noir-lang/acvm_js'; +export { ecdsa_secp256r1_verify, ecdsa_secp256k1_verify, blake2s256, xor, and } from '@noir-lang/acvm_js'; export { InputMap } from '@noir-lang/noirc_abi'; export { WitnessMap, ForeignCallHandler, ForeignCallInput, ForeignCallOutput } from '@noir-lang/acvm_js'; diff --git a/tooling/noir_js_backend_barretenberg/package.json b/tooling/noir_js_backend_barretenberg/package.json index 0c96f7d213c..560f91ffdc3 100644 --- a/tooling/noir_js_backend_barretenberg/package.json +++ b/tooling/noir_js_backend_barretenberg/package.json @@ -41,7 +41,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.56.0", + "@aztec/bb.js": "0.58.0", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/tooling/profiler/src/opcode_formatter.rs b/tooling/profiler/src/opcode_formatter.rs index f367360b189..68057b6d86f 100644 --- a/tooling/profiler/src/opcode_formatter.rs +++ b/tooling/profiler/src/opcode_formatter.rs @@ -17,13 +17,10 @@ fn format_blackbox_function(call: &BlackBoxFuncCall) -> String { BlackBoxFuncCall::Blake2s { .. } => "blake2s".to_string(), BlackBoxFuncCall::Blake3 { .. } => "blake3".to_string(), BlackBoxFuncCall::SchnorrVerify { .. } => "schnorr_verify".to_string(), - BlackBoxFuncCall::PedersenCommitment { .. } => "pedersen_commitment".to_string(), - BlackBoxFuncCall::PedersenHash { .. } => "pedersen_hash".to_string(), BlackBoxFuncCall::EcdsaSecp256k1 { .. } => "ecdsa_secp256k1".to_string(), BlackBoxFuncCall::EcdsaSecp256r1 { .. } => "ecdsa_secp256r1".to_string(), BlackBoxFuncCall::MultiScalarMul { .. } => "multi_scalar_mul".to_string(), BlackBoxFuncCall::EmbeddedCurveAdd { .. } => "embedded_curve_add".to_string(), - BlackBoxFuncCall::Keccak256 { .. } => "keccak256".to_string(), BlackBoxFuncCall::Keccakf1600 { .. } => "keccakf1600".to_string(), BlackBoxFuncCall::RecursiveAggregation { .. } => "recursive_aggregation".to_string(), BlackBoxFuncCall::BigIntAdd { .. } => "big_int_add".to_string(), @@ -43,13 +40,10 @@ fn format_blackbox_op(call: &BlackBoxOp) -> String { BlackBoxOp::Blake2s { .. } => "blake2s".to_string(), BlackBoxOp::Blake3 { .. } => "blake3".to_string(), BlackBoxOp::SchnorrVerify { .. } => "schnorr_verify".to_string(), - BlackBoxOp::PedersenCommitment { .. } => "pedersen_commitment".to_string(), - BlackBoxOp::PedersenHash { .. } => "pedersen_hash".to_string(), BlackBoxOp::EcdsaSecp256k1 { .. } => "ecdsa_secp256k1".to_string(), BlackBoxOp::EcdsaSecp256r1 { .. } => "ecdsa_secp256r1".to_string(), BlackBoxOp::MultiScalarMul { .. } => "multi_scalar_mul".to_string(), BlackBoxOp::EmbeddedCurveAdd { .. } => "embedded_curve_add".to_string(), - BlackBoxOp::Keccak256 { .. } => "keccak256".to_string(), BlackBoxOp::Keccakf1600 { .. } => "keccakf1600".to_string(), BlackBoxOp::BigIntAdd { .. } => "big_int_add".to_string(), BlackBoxOp::BigIntSub { .. } => "big_int_sub".to_string(), diff --git a/yarn.lock b/yarn.lock index 4e69184763a..c0f6c0e75f3 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,9 +221,9 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.56.0": - version: 0.56.0 - resolution: "@aztec/bb.js@npm:0.56.0" +"@aztec/bb.js@npm:0.58.0": + version: 0.58.0 + resolution: "@aztec/bb.js@npm:0.58.0" dependencies: comlink: ^4.4.1 commander: ^10.0.1 @@ -231,7 +231,7 @@ __metadata: tslib: ^2.4.0 bin: bb.js: dest/node/main.js - checksum: 199a1e6c408e4c1399b69169e1a0a48bac92688299312a7dd6eca242e4970808bc370808d2fe4194f17e0d1fe7f5d09676709a05e3ad6ed569ac5553134be34a + checksum: b4e882a6668df737fab6e2223ee6b20ff499e8a0b67c18dcab8109efec47e674c6d8276e8c3b6662289d69f56b6e1d94d3312673fd0ace9909e33ebce7f10cbb languageName: node linkType: hard @@ -5348,7 +5348,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": 0.56.0 + "@aztec/bb.js": 0.58.0 "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3