diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index 0f94e91ab10..8fad51ff815 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -5,65 +5,172 @@ namespace Circuit { - struct Witness { - uint32_t value; + struct BinaryFieldOp { - friend bool operator==(const Witness&, const Witness&); - std::vector bincodeSerialize() const; - static Witness bincodeDeserialize(std::vector); - }; + struct Add { + friend bool operator==(const Add&, const Add&); + std::vector bincodeSerialize() const; + static Add bincodeDeserialize(std::vector); + }; - struct FunctionInput { - Circuit::Witness witness; - uint32_t num_bits; + struct Sub { + friend bool operator==(const Sub&, const Sub&); + std::vector bincodeSerialize() const; + static Sub bincodeDeserialize(std::vector); + }; - friend bool operator==(const FunctionInput&, const FunctionInput&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); + std::vector bincodeSerialize() const; + static Mul bincodeDeserialize(std::vector); + }; + + struct Div { + friend bool operator==(const Div&, const Div&); + std::vector bincodeSerialize() const; + static Div bincodeDeserialize(std::vector); + }; + + struct Equals { + friend bool operator==(const Equals&, const Equals&); + std::vector bincodeSerialize() const; + static Equals bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static FunctionInput bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct BlackBoxFuncCall { + struct BinaryIntOp { - struct AND { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + struct Add { + friend bool operator==(const Add&, const Add&); + std::vector bincodeSerialize() const; + static Add bincodeDeserialize(std::vector); + }; - friend bool operator==(const AND&, const AND&); + struct Sub { + friend bool operator==(const Sub&, const Sub&); std::vector bincodeSerialize() const; - static AND bincodeDeserialize(std::vector); + static Sub bincodeDeserialize(std::vector); }; - struct XOR { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + struct Mul { + friend bool operator==(const Mul&, const Mul&); + std::vector bincodeSerialize() const; + static Mul bincodeDeserialize(std::vector); + }; - friend bool operator==(const XOR&, const XOR&); + struct SignedDiv { + friend bool operator==(const SignedDiv&, const SignedDiv&); std::vector bincodeSerialize() const; - static XOR bincodeDeserialize(std::vector); + static SignedDiv bincodeDeserialize(std::vector); }; - struct RANGE { - Circuit::FunctionInput input; + struct UnsignedDiv { + friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); + std::vector bincodeSerialize() const; + static UnsignedDiv bincodeDeserialize(std::vector); + }; - friend bool operator==(const RANGE&, const RANGE&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static RANGE bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - struct SHA256 { - std::vector inputs; - std::vector outputs; + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); + std::vector bincodeSerialize() const; + static LessThan bincodeDeserialize(std::vector); + }; - friend bool operator==(const SHA256&, const SHA256&); + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); std::vector bincodeSerialize() const; - static SHA256 bincodeDeserialize(std::vector); + static LessThanEquals bincodeDeserialize(std::vector); + }; + + struct And { + friend bool operator==(const And&, const And&); + std::vector bincodeSerialize() const; + static And bincodeDeserialize(std::vector); + }; + + struct Or { + friend bool operator==(const Or&, const Or&); + std::vector bincodeSerialize() const; + static Or bincodeDeserialize(std::vector); + }; + + struct Xor { + friend bool operator==(const Xor&, const Xor&); + std::vector bincodeSerialize() const; + static Xor bincodeDeserialize(std::vector); + }; + + struct Shl { + friend bool operator==(const Shl&, const Shl&); + std::vector bincodeSerialize() const; + static Shl bincodeDeserialize(std::vector); + }; + + struct Shr { + friend bool operator==(const Shr&, const Shr&); + std::vector bincodeSerialize() const; + static Shr bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + std::vector bincodeSerialize() const; + static BinaryIntOp bincodeDeserialize(std::vector); + }; + + struct RegisterIndex { + uint64_t value; + + friend bool operator==(const RegisterIndex&, const RegisterIndex&); + std::vector bincodeSerialize() const; + static RegisterIndex bincodeDeserialize(std::vector); + }; + + struct HeapArray { + Circuit::RegisterIndex pointer; + uint64_t size; + + friend bool operator==(const HeapArray&, const HeapArray&); + std::vector bincodeSerialize() const; + static HeapArray bincodeDeserialize(std::vector); + }; + + struct HeapVector { + Circuit::RegisterIndex pointer; + Circuit::RegisterIndex size; + + friend bool operator==(const HeapVector&, const HeapVector&); + std::vector bincodeSerialize() const; + static HeapVector bincodeDeserialize(std::vector); + }; + + struct BlackBoxOp { + + struct Sha256 { + Circuit::HeapVector message; + Circuit::HeapArray output; + + friend bool operator==(const Sha256&, const Sha256&); + std::vector bincodeSerialize() const; + static Sha256 bincodeDeserialize(std::vector); }; struct Blake2s { - std::vector inputs; - std::vector outputs; + Circuit::HeapVector message; + Circuit::HeapArray output; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -71,52 +178,38 @@ namespace Circuit { }; struct Blake3 { - std::vector inputs; - std::vector outputs; + Circuit::HeapVector message; + Circuit::HeapArray output; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; static Blake3 bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Circuit::FunctionInput public_key_x; - Circuit::FunctionInput public_key_y; - std::vector signature; - std::vector message; - Circuit::Witness output; - - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); - std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); - }; - - struct PedersenCommitment { - std::vector inputs; - uint32_t domain_separator; - std::array outputs; + struct Keccak256 { + Circuit::HeapVector message; + Circuit::HeapArray output; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct PedersenHash { - std::vector inputs; - uint32_t domain_separator; - Circuit::Witness output; + struct Keccakf1600 { + Circuit::HeapVector message; + Circuit::HeapArray output; - friend bool operator==(const PedersenHash&, const PedersenHash&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + Circuit::HeapVector hashed_msg; + Circuit::HeapArray public_key_x; + Circuit::HeapArray public_key_y; + Circuit::HeapArray signature; + Circuit::RegisterIndex result; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -124,82 +217,75 @@ namespace Circuit { }; struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + Circuit::HeapVector hashed_msg; + Circuit::HeapArray public_key_x; + Circuit::HeapArray public_key_y; + Circuit::HeapArray signature; + Circuit::RegisterIndex result; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Circuit::FunctionInput low; - Circuit::FunctionInput high; - std::array outputs; - - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); - std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); - }; - - struct EmbeddedCurveAdd { - Circuit::FunctionInput input1_x; - Circuit::FunctionInput input1_y; - Circuit::FunctionInput input2_x; - Circuit::FunctionInput input2_y; - std::array outputs; + struct SchnorrVerify { + Circuit::RegisterIndex public_key_x; + Circuit::RegisterIndex public_key_y; + Circuit::HeapVector message; + Circuit::HeapVector signature; + Circuit::RegisterIndex result; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct Keccak256 { - std::vector inputs; - std::vector outputs; + struct PedersenCommitment { + Circuit::HeapVector inputs; + Circuit::RegisterIndex domain_separator; + Circuit::HeapArray output; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); }; - struct Keccak256VariableLength { - std::vector inputs; - Circuit::FunctionInput var_message_size; - std::vector outputs; + struct PedersenHash { + Circuit::HeapVector inputs; + Circuit::RegisterIndex domain_separator; + Circuit::RegisterIndex output; - friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); + friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; - static Keccak256VariableLength bincodeDeserialize(std::vector); + static PedersenHash bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + struct FixedBaseScalarMul { + Circuit::RegisterIndex low; + Circuit::RegisterIndex high; + Circuit::HeapArray result; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Circuit::FunctionInput key_hash; + struct EmbeddedCurveAdd { + Circuit::RegisterIndex input1_x; + Circuit::RegisterIndex input1_y; + Circuit::RegisterIndex input2_x; + Circuit::RegisterIndex input2_y; + Circuit::HeapArray result; - friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static RecursiveAggregation bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; struct BigIntAdd { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::RegisterIndex lhs; + Circuit::RegisterIndex rhs; + Circuit::RegisterIndex output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; @@ -207,9 +293,9 @@ namespace Circuit { }; struct BigIntNeg { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::RegisterIndex lhs; + Circuit::RegisterIndex rhs; + Circuit::RegisterIndex output; friend bool operator==(const BigIntNeg&, const BigIntNeg&); std::vector bincodeSerialize() const; @@ -217,9 +303,9 @@ namespace Circuit { }; struct BigIntMul { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::RegisterIndex lhs; + Circuit::RegisterIndex rhs; + Circuit::RegisterIndex output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -227,9 +313,9 @@ namespace Circuit { }; struct BigIntDiv { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::RegisterIndex lhs; + Circuit::RegisterIndex rhs; + Circuit::RegisterIndex output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -237,9 +323,9 @@ namespace Circuit { }; struct BigIntFromLeBytes { - std::vector inputs; - std::vector modulus; - uint32_t output; + Circuit::HeapVector inputs; + Circuit::HeapVector modulus; + Circuit::RegisterIndex output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -247,8 +333,8 @@ namespace Circuit { }; struct BigIntToLeBytes { - uint32_t input; - std::vector outputs; + Circuit::RegisterIndex input; + Circuit::HeapVector output; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -256,9 +342,9 @@ namespace Circuit { }; struct Poseidon2Permutation { - std::vector inputs; - std::vector outputs; - uint32_t len; + Circuit::HeapVector message; + Circuit::HeapArray output; + Circuit::RegisterIndex len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; @@ -266,605 +352,555 @@ namespace Circuit { }; struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; - - friend bool operator==(const Sha256Compression&, const Sha256Compression&); - std::vector bincodeSerialize() const; - static Sha256Compression bincodeDeserialize(std::vector); - }; - - std::variant value; - - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); - std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); - }; - - struct BlockId { - uint32_t value; - - friend bool operator==(const BlockId&, const BlockId&); - std::vector bincodeSerialize() const; - static BlockId bincodeDeserialize(std::vector); - }; - - struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; - std::string q_c; - - friend bool operator==(const Expression&, const Expression&); - std::vector bincodeSerialize() const; - static Expression bincodeDeserialize(std::vector); - }; - - struct BrilligInputs { - - struct Single { - Circuit::Expression value; - - friend bool operator==(const Single&, const Single&); - std::vector bincodeSerialize() const; - static Single bincodeDeserialize(std::vector); - }; - - struct Array { - std::vector value; - - friend bool operator==(const Array&, const Array&); - std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); - }; - - std::variant value; - - friend bool operator==(const BrilligInputs&, const BrilligInputs&); - std::vector bincodeSerialize() const; - static BrilligInputs bincodeDeserialize(std::vector); - }; - - struct BinaryFieldOp { - - struct Add { - friend bool operator==(const Add&, const Add&); - std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); - }; - - struct Sub { - friend bool operator==(const Sub&, const Sub&); - std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); - }; - - struct Mul { - friend bool operator==(const Mul&, const Mul&); - std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); - }; - - struct Div { - friend bool operator==(const Div&, const Div&); - std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); - }; + Circuit::HeapVector input; + Circuit::HeapVector hash_values; + Circuit::HeapArray output; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); + static BlackBoxOp bincodeDeserialize(std::vector); }; - struct BinaryIntOp { + struct HeapValueType; - struct Add { - friend bool operator==(const Add&, const Add&); - std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); - }; + struct HeapValueType { - struct Sub { - friend bool operator==(const Sub&, const Sub&); + struct Simple { + friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static Simple bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); - std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); - }; + struct Array { + std::vector value_types; + uint64_t size; - struct SignedDiv { - friend bool operator==(const SignedDiv&, const SignedDiv&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static SignedDiv bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct UnsignedDiv { - friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); - std::vector bincodeSerialize() const; - static UnsignedDiv bincodeDeserialize(std::vector); - }; + struct Vector { + std::vector value_types; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + friend bool operator==(const Vector&, const Vector&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static Vector bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); - std::vector bincodeSerialize() const; - static LessThan bincodeDeserialize(std::vector); - }; + std::variant value; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); - std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); - }; + friend bool operator==(const HeapValueType&, const HeapValueType&); + std::vector bincodeSerialize() const; + static HeapValueType bincodeDeserialize(std::vector); + }; - struct And { - friend bool operator==(const And&, const And&); - std::vector bincodeSerialize() const; - static And bincodeDeserialize(std::vector); - }; + struct RegisterOrMemory { - struct Or { - friend bool operator==(const Or&, const Or&); - std::vector bincodeSerialize() const; - static Or bincodeDeserialize(std::vector); - }; + struct RegisterIndex { + Circuit::RegisterIndex value; - struct Xor { - friend bool operator==(const Xor&, const Xor&); + friend bool operator==(const RegisterIndex&, const RegisterIndex&); std::vector bincodeSerialize() const; - static Xor bincodeDeserialize(std::vector); + static RegisterIndex bincodeDeserialize(std::vector); }; - struct Shl { - friend bool operator==(const Shl&, const Shl&); - std::vector bincodeSerialize() const; - static Shl bincodeDeserialize(std::vector); - }; + struct HeapArray { + Circuit::HeapArray value; - struct Shr { - friend bool operator==(const Shr&, const Shr&); + friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; - static Shr bincodeDeserialize(std::vector); + static HeapArray bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); - std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); - }; - - struct RegisterIndex { - uint64_t value; + struct HeapVector { + Circuit::HeapVector value; - friend bool operator==(const RegisterIndex&, const RegisterIndex&); - std::vector bincodeSerialize() const; - static RegisterIndex bincodeDeserialize(std::vector); - }; + friend bool operator==(const HeapVector&, const HeapVector&); + std::vector bincodeSerialize() const; + static HeapVector bincodeDeserialize(std::vector); + }; - struct HeapArray { - Circuit::RegisterIndex pointer; - uint64_t size; + std::variant value; - friend bool operator==(const HeapArray&, const HeapArray&); + friend bool operator==(const RegisterOrMemory&, const RegisterOrMemory&); std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); + static RegisterOrMemory bincodeDeserialize(std::vector); }; - struct HeapVector { - Circuit::RegisterIndex pointer; - Circuit::RegisterIndex size; + struct Value { + std::string inner; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const Value&, const Value&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static Value bincodeDeserialize(std::vector); }; - struct BlackBoxOp { + struct BrilligOpcode { - struct Sha256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct BinaryFieldOp { + Circuit::RegisterIndex destination; + Circuit::BinaryFieldOp op; + Circuit::RegisterIndex lhs; + Circuit::RegisterIndex rhs; - friend bool operator==(const Sha256&, const Sha256&); + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static Sha256 bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct Blake2s { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct BinaryIntOp { + Circuit::RegisterIndex destination; + Circuit::BinaryIntOp op; + uint32_t bit_size; + Circuit::RegisterIndex lhs; + Circuit::RegisterIndex rhs; - friend bool operator==(const Blake2s&, const Blake2s&); + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; - static Blake2s bincodeDeserialize(std::vector); + static BinaryIntOp bincodeDeserialize(std::vector); }; - struct Blake3 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct JumpIfNot { + Circuit::RegisterIndex condition; + uint64_t location; - friend bool operator==(const Blake3&, const Blake3&); + friend bool operator==(const JumpIfNot&, const JumpIfNot&); std::vector bincodeSerialize() const; - static Blake3 bincodeDeserialize(std::vector); + static JumpIfNot bincodeDeserialize(std::vector); }; - struct Keccak256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct JumpIf { + Circuit::RegisterIndex condition; + uint64_t location; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const JumpIf&, const JumpIf&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static JumpIf bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct Jump { + uint64_t location; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const Jump&, const Jump&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static Jump bincodeDeserialize(std::vector); }; - struct EcdsaSecp256k1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::RegisterIndex result; + struct Call { + uint64_t location; - friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); + friend bool operator==(const Call&, const Call&); std::vector bincodeSerialize() const; - static EcdsaSecp256k1 bincodeDeserialize(std::vector); + static Call bincodeDeserialize(std::vector); }; - struct EcdsaSecp256r1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::RegisterIndex result; + struct Const { + Circuit::RegisterIndex destination; + Circuit::Value value; - friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + friend bool operator==(const Const&, const Const&); std::vector bincodeSerialize() const; - static EcdsaSecp256r1 bincodeDeserialize(std::vector); + static Const bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Circuit::RegisterIndex public_key_x; - Circuit::RegisterIndex public_key_y; - Circuit::HeapVector message; - Circuit::HeapVector signature; - Circuit::RegisterIndex result; - - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + struct Return { + friend bool operator==(const Return&, const Return&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static Return bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - Circuit::HeapVector inputs; - Circuit::RegisterIndex domain_separator; - Circuit::HeapArray output; + struct ForeignCall { + std::string function; + std::vector destinations; + std::vector destination_value_types; + std::vector inputs; + std::vector input_value_types; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + friend bool operator==(const ForeignCall&, const ForeignCall&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static ForeignCall bincodeDeserialize(std::vector); }; - struct PedersenHash { - Circuit::HeapVector inputs; - Circuit::RegisterIndex domain_separator; - Circuit::RegisterIndex output; + struct Mov { + Circuit::RegisterIndex destination; + Circuit::RegisterIndex source; - friend bool operator==(const PedersenHash&, const PedersenHash&); + friend bool operator==(const Mov&, const Mov&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Mov bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Circuit::RegisterIndex low; - Circuit::RegisterIndex high; - Circuit::HeapArray result; + struct Load { + Circuit::RegisterIndex destination; + Circuit::RegisterIndex source_pointer; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + friend bool operator==(const Load&, const Load&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static Load bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Circuit::RegisterIndex input1_x; - Circuit::RegisterIndex input1_y; - Circuit::RegisterIndex input2_x; - Circuit::RegisterIndex input2_y; - Circuit::HeapArray result; + struct Store { + Circuit::RegisterIndex destination_pointer; + Circuit::RegisterIndex source; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const Store&, const Store&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static Store bincodeDeserialize(std::vector); }; - struct BigIntAdd { - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; - Circuit::RegisterIndex output; + struct BlackBox { + Circuit::BlackBoxOp value; - friend bool operator==(const BigIntAdd&, const BigIntAdd&); + friend bool operator==(const BlackBox&, const BlackBox&); std::vector bincodeSerialize() const; - static BigIntAdd bincodeDeserialize(std::vector); + static BlackBox bincodeDeserialize(std::vector); }; - struct BigIntNeg { - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; - Circuit::RegisterIndex output; + struct Trap { + friend bool operator==(const Trap&, const Trap&); + std::vector bincodeSerialize() const; + static Trap bincodeDeserialize(std::vector); + }; - friend bool operator==(const BigIntNeg&, const BigIntNeg&); + struct Stop { + friend bool operator==(const Stop&, const Stop&); std::vector bincodeSerialize() const; - static BigIntNeg bincodeDeserialize(std::vector); + static Stop bincodeDeserialize(std::vector); }; - struct BigIntMul { - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; - Circuit::RegisterIndex output; + std::variant value; - friend bool operator==(const BigIntMul&, const BigIntMul&); + friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); + std::vector bincodeSerialize() const; + static BrilligOpcode bincodeDeserialize(std::vector); + }; + + struct Witness { + uint32_t value; + + friend bool operator==(const Witness&, const Witness&); + std::vector bincodeSerialize() const; + static Witness bincodeDeserialize(std::vector); + }; + + struct FunctionInput { + Circuit::Witness witness; + uint32_t num_bits; + + friend bool operator==(const FunctionInput&, const FunctionInput&); + std::vector bincodeSerialize() const; + static FunctionInput bincodeDeserialize(std::vector); + }; + + struct BlackBoxFuncCall { + + struct AND { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; + + friend bool operator==(const AND&, const AND&); std::vector bincodeSerialize() const; - static BigIntMul bincodeDeserialize(std::vector); + static AND bincodeDeserialize(std::vector); }; - struct BigIntDiv { - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; - Circuit::RegisterIndex output; + struct XOR { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; - friend bool operator==(const BigIntDiv&, const BigIntDiv&); + friend bool operator==(const XOR&, const XOR&); std::vector bincodeSerialize() const; - static BigIntDiv bincodeDeserialize(std::vector); + static XOR bincodeDeserialize(std::vector); }; - struct BigIntFromLeBytes { - Circuit::HeapVector inputs; - Circuit::HeapVector modulus; - Circuit::RegisterIndex output; + struct RANGE { + Circuit::FunctionInput input; - friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); + friend bool operator==(const RANGE&, const RANGE&); std::vector bincodeSerialize() const; - static BigIntFromLeBytes bincodeDeserialize(std::vector); + static RANGE bincodeDeserialize(std::vector); }; - struct BigIntToLeBytes { - Circuit::RegisterIndex input; - Circuit::HeapVector output; + struct SHA256 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); + friend bool operator==(const SHA256&, const SHA256&); std::vector bincodeSerialize() const; - static BigIntToLeBytes bincodeDeserialize(std::vector); + static SHA256 bincodeDeserialize(std::vector); }; - struct Poseidon2Permutation { - Circuit::HeapVector message; - Circuit::HeapArray output; - Circuit::RegisterIndex len; + struct Blake2s { + std::vector inputs; + std::vector outputs; - friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); + friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; - static Poseidon2Permutation bincodeDeserialize(std::vector); + static Blake2s bincodeDeserialize(std::vector); }; - struct Sha256Compression { - Circuit::HeapVector input; - Circuit::HeapVector hash_values; - Circuit::HeapArray output; + struct Blake3 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const Sha256Compression&, const Sha256Compression&); + friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; - static Sha256Compression bincodeDeserialize(std::vector); + static Blake3 bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); - std::vector bincodeSerialize() const; - static BlackBoxOp bincodeDeserialize(std::vector); - }; + struct SchnorrVerify { + Circuit::FunctionInput public_key_x; + Circuit::FunctionInput public_key_y; + std::vector signature; + std::vector message; + Circuit::Witness output; - struct RegisterOrMemory { + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + std::vector bincodeSerialize() const; + static SchnorrVerify bincodeDeserialize(std::vector); + }; - struct RegisterIndex { - Circuit::RegisterIndex value; + struct PedersenCommitment { + std::vector inputs; + uint32_t domain_separator; + std::array outputs; - friend bool operator==(const RegisterIndex&, const RegisterIndex&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static RegisterIndex bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); }; - struct HeapArray { - Circuit::HeapArray value; + struct PedersenHash { + std::vector inputs; + uint32_t domain_separator; + Circuit::Witness output; - friend bool operator==(const HeapArray&, const HeapArray&); + friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); + static PedersenHash bincodeDeserialize(std::vector); }; - struct HeapVector { - Circuit::HeapVector value; + struct EcdsaSecp256k1 { + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static EcdsaSecp256k1 bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const RegisterOrMemory&, const RegisterOrMemory&); - std::vector bincodeSerialize() const; - static RegisterOrMemory bincodeDeserialize(std::vector); - }; + struct EcdsaSecp256r1 { + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; - struct Value { - std::string inner; + friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + std::vector bincodeSerialize() const; + static EcdsaSecp256r1 bincodeDeserialize(std::vector); + }; - friend bool operator==(const Value&, const Value&); - std::vector bincodeSerialize() const; - static Value bincodeDeserialize(std::vector); - }; + struct FixedBaseScalarMul { + Circuit::FunctionInput low; + Circuit::FunctionInput high; + std::array outputs; - struct BrilligOpcode { + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + std::vector bincodeSerialize() const; + static FixedBaseScalarMul bincodeDeserialize(std::vector); + }; - struct BinaryFieldOp { - Circuit::RegisterIndex destination; - Circuit::BinaryFieldOp op; - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; + struct EmbeddedCurveAdd { + Circuit::FunctionInput input1_x; + Circuit::FunctionInput input1_y; + Circuit::FunctionInput input2_x; + Circuit::FunctionInput input2_y; + std::array outputs; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - struct BinaryIntOp { - Circuit::RegisterIndex destination; - Circuit::BinaryIntOp op; - uint32_t bit_size; - Circuit::RegisterIndex lhs; - Circuit::RegisterIndex rhs; + struct Keccak256 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct JumpIfNot { - Circuit::RegisterIndex condition; - uint64_t location; + struct Keccak256VariableLength { + std::vector inputs; + Circuit::FunctionInput var_message_size; + std::vector outputs; - friend bool operator==(const JumpIfNot&, const JumpIfNot&); + friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); std::vector bincodeSerialize() const; - static JumpIfNot bincodeDeserialize(std::vector); + static Keccak256VariableLength bincodeDeserialize(std::vector); }; - struct JumpIf { - Circuit::RegisterIndex condition; - uint64_t location; + struct Keccakf1600 { + std::vector inputs; + std::vector outputs; - friend bool operator==(const JumpIf&, const JumpIf&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static JumpIf bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; - struct Jump { - uint64_t location; + struct RecursiveAggregation { + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Circuit::FunctionInput key_hash; - friend bool operator==(const Jump&, const Jump&); + friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); std::vector bincodeSerialize() const; - static Jump bincodeDeserialize(std::vector); + static RecursiveAggregation bincodeDeserialize(std::vector); }; - struct Call { - uint64_t location; + struct BigIntAdd { + uint32_t lhs; + uint32_t rhs; + uint32_t output; - friend bool operator==(const Call&, const Call&); + friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; - static Call bincodeDeserialize(std::vector); + static BigIntAdd bincodeDeserialize(std::vector); }; - struct Const { - Circuit::RegisterIndex destination; - Circuit::Value value; + struct BigIntNeg { + uint32_t lhs; + uint32_t rhs; + uint32_t output; - friend bool operator==(const Const&, const Const&); + friend bool operator==(const BigIntNeg&, const BigIntNeg&); std::vector bincodeSerialize() const; - static Const bincodeDeserialize(std::vector); + static BigIntNeg bincodeDeserialize(std::vector); }; - struct Return { - friend bool operator==(const Return&, const Return&); + struct BigIntMul { + uint32_t lhs; + uint32_t rhs; + uint32_t output; + + friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; - static Return bincodeDeserialize(std::vector); + static BigIntMul bincodeDeserialize(std::vector); }; - struct ForeignCall { - std::string function; - std::vector destinations; - std::vector inputs; + struct BigIntDiv { + uint32_t lhs; + uint32_t rhs; + uint32_t output; - friend bool operator==(const ForeignCall&, const ForeignCall&); + friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; - static ForeignCall bincodeDeserialize(std::vector); + static BigIntDiv bincodeDeserialize(std::vector); }; - struct Mov { - Circuit::RegisterIndex destination; - Circuit::RegisterIndex source; + struct BigIntFromLeBytes { + std::vector inputs; + std::vector modulus; + uint32_t output; - friend bool operator==(const Mov&, const Mov&); + friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; - static Mov bincodeDeserialize(std::vector); + static BigIntFromLeBytes bincodeDeserialize(std::vector); }; - struct Load { - Circuit::RegisterIndex destination; - Circuit::RegisterIndex source_pointer; + struct BigIntToLeBytes { + uint32_t input; + std::vector outputs; - friend bool operator==(const Load&, const Load&); + friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; - static Load bincodeDeserialize(std::vector); + static BigIntToLeBytes bincodeDeserialize(std::vector); }; - struct Store { - Circuit::RegisterIndex destination_pointer; - Circuit::RegisterIndex source; + struct Poseidon2Permutation { + std::vector inputs; + std::vector outputs; + uint32_t len; - friend bool operator==(const Store&, const Store&); + friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; - static Store bincodeDeserialize(std::vector); + static Poseidon2Permutation bincodeDeserialize(std::vector); }; - struct BlackBox { - Circuit::BlackBoxOp value; + struct Sha256Compression { + std::vector inputs; + std::vector hash_values; + std::vector outputs; - friend bool operator==(const BlackBox&, const BlackBox&); + friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; - static BlackBox bincodeDeserialize(std::vector); + static Sha256Compression bincodeDeserialize(std::vector); }; - struct Trap { - friend bool operator==(const Trap&, const Trap&); + std::variant value; + + friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); + std::vector bincodeSerialize() const; + static BlackBoxFuncCall bincodeDeserialize(std::vector); + }; + + struct BlockId { + uint32_t value; + + friend bool operator==(const BlockId&, const BlockId&); + std::vector bincodeSerialize() const; + static BlockId bincodeDeserialize(std::vector); + }; + + struct Expression { + std::vector> mul_terms; + std::vector> linear_combinations; + std::string q_c; + + friend bool operator==(const Expression&, const Expression&); + std::vector bincodeSerialize() const; + static Expression bincodeDeserialize(std::vector); + }; + + struct BrilligInputs { + + struct Single { + Circuit::Expression value; + + friend bool operator==(const Single&, const Single&); std::vector bincodeSerialize() const; - static Trap bincodeDeserialize(std::vector); + static Single bincodeDeserialize(std::vector); }; - struct Stop { - friend bool operator==(const Stop&, const Stop&); + struct Array { + std::vector value; + + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static Stop bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); + friend bool operator==(const BrilligInputs&, const BrilligInputs&); std::vector bincodeSerialize() const; - static BrilligOpcode bincodeDeserialize(std::vector); + static BrilligInputs bincodeDeserialize(std::vector); }; struct BrilligOutputs { @@ -4429,7 +4465,9 @@ namespace Circuit { inline bool operator==(const BrilligOpcode::ForeignCall &lhs, const BrilligOpcode::ForeignCall &rhs) { if (!(lhs.function == rhs.function)) { return false; } if (!(lhs.destinations == rhs.destinations)) { return false; } + if (!(lhs.destination_value_types == rhs.destination_value_types)) { return false; } if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.input_value_types == rhs.input_value_types)) { return false; } return true; } @@ -4455,7 +4493,9 @@ template void serde::Serializable::serialize(const Circuit::BrilligOpcode::ForeignCall &obj, Serializer &serializer) { serde::Serializable::serialize(obj.function, serializer); serde::Serializable::serialize(obj.destinations, serializer); + serde::Serializable::serialize(obj.destination_value_types, serializer); serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.input_value_types, serializer); } template <> @@ -4464,7 +4504,9 @@ Circuit::BrilligOpcode::ForeignCall serde::Deserializable::deserialize(deserializer); obj.destinations = serde::Deserializable::deserialize(deserializer); + obj.destination_value_types = serde::Deserializable::deserialize(deserializer); obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.input_value_types = serde::Deserializable::deserialize(deserializer); return obj; } @@ -5145,6 +5187,162 @@ Circuit::HeapArray serde::Deserializable::deserialize(Deseri return obj; } +namespace Circuit { + + inline bool operator==(const HeapValueType &lhs, const HeapValueType &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector HeapValueType::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType HeapValueType::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Circuit::HeapValueType serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::HeapValueType obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Simple &lhs, const HeapValueType::Simple &rhs) { + return true; + } + + inline std::vector HeapValueType::Simple::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Simple HeapValueType::Simple::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Simple &obj, Serializer &serializer) { +} + +template <> +template +Circuit::HeapValueType::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Simple obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Array &lhs, const HeapValueType::Array &rhs) { + if (!(lhs.value_types == rhs.value_types)) { return false; } + if (!(lhs.size == rhs.size)) { return false; } + return true; + } + + inline std::vector HeapValueType::Array::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Array HeapValueType::Array::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Array &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value_types, serializer); + serde::Serializable::serialize(obj.size, serializer); +} + +template <> +template +Circuit::HeapValueType::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Array obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); + obj.size = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Vector &lhs, const HeapValueType::Vector &rhs) { + if (!(lhs.value_types == rhs.value_types)) { return false; } + return true; + } + + inline std::vector HeapValueType::Vector::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Vector HeapValueType::Vector::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Vector &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value_types, serializer); +} + +template <> +template +Circuit::HeapValueType::Vector serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Vector obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const HeapVector &lhs, const HeapVector &rhs) { diff --git a/acvm-repo/acir/src/lib.rs b/acvm-repo/acir/src/lib.rs index b7bcaa0c5c0..50de09c5ad9 100644 --- a/acvm-repo/acir/src/lib.rs +++ b/acvm-repo/acir/src/lib.rs @@ -32,7 +32,8 @@ mod reflection { }; use brillig::{ - BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode, RegisterOrMemory, + BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, Opcode as BrilligOpcode, + RegisterOrMemory, }; use serde_reflection::{Tracer, TracerConfig}; @@ -70,6 +71,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 7d3b7b32d35..6dc1bd1dc43 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -20,7 +20,7 @@ use acir::{ native_types::{Expression, Witness}, }; use acir_field::FieldElement; -use brillig::{HeapArray, RegisterIndex, RegisterOrMemory}; +use brillig::{HeapArray, HeapValueType, RegisterIndex, RegisterOrMemory}; #[test] fn addition_circuit() { @@ -180,7 +180,9 @@ fn simple_brillig_foreign_call() { bytecode: vec![brillig::Opcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }], predicate: None, }; @@ -196,10 +198,11 @@ fn simple_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 49, 10, 64, 33, 12, 67, 99, 63, 124, 60, 142, - 222, 192, 203, 56, 184, 56, 136, 120, 126, 5, 21, 226, 160, 139, 62, 40, 13, 45, 132, 68, - 3, 80, 232, 124, 164, 153, 121, 115, 99, 155, 59, 172, 122, 231, 101, 56, 175, 80, 86, 221, - 230, 31, 58, 196, 226, 83, 62, 53, 91, 16, 122, 10, 246, 84, 99, 243, 0, 30, 59, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 49, 10, 0, 33, 12, 4, 215, 28, 28, 62, 199, + 251, 193, 125, 198, 194, 198, 66, 196, 247, 43, 168, 176, 136, 218, 232, 64, 200, 50, 69, + 216, 104, 0, 10, 149, 135, 50, 211, 221, 223, 182, 57, 227, 83, 247, 110, 25, 238, 43, 212, + 85, 151, 121, 91, 118, 62, 217, 16, 119, 159, 141, 121, 234, 132, 164, 96, 77, 6, 148, 102, + 152, 53, 83, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -248,11 +251,20 @@ fn complex_brillig_foreign_call() { RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)), ], + input_value_types: vec![ + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, + HeapValueType::Simple, + ], destinations: vec![ RegisterOrMemory::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), RegisterOrMemory::RegisterIndex(RegisterIndex::from(1)), RegisterOrMemory::RegisterIndex(RegisterIndex::from(2)), ], + destination_value_types: vec![ + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, + HeapValueType::Simple, + HeapValueType::Simple, + ], }, ], predicate: None, @@ -269,13 +281,13 @@ fn complex_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 219, 10, 128, 48, 8, 117, 174, 139, 159, 179, - 254, 160, 127, 137, 222, 138, 122, 236, 243, 19, 114, 32, 22, 244, 144, 131, 118, 64, 156, - 178, 29, 14, 59, 74, 0, 16, 224, 66, 228, 64, 57, 7, 169, 53, 242, 189, 81, 114, 250, 134, - 33, 248, 113, 165, 82, 26, 177, 2, 141, 177, 128, 198, 60, 15, 63, 245, 219, 211, 23, 215, - 255, 139, 15, 251, 211, 112, 180, 28, 157, 212, 189, 100, 82, 179, 64, 170, 63, 109, 235, - 190, 204, 135, 166, 178, 150, 216, 62, 154, 252, 250, 70, 147, 35, 220, 119, 93, 227, 4, - 182, 131, 81, 25, 36, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 109, 10, 128, 48, 8, 85, 215, 199, 142, 179, + 110, 208, 93, 162, 127, 69, 253, 236, 248, 13, 114, 240, 88, 81, 65, 27, 180, 7, 226, 116, + 238, 41, 83, 45, 17, 49, 29, 48, 94, 68, 207, 172, 54, 34, 196, 245, 170, 221, 55, 116, + 156, 142, 203, 229, 170, 81, 10, 168, 209, 100, 168, 49, 204, 195, 79, 251, 157, 178, 47, + 73, 255, 207, 92, 236, 79, 229, 165, 246, 210, 168, 221, 170, 182, 48, 11, 22, 252, 195, + 50, 175, 211, 184, 33, 85, 220, 146, 216, 47, 209, 61, 223, 188, 195, 248, 39, 110, 121, + 195, 135, 73, 133, 206, 201, 16, 59, 245, 249, 221, 124, 112, 4, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 486e04d5bf1..7883e51e126 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -13,6 +13,7 @@ use acir::{ use acvm::pwg::{ACVMStatus, ErrorLocation, ForeignCallWaitInfo, OpcodeResolutionError, ACVM}; use acvm_blackbox_solver::StubbedBlackBoxSolver; +use brillig_vm::brillig::HeapValueType; // Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib. @@ -64,7 +65,9 @@ fn inversion_brillig_oracle_equivalence() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: None, @@ -185,12 +188,16 @@ fn double_inversion_brillig_oracle() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(3))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(2))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: None, @@ -310,12 +317,16 @@ fn oracle_dependent_execution() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(3))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(2))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: None, @@ -430,7 +441,9 @@ fn brillig_oracle_predicate() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: Some(Expression::default()), 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 1b6f5e4319a..7e12ec1e13a 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,11 +2,12 @@ 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, 83, 219, 10, 128, 48, 8, 117, 174, 139, 159, 179, 254, 160, 127, 137, 222, - 138, 122, 236, 243, 19, 114, 32, 22, 244, 144, 131, 118, 64, 156, 178, 29, 14, 59, 74, 0, 16, 224, 66, 228, 64, 57, 7, - 169, 53, 242, 189, 81, 114, 250, 134, 33, 248, 113, 165, 82, 26, 177, 2, 141, 177, 128, 198, 60, 15, 63, 245, 219, - 211, 23, 215, 255, 139, 15, 251, 211, 112, 180, 28, 157, 212, 189, 100, 82, 179, 64, 170, 63, 109, 235, 190, 204, 135, - 166, 178, 150, 216, 62, 154, 252, 250, 70, 147, 35, 220, 119, 93, 227, 4, 182, 131, 81, 25, 36, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 109, 10, 128, 48, 8, 85, 215, 199, 142, 179, 110, 208, 93, 162, 127, 69, + 253, 236, 248, 13, 114, 240, 88, 81, 65, 27, 180, 7, 226, 116, 238, 41, 83, 45, 17, 49, 29, 48, 94, 68, 207, 172, 54, + 34, 196, 245, 170, 221, 55, 116, 156, 142, 203, 229, 170, 81, 10, 168, 209, 100, 168, 49, 204, 195, 79, 251, 157, 178, + 47, 73, 255, 207, 92, 236, 79, 229, 165, 246, 210, 168, 221, 170, 182, 48, 11, 22, 252, 195, 50, 175, 211, 184, 33, + 85, 220, 146, 216, 47, 209, 61, 223, 188, 195, 248, 39, 110, 121, 195, 135, 73, 133, 206, 201, 16, 59, 245, 249, 221, + 124, 112, 4, 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 178ec3a09d1..d9184b79b5d 100644 --- a/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,10 +2,10 @@ 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, 143, 49, 10, 64, 33, 12, 67, 99, 63, 124, 60, 142, 222, 192, 203, 56, 184, 56, - 136, 120, 126, 5, 21, 226, 160, 139, 62, 40, 13, 45, 132, 68, 3, 80, 232, 124, 164, 153, 121, 115, 99, 155, 59, 172, - 122, 231, 101, 56, 175, 80, 86, 221, 230, 31, 58, 196, 226, 83, 62, 53, 91, 16, 122, 10, 246, 84, 99, 243, 0, 30, 59, - 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 49, 10, 0, 33, 12, 4, 215, 28, 28, 62, 199, 251, 193, 125, 198, 194, 198, + 66, 196, 247, 43, 168, 176, 136, 218, 232, 64, 200, 50, 69, 216, 104, 0, 10, 149, 135, 50, 211, 221, 223, 182, 57, + 227, 83, 247, 110, 25, 238, 43, 212, 85, 151, 121, 91, 118, 62, 217, 16, 119, 159, 141, 121, 234, 132, 164, 96, 77, 6, + 148, 102, 152, 53, 83, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/acvm-repo/brillig/src/lib.rs b/acvm-repo/brillig/src/lib.rs index 5e033e3c792..8d32b8d6ce7 100644 --- a/acvm-repo/brillig/src/lib.rs +++ b/acvm-repo/brillig/src/lib.rs @@ -18,7 +18,8 @@ mod value; pub use black_box::BlackBoxOp; pub use foreign_call::{ForeignCallParam, ForeignCallResult}; pub use opcodes::{ - BinaryFieldOp, BinaryIntOp, HeapArray, HeapVector, RegisterIndex, RegisterOrMemory, + BinaryFieldOp, BinaryIntOp, HeapArray, HeapValueType, HeapVector, RegisterIndex, + RegisterOrMemory, }; pub use opcodes::{BrilligOpcode as Opcode, Label}; pub use value::Typ; diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index 79295cc6e5d..780b58aa8b4 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -19,6 +19,27 @@ impl From for RegisterIndex { } } +/// Describes the memory layout for an array/vector element +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub enum HeapValueType { + // A single field element is enough to represent the value + Simple, + // The value read should be interpreted as a pointer to a heap array, which + // consists of a pointer to a slice of memory of size elements, and a + // reference count + Array { value_types: Vec, size: usize }, + // The value read should be interpreted as a pointer to a heap vector, which + // consists of a pointer to a slice of memory, a number of elements in that + // slice, and a reference count + Vector { value_types: Vec }, +} + +impl HeapValueType { + pub fn all_simple(types: &[HeapValueType]) -> bool { + types.iter().all(|typ| matches!(typ, HeapValueType::Simple)) + } +} + /// A fixed-sized array starting from a Brillig register memory location. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub struct HeapArray { @@ -111,8 +132,13 @@ pub enum BrilligOpcode { function: String, /// Destination registers (may be single values or memory pointers). destinations: Vec, + /// Destination value types + destination_value_types: Vec, /// Input registers (may be single values or memory pointers). inputs: Vec, + /// Input value types (for heap allocated structures indicates how to + /// retrieve the elements) + input_value_types: Vec, }, Mov { destination: RegisterIndex, diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 38a562e65a1..175d99b6111 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -12,8 +12,8 @@ //! [acvm]: https://crates.io/crates/acvm use acir::brillig::{ - BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapVector, Opcode, - RegisterIndex, RegisterOrMemory, Value, + BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapValueType, + HeapVector, Opcode, RegisterIndex, RegisterOrMemory, Value, }; use acir::FieldElement; // Re-export `brillig`. @@ -216,7 +216,16 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.fail("return opcode hit, but callstack already empty".to_string()) } } - Opcode::ForeignCall { function, destinations, inputs } => { + Opcode::ForeignCall { + function, + destinations, + destination_value_types, + inputs, + input_value_types, + } => { + assert!(inputs.len() == input_value_types.len()); + assert!(destinations.len() == destination_value_types.len()); + if self.foreign_call_counter >= self.foreign_call_results.len() { // When this opcode is called, it is possible that the results of a foreign call are // not yet known (not enough entries in `foreign_call_results`). @@ -227,7 +236,10 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { // but has the necessary results to proceed with execution. let resolved_inputs = inputs .iter() - .map(|input| self.get_register_value_or_memory_values(*input)) + .zip(input_value_types) + .map(|(input, input_type)| { + self.get_register_value_or_memory_values(*input, input_type) + }) .collect::>(); return self.wait_for_foreign_call(function.clone(), resolved_inputs); } @@ -235,46 +247,71 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { let values = &self.foreign_call_results[self.foreign_call_counter].values; let mut invalid_foreign_call_result = false; - for (destination, output) in destinations.iter().zip(values) { + for ((destination, value_type), output) in + destinations.iter().zip(destination_value_types).zip(values) + { match destination { - RegisterOrMemory::RegisterIndex(value_index) => match output { - ForeignCallParam::Single(value) => { - self.registers.set(*value_index, *value); + RegisterOrMemory::RegisterIndex(value_index) => { + assert!(*value_type == HeapValueType::Simple); + match output { + ForeignCallParam::Single(value) => { + self.registers.set(*value_index, *value); + } + _ => unreachable!( + "Function result size does not match brillig bytecode. Expected 1 result but got {output:?}" + ), } - _ => unreachable!( - "Function result size does not match brillig bytecode. Expected 1 result but got {output:?}" - ), - }, + } RegisterOrMemory::HeapArray(HeapArray { pointer: pointer_index, size }) => { - match output { - ForeignCallParam::Array(values) => { - if values.len() != *size { - invalid_foreign_call_result = true; - break; + let HeapValueType::Array { value_types, size: type_size } = value_type else { + unreachable!("Expected array heap type"); + }; + assert!(size == type_size); + if HeapValueType::all_simple(value_types) { + match output { + ForeignCallParam::Array(values) => { + if values.len() != *size { + invalid_foreign_call_result = true; + break; + } + // Convert the destination pointer to a usize + let destination = + self.registers.get(*pointer_index).to_usize(); + // Write to our destination memory + self.memory.write_slice(destination, values); + } + _ => { + unreachable!("Function result size does not match brillig bytecode size") } - // Convert the destination pointer to a usize - let destination = self.registers.get(*pointer_index).to_usize(); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") } + } else { + unimplemented!("deflattening heap arrays from foreign calls"); } } - RegisterOrMemory::HeapVector(HeapVector { pointer: pointer_index, size: size_index }) => { - match output { - ForeignCallParam::Array(values) => { - // Set our size in the size register - self.registers.set(*size_index, Value::from(values.len())); - // Convert the destination pointer to a usize - let destination = self.registers.get(*pointer_index).to_usize(); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") + RegisterOrMemory::HeapVector(HeapVector { + pointer: pointer_index, + size: size_index, + }) => { + let HeapValueType::Vector { value_types } = value_type else { + unreachable!("Expected vector heap type"); + }; + if HeapValueType::all_simple(value_types) { + match output { + ForeignCallParam::Array(values) => { + // Set our size in the size register + self.registers.set(*size_index, Value::from(values.len())); + // Convert the destination pointer to a usize + let destination = + self.registers.get(*pointer_index).to_usize(); + // Write to our destination memory + self.memory.write_slice(destination, values); + } + _ => { + unreachable!("Function result size does not match brillig bytecode size") + } } + } else { + unimplemented!("deflattening heap vectors from foreign calls"); } } } @@ -358,24 +395,80 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.status.clone() } - fn get_register_value_or_memory_values(&self, input: RegisterOrMemory) -> ForeignCallParam { + fn get_register_value_or_memory_values( + &self, + input: RegisterOrMemory, + value_type: &HeapValueType, + ) -> ForeignCallParam { match input { - RegisterOrMemory::RegisterIndex(value_index) => self.registers.get(value_index).into(), + RegisterOrMemory::RegisterIndex(value_index) => { + assert!(*value_type == HeapValueType::Simple); + self.registers.get(value_index).into() + } RegisterOrMemory::HeapArray(HeapArray { pointer: pointer_index, size }) => { - let start = self.registers.get(pointer_index); - self.memory.read_slice(start.to_usize(), size).to_vec().into() + let HeapValueType::Array { value_types, size: type_size } = value_type else { + unreachable!("expected array heap value type"); + }; + assert!(*type_size == size); + let ptr = self.registers.get(pointer_index).to_usize(); + self.read_slice_of_values_from_memory(ptr, size, value_types).into() } RegisterOrMemory::HeapVector(HeapVector { pointer: pointer_index, size: size_index, }) => { - let start = self.registers.get(pointer_index); - let size = self.registers.get(size_index); - self.memory.read_slice(start.to_usize(), size.to_usize()).to_vec().into() + let HeapValueType::Vector { value_types } = value_type else { + unreachable!("expected vector heap value type"); + }; + let ptr = self.registers.get(pointer_index).to_usize(); + let size = self.registers.get(size_index).to_usize(); + self.read_slice_of_values_from_memory(ptr, size, value_types).into() } } } + /// Reads an array/vector from memory but recursively reads pointers to + /// nested arrays/vectors according to the sequence of value types. + fn read_slice_of_values_from_memory( + &self, + ptr: usize, + size: usize, + value_types: &[HeapValueType], + ) -> Vec { + if HeapValueType::all_simple(value_types) { + self.memory.read_slice(ptr, size).to_vec() + } else { + // Check that the sequence of value types fit an integer number of + // times inside the given size. + assert!( + 0 == size % value_types.len(), + "array/vector does not contain a whole number of elements" + ); + (0..size) + .zip(value_types.iter().cycle()) + .flat_map(|(i, value_type)| { + let value = self.memory.read(ptr + i); + match value_type { + HeapValueType::Simple => vec![value], + HeapValueType::Array { value_types, size } => { + let inner_ptr = self.memory.read(value.to_usize()).to_usize(); + self.read_slice_of_values_from_memory(inner_ptr, *size, value_types) + } + HeapValueType::Vector { value_types } => { + let inner_ptr = self.memory.read(value.to_usize()).to_usize(); + let inner_size = self.memory.read(value.to_usize() + 1).to_usize(); + self.read_slice_of_values_from_memory( + inner_ptr, + inner_size, + value_types, + ) + } + } + }) + .collect::>() + } + } + /// Process a binary operation. /// This method will not modify the program counter. fn process_binary_field_op( @@ -951,7 +1044,9 @@ mod tests { Opcode::ForeignCall { function: "double".into(), destinations: vec![RegisterOrMemory::RegisterIndex(r_result)], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![RegisterOrMemory::RegisterIndex(r_input)], + input_value_types: vec![HeapValueType::Simple], }, ]; @@ -1009,10 +1104,18 @@ mod tests { pointer: r_output, size: initial_matrix.len(), })], + destination_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), })], + input_value_types: vec![HeapValueType::Array { + value_types: vec![HeapValueType::Simple], + size: initial_matrix.len(), + }], }, ]; @@ -1082,10 +1185,16 @@ mod tests { pointer: r_output_pointer, size: r_output_size, })], + destination_value_types: vec![HeapValueType::Vector { + value_types: vec![HeapValueType::Simple], + }], inputs: vec![RegisterOrMemory::HeapVector(HeapVector { pointer: r_input_pointer, size: r_input_size, })], + input_value_types: vec![HeapValueType::Vector { + value_types: vec![HeapValueType::Simple], + }], }, ]; @@ -1144,10 +1253,18 @@ mod tests { pointer: r_output, size: initial_matrix.len(), })], + destination_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![RegisterOrMemory::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), })], + input_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], }, ]; @@ -1222,6 +1339,10 @@ mod tests { pointer: r_output, size: matrix_a.len(), })], + destination_value_types: vec![HeapValueType::Array { + size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ RegisterOrMemory::HeapArray(HeapArray { pointer: r_input_a, @@ -1232,6 +1353,16 @@ mod tests { size: matrix_b.len(), }), ], + input_value_types: vec![ + HeapValueType::Array { + size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], + }, + HeapValueType::Array { + size: matrix_b.len(), + value_types: vec![HeapValueType::Simple], + }, + ], }, ]; let mut initial_memory = matrix_a.clone(); @@ -1263,4 +1394,113 @@ mod tests { // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); } + + #[test] + fn foreign_call_opcode_nested_arrays_and_slices_input() { + // [(1, <2,3>, [4]), (5, <6,7,8>, [9])] + + let v2 = vec![Value::from(2u128), Value::from(3u128)]; + let a4 = vec![Value::from(4u128)]; + let v6 = vec![Value::from(6u128), Value::from(7u128), Value::from(8u128)]; + let a9 = vec![Value::from(9u128)]; + + // construct memory by declaring all inner arrays/vectors first + let v2_ptr = 0u128; + let mut memory = v2.clone(); + let v2_start = memory.len(); + memory.extend(vec![Value::from(v2_ptr), Value::from(v2.len()), Value::from(1u128)]); + let a4_ptr = memory.len(); + memory.extend(a4.clone()); + let a4_start = memory.len(); + memory.extend(vec![Value::from(a4_ptr), Value::from(1u128)]); + let v6_ptr = memory.len(); + memory.extend(v6.clone()); + let v6_start = memory.len(); + memory.extend(vec![Value::from(v6_ptr), Value::from(v6.len()), Value::from(1u128)]); + let a9_ptr = memory.len(); + memory.extend(a9.clone()); + let a9_start = memory.len(); + memory.extend(vec![Value::from(a9_ptr), Value::from(1u128)]); + // finally we add the contents of the outer array + let outer_ptr = memory.len(); + let outer_array = vec![ + Value::from(1u128), + Value::from(v2.len()), + Value::from(v2_start), + Value::from(a4_start), + Value::from(5u128), + Value::from(v6.len()), + Value::from(v6_start), + Value::from(a9_start), + ]; + memory.extend(outer_array.clone()); + + let input_array_value_types = vec![ + HeapValueType::Simple, + HeapValueType::Simple, // size of following vector + HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }, + HeapValueType::Array { value_types: vec![HeapValueType::Simple], size: 1 }, + ]; + + let r_input = RegisterIndex::from(0); + let r_output = RegisterIndex::from(1); + + let program = vec![ + // input = 0 + Opcode::Const { destination: r_input, value: Value::from(outer_ptr) }, + // some_function(input) + Opcode::ForeignCall { + function: "flat_sum".into(), + destinations: vec![RegisterOrMemory::RegisterIndex(r_output)], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![RegisterOrMemory::HeapArray(HeapArray { + pointer: r_input, + size: outer_array.len(), + })], + input_value_types: vec![HeapValueType::Array { + value_types: input_array_value_types, + size: outer_array.len(), + }], + }, + ]; + + let mut vm = brillig_execute_and_get_vm(memory, &program); + + // Check that VM is waiting + assert_eq!( + vm.status, + VMStatus::ForeignCallWait { + function: "flat_sum".into(), + inputs: vec![ForeignCallParam::Array(vec![ + Value::from(1u128), + Value::from(2u128), // size of following vector + Value::from(2u128), + Value::from(3u128), + Value::from(4u128), + Value::from(5u128), + Value::from(3u128), // size of following vector + Value::from(6u128), + Value::from(7u128), + Value::from(8u128), + Value::from(9u128), + ])], + } + ); + + // Push result we're waiting for + vm.resolve_foreign_call(Value::from(45u128).into()); + + // Resume VM + brillig_execute(&mut vm); + + // Check that VM finished once resumed + assert_eq!(vm.status, VMStatus::Finished); + + // Check result + let result_value = vm.registers.get(r_output); + assert_eq!(result_value, Value::from(45u128)); + + // Ensure the foreign call counter has been incremented + assert_eq!(vm.foreign_call_counter, 1); + } } 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 632add74e6d..d30ed178777 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,4 +1,6 @@ -use crate::brillig::brillig_ir::brillig_variable::{BrilligArray, BrilligVariable, BrilligVector}; +use crate::brillig::brillig_ir::brillig_variable::{ + type_to_heap_value_type, BrilligArray, BrilligVariable, BrilligVector, +}; use crate::brillig::brillig_ir::{ BrilligBinaryOp, BrilligContext, BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, }; @@ -356,13 +358,23 @@ impl<'block> BrilligBlock<'block> { let input_registers = vecmap(arguments, |value_id| { self.convert_ssa_value(*value_id, dfg).to_register_or_memory() }); + let input_value_types = vecmap(arguments, |value_id| { + let value_type = dfg.type_of_value(*value_id); + type_to_heap_value_type(&value_type) + }); let output_registers = vecmap(result_ids, |value_id| { self.allocate_external_call_result(*value_id, dfg).to_register_or_memory() }); + let output_value_types = vecmap(result_ids, |value_id| { + let value_type = dfg.type_of_value(*value_id); + type_to_heap_value_type(&value_type) + }); self.brillig_context.foreign_call_instruction( func_name.to_owned(), &input_registers, + &input_value_types, &output_registers, + &output_value_types, ); for (i, output_register) in output_registers.iter().enumerate() { diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 3e6c3d4d7de..9ee92278a61 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -23,6 +23,7 @@ use acvm::{ BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory, Value, }, + brillig_vm::brillig::HeapValueType, FieldElement, }; use debug_show::DebugShow; @@ -566,13 +567,19 @@ impl BrilligContext { &mut self, func_name: String, inputs: &[RegisterOrMemory], + input_value_types: &[HeapValueType], outputs: &[RegisterOrMemory], + output_value_types: &[HeapValueType], ) { + assert!(inputs.len() == input_value_types.len()); + assert!(outputs.len() == output_value_types.len()); self.debug_show.foreign_call_instruction(func_name.clone(), inputs, outputs); let opcode = BrilligOpcode::ForeignCall { function: func_name, destinations: outputs.to_vec(), + destination_value_types: output_value_types.to_vec(), inputs: inputs.to_vec(), + input_value_types: input_value_types.to_vec(), }; self.push_opcode(opcode); } @@ -930,7 +937,7 @@ impl BrilligContext { /// Issues a blackbox operation. pub(crate) fn black_box_op_instruction(&mut self, op: BlackBoxOp) { - self.debug_show.black_box_op_instruction(op); + self.debug_show.black_box_op_instruction(&op); self.push_opcode(BrilligOpcode::BlackBox(op)); } @@ -1045,6 +1052,7 @@ pub(crate) mod tests { BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapVector, RegisterIndex, RegisterOrMemory, Value, }; + use acvm::brillig_vm::brillig::HeapValueType; use acvm::brillig_vm::{Registers, VMStatus, VM}; use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; @@ -1161,7 +1169,9 @@ pub(crate) mod tests { context.foreign_call_instruction( "make_number_sequence".into(), &[RegisterOrMemory::RegisterIndex(r_input_size)], + &[HeapValueType::Simple], &[RegisterOrMemory::HeapVector(HeapVector { pointer: r_stack, size: r_output_size })], + &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }], ); // push stack frame by r_returned_size context.memory_op(r_stack, r_output_size, r_stack, BinaryIntOp::Add); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index 46c54d55ecb..5014b275748 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -1,6 +1,10 @@ -use acvm::brillig_vm::brillig::{HeapArray, HeapVector, RegisterIndex, RegisterOrMemory}; +use acvm::brillig_vm::brillig::{ + HeapArray, HeapValueType, HeapVector, RegisterIndex, RegisterOrMemory, +}; use serde::{Deserialize, Serialize}; +use crate::ssa::ir::types::Type; + /// The representation of a noir array in the Brillig IR #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) struct BrilligArray { @@ -97,3 +101,16 @@ impl BrilligVariable { } } } + +pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType { + match typ { + Type::Numeric(_) | Type::Reference(_) | Type::Function => HeapValueType::Simple, + Type::Array(elem_type, size) => HeapValueType::Array { + value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), + size: typ.element_size() * size, + }, + Type::Slice(elem_type) => HeapValueType::Vector { + value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), + }, + } +} 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 a8563dc9efe..092623b6995 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -342,7 +342,7 @@ impl DebugShow { } /// Debug function for black_box_op - pub(crate) fn black_box_op_instruction(&self, op: BlackBoxOp) { + pub(crate) fn black_box_op_instruction(&self, op: &BlackBoxOp) { match op { BlackBoxOp::Sha256 { message, output } => { debug_println!(self.enable_debug_trace, " SHA256 {} -> {}", message, output); diff --git a/test_programs/execution_success/debug_logs/src/main.nr b/test_programs/execution_success/debug_logs/src/main.nr index b640e4f5f0c..49e0041594a 100644 --- a/test_programs/execution_success/debug_logs/src/main.nr +++ b/test_programs/execution_success/debug_logs/src/main.nr @@ -57,6 +57,12 @@ fn main(x: Field, y: pub Field) { regression_2906(); + let first_array = [1, 2, 3]; + let second_array = [4, 5, 6]; + let arrays_nested = [first_array, second_array]; + std::println(f"first_array: {first_array}, second_array: {second_array}"); + std::println(f"arrays_nested: {arrays_nested}"); + let free_lambda = |x| x + 1; let sentinel: u32 = 8888; std::println(f"free_lambda: {free_lambda}, sentinel: {sentinel}"); diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index ab807c65a46..f0a846bfd69 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -446,7 +446,7 @@ mod tests { }, blackbox_solver::StubbedBlackBoxSolver, brillig_vm::brillig::{ - BinaryFieldOp, Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory, + BinaryFieldOp, HeapValueType, Opcode as BrilligOpcode, RegisterIndex, RegisterOrMemory, }, }; use nargo::{artifacts::debug::DebugArtifact, ops::DefaultForeignCallExecutor}; @@ -472,7 +472,9 @@ mod tests { BrilligOpcode::ForeignCall { function: "clear_mock".into(), destinations: vec![], + destination_value_types: vec![], inputs: vec![RegisterOrMemory::RegisterIndex(RegisterIndex::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::Stop, ],