From a889d18f92f78ce0d2a190c507767ce604c082fa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=C3=81lvaro=20Rodr=C3=ADguez?= Date: Fri, 26 Apr 2024 14:53:47 +0200 Subject: [PATCH] feat: Dynamic assertion payloads v2 (#5949) This PR implements this proposal: https://github.com/noir-lang/noir/issues/4239#issuecomment-2064068639 - Removes legacy dynamic assertions via calling brillig + oracle - Removes legacy oracle handling for assertions - Frontend adds the HirType in the ConstrainError instead of embedding metadata about it in the program logic. - Constrain instruction in SSA now has `Values` for payload - SSA gen generates an error selector from the payload type - ACIR gen and Brillig gen handle the payload ValueIds and error selector - ABI has now error_types for non-string errors - ACVM now resolves the payload for non-constant AssertionPayloads - Nargo decodes the error for non-string errors using the ABI, allowing use in nargo tests Things to do in a followup PR: - Add an entry point in noirc_abi_wasm that allows decoding a given `Raw` (non-string) using the ABI in the same way that nargo does. --- .../dsl/acir_format/serde/acir.hpp | 354 +++++++++++++++++- 1 file changed, 343 insertions(+), 11 deletions(-) diff --git a/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index 09005b299..e2c9d020d 100644 --- a/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -1094,8 +1094,7 @@ struct BrilligOpcode { }; struct Trap { - uint64_t revert_data_offset; - uint64_t revert_data_size; + Program::HeapArray revert_data; friend bool operator==(const Trap&, const Trap&); std::vector bincodeSerialize() const; @@ -1136,6 +1135,56 @@ struct BrilligOpcode { static BrilligOpcode bincodeDeserialize(std::vector); }; +struct ExpressionOrMemory { + + struct Expression { + Program::Expression value; + + friend bool operator==(const Expression&, const Expression&); + std::vector bincodeSerialize() const; + static Expression bincodeDeserialize(std::vector); + }; + + struct Memory { + Program::BlockId value; + + friend bool operator==(const Memory&, const Memory&); + std::vector bincodeSerialize() const; + static Memory bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const ExpressionOrMemory&, const ExpressionOrMemory&); + std::vector bincodeSerialize() const; + static ExpressionOrMemory bincodeDeserialize(std::vector); +}; + +struct AssertionPayload { + + struct StaticString { + std::string value; + + friend bool operator==(const StaticString&, const StaticString&); + std::vector bincodeSerialize() const; + static StaticString bincodeDeserialize(std::vector); + }; + + struct Dynamic { + std::tuple> value; + + friend bool operator==(const Dynamic&, const Dynamic&); + std::vector bincodeSerialize() const; + static Dynamic bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const AssertionPayload&, const AssertionPayload&); + std::vector bincodeSerialize() const; + static AssertionPayload bincodeDeserialize(std::vector); +}; + struct ExpressionWidth { struct Unbounded { @@ -1200,7 +1249,7 @@ struct Circuit { std::vector private_parameters; Program::PublicInputs public_parameters; Program::PublicInputs return_values; - std::vector> assert_messages; + std::vector> assert_messages; bool recursive; friend bool operator==(const Circuit&, const Circuit&); @@ -1229,6 +1278,150 @@ struct Program { namespace Program { +inline bool operator==(const AssertionPayload& lhs, const AssertionPayload& rhs) +{ + if (!(lhs.value == rhs.value)) { + return false; + } + return true; +} + +inline std::vector AssertionPayload::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline AssertionPayload AssertionPayload::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::AssertionPayload& obj, + Serializer& serializer) +{ + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Program::AssertionPayload serde::Deserializable::deserialize(Deserializer& deserializer) +{ + deserializer.increase_container_depth(); + Program::AssertionPayload obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Program { + +inline bool operator==(const AssertionPayload::StaticString& lhs, const AssertionPayload::StaticString& rhs) +{ + if (!(lhs.value == rhs.value)) { + return false; + } + return true; +} + +inline std::vector AssertionPayload::StaticString::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline AssertionPayload::StaticString AssertionPayload::StaticString::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize( + const Program::AssertionPayload::StaticString& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::AssertionPayload::StaticString serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Program::AssertionPayload::StaticString obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + +inline bool operator==(const AssertionPayload::Dynamic& lhs, const AssertionPayload::Dynamic& rhs) +{ + if (!(lhs.value == rhs.value)) { + return false; + } + return true; +} + +inline std::vector AssertionPayload::Dynamic::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline AssertionPayload::Dynamic AssertionPayload::Dynamic::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::AssertionPayload::Dynamic& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::AssertionPayload::Dynamic serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Program::AssertionPayload::Dynamic obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + inline bool operator==(const BinaryFieldOp& lhs, const BinaryFieldOp& rhs) { if (!(lhs.value == rhs.value)) { @@ -5980,10 +6173,7 @@ namespace Program { inline bool operator==(const BrilligOpcode::Trap& lhs, const BrilligOpcode::Trap& rhs) { - if (!(lhs.revert_data_offset == rhs.revert_data_offset)) { - return false; - } - if (!(lhs.revert_data_size == rhs.revert_data_size)) { + if (!(lhs.revert_data == rhs.revert_data)) { return false; } return true; @@ -6013,8 +6203,7 @@ template void serde::Serializable::serialize(const Program::BrilligOpcode::Trap& obj, Serializer& serializer) { - serde::Serializable::serialize(obj.revert_data_offset, serializer); - serde::Serializable::serialize(obj.revert_data_size, serializer); + serde::Serializable::serialize(obj.revert_data, serializer); } template <> @@ -6023,8 +6212,7 @@ Program::BrilligOpcode::Trap serde::Deserializable Deserializer& deserializer) { Program::BrilligOpcode::Trap obj; - obj.revert_data_offset = serde::Deserializable::deserialize(deserializer); - obj.revert_data_size = serde::Deserializable::deserialize(deserializer); + obj.revert_data = serde::Deserializable::deserialize(deserializer); return obj; } @@ -6474,6 +6662,150 @@ Program::Expression serde::Deserializable::deserialize(Dese namespace Program { +inline bool operator==(const ExpressionOrMemory& lhs, const ExpressionOrMemory& rhs) +{ + if (!(lhs.value == rhs.value)) { + return false; + } + return true; +} + +inline std::vector ExpressionOrMemory::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline ExpressionOrMemory ExpressionOrMemory::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::ExpressionOrMemory& obj, + Serializer& serializer) +{ + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Program::ExpressionOrMemory serde::Deserializable::deserialize(Deserializer& deserializer) +{ + deserializer.increase_container_depth(); + Program::ExpressionOrMemory obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Program { + +inline bool operator==(const ExpressionOrMemory::Expression& lhs, const ExpressionOrMemory::Expression& rhs) +{ + if (!(lhs.value == rhs.value)) { + return false; + } + return true; +} + +inline std::vector ExpressionOrMemory::Expression::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline ExpressionOrMemory::Expression ExpressionOrMemory::Expression::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize( + const Program::ExpressionOrMemory::Expression& obj, Serializer& serializer) +{ + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::ExpressionOrMemory::Expression serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Program::ExpressionOrMemory::Expression obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + +inline bool operator==(const ExpressionOrMemory::Memory& lhs, const ExpressionOrMemory::Memory& rhs) +{ + if (!(lhs.value == rhs.value)) { + return false; + } + return true; +} + +inline std::vector ExpressionOrMemory::Memory::bincodeSerialize() const +{ + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); +} + +inline ExpressionOrMemory::Memory ExpressionOrMemory::Memory::bincodeDeserialize(std::vector input) +{ + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw_or_abort("Some input bytes were not read"); + } + return value; +} + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::ExpressionOrMemory::Memory& obj, + Serializer& serializer) +{ + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Program::ExpressionOrMemory::Memory serde::Deserializable::deserialize( + Deserializer& deserializer) +{ + Program::ExpressionOrMemory::Memory obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Program { + inline bool operator==(const ExpressionWidth& lhs, const ExpressionWidth& rhs) { if (!(lhs.value == rhs.value)) {