From daad75c26d19ae707b90a7424b77dab9937e8575 Mon Sep 17 00:00:00 2001 From: Aztec Bot <49558828+AztecBot@users.noreply.github.com> Date: Tue, 30 Jul 2024 14:03:01 -0400 Subject: [PATCH] feat: Sync from aztec-packages (#5598) Automated pull of Noir development from [aztec-packages](https://github.com/AztecProtocol/aztec-packages). BEGIN_COMMIT_OVERRIDE feat: Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/7583) feat: Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/7577) feat: Make Brillig do integer arithmetic operations using u128 instead of Bigint (https://github.com/AztecProtocol/aztec-packages/pull/7518) feat: Avoid heap allocs when going to/from field (https://github.com/AztecProtocol/aztec-packages/pull/7547) fix: Revert "feat: Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/7512)" (https://github.com/AztecProtocol/aztec-packages/pull/7558) feat: Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/7512) feat: Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/7454) chore: turn on elaborator (https://github.com/AztecProtocol/aztec-packages/pull/7451) fix: Add trailing extra arguments for backend in gates_flamegraph (https://github.com/AztecProtocol/aztec-packages/pull/7472) feat: Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/7444) feat: Sync from noir (https://github.com/AztecProtocol/aztec-packages/pull/7432) feat: Integrate new proving systems in e2e (https://github.com/AztecProtocol/aztec-packages/pull/6971) feat: typing return values of embedded_curve_ops (https://github.com/AztecProtocol/aztec-packages/pull/7413) END_COMMIT_OVERRIDE --------- Co-authored-by: Maxim Vezenov --- .aztec-sync-commit | 2 +- acvm-repo/acir/codegen/acir.cpp | 1874 +++++++++++------ acvm-repo/acir/src/lib.rs | 6 +- .../acir/tests/test_program_serialization.rs | 33 +- acvm-repo/acir_field/src/field_element.rs | 32 +- acvm-repo/acvm/src/pwg/brillig.rs | 3 +- .../test/shared/complex_foreign_call.ts | 14 +- acvm-repo/acvm_js/test/shared/foreign_call.ts | 8 +- acvm-repo/brillig/src/lib.rs | 2 +- acvm-repo/brillig/src/opcodes.rs | 91 +- acvm-repo/brillig_vm/src/arithmetic.rs | 245 ++- acvm-repo/brillig_vm/src/black_box.rs | 14 +- acvm-repo/brillig_vm/src/lib.rs | 145 +- acvm-repo/brillig_vm/src/memory.rs | 215 +- .../src/transforms/contract_interface.rs | 69 +- aztec_macros/src/transforms/note_interface.rs | 4 +- aztec_macros/src/utils/constants.rs | 1 - .../brillig/brillig_gen/brillig_directive.rs | 146 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 9 +- .../brillig/brillig_ir/brillig_variable.rs | 8 +- .../brillig/brillig_ir/codegen_intrinsic.rs | 47 +- .../src/brillig/brillig_ir/instructions.rs | 16 +- .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 4 +- .../ssa/acir_gen/acir_ir/generated_acir.rs | 7 +- .../noirc_evaluator/src/ssa/acir_gen/mod.rs | 2 +- .../src/ssa/ir/function_inserter.rs | 17 +- noir_stdlib/src/embedded_curve_ops.nr | 17 +- noir_stdlib/src/hash/keccak.nr | 19 +- noir_stdlib/src/hash/mod.nr | 26 +- scripts/install_bb.sh | 2 +- .../embedded_curve_ops/src/main.nr | 6 +- .../regression_5045/src/main.nr | 2 +- .../execution_success/schnorr/src/main.nr | 8 +- .../simple_shield/src/main.nr | 7 +- .../embedded_curve_ops/src/main.nr | 10 +- test_programs/rebuild.sh | 2 +- tooling/debugger/src/context.rs | 11 +- tooling/debugger/src/repl.rs | 14 +- tooling/fuzzer/src/dictionary/mod.rs | 8 +- .../noir_js_backend_barretenberg/package.json | 2 +- .../profiler/src/cli/gates_flamegraph_cmd.rs | 8 +- tooling/profiler/src/gates_provider.rs | 12 +- yarn.lock | 10 +- 43 files changed, 1924 insertions(+), 1254 deletions(-) diff --git a/.aztec-sync-commit b/.aztec-sync-commit index 18e53f2bd3b..379f006b5c0 100644 --- a/.aztec-sync-commit +++ b/.aztec-sync-commit @@ -1 +1 @@ -e44ef7042c87d3c78a14413ad7d54e4ed642ad89 +a26419f00f5f082a9ed856346addf6276fbdb4d7 diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index c1160930571..232b3ba12cf 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -5,704 +5,819 @@ namespace Program { - 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 ConstantOrWitnessEnum { + struct Sub { + friend bool operator==(const Sub&, const Sub&); + std::vector bincodeSerialize() const; + static Sub bincodeDeserialize(std::vector); + }; - struct Constant { - std::string value; + struct Mul { + friend bool operator==(const Mul&, const Mul&); + std::vector bincodeSerialize() const; + static Mul bincodeDeserialize(std::vector); + }; - friend bool operator==(const Constant&, const Constant&); + struct Div { + friend bool operator==(const Div&, const Div&); std::vector bincodeSerialize() const; - static Constant bincodeDeserialize(std::vector); + static Div bincodeDeserialize(std::vector); }; - struct Witness { - Program::Witness value; + struct IntegerDiv { + friend bool operator==(const IntegerDiv&, const IntegerDiv&); + std::vector bincodeSerialize() const; + static IntegerDiv bincodeDeserialize(std::vector); + }; - friend bool operator==(const Witness&, const Witness&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static Witness bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - std::variant value; + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); + std::vector bincodeSerialize() const; + static LessThan bincodeDeserialize(std::vector); + }; - friend bool operator==(const ConstantOrWitnessEnum&, const ConstantOrWitnessEnum&); - std::vector bincodeSerialize() const; - static ConstantOrWitnessEnum bincodeDeserialize(std::vector); - }; + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); + std::vector bincodeSerialize() const; + static LessThanEquals bincodeDeserialize(std::vector); + }; - struct FunctionInput { - Program::ConstantOrWitnessEnum input; - uint32_t num_bits; + std::variant value; - friend bool operator==(const FunctionInput&, const FunctionInput&); + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static FunctionInput bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct BlackBoxFuncCall { - - struct AES128Encrypt { - std::vector inputs; - std::array iv; - std::array key; - std::vector outputs; + struct BinaryIntOp { - friend bool operator==(const AES128Encrypt&, const AES128Encrypt&); + struct Add { + friend bool operator==(const Add&, const Add&); std::vector bincodeSerialize() const; - static AES128Encrypt bincodeDeserialize(std::vector); + static Add bincodeDeserialize(std::vector); }; - struct AND { - Program::FunctionInput lhs; - Program::FunctionInput rhs; - Program::Witness output; - - 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 { - Program::FunctionInput lhs; - Program::FunctionInput rhs; - Program::Witness output; - - friend bool operator==(const XOR&, const XOR&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); std::vector bincodeSerialize() const; - static XOR bincodeDeserialize(std::vector); + static Mul bincodeDeserialize(std::vector); }; - struct RANGE { - Program::FunctionInput input; - - friend bool operator==(const RANGE&, const RANGE&); + struct Div { + friend bool operator==(const Div&, const Div&); std::vector bincodeSerialize() const; - static RANGE bincodeDeserialize(std::vector); + static Div bincodeDeserialize(std::vector); }; - struct SHA256 { - std::vector inputs; - std::array outputs; - - friend bool operator==(const SHA256&, const SHA256&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static SHA256 bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - struct Blake2s { - std::vector inputs; - std::array outputs; - - friend bool operator==(const Blake2s&, const Blake2s&); + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); std::vector bincodeSerialize() const; - static Blake2s bincodeDeserialize(std::vector); + static LessThan bincodeDeserialize(std::vector); }; - struct Blake3 { - std::vector inputs; - std::array outputs; - - friend bool operator==(const Blake3&, const Blake3&); + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); std::vector bincodeSerialize() const; - static Blake3 bincodeDeserialize(std::vector); + static LessThanEquals bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Program::FunctionInput public_key_x; - Program::FunctionInput public_key_y; - std::array signature; - std::vector message; - Program::Witness output; - - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + struct And { + friend bool operator==(const And&, const And&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static And bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - std::vector inputs; - uint32_t domain_separator; - std::array outputs; - - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + struct Or { + friend bool operator==(const Or&, const Or&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static Or bincodeDeserialize(std::vector); }; - struct PedersenHash { - std::vector inputs; - uint32_t domain_separator; - Program::Witness output; - - friend bool operator==(const PedersenHash&, const PedersenHash&); + struct Xor { + friend bool operator==(const Xor&, const Xor&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Xor bincodeDeserialize(std::vector); }; - struct EcdsaSecp256k1 { - std::array public_key_x; - std::array public_key_y; - std::array signature; - std::array hashed_message; - Program::Witness output; + struct Shl { + friend bool operator==(const Shl&, const Shl&); + std::vector bincodeSerialize() const; + static Shl bincodeDeserialize(std::vector); + }; - friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); + struct Shr { + friend bool operator==(const Shr&, const Shr&); std::vector bincodeSerialize() const; - static EcdsaSecp256k1 bincodeDeserialize(std::vector); + static Shr bincodeDeserialize(std::vector); }; - struct EcdsaSecp256r1 { - std::array public_key_x; - std::array public_key_y; - std::array signature; - std::array hashed_message; - Program::Witness output; + std::variant value; - friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + std::vector bincodeSerialize() const; + static BinaryIntOp bincodeDeserialize(std::vector); + }; + + struct IntegerBitSize { + + struct U0 { + friend bool operator==(const U0&, const U0&); std::vector bincodeSerialize() const; - static EcdsaSecp256r1 bincodeDeserialize(std::vector); + static U0 bincodeDeserialize(std::vector); }; - struct MultiScalarMul { - std::vector points; - std::vector scalars; - std::array outputs; + struct U1 { + friend bool operator==(const U1&, const U1&); + std::vector bincodeSerialize() const; + static U1 bincodeDeserialize(std::vector); + }; - friend bool operator==(const MultiScalarMul&, const MultiScalarMul&); + struct U8 { + friend bool operator==(const U8&, const U8&); std::vector bincodeSerialize() const; - static MultiScalarMul bincodeDeserialize(std::vector); + static U8 bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - std::array input1; - std::array input2; - std::array outputs; + struct U16 { + friend bool operator==(const U16&, const U16&); + std::vector bincodeSerialize() const; + static U16 bincodeDeserialize(std::vector); + }; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + struct U32 { + friend bool operator==(const U32&, const U32&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static U32 bincodeDeserialize(std::vector); }; - struct Keccak256 { - std::vector inputs; - Program::FunctionInput var_message_size; - std::array outputs; + struct U64 { + friend bool operator==(const U64&, const U64&); + std::vector bincodeSerialize() const; + static U64 bincodeDeserialize(std::vector); + }; - friend bool operator==(const Keccak256&, const Keccak256&); + struct U128 { + friend bool operator==(const U128&, const U128&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static U128 bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - std::array inputs; - std::array outputs; + std::variant value; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const IntegerBitSize&, const IntegerBitSize&); + std::vector bincodeSerialize() const; + static IntegerBitSize bincodeDeserialize(std::vector); + }; + + struct BitSize { + + struct Field { + friend bool operator==(const Field&, const Field&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static Field bincodeDeserialize(std::vector); }; - struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Program::FunctionInput key_hash; + struct Integer { + Program::IntegerBitSize value; - friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); + friend bool operator==(const Integer&, const Integer&); std::vector bincodeSerialize() const; - static RecursiveAggregation bincodeDeserialize(std::vector); + static Integer bincodeDeserialize(std::vector); }; - struct BigIntAdd { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + std::variant value; - friend bool operator==(const BigIntAdd&, const BigIntAdd&); + friend bool operator==(const BitSize&, const BitSize&); + std::vector bincodeSerialize() const; + static BitSize bincodeDeserialize(std::vector); + }; + + struct MemoryAddress { + uint64_t value; + + friend bool operator==(const MemoryAddress&, const MemoryAddress&); + std::vector bincodeSerialize() const; + static MemoryAddress bincodeDeserialize(std::vector); + }; + + struct HeapArray { + Program::MemoryAddress pointer; + uint64_t size; + + friend bool operator==(const HeapArray&, const HeapArray&); + std::vector bincodeSerialize() const; + static HeapArray bincodeDeserialize(std::vector); + }; + + struct HeapVector { + Program::MemoryAddress pointer; + Program::MemoryAddress size; + + friend bool operator==(const HeapVector&, const HeapVector&); + std::vector bincodeSerialize() const; + static HeapVector bincodeDeserialize(std::vector); + }; + + struct BlackBoxOp { + + struct AES128Encrypt { + Program::HeapVector inputs; + Program::HeapArray iv; + Program::HeapArray key; + Program::HeapVector outputs; + + friend bool operator==(const AES128Encrypt&, const AES128Encrypt&); std::vector bincodeSerialize() const; - static BigIntAdd bincodeDeserialize(std::vector); + static AES128Encrypt bincodeDeserialize(std::vector); }; - struct BigIntSub { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct Sha256 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const BigIntSub&, const BigIntSub&); + friend bool operator==(const Sha256&, const Sha256&); std::vector bincodeSerialize() const; - static BigIntSub bincodeDeserialize(std::vector); + static Sha256 bincodeDeserialize(std::vector); }; - struct BigIntMul { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct Blake2s { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const BigIntMul&, const BigIntMul&); + friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; - static BigIntMul bincodeDeserialize(std::vector); + static Blake2s bincodeDeserialize(std::vector); }; - struct BigIntDiv { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct Blake3 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const BigIntDiv&, const BigIntDiv&); + friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; - static BigIntDiv bincodeDeserialize(std::vector); + static Blake3 bincodeDeserialize(std::vector); }; - struct BigIntFromLeBytes { - std::vector inputs; - std::vector modulus; - uint32_t output; + struct Keccak256 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static BigIntFromLeBytes bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct BigIntToLeBytes { - uint32_t input; - std::vector outputs; + struct Keccakf1600 { + Program::HeapVector message; + Program::HeapArray output; - friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static BigIntToLeBytes bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; - struct Poseidon2Permutation { - std::vector inputs; - std::vector outputs; - uint32_t len; + struct EcdsaSecp256k1 { + Program::HeapVector hashed_msg; + Program::HeapArray public_key_x; + Program::HeapArray public_key_y; + Program::HeapArray signature; + Program::MemoryAddress result; - friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); + friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; - static Poseidon2Permutation bincodeDeserialize(std::vector); + static EcdsaSecp256k1 bincodeDeserialize(std::vector); }; - struct Sha256Compression { - std::array inputs; - std::array hash_values; - std::array outputs; + struct EcdsaSecp256r1 { + Program::HeapVector hashed_msg; + Program::HeapArray public_key_x; + Program::HeapArray public_key_y; + Program::HeapArray signature; + Program::MemoryAddress result; - friend bool operator==(const Sha256Compression&, const Sha256Compression&); + friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; - static Sha256Compression bincodeDeserialize(std::vector); + static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - std::variant value; + struct SchnorrVerify { + Program::MemoryAddress public_key_x; + Program::MemoryAddress public_key_y; + Program::HeapVector message; + Program::HeapVector signature; + Program::MemoryAddress result; - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); - std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); - }; + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + std::vector bincodeSerialize() const; + static SchnorrVerify bincodeDeserialize(std::vector); + }; - struct BlockId { - uint32_t value; + struct PedersenCommitment { + Program::HeapVector inputs; + Program::MemoryAddress domain_separator; + Program::HeapArray output; - friend bool operator==(const BlockId&, const BlockId&); - std::vector bincodeSerialize() const; - static BlockId bincodeDeserialize(std::vector); - }; + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + std::vector bincodeSerialize() const; + static PedersenCommitment bincodeDeserialize(std::vector); + }; - struct BlockType { + struct PedersenHash { + Program::HeapVector inputs; + Program::MemoryAddress domain_separator; + Program::MemoryAddress output; - struct Memory { - friend bool operator==(const Memory&, const Memory&); + friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; - static Memory bincodeDeserialize(std::vector); + static PedersenHash bincodeDeserialize(std::vector); }; - struct CallData { - friend bool operator==(const CallData&, const CallData&); + struct MultiScalarMul { + Program::HeapVector points; + Program::HeapVector scalars; + Program::HeapArray outputs; + + friend bool operator==(const MultiScalarMul&, const MultiScalarMul&); std::vector bincodeSerialize() const; - static CallData bincodeDeserialize(std::vector); + static MultiScalarMul bincodeDeserialize(std::vector); }; - struct ReturnData { - friend bool operator==(const ReturnData&, const ReturnData&); + struct EmbeddedCurveAdd { + Program::MemoryAddress input1_x; + Program::MemoryAddress input1_y; + Program::MemoryAddress input1_infinite; + Program::MemoryAddress input2_x; + Program::MemoryAddress input2_y; + Program::MemoryAddress input2_infinite; + Program::HeapArray result; + + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static ReturnData bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BlockType&, const BlockType&); - std::vector bincodeSerialize() const; - static BlockType bincodeDeserialize(std::vector); - }; + struct BigIntAdd { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; - std::string q_c; + friend bool operator==(const BigIntAdd&, const BigIntAdd&); + std::vector bincodeSerialize() const; + static BigIntAdd bincodeDeserialize(std::vector); + }; - friend bool operator==(const Expression&, const Expression&); - std::vector bincodeSerialize() const; - static Expression bincodeDeserialize(std::vector); - }; + struct BigIntSub { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - struct BrilligInputs { + friend bool operator==(const BigIntSub&, const BigIntSub&); + std::vector bincodeSerialize() const; + static BigIntSub bincodeDeserialize(std::vector); + }; - struct Single { - Program::Expression value; + struct BigIntMul { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - friend bool operator==(const Single&, const Single&); + friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; - static Single bincodeDeserialize(std::vector); + static BigIntMul bincodeDeserialize(std::vector); }; - struct Array { - std::vector value; + struct BigIntDiv { + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; + Program::MemoryAddress output; - friend bool operator==(const Array&, const Array&); + friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); + static BigIntDiv bincodeDeserialize(std::vector); }; - struct MemoryArray { - Program::BlockId value; + struct BigIntFromLeBytes { + Program::HeapVector inputs; + Program::HeapVector modulus; + Program::MemoryAddress output; - friend bool operator==(const MemoryArray&, const MemoryArray&); + friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; - static MemoryArray bincodeDeserialize(std::vector); + static BigIntFromLeBytes bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BrilligInputs&, const BrilligInputs&); - std::vector bincodeSerialize() const; - static BrilligInputs bincodeDeserialize(std::vector); - }; - - struct BrilligOutputs { - - struct Simple { - Program::Witness value; + struct BigIntToLeBytes { + Program::MemoryAddress input; + Program::HeapVector output; - friend bool operator==(const Simple&, const Simple&); + friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; - static Simple bincodeDeserialize(std::vector); + static BigIntToLeBytes bincodeDeserialize(std::vector); }; - struct Array { - std::vector value; + struct Poseidon2Permutation { + Program::HeapVector message; + Program::HeapArray output; + Program::MemoryAddress len; - friend bool operator==(const Array&, const Array&); + friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); + static Poseidon2Permutation bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BrilligOutputs&, const BrilligOutputs&); - std::vector bincodeSerialize() const; - static BrilligOutputs bincodeDeserialize(std::vector); - }; + struct Sha256Compression { + Program::HeapVector input; + Program::HeapVector hash_values; + Program::HeapArray output; - struct Directive { + friend bool operator==(const Sha256Compression&, const Sha256Compression&); + std::vector bincodeSerialize() const; + static Sha256Compression bincodeDeserialize(std::vector); + }; - struct ToLeRadix { - Program::Expression a; - std::vector b; + struct ToRadix { + Program::MemoryAddress input; uint32_t radix; + Program::HeapArray output; - friend bool operator==(const ToLeRadix&, const ToLeRadix&); + friend bool operator==(const ToRadix&, const ToRadix&); std::vector bincodeSerialize() const; - static ToLeRadix bincodeDeserialize(std::vector); + static ToRadix bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const Directive&, const Directive&); + friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; - static Directive bincodeDeserialize(std::vector); + static BlackBoxOp bincodeDeserialize(std::vector); }; - struct MemOp { - Program::Expression operation; - Program::Expression index; - Program::Expression value; - - friend bool operator==(const MemOp&, const MemOp&); - std::vector bincodeSerialize() const; - static MemOp bincodeDeserialize(std::vector); - }; + struct HeapValueType; - struct Opcode { + struct HeapValueType { - struct AssertZero { - Program::Expression value; + struct Simple { + Program::BitSize value; - friend bool operator==(const AssertZero&, const AssertZero&); + friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; - static AssertZero bincodeDeserialize(std::vector); + static Simple bincodeDeserialize(std::vector); }; - struct BlackBoxFuncCall { - Program::BlackBoxFuncCall value; + struct Array { + std::vector value_types; + uint64_t size; - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct Directive { - Program::Directive value; + struct Vector { + std::vector value_types; - friend bool operator==(const Directive&, const Directive&); + friend bool operator==(const Vector&, const Vector&); std::vector bincodeSerialize() const; - static Directive bincodeDeserialize(std::vector); + static Vector bincodeDeserialize(std::vector); }; - struct MemoryOp { - Program::BlockId block_id; - Program::MemOp op; - std::optional predicate; + std::variant value; - friend bool operator==(const MemoryOp&, const MemoryOp&); - std::vector bincodeSerialize() const; - static MemoryOp bincodeDeserialize(std::vector); - }; + friend bool operator==(const HeapValueType&, const HeapValueType&); + std::vector bincodeSerialize() const; + static HeapValueType bincodeDeserialize(std::vector); + }; - struct MemoryInit { - Program::BlockId block_id; - std::vector init; - Program::BlockType block_type; + struct ValueOrArray { - friend bool operator==(const MemoryInit&, const MemoryInit&); + struct MemoryAddress { + Program::MemoryAddress value; + + friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; - static MemoryInit bincodeDeserialize(std::vector); + static MemoryAddress bincodeDeserialize(std::vector); }; - struct BrilligCall { - uint32_t id; - std::vector inputs; - std::vector outputs; - std::optional predicate; + struct HeapArray { + Program::HeapArray value; - friend bool operator==(const BrilligCall&, const BrilligCall&); + friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; - static BrilligCall bincodeDeserialize(std::vector); + static HeapArray bincodeDeserialize(std::vector); }; - struct Call { - uint32_t id; - std::vector inputs; - std::vector outputs; - std::optional predicate; + struct HeapVector { + Program::HeapVector value; - friend bool operator==(const Call&, const Call&); + friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; - static Call bincodeDeserialize(std::vector); + static HeapVector bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const Opcode&, const Opcode&); + friend bool operator==(const ValueOrArray&, const ValueOrArray&); std::vector bincodeSerialize() const; - static Opcode bincodeDeserialize(std::vector); + static ValueOrArray bincodeDeserialize(std::vector); }; - struct BinaryFieldOp { + struct BrilligOpcode { - struct Add { - friend bool operator==(const Add&, const Add&); - std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); - }; + struct BinaryFieldOp { + Program::MemoryAddress destination; + Program::BinaryFieldOp op; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); - std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); - }; + struct BinaryIntOp { + Program::MemoryAddress destination; + Program::BinaryIntOp op; + Program::IntegerBitSize bit_size; + Program::MemoryAddress lhs; + Program::MemoryAddress rhs; - struct Div { - friend bool operator==(const Div&, const Div&); + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); + static BinaryIntOp bincodeDeserialize(std::vector); }; - struct IntegerDiv { - friend bool operator==(const IntegerDiv&, const IntegerDiv&); - std::vector bincodeSerialize() const; - static IntegerDiv bincodeDeserialize(std::vector); - }; + struct Cast { + Program::MemoryAddress destination; + Program::MemoryAddress source; + Program::BitSize bit_size; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + friend bool operator==(const Cast&, const Cast&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static Cast bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); + struct JumpIfNot { + Program::MemoryAddress condition; + uint64_t location; + + friend bool operator==(const JumpIfNot&, const JumpIfNot&); std::vector bincodeSerialize() const; - static LessThan bincodeDeserialize(std::vector); + static JumpIfNot bincodeDeserialize(std::vector); }; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); + struct JumpIf { + Program::MemoryAddress condition; + uint64_t location; + + friend bool operator==(const JumpIf&, const JumpIf&); std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); + static JumpIf bincodeDeserialize(std::vector); }; - std::variant value; + struct Jump { + uint64_t location; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); - std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); - }; + friend bool operator==(const Jump&, const Jump&); + std::vector bincodeSerialize() const; + static Jump bincodeDeserialize(std::vector); + }; - struct BinaryIntOp { + struct CalldataCopy { + Program::MemoryAddress destination_address; + uint64_t size; + uint64_t offset; - struct Add { - friend bool operator==(const Add&, const Add&); + friend bool operator==(const CalldataCopy&, const CalldataCopy&); std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); + static CalldataCopy bincodeDeserialize(std::vector); }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + struct Call { + uint64_t location; + + friend bool operator==(const Call&, const Call&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static Call bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct Const { + Program::MemoryAddress destination; + Program::BitSize bit_size; + std::string value; + + friend bool operator==(const Const&, const Const&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static Const bincodeDeserialize(std::vector); }; - struct Div { - friend bool operator==(const Div&, const Div&); + struct Return { + friend bool operator==(const Return&, const Return&); std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); + static Return bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + 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 ForeignCall&, const ForeignCall&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static ForeignCall bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); + struct Mov { + Program::MemoryAddress destination; + Program::MemoryAddress source; + + friend bool operator==(const Mov&, const Mov&); std::vector bincodeSerialize() const; - static LessThan bincodeDeserialize(std::vector); + static Mov bincodeDeserialize(std::vector); }; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); + struct ConditionalMov { + Program::MemoryAddress destination; + Program::MemoryAddress source_a; + Program::MemoryAddress source_b; + Program::MemoryAddress condition; + + friend bool operator==(const ConditionalMov&, const ConditionalMov&); std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); + static ConditionalMov bincodeDeserialize(std::vector); }; - struct And { - friend bool operator==(const And&, const And&); + struct Load { + Program::MemoryAddress destination; + Program::MemoryAddress source_pointer; + + friend bool operator==(const Load&, const Load&); std::vector bincodeSerialize() const; - static And bincodeDeserialize(std::vector); + static Load bincodeDeserialize(std::vector); }; - struct Or { - friend bool operator==(const Or&, const Or&); + struct Store { + Program::MemoryAddress destination_pointer; + Program::MemoryAddress source; + + friend bool operator==(const Store&, const Store&); std::vector bincodeSerialize() const; - static Or bincodeDeserialize(std::vector); + static Store bincodeDeserialize(std::vector); }; - struct Xor { - friend bool operator==(const Xor&, const Xor&); + struct BlackBox { + Program::BlackBoxOp value; + + friend bool operator==(const BlackBox&, const BlackBox&); std::vector bincodeSerialize() const; - static Xor bincodeDeserialize(std::vector); + static BlackBox bincodeDeserialize(std::vector); }; - struct Shl { - friend bool operator==(const Shl&, const Shl&); + struct Trap { + Program::HeapArray revert_data; + + friend bool operator==(const Trap&, const Trap&); std::vector bincodeSerialize() const; - static Shl bincodeDeserialize(std::vector); + static Trap bincodeDeserialize(std::vector); }; - struct Shr { - friend bool operator==(const Shr&, const Shr&); + struct Stop { + uint64_t return_data_offset; + uint64_t return_data_size; + + friend bool operator==(const Stop&, const Stop&); std::vector bincodeSerialize() const; - static Shr bincodeDeserialize(std::vector); + static Stop bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); + static BrilligOpcode bincodeDeserialize(std::vector); }; - struct MemoryAddress { - uint64_t value; + struct Witness { + uint32_t value; - friend bool operator==(const MemoryAddress&, const MemoryAddress&); + friend bool operator==(const Witness&, const Witness&); std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); + static Witness bincodeDeserialize(std::vector); }; - struct HeapArray { - Program::MemoryAddress pointer; - uint64_t size; + struct ConstantOrWitnessEnum { - friend bool operator==(const HeapArray&, const HeapArray&); + struct Constant { + std::string value; + + friend bool operator==(const Constant&, const Constant&); + std::vector bincodeSerialize() const; + static Constant bincodeDeserialize(std::vector); + }; + + struct Witness { + Program::Witness value; + + friend bool operator==(const Witness&, const Witness&); + std::vector bincodeSerialize() const; + static Witness bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const ConstantOrWitnessEnum&, const ConstantOrWitnessEnum&); std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); + static ConstantOrWitnessEnum bincodeDeserialize(std::vector); }; - struct HeapVector { - Program::MemoryAddress pointer; - Program::MemoryAddress size; + struct FunctionInput { + Program::ConstantOrWitnessEnum input; + uint32_t num_bits; - friend bool operator==(const HeapVector&, const HeapVector&); + friend bool operator==(const FunctionInput&, const FunctionInput&); std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); + static FunctionInput bincodeDeserialize(std::vector); }; - struct BlackBoxOp { + struct BlackBoxFuncCall { struct AES128Encrypt { - Program::HeapVector inputs; - Program::HeapArray iv; - Program::HeapArray key; - Program::HeapVector outputs; + std::vector inputs; + std::array iv; + std::array key; + std::vector outputs; friend bool operator==(const AES128Encrypt&, const AES128Encrypt&); std::vector bincodeSerialize() const; static AES128Encrypt bincodeDeserialize(std::vector); }; - struct Sha256 { - Program::HeapVector message; - Program::HeapArray output; + struct AND { + Program::FunctionInput lhs; + Program::FunctionInput rhs; + Program::Witness output; - friend bool operator==(const Sha256&, const Sha256&); + friend bool operator==(const AND&, const AND&); std::vector bincodeSerialize() const; - static Sha256 bincodeDeserialize(std::vector); + static AND bincodeDeserialize(std::vector); + }; + + struct XOR { + Program::FunctionInput lhs; + Program::FunctionInput rhs; + Program::Witness output; + + friend bool operator==(const XOR&, const XOR&); + std::vector bincodeSerialize() const; + static XOR bincodeDeserialize(std::vector); + }; + + struct RANGE { + Program::FunctionInput input; + + friend bool operator==(const RANGE&, const RANGE&); + std::vector bincodeSerialize() const; + static RANGE bincodeDeserialize(std::vector); + }; + + struct SHA256 { + std::vector inputs; + std::array outputs; + + friend bool operator==(const SHA256&, const SHA256&); + std::vector bincodeSerialize() const; + static SHA256 bincodeDeserialize(std::vector); }; struct Blake2s { - Program::HeapVector message; - Program::HeapArray output; + std::vector inputs; + std::array outputs; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -710,38 +825,52 @@ namespace Program { }; struct Blake3 { - Program::HeapVector message; - Program::HeapArray output; + std::vector inputs; + std::array outputs; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; static Blake3 bincodeDeserialize(std::vector); }; - struct Keccak256 { - Program::HeapVector message; - Program::HeapArray output; + struct SchnorrVerify { + Program::FunctionInput public_key_x; + Program::FunctionInput public_key_y; + std::array signature; + std::vector message; + Program::Witness output; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - Program::HeapVector message; - Program::HeapArray output; + struct PedersenCommitment { + std::vector inputs; + uint32_t domain_separator; + std::array outputs; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); + }; + + struct PedersenHash { + std::vector inputs; + uint32_t domain_separator; + Program::Witness output; + + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); }; struct EcdsaSecp256k1 { - Program::HeapVector hashed_msg; - Program::HeapArray public_key_x; - Program::HeapArray public_key_y; - Program::HeapArray signature; - Program::MemoryAddress result; + std::array public_key_x; + std::array public_key_y; + std::array signature; + std::array hashed_message; + Program::Witness output; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -749,77 +878,71 @@ namespace Program { }; struct EcdsaSecp256r1 { - Program::HeapVector hashed_msg; - Program::HeapArray public_key_x; - Program::HeapArray public_key_y; - Program::HeapArray signature; - Program::MemoryAddress result; + std::array public_key_x; + std::array public_key_y; + std::array signature; + std::array hashed_message; + Program::Witness output; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Program::MemoryAddress public_key_x; - Program::MemoryAddress public_key_y; - Program::HeapVector message; - Program::HeapVector signature; - Program::MemoryAddress result; + struct MultiScalarMul { + std::vector points; + std::vector scalars; + std::array outputs; - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + friend bool operator==(const MultiScalarMul&, const MultiScalarMul&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static MultiScalarMul bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - Program::HeapVector inputs; - Program::MemoryAddress domain_separator; - Program::HeapArray output; + struct EmbeddedCurveAdd { + std::array input1; + std::array input2; + std::array outputs; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; - struct PedersenHash { - Program::HeapVector inputs; - Program::MemoryAddress domain_separator; - Program::MemoryAddress output; + struct Keccak256 { + std::vector inputs; + Program::FunctionInput var_message_size; + std::array outputs; - friend bool operator==(const PedersenHash&, const PedersenHash&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct MultiScalarMul { - Program::HeapVector points; - Program::HeapVector scalars; - Program::HeapArray outputs; + struct Keccakf1600 { + std::array inputs; + std::array outputs; - friend bool operator==(const MultiScalarMul&, const MultiScalarMul&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static MultiScalarMul bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Program::MemoryAddress input1_x; - Program::MemoryAddress input1_y; - Program::MemoryAddress input1_infinite; - Program::MemoryAddress input2_x; - Program::MemoryAddress input2_y; - Program::MemoryAddress input2_infinite; - Program::HeapArray result; + struct RecursiveAggregation { + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Program::FunctionInput key_hash; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static RecursiveAggregation bincodeDeserialize(std::vector); }; struct BigIntAdd { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; @@ -827,9 +950,9 @@ namespace Program { }; struct BigIntSub { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; @@ -837,9 +960,9 @@ namespace Program { }; struct BigIntMul { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -847,9 +970,9 @@ namespace Program { }; struct BigIntDiv { - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; - Program::MemoryAddress output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -857,9 +980,9 @@ namespace Program { }; struct BigIntFromLeBytes { - Program::HeapVector inputs; - Program::HeapVector modulus; - Program::MemoryAddress output; + std::vector inputs; + std::vector modulus; + uint32_t output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -867,8 +990,8 @@ namespace Program { }; struct BigIntToLeBytes { - Program::MemoryAddress input; - Program::HeapVector output; + uint32_t input; + std::vector outputs; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -876,9 +999,9 @@ namespace Program { }; struct Poseidon2Permutation { - Program::HeapVector message; - Program::HeapArray output; - Program::MemoryAddress len; + std::vector inputs; + std::vector outputs; + uint32_t len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; @@ -886,276 +1009,227 @@ namespace Program { }; struct Sha256Compression { - Program::HeapVector input; - Program::HeapVector hash_values; - Program::HeapArray output; + std::array inputs; + std::array hash_values; + std::array outputs; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; static Sha256Compression bincodeDeserialize(std::vector); }; - struct ToRadix { - Program::MemoryAddress input; - uint32_t radix; - Program::HeapArray output; - - friend bool operator==(const ToRadix&, const ToRadix&); - std::vector bincodeSerialize() const; - static ToRadix bincodeDeserialize(std::vector); - }; - - std::variant value; + std::variant value; - friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); + friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; - static BlackBoxOp bincodeDeserialize(std::vector); + static BlackBoxFuncCall bincodeDeserialize(std::vector); }; - struct HeapValueType; + struct BlockId { + uint32_t value; - struct HeapValueType { + friend bool operator==(const BlockId&, const BlockId&); + std::vector bincodeSerialize() const; + static BlockId bincodeDeserialize(std::vector); + }; - struct Simple { - uint32_t value; + struct BlockType { - friend bool operator==(const Simple&, const Simple&); + struct Memory { + friend bool operator==(const Memory&, const Memory&); std::vector bincodeSerialize() const; - static Simple bincodeDeserialize(std::vector); + static Memory bincodeDeserialize(std::vector); }; - struct Array { - std::vector value_types; - uint64_t size; - - friend bool operator==(const Array&, const Array&); + struct CallData { + friend bool operator==(const CallData&, const CallData&); std::vector bincodeSerialize() const; - static Array bincodeDeserialize(std::vector); + static CallData bincodeDeserialize(std::vector); }; - struct Vector { - std::vector value_types; - - friend bool operator==(const Vector&, const Vector&); + struct ReturnData { + friend bool operator==(const ReturnData&, const ReturnData&); std::vector bincodeSerialize() const; - static Vector bincodeDeserialize(std::vector); + static ReturnData bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const HeapValueType&, const HeapValueType&); + friend bool operator==(const BlockType&, const BlockType&); std::vector bincodeSerialize() const; - static HeapValueType bincodeDeserialize(std::vector); + static BlockType bincodeDeserialize(std::vector); }; - struct ValueOrArray { - - struct MemoryAddress { - Program::MemoryAddress value; - - friend bool operator==(const MemoryAddress&, const MemoryAddress&); - std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); - }; - - struct HeapArray { - Program::HeapArray value; - - friend bool operator==(const HeapArray&, const HeapArray&); - std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); - }; - - struct HeapVector { - Program::HeapVector value; - - friend bool operator==(const HeapVector&, const HeapVector&); - std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); - }; - - std::variant value; + struct Expression { + std::vector> mul_terms; + std::vector> linear_combinations; + std::string q_c; - friend bool operator==(const ValueOrArray&, const ValueOrArray&); + friend bool operator==(const Expression&, const Expression&); std::vector bincodeSerialize() const; - static ValueOrArray bincodeDeserialize(std::vector); + static Expression bincodeDeserialize(std::vector); }; - struct BrilligOpcode { + struct BrilligInputs { - struct BinaryFieldOp { - Program::MemoryAddress destination; - Program::BinaryFieldOp op; - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; + struct Single { + Program::Expression value; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); + friend bool operator==(const Single&, const Single&); std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); + static Single bincodeDeserialize(std::vector); }; - struct BinaryIntOp { - Program::MemoryAddress destination; - Program::BinaryIntOp op; - uint32_t bit_size; - Program::MemoryAddress lhs; - Program::MemoryAddress rhs; + struct Array { + std::vector value; - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct Cast { - Program::MemoryAddress destination; - Program::MemoryAddress source; - uint32_t bit_size; + struct MemoryArray { + Program::BlockId value; - friend bool operator==(const Cast&, const Cast&); + friend bool operator==(const MemoryArray&, const MemoryArray&); std::vector bincodeSerialize() const; - static Cast bincodeDeserialize(std::vector); + static MemoryArray bincodeDeserialize(std::vector); }; - struct JumpIfNot { - Program::MemoryAddress condition; - uint64_t location; + std::variant value; - friend bool operator==(const JumpIfNot&, const JumpIfNot&); - std::vector bincodeSerialize() const; - static JumpIfNot bincodeDeserialize(std::vector); - }; + friend bool operator==(const BrilligInputs&, const BrilligInputs&); + std::vector bincodeSerialize() const; + static BrilligInputs bincodeDeserialize(std::vector); + }; - struct JumpIf { - Program::MemoryAddress condition; - uint64_t location; + struct BrilligOutputs { + + struct Simple { + Program::Witness value; - friend bool operator==(const JumpIf&, const JumpIf&); + friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; - static JumpIf bincodeDeserialize(std::vector); + static Simple bincodeDeserialize(std::vector); }; - struct Jump { - uint64_t location; + struct Array { + std::vector value; - friend bool operator==(const Jump&, const Jump&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static Jump bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct CalldataCopy { - Program::MemoryAddress destination_address; - uint64_t size; - uint64_t offset; + std::variant value; - friend bool operator==(const CalldataCopy&, const CalldataCopy&); - std::vector bincodeSerialize() const; - static CalldataCopy bincodeDeserialize(std::vector); - }; + friend bool operator==(const BrilligOutputs&, const BrilligOutputs&); + std::vector bincodeSerialize() const; + static BrilligOutputs bincodeDeserialize(std::vector); + }; - struct Call { - uint64_t location; + struct Directive { - friend bool operator==(const Call&, const Call&); + struct ToLeRadix { + Program::Expression a; + std::vector b; + uint32_t radix; + + friend bool operator==(const ToLeRadix&, const ToLeRadix&); std::vector bincodeSerialize() const; - static Call bincodeDeserialize(std::vector); + static ToLeRadix bincodeDeserialize(std::vector); }; - struct Const { - Program::MemoryAddress destination; - uint32_t bit_size; - std::string value; + std::variant value; - friend bool operator==(const Const&, const Const&); - std::vector bincodeSerialize() const; - static Const bincodeDeserialize(std::vector); - }; + friend bool operator==(const Directive&, const Directive&); + std::vector bincodeSerialize() const; + static Directive bincodeDeserialize(std::vector); + }; - struct Return { - friend bool operator==(const Return&, const Return&); - std::vector bincodeSerialize() const; - static Return bincodeDeserialize(std::vector); - }; + struct MemOp { + Program::Expression operation; + Program::Expression index; + Program::Expression value; - 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 MemOp&, const MemOp&); + std::vector bincodeSerialize() const; + static MemOp bincodeDeserialize(std::vector); + }; - friend bool operator==(const ForeignCall&, const ForeignCall&); - std::vector bincodeSerialize() const; - static ForeignCall bincodeDeserialize(std::vector); - }; + struct Opcode { - struct Mov { - Program::MemoryAddress destination; - Program::MemoryAddress source; + struct AssertZero { + Program::Expression value; - friend bool operator==(const Mov&, const Mov&); + friend bool operator==(const AssertZero&, const AssertZero&); std::vector bincodeSerialize() const; - static Mov bincodeDeserialize(std::vector); + static AssertZero bincodeDeserialize(std::vector); }; - struct ConditionalMov { - Program::MemoryAddress destination; - Program::MemoryAddress source_a; - Program::MemoryAddress source_b; - Program::MemoryAddress condition; + struct BlackBoxFuncCall { + Program::BlackBoxFuncCall value; - friend bool operator==(const ConditionalMov&, const ConditionalMov&); + friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); std::vector bincodeSerialize() const; - static ConditionalMov bincodeDeserialize(std::vector); + static BlackBoxFuncCall bincodeDeserialize(std::vector); }; - struct Load { - Program::MemoryAddress destination; - Program::MemoryAddress source_pointer; + struct Directive { + Program::Directive value; - friend bool operator==(const Load&, const Load&); + friend bool operator==(const Directive&, const Directive&); std::vector bincodeSerialize() const; - static Load bincodeDeserialize(std::vector); + static Directive bincodeDeserialize(std::vector); }; - struct Store { - Program::MemoryAddress destination_pointer; - Program::MemoryAddress source; + struct MemoryOp { + Program::BlockId block_id; + Program::MemOp op; + std::optional predicate; - friend bool operator==(const Store&, const Store&); + friend bool operator==(const MemoryOp&, const MemoryOp&); std::vector bincodeSerialize() const; - static Store bincodeDeserialize(std::vector); + static MemoryOp bincodeDeserialize(std::vector); }; - struct BlackBox { - Program::BlackBoxOp value; + struct MemoryInit { + Program::BlockId block_id; + std::vector init; + Program::BlockType block_type; - friend bool operator==(const BlackBox&, const BlackBox&); + friend bool operator==(const MemoryInit&, const MemoryInit&); std::vector bincodeSerialize() const; - static BlackBox bincodeDeserialize(std::vector); + static MemoryInit bincodeDeserialize(std::vector); }; - struct Trap { - Program::HeapArray revert_data; + struct BrilligCall { + uint32_t id; + std::vector inputs; + std::vector outputs; + std::optional predicate; - friend bool operator==(const Trap&, const Trap&); + friend bool operator==(const BrilligCall&, const BrilligCall&); std::vector bincodeSerialize() const; - static Trap bincodeDeserialize(std::vector); + static BrilligCall bincodeDeserialize(std::vector); }; - struct Stop { - uint64_t return_data_offset; - uint64_t return_data_size; + struct Call { + uint32_t id; + std::vector inputs; + std::vector outputs; + std::optional predicate; - friend bool operator==(const Stop&, const Stop&); + friend bool operator==(const Call&, const Call&); std::vector bincodeSerialize() const; - static Stop bincodeDeserialize(std::vector); + static Call bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); + friend bool operator==(const Opcode&, const Opcode&); std::vector bincodeSerialize() const; - static BrilligOpcode bincodeDeserialize(std::vector); + static Opcode bincodeDeserialize(std::vector); }; struct ExpressionOrMemory { @@ -2103,15 +2177,121 @@ namespace Program { return true; } - inline std::vector BinaryIntOp::Xor::bincodeSerialize() const { + inline std::vector BinaryIntOp::Xor::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryIntOp::Xor BinaryIntOp::Xor::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::BinaryIntOp::Xor &obj, Serializer &serializer) { +} + +template <> +template +Program::BinaryIntOp::Xor serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Xor obj; + return obj; +} + +namespace Program { + + inline bool operator==(const BinaryIntOp::Shl &lhs, const BinaryIntOp::Shl &rhs) { + return true; + } + + inline std::vector BinaryIntOp::Shl::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryIntOp::Shl BinaryIntOp::Shl::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::BinaryIntOp::Shl &obj, Serializer &serializer) { +} + +template <> +template +Program::BinaryIntOp::Shl serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Shl obj; + return obj; +} + +namespace Program { + + inline bool operator==(const BinaryIntOp::Shr &lhs, const BinaryIntOp::Shr &rhs) { + return true; + } + + inline std::vector BinaryIntOp::Shr::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BinaryIntOp::Shr BinaryIntOp::Shr::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::BinaryIntOp::Shr &obj, Serializer &serializer) { +} + +template <> +template +Program::BinaryIntOp::Shr serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BinaryIntOp::Shr obj; + return obj; +} + +namespace Program { + + inline bool operator==(const BitSize &lhs, const BitSize &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector BitSize::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Xor BinaryIntOp::Xor::bincodeDeserialize(std::vector input) { + inline BitSize BitSize::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2122,31 +2302,37 @@ namespace Program { template <> template -void serde::Serializable::serialize(const Program::BinaryIntOp::Xor &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BitSize &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); } template <> template -Program::BinaryIntOp::Xor serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BinaryIntOp::Xor obj; +Program::BitSize serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Program::BitSize obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); return obj; } namespace Program { - inline bool operator==(const BinaryIntOp::Shl &lhs, const BinaryIntOp::Shl &rhs) { + inline bool operator==(const BitSize::Field &lhs, const BitSize::Field &rhs) { return true; } - inline std::vector BinaryIntOp::Shl::bincodeSerialize() const { + inline std::vector BitSize::Field::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Shl BinaryIntOp::Shl::bincodeDeserialize(std::vector input) { + inline BitSize::Field BitSize::Field::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2157,31 +2343,32 @@ namespace Program { template <> template -void serde::Serializable::serialize(const Program::BinaryIntOp::Shl &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BitSize::Field &obj, Serializer &serializer) { } template <> template -Program::BinaryIntOp::Shl serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BinaryIntOp::Shl obj; +Program::BitSize::Field serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BitSize::Field obj; return obj; } namespace Program { - inline bool operator==(const BinaryIntOp::Shr &lhs, const BinaryIntOp::Shr &rhs) { + inline bool operator==(const BitSize::Integer &lhs, const BitSize::Integer &rhs) { + if (!(lhs.value == rhs.value)) { return false; } return true; } - inline std::vector BinaryIntOp::Shr::bincodeSerialize() const { + inline std::vector BitSize::Integer::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BinaryIntOp::Shr BinaryIntOp::Shr::bincodeDeserialize(std::vector input) { + inline BitSize::Integer BitSize::Integer::bincodeDeserialize(std::vector input) { auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); + auto value = serde::Deserializable::deserialize(deserializer); if (deserializer.get_buffer_offset() < input.size()) { throw serde::deserialization_error("Some input bytes were not read"); } @@ -2192,13 +2379,15 @@ namespace Program { template <> template -void serde::Serializable::serialize(const Program::BinaryIntOp::Shr &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Program::BitSize::Integer &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); } template <> template -Program::BinaryIntOp::Shr serde::Deserializable::deserialize(Deserializer &deserializer) { - Program::BinaryIntOp::Shr obj; +Program::BitSize::Integer serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::BitSize::Integer obj; + obj.value = serde::Deserializable::deserialize(deserializer); return obj; } @@ -6520,6 +6709,293 @@ Program::HeapVector serde::Deserializable::deserialize(Dese return obj; } +namespace Program { + + inline bool operator==(const IntegerBitSize &lhs, const IntegerBitSize &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector IntegerBitSize::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline IntegerBitSize IntegerBitSize::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::IntegerBitSize &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Program::IntegerBitSize serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Program::IntegerBitSize obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Program { + + inline bool operator==(const IntegerBitSize::U0 &lhs, const IntegerBitSize::U0 &rhs) { + return true; + } + + inline std::vector IntegerBitSize::U0::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline IntegerBitSize::U0 IntegerBitSize::U0::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::IntegerBitSize::U0 &obj, Serializer &serializer) { +} + +template <> +template +Program::IntegerBitSize::U0 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::IntegerBitSize::U0 obj; + return obj; +} + +namespace Program { + + inline bool operator==(const IntegerBitSize::U1 &lhs, const IntegerBitSize::U1 &rhs) { + return true; + } + + inline std::vector IntegerBitSize::U1::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline IntegerBitSize::U1 IntegerBitSize::U1::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::IntegerBitSize::U1 &obj, Serializer &serializer) { +} + +template <> +template +Program::IntegerBitSize::U1 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::IntegerBitSize::U1 obj; + return obj; +} + +namespace Program { + + inline bool operator==(const IntegerBitSize::U8 &lhs, const IntegerBitSize::U8 &rhs) { + return true; + } + + inline std::vector IntegerBitSize::U8::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline IntegerBitSize::U8 IntegerBitSize::U8::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::IntegerBitSize::U8 &obj, Serializer &serializer) { +} + +template <> +template +Program::IntegerBitSize::U8 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::IntegerBitSize::U8 obj; + return obj; +} + +namespace Program { + + inline bool operator==(const IntegerBitSize::U16 &lhs, const IntegerBitSize::U16 &rhs) { + return true; + } + + inline std::vector IntegerBitSize::U16::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline IntegerBitSize::U16 IntegerBitSize::U16::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::IntegerBitSize::U16 &obj, Serializer &serializer) { +} + +template <> +template +Program::IntegerBitSize::U16 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::IntegerBitSize::U16 obj; + return obj; +} + +namespace Program { + + inline bool operator==(const IntegerBitSize::U32 &lhs, const IntegerBitSize::U32 &rhs) { + return true; + } + + inline std::vector IntegerBitSize::U32::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline IntegerBitSize::U32 IntegerBitSize::U32::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::IntegerBitSize::U32 &obj, Serializer &serializer) { +} + +template <> +template +Program::IntegerBitSize::U32 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::IntegerBitSize::U32 obj; + return obj; +} + +namespace Program { + + inline bool operator==(const IntegerBitSize::U64 &lhs, const IntegerBitSize::U64 &rhs) { + return true; + } + + inline std::vector IntegerBitSize::U64::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline IntegerBitSize::U64 IntegerBitSize::U64::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::IntegerBitSize::U64 &obj, Serializer &serializer) { +} + +template <> +template +Program::IntegerBitSize::U64 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::IntegerBitSize::U64 obj; + return obj; +} + +namespace Program { + + inline bool operator==(const IntegerBitSize::U128 &lhs, const IntegerBitSize::U128 &rhs) { + return true; + } + + inline std::vector IntegerBitSize::U128::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline IntegerBitSize::U128 IntegerBitSize::U128::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Program + +template <> +template +void serde::Serializable::serialize(const Program::IntegerBitSize::U128 &obj, Serializer &serializer) { +} + +template <> +template +Program::IntegerBitSize::U128 serde::Deserializable::deserialize(Deserializer &deserializer) { + Program::IntegerBitSize::U128 obj; + return obj; +} + namespace Program { inline bool operator==(const MemOp &lhs, const MemOp &rhs) { diff --git a/acvm-repo/acir/src/lib.rs b/acvm-repo/acir/src/lib.rs index 540e0f07eb5..845a1d6ad5a 100644 --- a/acvm-repo/acir/src/lib.rs +++ b/acvm-repo/acir/src/lib.rs @@ -33,8 +33,8 @@ mod reflection { use acir_field::FieldElement; use brillig::{ - BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, Opcode as BrilligOpcode, - ValueOrArray, + BinaryFieldOp, BinaryIntOp, BitSize, BlackBoxOp, HeapValueType, IntegerBitSize, + Opcode as BrilligOpcode, ValueOrArray, }; use serde_reflection::{Tracer, TracerConfig}; @@ -81,6 +81,8 @@ mod reflection { tracer.trace_simple_type::().unwrap(); 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 3047ac002e8..3610ce6493e 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::{AcirField, FieldElement}; -use brillig::{HeapArray, HeapValueType, MemoryAddress, ValueOrArray}; +use brillig::{BitSize, HeapArray, HeapValueType, IntegerBitSize, MemoryAddress, ValueOrArray}; #[test] fn addition_circuit() { @@ -204,12 +204,11 @@ fn simple_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 193, 10, 192, 32, 8, 134, 117, 99, 99, 236, - 182, 55, 105, 111, 176, 151, 217, 161, 75, 135, 136, 30, 63, 42, 82, 144, 8, 47, 245, 65, - 252, 230, 47, 162, 34, 52, 174, 242, 144, 226, 131, 148, 255, 18, 206, 125, 164, 102, 142, - 23, 215, 245, 50, 114, 222, 173, 15, 80, 38, 65, 217, 108, 39, 61, 7, 30, 115, 11, 223, - 186, 248, 251, 160, 221, 170, 146, 64, 191, 39, 215, 60, 3, 47, 3, 99, 171, 188, 84, 164, - 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 80, 49, 10, 192, 32, 12, 52, 45, 45, 165, 155, 63, + 209, 31, 248, 25, 7, 23, 7, 17, 223, 175, 96, 2, 65, 162, 139, 30, 132, 203, 221, 65, 72, + 2, 170, 227, 107, 5, 216, 63, 200, 164, 57, 200, 115, 200, 102, 15, 22, 206, 205, 50, 124, + 223, 107, 108, 128, 155, 106, 113, 217, 141, 252, 10, 25, 225, 103, 121, 136, 197, 167, + 188, 250, 213, 76, 75, 158, 22, 178, 10, 176, 188, 242, 119, 164, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -239,7 +238,7 @@ fn complex_brillig_foreign_call() { brillig::Opcode::Const { destination: MemoryAddress(0), value: FieldElement::from(32_usize), - bit_size: 32, + bit_size: BitSize::Integer(IntegerBitSize::U32), }, brillig::Opcode::CalldataCopy { destination_address: MemoryAddress(1), @@ -308,15 +307,15 @@ fn complex_brillig_foreign_call() { let bytes = Program::serialize_program(&program); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 131, 64, 12, 77, 102, 90, 43, 221, 245, - 6, 133, 246, 0, 211, 158, 192, 187, 136, 59, 69, 151, 158, 94, 116, 48, 131, 241, 233, 70, - 28, 65, 3, 195, 155, 79, 62, 47, 9, 25, 166, 81, 210, 97, 177, 236, 239, 130, 70, 208, 223, - 91, 154, 75, 208, 205, 4, 221, 62, 249, 113, 60, 95, 238, 40, 142, 230, 2, 28, 237, 1, 28, - 73, 245, 255, 132, 253, 142, 217, 151, 168, 245, 179, 43, 243, 115, 163, 113, 190, 18, 57, - 63, 4, 83, 44, 180, 55, 50, 180, 28, 188, 153, 224, 196, 122, 175, 111, 112, 68, 24, 65, - 116, 178, 40, 89, 254, 93, 162, 120, 48, 196, 126, 170, 12, 243, 186, 106, 202, 162, 181, - 160, 138, 84, 63, 106, 255, 133, 119, 6, 187, 14, 108, 59, 133, 250, 243, 90, 139, 19, 238, - 205, 6, 223, 47, 154, 202, 27, 74, 222, 3, 234, 73, 242, 82, 65, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 77, 90, 199, 145, 217, + 205, 13, 6, 102, 14, 208, 241, 4, 222, 69, 220, 41, 186, 244, 248, 90, 140, 24, 159, 5, 23, + 86, 208, 7, 37, 253, 228, 243, 146, 144, 50, 77, 200, 198, 197, 178, 127, 136, 52, 34, 253, + 189, 165, 53, 102, 221, 66, 164, 59, 134, 63, 199, 243, 229, 206, 226, 104, 110, 192, 209, + 158, 192, 145, 84, 255, 47, 216, 239, 152, 125, 137, 90, 63, 27, 152, 159, 132, 166, 249, + 74, 229, 252, 20, 153, 97, 161, 189, 145, 161, 237, 224, 173, 128, 19, 235, 189, 126, 192, + 17, 97, 4, 177, 75, 162, 101, 154, 187, 84, 113, 97, 136, 255, 82, 89, 150, 109, 211, 213, + 85, 111, 65, 21, 233, 126, 213, 254, 7, 239, 12, 118, 104, 171, 161, 63, 176, 144, 46, 7, + 244, 246, 124, 191, 105, 41, 241, 92, 246, 1, 235, 222, 207, 212, 69, 5, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm-repo/acir_field/src/field_element.rs b/acvm-repo/acir_field/src/field_element.rs index 3c16276adc9..92ccbc4e5f6 100644 --- a/acvm-repo/acir_field/src/field_element.rs +++ b/acvm-repo/acir_field/src/field_element.rs @@ -139,17 +139,25 @@ impl<'de, T: ark_ff::PrimeField> Deserialize<'de> for FieldElement { impl From for FieldElement { fn from(a: u128) -> FieldElement { - let result = match F::from_str(&a.to_string()) { - Ok(result) => result, - Err(_) => panic!("Cannot convert u128 as a string to a field element"), - }; - FieldElement(result) + FieldElement(F::from(a)) } } impl From for FieldElement { fn from(a: usize) -> FieldElement { - FieldElement::from(a as u128) + FieldElement::from(a as u64) + } +} + +impl From for FieldElement { + fn from(a: u64) -> FieldElement { + FieldElement(F::from(a)) + } +} + +impl From for FieldElement { + fn from(a: u32) -> FieldElement { + FieldElement(F::from(a)) } } @@ -265,8 +273,16 @@ impl AcirField for FieldElement { } fn to_u128(self) -> u128 { - let bytes = self.to_be_bytes(); - u128::from_be_bytes(bytes[16..32].try_into().unwrap()) + let as_bigint = self.0.into_bigint(); + let limbs = as_bigint.as_ref(); + + let mut result = limbs[0] as u128; + if limbs.len() > 1 { + let high_limb = limbs[1] as u128; + result += high_limb << 64; + } + + result } fn try_into_u128(self) -> Option { diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 91dedac8e35..635aa154c3e 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -264,6 +264,7 @@ fn extract_failure_payload_from_memory( let error_selector = ErrorSelector::new( revert_values_iter .next() + .copied() .expect("Incorrect revert data size") .try_into() .expect("Error selector is not u64"), @@ -273,7 +274,7 @@ fn extract_failure_payload_from_memory( STRING_ERROR_SELECTOR => { // If the error selector is 0, it means the error is a string let string = revert_values_iter - .map(|memory_value| { + .map(|&memory_value| { let as_u8: u8 = memory_value.try_into().expect("String item is not u8"); as_u8 as char }) 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 8ec2ddd1cb2..82f983e407b 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,13 +2,13 @@ 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, 84, 75, 10, 131, 64, 12, 77, 102, 90, 43, 221, 245, 6, 133, 246, 0, 211, 158, - 192, 187, 136, 59, 69, 151, 158, 94, 116, 48, 131, 241, 233, 70, 28, 65, 3, 195, 155, 79, 62, 47, 9, 25, 166, 81, 210, - 97, 177, 236, 239, 130, 70, 208, 223, 91, 154, 75, 208, 205, 4, 221, 62, 249, 113, 60, 95, 238, 40, 142, 230, 2, 28, - 237, 1, 28, 73, 245, 255, 132, 253, 142, 217, 151, 168, 245, 179, 43, 243, 115, 163, 113, 190, 18, 57, 63, 4, 83, 44, - 180, 55, 50, 180, 28, 188, 153, 224, 196, 122, 175, 111, 112, 68, 24, 65, 116, 178, 40, 89, 254, 93, 162, 120, 48, - 196, 126, 170, 12, 243, 186, 106, 202, 162, 181, 160, 138, 84, 63, 106, 255, 133, 119, 6, 187, 14, 108, 59, 133, 250, - 243, 90, 139, 19, 238, 205, 6, 223, 47, 154, 202, 27, 74, 222, 3, 234, 73, 242, 82, 65, 5, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 75, 10, 132, 48, 12, 77, 90, 199, 145, 217, 205, 13, 6, 102, 14, 208, 241, + 4, 222, 69, 220, 41, 186, 244, 248, 90, 140, 24, 159, 5, 23, 86, 208, 7, 37, 253, 228, 243, 146, 144, 50, 77, 200, + 198, 197, 178, 127, 136, 52, 34, 253, 189, 165, 53, 102, 221, 66, 164, 59, 134, 63, 199, 243, 229, 206, 226, 104, 110, + 192, 209, 158, 192, 145, 84, 255, 47, 216, 239, 152, 125, 137, 90, 63, 27, 152, 159, 132, 166, 249, 74, 229, 252, 20, + 153, 97, 161, 189, 145, 161, 237, 224, 173, 128, 19, 235, 189, 126, 192, 17, 97, 4, 177, 75, 162, 101, 154, 187, 84, + 113, 97, 136, 255, 82, 89, 150, 109, 211, 213, 85, 111, 65, 21, 233, 126, 213, 254, 7, 239, 12, 118, 104, 171, 161, + 63, 176, 144, 46, 7, 244, 246, 124, 191, 105, 41, 241, 92, 246, 1, 235, 222, 207, 212, 69, 5, 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 3c66ba18629..dad7c7e1568 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, 144, 193, 10, 192, 32, 8, 134, 117, 99, 99, 236, 182, 55, 105, 111, 176, 151, - 217, 161, 75, 135, 136, 30, 63, 42, 82, 144, 8, 47, 245, 65, 252, 230, 47, 162, 34, 52, 174, 242, 144, 226, 131, 148, - 255, 18, 206, 125, 164, 102, 142, 23, 215, 245, 50, 114, 222, 173, 15, 80, 38, 65, 217, 108, 39, 61, 7, 30, 115, 11, - 223, 186, 248, 251, 160, 221, 170, 146, 64, 191, 39, 215, 60, 3, 47, 3, 99, 171, 188, 84, 164, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 80, 49, 10, 192, 32, 12, 52, 45, 45, 165, 155, 63, 209, 31, 248, 25, 7, 23, 7, + 17, 223, 175, 96, 2, 65, 162, 139, 30, 132, 203, 221, 65, 72, 2, 170, 227, 107, 5, 216, 63, 200, 164, 57, 200, 115, + 200, 102, 15, 22, 206, 205, 50, 124, 223, 107, 108, 128, 155, 106, 113, 217, 141, 252, 10, 25, 225, 103, 121, 136, + 197, 167, 188, 250, 213, 76, 75, 158, 22, 178, 10, 176, 188, 242, 119, 164, 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 40f2e15acfe..5bd9f898d59 100644 --- a/acvm-repo/brillig/src/lib.rs +++ b/acvm-repo/brillig/src/lib.rs @@ -19,4 +19,4 @@ pub use foreign_call::{ForeignCallParam, ForeignCallResult}; pub use opcodes::{ BinaryFieldOp, BinaryIntOp, HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray, }; -pub use opcodes::{BrilligOpcode as Opcode, Label}; +pub use opcodes::{BitSize, BrilligOpcode as Opcode, IntegerBitSize, Label}; diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index 78c6ba8097c..fdcae01b5b5 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -1,5 +1,5 @@ use crate::black_box::BlackBoxOp; -use acir_field::{AcirField, FieldElement}; +use acir_field::AcirField; use serde::{Deserialize, Serialize}; pub type Label = usize; @@ -24,7 +24,7 @@ impl From for MemoryAddress { #[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] pub enum HeapValueType { // A single field element is enough to represent the value with a given bit size - Simple(u32), + Simple(BitSize), // 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 @@ -41,7 +41,7 @@ impl HeapValueType { } pub fn field() -> HeapValueType { - HeapValueType::Simple(FieldElement::max_num_bits()) + HeapValueType::Simple(BitSize::Field) } } @@ -65,6 +65,85 @@ pub struct HeapVector { pub size: MemoryAddress, } +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord)] +pub enum IntegerBitSize { + U0, // Uninitialized + U1, + U8, + U16, + U32, + U64, + U128, +} + +impl From for u32 { + fn from(bit_size: IntegerBitSize) -> u32 { + match bit_size { + IntegerBitSize::U0 => 0, + IntegerBitSize::U1 => 1, + IntegerBitSize::U8 => 8, + IntegerBitSize::U16 => 16, + IntegerBitSize::U32 => 32, + IntegerBitSize::U64 => 64, + IntegerBitSize::U128 => 128, + } + } +} + +impl TryFrom for IntegerBitSize { + type Error = &'static str; + + fn try_from(value: u32) -> Result { + match value { + 0 => Ok(IntegerBitSize::U0), + 1 => Ok(IntegerBitSize::U1), + 8 => Ok(IntegerBitSize::U8), + 16 => Ok(IntegerBitSize::U16), + 32 => Ok(IntegerBitSize::U32), + 64 => Ok(IntegerBitSize::U64), + 128 => Ok(IntegerBitSize::U128), + _ => Err("Invalid bit size"), + } + } +} + +impl std::fmt::Display for IntegerBitSize { + fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { + match self { + IntegerBitSize::U0 => write!(f, "null"), + IntegerBitSize::U1 => write!(f, "bool"), + IntegerBitSize::U8 => write!(f, "u8"), + IntegerBitSize::U16 => write!(f, "u16"), + IntegerBitSize::U32 => write!(f, "u32"), + IntegerBitSize::U64 => write!(f, "u64"), + IntegerBitSize::U128 => write!(f, "u128"), + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy, PartialOrd, Ord)] +pub enum BitSize { + Field, + Integer(IntegerBitSize), +} + +impl BitSize { + pub fn to_u32(self) -> u32 { + match self { + BitSize::Field => F::max_num_bits(), + BitSize::Integer(bit_size) => bit_size.into(), + } + } + + pub fn try_from_u32(value: u32) -> Result { + if value == F::max_num_bits() { + Ok(BitSize::Field) + } else { + Ok(BitSize::Integer(IntegerBitSize::try_from(value)?)) + } + } +} + /// Lays out various ways an external foreign call's input and output data may be interpreted inside Brillig. /// This data can either be an individual value or memory. /// @@ -105,14 +184,14 @@ pub enum BrilligOpcode { BinaryIntOp { destination: MemoryAddress, op: BinaryIntOp, - bit_size: u32, + bit_size: IntegerBitSize, lhs: MemoryAddress, rhs: MemoryAddress, }, Cast { destination: MemoryAddress, source: MemoryAddress, - bit_size: u32, + bit_size: BitSize, }, JumpIfNot { condition: MemoryAddress, @@ -141,7 +220,7 @@ pub enum BrilligOpcode { }, Const { destination: MemoryAddress, - bit_size: u32, + bit_size: BitSize, value: F, }, Return, diff --git a/acvm-repo/brillig_vm/src/arithmetic.rs b/acvm-repo/brillig_vm/src/arithmetic.rs index c88e06e2b94..7cd31cd6443 100644 --- a/acvm-repo/brillig_vm/src/arithmetic.rs +++ b/acvm-repo/brillig_vm/src/arithmetic.rs @@ -1,8 +1,6 @@ -use acir::brillig::{BinaryFieldOp, BinaryIntOp}; +use acir::brillig::{BinaryFieldOp, BinaryIntOp, IntegerBitSize}; use acir::AcirField; use num_bigint::BigUint; -use num_traits::ToPrimitive; -use num_traits::{One, Zero}; use crate::memory::{MemoryTypeError, MemoryValue}; @@ -12,10 +10,8 @@ pub(crate) enum BrilligArithmeticError { MismatchedLhsBitSize { lhs_bit_size: u32, op_bit_size: u32 }, #[error("Bit size for rhs {rhs_bit_size} does not match op bit size {op_bit_size}")] MismatchedRhsBitSize { rhs_bit_size: u32, op_bit_size: u32 }, - #[error("Integer operation BinaryIntOp::{op:?} is not supported on FieldElement")] - IntegerOperationOnField { op: BinaryIntOp }, - #[error("Shift with bit size {op_bit_size} is invalid")] - InvalidShift { op_bit_size: u32 }, + #[error("Attempted to divide by zero")] + DivisionByZero, } /// Evaluate a binary operation on two FieldElement memory values. @@ -24,17 +20,23 @@ pub(crate) fn evaluate_binary_field_op( lhs: MemoryValue, rhs: MemoryValue, ) -> Result, BrilligArithmeticError> { - let MemoryValue::Field(a) = lhs else { - return Err(BrilligArithmeticError::MismatchedLhsBitSize { - lhs_bit_size: lhs.bit_size(), - op_bit_size: F::max_num_bits(), - }); + let a = match lhs { + MemoryValue::Field(a) => a, + MemoryValue::Integer(_, bit_size) => { + return Err(BrilligArithmeticError::MismatchedLhsBitSize { + lhs_bit_size: bit_size.into(), + op_bit_size: F::max_num_bits(), + }); + } }; - let MemoryValue::Field(b) = rhs else { - return Err(BrilligArithmeticError::MismatchedLhsBitSize { - lhs_bit_size: rhs.bit_size(), - op_bit_size: F::max_num_bits(), - }); + let b = match rhs { + MemoryValue::Field(b) => b, + MemoryValue::Integer(_, bit_size) => { + return Err(BrilligArithmeticError::MismatchedRhsBitSize { + rhs_bit_size: bit_size.into(), + op_bit_size: F::max_num_bits(), + }); + } }; Ok(match op { @@ -44,11 +46,15 @@ pub(crate) fn evaluate_binary_field_op( BinaryFieldOp::Mul => MemoryValue::new_field(a * b), BinaryFieldOp::Div => MemoryValue::new_field(a / b), BinaryFieldOp::IntegerDiv => { - let a_big = BigUint::from_bytes_be(&a.to_be_bytes()); - let b_big = BigUint::from_bytes_be(&b.to_be_bytes()); + if b.is_zero() { + return Err(BrilligArithmeticError::DivisionByZero); + } else { + let a_big = BigUint::from_bytes_be(&a.to_be_bytes()); + let b_big = BigUint::from_bytes_be(&b.to_be_bytes()); - let result = a_big / b_big; - MemoryValue::new_field(F::from_be_bytes_reduce(&result.to_bytes_be())) + let result = a_big / b_big; + MemoryValue::new_field(F::from_be_bytes_reduce(&result.to_bytes_be())) + } } BinaryFieldOp::Equals => (a == b).into(), BinaryFieldOp::LessThan => (a < b).into(), @@ -61,7 +67,7 @@ pub(crate) fn evaluate_binary_int_op( op: &BinaryIntOp, lhs: MemoryValue, rhs: MemoryValue, - bit_size: u32, + bit_size: IntegerBitSize, ) -> Result, BrilligArithmeticError> { let lhs = lhs.expect_integer_with_bit_size(bit_size).map_err(|err| match err { MemoryTypeError::MismatchedBitSize { value_bit_size, expected_bit_size } => { @@ -71,8 +77,13 @@ pub(crate) fn evaluate_binary_int_op( } } })?; - let rhs_bit_size = - if op == &BinaryIntOp::Shl || op == &BinaryIntOp::Shr { 8 } else { bit_size }; + + let rhs_bit_size = if op == &BinaryIntOp::Shl || op == &BinaryIntOp::Shr { + IntegerBitSize::U8 + } else { + bit_size + }; + let rhs = rhs.expect_integer_with_bit_size(rhs_bit_size).map_err(|err| match err { MemoryTypeError::MismatchedBitSize { value_bit_size, expected_bit_size } => { BrilligArithmeticError::MismatchedRhsBitSize { @@ -82,74 +93,107 @@ pub(crate) fn evaluate_binary_int_op( } })?; - if bit_size == F::max_num_bits() { - return Err(BrilligArithmeticError::IntegerOperationOnField { op: *op }); - } + let result = if bit_size == IntegerBitSize::U128 { + evaluate_binary_int_op_128(op, lhs, rhs)? + } else { + evaluate_binary_int_op_generic(op, lhs, rhs, bit_size)? + }; - let bit_modulo = &(BigUint::one() << bit_size); + Ok(match op { + BinaryIntOp::Equals | BinaryIntOp::LessThan | BinaryIntOp::LessThanEquals => { + MemoryValue::new_integer(result, IntegerBitSize::U1) + } + _ => MemoryValue::new_integer(result, bit_size), + }) +} + +fn evaluate_binary_int_op_128( + op: &BinaryIntOp, + lhs: u128, + rhs: u128, +) -> Result { let result = match op { - // Perform addition, subtraction, and multiplication, applying a modulo operation to keep the result within the bit size. - BinaryIntOp::Add => (lhs + rhs) % bit_modulo, - BinaryIntOp::Sub => (bit_modulo + lhs - rhs) % bit_modulo, - BinaryIntOp::Mul => (lhs * rhs) % bit_modulo, - // Perform unsigned division using the modulo operation on a and b. + BinaryIntOp::Add => lhs.wrapping_add(rhs), + BinaryIntOp::Sub => lhs.wrapping_sub(rhs), + BinaryIntOp::Mul => lhs.wrapping_mul(rhs), BinaryIntOp::Div => { - if rhs.is_zero() { - BigUint::zero() + if rhs == 0 { + return Err(BrilligArithmeticError::DivisionByZero); } else { lhs / rhs } } - // Perform a == operation, returning 0 or 1 - BinaryIntOp::Equals => { - if lhs == rhs { - BigUint::one() + BinaryIntOp::Equals => (lhs == rhs) as u128, + BinaryIntOp::LessThan => (lhs < rhs) as u128, + BinaryIntOp::LessThanEquals => (lhs <= rhs) as u128, + BinaryIntOp::And => lhs & rhs, + BinaryIntOp::Or => lhs | rhs, + BinaryIntOp::Xor => lhs ^ rhs, + BinaryIntOp::Shl => { + if rhs >= 128 { + 0 } else { - BigUint::zero() + lhs.wrapping_shl(rhs as u32) } } - // Perform a < operation, returning 0 or 1 - BinaryIntOp::LessThan => { - if lhs < rhs { - BigUint::one() + BinaryIntOp::Shr => { + if rhs >= 128 { + 0 } else { - BigUint::zero() + lhs.wrapping_shr(rhs as u32) } } - // Perform a <= operation, returning 0 or 1 - BinaryIntOp::LessThanEquals => { - if lhs <= rhs { - BigUint::one() + }; + Ok(result) +} + +fn evaluate_binary_int_op_generic( + op: &BinaryIntOp, + lhs: u128, + rhs: u128, + bit_size: IntegerBitSize, +) -> Result { + let bit_size: u32 = bit_size.into(); + let bit_modulo = 1 << bit_size; + let result = match op { + // Perform addition, subtraction, and multiplication, applying a modulo operation to keep the result within the bit size. + BinaryIntOp::Add => (lhs + rhs) % bit_modulo, + BinaryIntOp::Sub => (bit_modulo + lhs - rhs) % bit_modulo, + BinaryIntOp::Mul => (lhs * rhs) % bit_modulo, + // Perform unsigned division using the modulo operation on a and b. + BinaryIntOp::Div => { + if rhs == 0 { + return Err(BrilligArithmeticError::DivisionByZero); } else { - BigUint::zero() + lhs / rhs } } + // Perform a == operation, returning 0 or 1 + BinaryIntOp::Equals => (lhs == rhs) as u128, + // Perform a < operation, returning 0 or 1 + BinaryIntOp::LessThan => (lhs < rhs) as u128, + // Perform a <= operation, returning 0 or 1 + BinaryIntOp::LessThanEquals => (lhs <= rhs) as u128, // Perform bitwise AND, OR, XOR, left shift, and right shift operations, applying a modulo operation to keep the result within the bit size. BinaryIntOp::And => lhs & rhs, BinaryIntOp::Or => lhs | rhs, BinaryIntOp::Xor => lhs ^ rhs, BinaryIntOp::Shl => { - if bit_size > 128 { - return Err(BrilligArithmeticError::InvalidShift { op_bit_size: bit_size }); + if rhs >= (bit_size as u128) { + 0 + } else { + (lhs << rhs) % bit_modulo } - let rhs = rhs.to_u128().unwrap(); - (lhs << rhs) % bit_modulo } BinaryIntOp::Shr => { - if bit_size > 128 { - return Err(BrilligArithmeticError::InvalidShift { op_bit_size: bit_size }); + if rhs >= (bit_size as u128) { + 0 + } else { + lhs >> rhs } - let rhs = rhs.to_u128().unwrap(); - lhs >> rhs } }; - - Ok(match op { - BinaryIntOp::Equals | BinaryIntOp::LessThan | BinaryIntOp::LessThanEquals => { - MemoryValue::new_integer(result, 1) - } - _ => MemoryValue::new_integer(result, bit_size), - }) + Ok(result) } #[cfg(test)] @@ -163,11 +207,11 @@ mod tests { result: u128, } - fn evaluate_u128(op: &BinaryIntOp, a: u128, b: u128, bit_size: u32) -> u128 { + fn evaluate_u128(op: &BinaryIntOp, a: u128, b: u128, bit_size: IntegerBitSize) -> u128 { let result_value: MemoryValue = evaluate_binary_int_op( op, - MemoryValue::new_integer(a.into(), bit_size), - MemoryValue::new_integer(b.into(), bit_size), + MemoryValue::new_integer(a, bit_size), + MemoryValue::new_integer(b, bit_size), bit_size, ) .unwrap(); @@ -175,13 +219,17 @@ mod tests { result_value.to_field().to_u128() } - fn to_negative(a: u128, bit_size: u32) -> u128 { + fn to_negative(a: u128, bit_size: IntegerBitSize) -> u128 { assert!(a > 0); - let two_pow = 2_u128.pow(bit_size); - two_pow - a + if bit_size == IntegerBitSize::U128 { + 0_u128.wrapping_sub(a) + } else { + let two_pow = 2_u128.pow(bit_size.into()); + two_pow - a + } } - fn evaluate_int_ops(test_params: Vec, op: BinaryIntOp, bit_size: u32) { + fn evaluate_int_ops(test_params: Vec, op: BinaryIntOp, bit_size: IntegerBitSize) { for test in test_params { assert_eq!(evaluate_u128(&op, test.a, test.b, bit_size), test.result); } @@ -189,64 +237,83 @@ mod tests { #[test] fn add_test() { - let bit_size = 4; + let bit_size = IntegerBitSize::U8; let test_ops = vec![ - TestParams { a: 5, b: 10, result: 15 }, - TestParams { a: 10, b: 10, result: 4 }, + TestParams { a: 50, b: 100, result: 150 }, + TestParams { a: 250, b: 10, result: 4 }, TestParams { a: 5, b: to_negative(3, bit_size), result: 2 }, TestParams { a: to_negative(3, bit_size), b: 1, result: to_negative(2, bit_size) }, TestParams { a: 5, b: to_negative(6, bit_size), result: to_negative(1, bit_size) }, ]; + evaluate_int_ops(test_ops, BinaryIntOp::Add, bit_size); + + let bit_size = IntegerBitSize::U128; + let test_ops = vec![ + TestParams { a: 5, b: to_negative(3, bit_size), result: 2 }, + TestParams { a: to_negative(3, bit_size), b: 1, result: to_negative(2, bit_size) }, + ]; evaluate_int_ops(test_ops, BinaryIntOp::Add, bit_size); } #[test] fn sub_test() { - let bit_size = 4; + let bit_size = IntegerBitSize::U8; let test_ops = vec![ - TestParams { a: 5, b: 3, result: 2 }, + TestParams { a: 50, b: 30, result: 20 }, TestParams { a: 5, b: 10, result: to_negative(5, bit_size) }, TestParams { a: 5, b: to_negative(3, bit_size), result: 8 }, TestParams { a: to_negative(3, bit_size), b: 2, result: to_negative(5, bit_size) }, - TestParams { a: 14, b: to_negative(3, bit_size), result: 1 }, + TestParams { a: 254, b: to_negative(3, bit_size), result: 1 }, ]; + evaluate_int_ops(test_ops, BinaryIntOp::Sub, bit_size); + let bit_size = IntegerBitSize::U128; + + let test_ops = vec![ + TestParams { a: 5, b: 10, result: to_negative(5, bit_size) }, + TestParams { a: to_negative(3, bit_size), b: 2, result: to_negative(5, bit_size) }, + ]; evaluate_int_ops(test_ops, BinaryIntOp::Sub, bit_size); } #[test] fn mul_test() { - let bit_size = 4; + let bit_size = IntegerBitSize::U8; let test_ops = vec![ TestParams { a: 5, b: 3, result: 15 }, - TestParams { a: 5, b: 10, result: 2 }, + TestParams { a: 5, b: 100, result: 244 }, TestParams { a: to_negative(1, bit_size), b: to_negative(5, bit_size), result: 5 }, TestParams { a: to_negative(1, bit_size), b: 5, result: to_negative(5, bit_size) }, - TestParams { - a: to_negative(2, bit_size), - b: 7, - // negative 14 wraps to a 2 - result: to_negative(14, bit_size), - }, + TestParams { a: to_negative(2, bit_size), b: 7, result: to_negative(14, bit_size) }, ]; evaluate_int_ops(test_ops, BinaryIntOp::Mul, bit_size); - let bit_size = 127; - let a = 2_u128.pow(bit_size) - 1; + let bit_size = IntegerBitSize::U64; + let a = 2_u128.pow(bit_size.into()) - 1; let b = 3; // ( 2**(n-1) - 1 ) * 3 = 2*2**(n-1) - 2 + (2**(n-1) - 1) => wraps to (2**(n-1) - 1) - 2 assert_eq!(evaluate_u128(&BinaryIntOp::Mul, a, b, bit_size), a - 2); + + let bit_size = IntegerBitSize::U128; + + let test_ops = vec![ + TestParams { a: to_negative(1, bit_size), b: to_negative(5, bit_size), result: 5 }, + TestParams { a: to_negative(1, bit_size), b: 5, result: to_negative(5, bit_size) }, + TestParams { a: to_negative(2, bit_size), b: 7, result: to_negative(14, bit_size) }, + ]; + + evaluate_int_ops(test_ops, BinaryIntOp::Mul, bit_size); } #[test] fn div_test() { - let bit_size = 4; + let bit_size = IntegerBitSize::U8; let test_ops = vec![TestParams { a: 5, b: 3, result: 1 }, TestParams { a: 5, b: 10, result: 0 }]; diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index d37258036fc..b49757944ad 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -28,7 +28,7 @@ fn read_heap_array<'a, F: AcirField>( /// Extracts the last byte of every value fn to_u8_vec(inputs: &[MemoryValue]) -> Vec { let mut result = Vec::with_capacity(inputs.len()); - for input in inputs { + for &input in inputs { result.push(input.try_into().unwrap()); } result @@ -91,7 +91,7 @@ pub(crate) fn evaluate_black_box BlackBoxOp::Keccakf1600 { message, output } => { let state_vec: Vec = read_heap_vector(memory, message) .iter() - .map(|memory_value| memory_value.try_into().unwrap()) + .map(|&memory_value| memory_value.try_into().unwrap()) .collect(); let state: [u64; 25] = state_vec.try_into().unwrap(); @@ -166,7 +166,7 @@ pub(crate) fn evaluate_black_box let points: Vec = read_heap_vector(memory, points) .iter() .enumerate() - .map(|(i, x)| { + .map(|(i, &x)| { if i % 3 == 2 { let is_infinite: bool = x.try_into().unwrap(); F::from(is_infinite as u128) @@ -301,9 +301,9 @@ pub(crate) fn evaluate_black_box } BlackBoxOp::BigIntFromLeBytes { inputs, modulus, output } => { let input = read_heap_vector(memory, inputs); - let input: Vec = input.iter().map(|x| x.try_into().unwrap()).collect(); + let input: Vec = input.iter().map(|&x| x.try_into().unwrap()).collect(); let modulus = read_heap_vector(memory, modulus); - let modulus: Vec = modulus.iter().map(|x| x.try_into().unwrap()).collect(); + let modulus: Vec = modulus.iter().map(|&x| x.try_into().unwrap()).collect(); let new_id = bigint_solver.bigint_from_bytes(&input, &modulus)?; memory.write(*output, new_id.into()); @@ -345,7 +345,7 @@ pub(crate) fn evaluate_black_box format!("Expected 16 inputs but encountered {}", &inputs.len()), )); } - for (i, input) in inputs.iter().enumerate() { + for (i, &input) in inputs.iter().enumerate() { message[i] = input.try_into().unwrap(); } let mut state = [0; 8]; @@ -356,7 +356,7 @@ pub(crate) fn evaluate_black_box format!("Expected 8 values but encountered {}", &values.len()), )); } - for (i, value) in values.iter().enumerate() { + for (i, &value) in values.iter().enumerate() { state[i] = value.try_into().unwrap(); } diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 4d2dd2b8333..936ad120335 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -12,14 +12,13 @@ //! [acvm]: https://crates.io/crates/acvm use acir::brillig::{ - BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapValueType, - HeapVector, MemoryAddress, Opcode, ValueOrArray, + BinaryFieldOp, BinaryIntOp, BitSize, ForeignCallParam, ForeignCallResult, HeapArray, + HeapValueType, HeapVector, IntegerBitSize, MemoryAddress, Opcode, ValueOrArray, }; use acir::AcirField; use acvm_blackbox_solver::BlackBoxFunctionSolver; use arithmetic::{evaluate_binary_field_op, evaluate_binary_int_op, BrilligArithmeticError}; use black_box::{evaluate_black_box, BrilligBigintSolver}; -use num_bigint::BigUint; // Re-export `brillig`. pub use acir::brillig; @@ -557,7 +556,7 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { &mut self, destination: MemoryAddress, value: &F, - value_bit_size: u32, + value_bit_size: BitSize, ) -> Result<(), String> { let memory_value = MemoryValue::new_checked(*value, value_bit_size); @@ -565,7 +564,7 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { self.memory.write(destination, memory_value); } else { return Err(format!( - "Foreign call result value {} does not fit in bit size {}", + "Foreign call result value {} does not fit in bit size {:?}", value, value_bit_size )); } @@ -689,7 +688,7 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { fn process_binary_int_op( &mut self, op: BinaryIntOp, - bit_size: u32, + bit_size: IntegerBitSize, lhs: MemoryAddress, rhs: MemoryAddress, result: MemoryAddress, @@ -703,18 +702,46 @@ impl<'a, F: AcirField, B: BlackBoxFunctionSolver> VM<'a, F, B> { } /// Casts a value to a different bit size. - fn cast(&self, bit_size: u32, source_value: MemoryValue) -> MemoryValue { - let lhs_big = source_value.to_integer(); - let mask = BigUint::from(2_u32).pow(bit_size) - 1_u32; - MemoryValue::new_from_integer(lhs_big & mask, bit_size) + fn cast(&self, target_bit_size: BitSize, source_value: MemoryValue) -> MemoryValue { + match (source_value, target_bit_size) { + // Field to field, no op + (MemoryValue::Field(_), BitSize::Field) => source_value, + // Field downcast to u128 + (MemoryValue::Field(field), BitSize::Integer(IntegerBitSize::U128)) => { + MemoryValue::Integer(field.to_u128(), IntegerBitSize::U128) + } + // Field downcast to arbitrary bit size + (MemoryValue::Field(field), BitSize::Integer(target_bit_size)) => { + let as_u128 = field.to_u128(); + let target_bit_size_u32: u32 = target_bit_size.into(); + let mask = (1_u128 << target_bit_size_u32) - 1; + MemoryValue::Integer(as_u128 & mask, target_bit_size) + } + // Integer upcast to field + (MemoryValue::Integer(integer, _), BitSize::Field) => { + MemoryValue::new_field(integer.into()) + } + // Integer upcast to integer + (MemoryValue::Integer(integer, source_bit_size), BitSize::Integer(target_bit_size)) + if source_bit_size <= target_bit_size => + { + MemoryValue::Integer(integer, target_bit_size) + } + // Integer downcast + (MemoryValue::Integer(integer, _), BitSize::Integer(target_bit_size)) => { + let target_bit_size_u32: u32 = target_bit_size.into(); + let mask = (1_u128 << target_bit_size_u32) - 1; + MemoryValue::Integer(integer & mask, target_bit_size) + } + } } } #[cfg(test)] mod tests { + use crate::memory::MEMORY_ADDRESSING_BIT_SIZE; use acir::{AcirField, FieldElement}; use acvm_blackbox_solver::StubbedBlackBoxSolver; - const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 32; use super::*; @@ -877,7 +904,7 @@ mod tests { Opcode::Cast { destination: MemoryAddress::from(1), source: MemoryAddress::from(0), - bit_size: 8, + bit_size: BitSize::Integer(IntegerBitSize::U8), }, Opcode::Stop { return_data_offset: 1, return_data_size: 1 }, ]; @@ -943,13 +970,13 @@ mod tests { let cast_zero = Opcode::Cast { destination: MemoryAddress::from(0), source: MemoryAddress::from(0), - bit_size: 1, + bit_size: BitSize::Integer(IntegerBitSize::U1), }; let cast_one = Opcode::Cast { destination: MemoryAddress::from(1), source: MemoryAddress::from(1), - bit_size: 1, + bit_size: BitSize::Integer(IntegerBitSize::U1), }; let opcodes = &[ @@ -997,7 +1024,7 @@ mod tests { #[test] fn cmp_binary_ops() { - let bit_size = BRILLIG_MEMORY_ADDRESSING_BIT_SIZE; + let bit_size = MEMORY_ADDRESSING_BIT_SIZE; let calldata: Vec = vec![(2u128).into(), (2u128).into(), (0u128).into(), (5u128).into(), (6u128).into()]; let calldata_size = calldata.len(); @@ -1012,7 +1039,7 @@ mod tests { .map(|index| Opcode::Cast { destination: MemoryAddress::from(index), source: MemoryAddress::from(index), - bit_size, + bit_size: BitSize::Integer(bit_size), }) .collect(); @@ -1099,7 +1126,8 @@ mod tests { /// i += 1; /// } fn brillig_write_memory(item_count: usize) -> Vec> { - let bit_size = BRILLIG_MEMORY_ADDRESSING_BIT_SIZE; + let integer_bit_size = MEMORY_ADDRESSING_BIT_SIZE; + let bit_size = BitSize::Integer(integer_bit_size); let r_i = MemoryAddress::from(0); let r_len = MemoryAddress::from(1); let r_tmp = MemoryAddress::from(2); @@ -1124,7 +1152,7 @@ mod tests { lhs: r_i, op: BinaryIntOp::Add, rhs: r_tmp, - bit_size, + bit_size: integer_bit_size, }, // pointer = pointer + 1 Opcode::BinaryIntOp { @@ -1132,7 +1160,7 @@ mod tests { lhs: r_pointer, op: BinaryIntOp::Add, rhs: r_tmp, - bit_size, + bit_size: integer_bit_size, }, // tmp = i < len Opcode::BinaryIntOp { @@ -1140,7 +1168,7 @@ mod tests { lhs: r_i, op: BinaryIntOp::LessThan, rhs: r_len, - bit_size, + bit_size: integer_bit_size, }, // if tmp != 0 goto loop_body Opcode::JumpIf { condition: r_tmp, location: start.len() }, @@ -1172,7 +1200,7 @@ mod tests { /// i += 1; /// } fn brillig_sum_memory(memory: Vec) -> FieldElement { - let bit_size = 32; + let bit_size = IntegerBitSize::U32; let r_i = MemoryAddress::from(0); let r_len = MemoryAddress::from(1); let r_sum = MemoryAddress::from(2); @@ -1181,17 +1209,25 @@ mod tests { let start: [Opcode; 5] = [ // sum = 0 + Opcode::Const { destination: r_sum, value: 0u128.into(), bit_size: BitSize::Field }, + // i = 0 Opcode::Const { - destination: r_sum, + destination: r_i, value: 0u128.into(), - bit_size: FieldElement::max_num_bits(), + bit_size: BitSize::Integer(bit_size), }, - // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into(), bit_size }, // len = array.len() (approximation) - Opcode::Const { destination: r_len, value: memory.len().into(), bit_size }, + Opcode::Const { + destination: r_len, + value: memory.len().into(), + bit_size: BitSize::Integer(bit_size), + }, // pointer = array_ptr - Opcode::Const { destination: r_pointer, value: 5u128.into(), bit_size }, + Opcode::Const { + destination: r_pointer, + value: 5u128.into(), + bit_size: BitSize::Integer(bit_size), + }, Opcode::CalldataCopy { destination_address: MemoryAddress(5), size: memory.len(), @@ -1209,7 +1245,11 @@ mod tests { rhs: r_tmp, }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size }, + Opcode::Const { + destination: r_tmp, + value: 1u128.into(), + bit_size: BitSize::Integer(bit_size), + }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -1268,7 +1308,8 @@ mod tests { /// } /// Note we represent a 100% in-stack optimized form in brillig fn brillig_recursive_write_memory(size: usize) -> Vec> { - let bit_size = BRILLIG_MEMORY_ADDRESSING_BIT_SIZE; + let integer_bit_size = MEMORY_ADDRESSING_BIT_SIZE; + let bit_size = BitSize::Integer(integer_bit_size); let r_i = MemoryAddress::from(0); let r_len = MemoryAddress::from(1); let r_tmp = MemoryAddress::from(2); @@ -1296,7 +1337,7 @@ mod tests { lhs: r_len, op: BinaryIntOp::LessThanEquals, rhs: r_i, - bit_size, + bit_size: integer_bit_size, }, // if !tmp, goto end Opcode::JumpIf { @@ -1313,7 +1354,7 @@ mod tests { lhs: r_i, op: BinaryIntOp::Add, rhs: r_tmp, - bit_size, + bit_size: integer_bit_size, }, // pointer = pointer + 1 Opcode::BinaryIntOp { @@ -1321,7 +1362,7 @@ mod tests { lhs: r_pointer, op: BinaryIntOp::Add, rhs: r_tmp, - bit_size, + bit_size: integer_bit_size, }, // call recursive_fn Opcode::Call { location: start.len() }, @@ -1374,15 +1415,19 @@ mod tests { Opcode::Const { destination: r_input, value: (5u128).into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // Call foreign function "double" with the input address Opcode::ForeignCall { function: "double".into(), destinations: vec![ValueOrArray::MemoryAddress(r_result)], - destination_value_types: vec![HeapValueType::Simple(32)], + destination_value_types: vec![HeapValueType::Simple(BitSize::Integer( + MEMORY_ADDRESSING_BIT_SIZE, + ))], inputs: vec![ValueOrArray::MemoryAddress(r_input)], - input_value_types: vec![HeapValueType::Simple(32)], + input_value_types: vec![HeapValueType::Simple(BitSize::Integer( + MEMORY_ADDRESSING_BIT_SIZE, + ))], }, ]; @@ -1439,13 +1484,13 @@ mod tests { Opcode::Const { destination: r_input, value: 2_usize.into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // output = 0 Opcode::Const { destination: r_output, value: 2_usize.into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { @@ -1529,25 +1574,25 @@ mod tests { Opcode::Const { destination: r_input_pointer, value: (4u128).into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // input_size = input_string.len() (constant here) Opcode::Const { destination: r_input_size, value: input_string.len().into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // output_pointer = 4 + input_size Opcode::Const { destination: r_output_pointer, value: (4 + input_string.len()).into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // output_size = input_size * 2 Opcode::Const { destination: r_output_size, value: (input_string.len() * 2).into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // output_pointer[0..output_size] = string_double(input_pointer[0...input_size]) Opcode::ForeignCall { @@ -1627,13 +1672,13 @@ mod tests { Opcode::Const { destination: r_input, value: (2u128).into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // output = 0 Opcode::Const { destination: r_output, value: (6u128).into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { @@ -1726,19 +1771,19 @@ mod tests { Opcode::Const { destination: r_input_a, value: (3u128).into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // input = 7 Opcode::Const { destination: r_input_b, value: (7u128).into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // output = 0 Opcode::Const { destination: r_output, value: (0u128).into(), - bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, + bit_size: BitSize::Integer(MEMORY_ADDRESSING_BIT_SIZE), }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { @@ -1853,7 +1898,7 @@ mod tests { let input_array_value_types: Vec = vec![ HeapValueType::field(), - HeapValueType::Simple(64), // size of following vector + HeapValueType::Simple(BitSize::Integer(IntegerBitSize::U64)), // size of following vector HeapValueType::Vector { value_types: vec![HeapValueType::field()] }, HeapValueType::Array { value_types: vec![HeapValueType::field()], size: 1 }, ]; @@ -1876,7 +1921,11 @@ mod tests { })) .chain(vec![ // input = 0 - Opcode::Const { destination: r_input, value: (outer_ptr).into(), bit_size: 32 }, + Opcode::Const { + destination: r_input, + value: (outer_ptr).into(), + bit_size: BitSize::Integer(IntegerBitSize::U32), + }, // some_function(input) Opcode::ForeignCall { function: "flat_sum".into(), diff --git a/acvm-repo/brillig_vm/src/memory.rs b/acvm-repo/brillig_vm/src/memory.rs index 95e28f7d863..ef1e0301387 100644 --- a/acvm-repo/brillig_vm/src/memory.rs +++ b/acvm-repo/brillig_vm/src/memory.rs @@ -1,13 +1,15 @@ -use acir::{brillig::MemoryAddress, AcirField}; -use num_bigint::BigUint; +use acir::{ + brillig::{BitSize, IntegerBitSize, MemoryAddress}, + AcirField, +}; use num_traits::{One, Zero}; -pub const MEMORY_ADDRESSING_BIT_SIZE: u32 = 32; +pub const MEMORY_ADDRESSING_BIT_SIZE: IntegerBitSize = IntegerBitSize::U32; -#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] pub enum MemoryValue { Field(F), - Integer(BigUint, u32), + Integer(u128, IntegerBitSize), } #[derive(Debug, thiserror::Error)] @@ -22,6 +24,11 @@ impl MemoryValue { MemoryValue::Field(value) } + /// Builds an integer-typed memory value. + pub fn new_integer(value: u128, bit_size: IntegerBitSize) -> Self { + MemoryValue::Integer(value, bit_size) + } + /// Extracts the field element from the memory value, if it is typed as field element. pub fn extract_field(&self) -> Option<&F> { match self { @@ -31,86 +38,63 @@ impl MemoryValue { } /// Extracts the integer from the memory value, if it is typed as integer. - pub fn extract_integer(&self) -> Option<(&BigUint, u32)> { + pub fn extract_integer(&self) -> Option<(u128, IntegerBitSize)> { match self { - MemoryValue::Integer(value, bit_size) => Some((value, *bit_size)), + MemoryValue::Integer(value, bit_size) => Some((*value, *bit_size)), _ => None, } } -} -impl MemoryValue { - /// Builds a memory value from a field element. - pub fn new_from_field(value: F, bit_size: u32) -> Self { - if bit_size == F::max_num_bits() { - MemoryValue::new_field(value) - } else { - MemoryValue::new_integer(BigUint::from_bytes_be(&value.to_be_bytes()), bit_size) + pub fn bit_size(&self) -> BitSize { + match self { + MemoryValue::Field(_) => BitSize::Field, + MemoryValue::Integer(_, bit_size) => BitSize::Integer(*bit_size), + } + } + + pub fn to_usize(&self) -> usize { + match self { + MemoryValue::Integer(_, bit_size) if *bit_size == MEMORY_ADDRESSING_BIT_SIZE => { + self.extract_integer().unwrap().0.try_into().unwrap() + } + _ => panic!("value is not typed as brillig usize"), } } +} - /// Builds a memory value from an integer - pub fn new_from_integer(value: BigUint, bit_size: u32) -> Self { - if bit_size == F::max_num_bits() { - MemoryValue::new_field(F::from_be_bytes_reduce(&value.to_bytes_be())) +impl MemoryValue { + /// Builds a memory value from a field element. + pub fn new_from_field(value: F, bit_size: BitSize) -> Self { + if let BitSize::Integer(bit_size) = bit_size { + MemoryValue::new_integer(value.to_u128(), bit_size) } else { - MemoryValue::new_integer(value, bit_size) + MemoryValue::new_field(value) } } /// Builds a memory value from a field element, checking that the value is within the bit size. - pub fn new_checked(value: F, bit_size: u32) -> Option { - if bit_size < F::max_num_bits() && value.num_bits() > bit_size { - return None; + pub fn new_checked(value: F, bit_size: BitSize) -> Option { + if let BitSize::Integer(bit_size) = bit_size { + if value.num_bits() > bit_size.into() { + return None; + } } Some(MemoryValue::new_from_field(value, bit_size)) } - /// Builds an integer-typed memory value. - pub fn new_integer(value: BigUint, bit_size: u32) -> Self { - assert!( - bit_size != F::max_num_bits(), - "Tried to build a field memory value via new_integer" - ); - MemoryValue::Integer(value, bit_size) - } - /// Converts the memory value to a field element, independent of its type. pub fn to_field(&self) -> F { match self { MemoryValue::Field(value) => *value, - MemoryValue::Integer(value, _) => F::from_be_bytes_reduce(&value.to_bytes_be()), - } - } - - /// Converts the memory value to an integer, independent of its type. - pub fn to_integer(self) -> BigUint { - match self { - MemoryValue::Field(value) => BigUint::from_bytes_be(&value.to_be_bytes()), - MemoryValue::Integer(value, _) => value, - } - } - - pub fn bit_size(&self) -> u32 { - match self { - MemoryValue::Field(_) => F::max_num_bits(), - MemoryValue::Integer(_, bit_size) => *bit_size, + MemoryValue::Integer(value, _) => F::from(*value), } } - pub fn to_usize(&self) -> usize { - assert!( - self.bit_size() == MEMORY_ADDRESSING_BIT_SIZE, - "value is not typed as brillig usize" - ); - self.extract_integer().unwrap().0.try_into().unwrap() - } - pub fn expect_field(&self) -> Result<&F, MemoryTypeError> { match self { MemoryValue::Integer(_, bit_size) => Err(MemoryTypeError::MismatchedBitSize { - value_bit_size: *bit_size, + value_bit_size: (*bit_size).into(), expected_bit_size: F::max_num_bits(), }), MemoryValue::Field(field) => Ok(field), @@ -119,21 +103,21 @@ impl MemoryValue { pub fn expect_integer_with_bit_size( &self, - expected_bit_size: u32, - ) -> Result<&BigUint, MemoryTypeError> { + expected_bit_size: IntegerBitSize, + ) -> Result { match self { MemoryValue::Integer(value, bit_size) => { if *bit_size != expected_bit_size { return Err(MemoryTypeError::MismatchedBitSize { - value_bit_size: *bit_size, - expected_bit_size, + value_bit_size: (*bit_size).into(), + expected_bit_size: expected_bit_size.into(), }); } - Ok(value) + Ok(*value) } MemoryValue::Field(_) => Err(MemoryTypeError::MismatchedBitSize { value_bit_size: F::max_num_bits(), - expected_bit_size, + expected_bit_size: expected_bit_size.into(), }), } } @@ -144,12 +128,7 @@ impl std::fmt::Display for MemoryValue { match self { MemoryValue::Field(value) => write!(f, "{}: field", value), MemoryValue::Integer(value, bit_size) => { - let typ = match bit_size { - 0 => "null".to_string(), - 1 => "bool".to_string(), - _ => format!("u{}", bit_size), - }; - write!(f, "{}: {}", value, typ) + write!(f, "{}: {}", value, bit_size) } } } @@ -157,62 +136,44 @@ impl std::fmt::Display for MemoryValue { impl Default for MemoryValue { fn default() -> Self { - MemoryValue::new_integer(BigUint::zero(), 0) - } -} - -impl From for MemoryValue { - fn from(value: usize) -> Self { - MemoryValue::new_integer(value.into(), MEMORY_ADDRESSING_BIT_SIZE) + MemoryValue::new_integer(0, IntegerBitSize::U0) } } -impl From for MemoryValue { - fn from(value: u32) -> Self { - MemoryValue::new_integer(value.into(), 32) - } -} - -impl From for MemoryValue { - fn from(value: u64) -> Self { - MemoryValue::new_integer(value.into(), 64) +impl From for MemoryValue { + fn from(value: bool) -> Self { + let value = if value { 1 } else { 0 }; + MemoryValue::new_integer(value, IntegerBitSize::U1) } } impl From for MemoryValue { fn from(value: u8) -> Self { - MemoryValue::new_integer(value.into(), 8) + MemoryValue::new_integer(value.into(), IntegerBitSize::U8) } } -impl From for MemoryValue { - fn from(value: bool) -> Self { - let value = if value { BigUint::one() } else { BigUint::zero() }; - MemoryValue::new_integer(value, 1) +impl From for MemoryValue { + fn from(value: usize) -> Self { + MemoryValue::new_integer(value as u128, MEMORY_ADDRESSING_BIT_SIZE) } } -impl TryFrom> for u64 { - type Error = MemoryTypeError; - - fn try_from(memory_value: MemoryValue) -> Result { - memory_value.expect_integer_with_bit_size(64).map(|value| value.try_into().unwrap()) +impl From for MemoryValue { + fn from(value: u32) -> Self { + MemoryValue::new_integer(value.into(), IntegerBitSize::U32) } } -impl TryFrom> for u32 { - type Error = MemoryTypeError; - - fn try_from(memory_value: MemoryValue) -> Result { - memory_value.expect_integer_with_bit_size(32).map(|value| value.try_into().unwrap()) +impl From for MemoryValue { + fn from(value: u64) -> Self { + MemoryValue::new_integer(value.into(), IntegerBitSize::U64) } } -impl TryFrom> for u8 { - type Error = MemoryTypeError; - - fn try_from(memory_value: MemoryValue) -> Result { - memory_value.expect_integer_with_bit_size(8).map(|value| value.try_into().unwrap()) +impl From for MemoryValue { + fn from(value: u128) -> Self { + MemoryValue::new_integer(value, IntegerBitSize::U128) } } @@ -220,7 +181,7 @@ impl TryFrom> for bool { type Error = MemoryTypeError; fn try_from(memory_value: MemoryValue) -> Result { - let as_integer = memory_value.expect_integer_with_bit_size(1)?; + let as_integer = memory_value.expect_integer_with_bit_size(IntegerBitSize::U1)?; if as_integer.is_zero() { Ok(false) @@ -232,49 +193,35 @@ impl TryFrom> for bool { } } -impl TryFrom<&MemoryValue> for u64 { +impl TryFrom> for u8 { type Error = MemoryTypeError; - fn try_from(memory_value: &MemoryValue) -> Result { - memory_value.expect_integer_with_bit_size(64).map(|value| { - value.try_into().expect("memory_value has been asserted to contain a 64 bit integer") - }) + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_integer_with_bit_size(IntegerBitSize::U8).map(|value| value as u8) } } -impl TryFrom<&MemoryValue> for u32 { +impl TryFrom> for u32 { type Error = MemoryTypeError; - fn try_from(memory_value: &MemoryValue) -> Result { - memory_value.expect_integer_with_bit_size(32).map(|value| { - value.try_into().expect("memory_value has been asserted to contain a 32 bit integer") - }) + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_integer_with_bit_size(IntegerBitSize::U32).map(|value| value as u32) } } -impl TryFrom<&MemoryValue> for u8 { +impl TryFrom> for u64 { type Error = MemoryTypeError; - fn try_from(memory_value: &MemoryValue) -> Result { - memory_value.expect_integer_with_bit_size(8).map(|value| { - value.try_into().expect("memory_value has been asserted to contain an 8 bit integer") - }) + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_integer_with_bit_size(IntegerBitSize::U64).map(|value| value as u64) } } -impl TryFrom<&MemoryValue> for bool { +impl TryFrom> for u128 { type Error = MemoryTypeError; - fn try_from(memory_value: &MemoryValue) -> Result { - let as_integer = memory_value.expect_integer_with_bit_size(1)?; - - if as_integer.is_zero() { - Ok(false) - } else if as_integer.is_one() { - Ok(true) - } else { - unreachable!("value typed as bool is greater than one") - } + fn try_from(memory_value: MemoryValue) -> Result { + memory_value.expect_integer_with_bit_size(IntegerBitSize::U128) } } @@ -288,7 +235,7 @@ pub struct Memory { impl Memory { /// Gets the value at pointer pub fn read(&self, ptr: MemoryAddress) -> MemoryValue { - self.inner.get(ptr.to_usize()).cloned().unwrap_or_default() + self.inner.get(ptr.to_usize()).copied().unwrap_or_default() } pub fn read_ref(&self, ptr: MemoryAddress) -> MemoryAddress { @@ -321,7 +268,7 @@ impl Memory { /// Sets the values after pointer `ptr` to `values` pub fn write_slice(&mut self, ptr: MemoryAddress, values: &[MemoryValue]) { self.resize_to_fit(ptr.to_usize() + values.len()); - self.inner[ptr.to_usize()..(ptr.to_usize() + values.len())].clone_from_slice(values); + self.inner[ptr.to_usize()..(ptr.to_usize() + values.len())].copy_from_slice(values); } /// Returns the values of the memory diff --git a/aztec_macros/src/transforms/contract_interface.rs b/aztec_macros/src/transforms/contract_interface.rs index e79cee66407..56107de77c5 100644 --- a/aztec_macros/src/transforms/contract_interface.rs +++ b/aztec_macros/src/transforms/contract_interface.rs @@ -1,15 +1,18 @@ +use acvm::acir::AcirField; + use noirc_errors::Location; use noirc_frontend::ast::{Ident, NoirFunction, UnresolvedTypeData}; use noirc_frontend::{ graph::CrateId, - macros_api::{FileId, HirContext, HirExpression, HirLiteral, HirStatement}, + macros_api::{FieldElement, FileId, HirContext, HirExpression, HirLiteral, HirStatement}, parse_program, parser::SortedModule, Type, }; +use tiny_keccak::{Hasher, Keccak}; + use crate::utils::{ - constants::SELECTOR_PLACEHOLDER, errors::AztecMacroError, hir_utils::{collect_crate_structs, get_contract_module_data, signature_of_type}, }; @@ -64,11 +67,6 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction, is_static_call .join(", "); let fn_return_type: noirc_frontend::ast::UnresolvedType = func.return_type(); - let fn_selector = format!( - "dep::aztec::protocol_types::abis::function_selector::FunctionSelector::from_signature(\"{}\")", - SELECTOR_PLACEHOLDER - ); - let parameters = func.parameters(); let is_void = if matches!(fn_return_type.typ, UnresolvedTypeData::Unit) { "Void" } else { "" }; let is_static = if is_static_call { "Static" } else { "" }; @@ -160,7 +158,7 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction, is_static_call let fn_body = format!( "{} - let selector = {}; + let selector = dep::aztec::protocol_types::abis::function_selector::FunctionSelector::from_field(0); dep::aztec::context::{}{}{}CallInterface {{ target_contract: self.target_contract, selector, @@ -172,7 +170,6 @@ pub fn stub_function(aztec_visibility: &str, func: &NoirFunction, is_static_call {} }}", args, - fn_selector, aztec_visibility, is_static, is_void, @@ -291,27 +288,34 @@ pub fn generate_contract_interface( Ok(()) } -fn compute_fn_signature(fn_name: &str, parameters: &[Type]) -> String { - format!( +fn compute_fn_signature_hash(fn_name: &str, parameters: &[Type]) -> u32 { + let signature = format!( "{}({})", fn_name, parameters.iter().map(signature_of_type).collect::>().join(",") - ) + ); + let mut keccak = Keccak::v256(); + let mut result = [0u8; 32]; + keccak.update(signature.as_bytes()); + keccak.finalize(&mut result); + // Take the first 4 bytes of the hash and convert them to an integer + // If you change the following value you have to change NUM_BYTES_PER_NOTE_TYPE_ID in l1_note_payload.ts as well + let num_bytes_per_note_type_id = 4; + u32::from_be_bytes(result[0..num_bytes_per_note_type_id].try_into().unwrap()) } // Updates the function signatures in the contract interface with the actual ones, replacing the placeholder. -// This is done by locating the contract interface struct, its functions (stubs) and assuming the last statement of each -// is the constructor for a CallInterface. This constructor has a selector field that holds a -// FunctionSelector::from_signature function that receives the signature as a string literal. +// This is done by locating the contract interface struct, its functions (stubs) and assuming the second to last statement of each +// is a let statement initializing the selector with a FunctionSelector::from_field call. pub fn update_fn_signatures_in_contract_interface( crate_id: &CrateId, context: &mut HirContext, ) -> Result<(), (AztecMacroError, FileId)> { - if let Some((name, _, file_id)) = get_contract_module_data(context, crate_id) { + if let Some((struct_name, _, file_id)) = get_contract_module_data(context, crate_id) { let maybe_interface_struct = collect_crate_structs(crate_id, context).iter().find_map(|struct_id| { let r#struct = context.def_interner.get_struct(*struct_id); - if r#struct.borrow().name.0.contents == name { + if r#struct.borrow().name.0.contents == struct_name { Some(r#struct) } else { None @@ -329,7 +333,7 @@ pub fn update_fn_signatures_in_contract_interface( continue; } - let fn_signature = compute_fn_signature( + let fn_signature_hash = compute_fn_signature_hash( name, &fn_parameters .iter() @@ -381,14 +385,12 @@ pub fn update_fn_signatures_in_contract_interface( context.def_interner.expression(¤t_fn_signature_expression_id); match current_fn_signature_expression { - HirExpression::Literal(HirLiteral::Str(signature)) => { - if signature != SELECTOR_PLACEHOLDER { + HirExpression::Literal(HirLiteral::Integer(value, _)) => { + if !value.is_zero() { Err(( AztecMacroError::CouldNotGenerateContractInterface { - secondary_message: Some(format!( - "Function signature argument must be a placeholder: {}", - SELECTOR_PLACEHOLDER - )), + secondary_message: Some( + "Function signature argument must be a placeholder with value 0".to_string()), }, file_id, )) @@ -397,20 +399,25 @@ pub fn update_fn_signatures_in_contract_interface( } } _ => Err(( - AztecMacroError::CouldNotAssignStorageSlots { + AztecMacroError::CouldNotGenerateContractInterface { secondary_message: Some( - "Function signature argument must be a literal string".to_string(), + "Function signature argument must be a literal field element" + .to_string(), ), }, file_id, )), }?; - context - .def_interner - .update_expression(current_fn_signature_expression_id, |expr| { - *expr = HirExpression::Literal(HirLiteral::Str(fn_signature)) - }); + context.def_interner.update_expression( + current_fn_signature_expression_id, + |expr| { + *expr = HirExpression::Literal(HirLiteral::Integer( + FieldElement::from(fn_signature_hash as u128), + false, + )) + }, + ); } } } diff --git a/aztec_macros/src/transforms/note_interface.rs b/aztec_macros/src/transforms/note_interface.rs index f8825f93832..1bf84779a45 100644 --- a/aztec_macros/src/transforms/note_interface.rs +++ b/aztec_macros/src/transforms/note_interface.rs @@ -99,7 +99,9 @@ pub fn generate_note_interface_impl(module: &mut SortedModule) -> Result<(), Azt }) .collect::, _>>()?; let [note_serialized_len, note_bytes_len]: [_; 2] = - note_interface_generics.try_into().unwrap(); + note_interface_generics.try_into().expect( + "NoteInterface must be generic over 2 types, NOTE_FIELDS_LEN and NOTE_BYTES_LEN", + ); // Automatically inject the header field if it's not present let (header_field_name, _) = if let Some(existing_header) = diff --git a/aztec_macros/src/utils/constants.rs b/aztec_macros/src/utils/constants.rs index 2178f7a2526..3e93b2aa545 100644 --- a/aztec_macros/src/utils/constants.rs +++ b/aztec_macros/src/utils/constants.rs @@ -1,3 +1,2 @@ pub const FUNCTION_TREE_HEIGHT: u32 = 5; pub const MAX_CONTRACT_PRIVATE_FUNCTIONS: usize = 2_usize.pow(FUNCTION_TREE_HEIGHT); -pub const SELECTOR_PLACEHOLDER: &str = "SELECTOR_PLACEHOLDER"; diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs index ae159f2c45c..dff4da56c1e 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -1,6 +1,6 @@ -use acvm::{ - acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode}, - acir::AcirField, +use acvm::acir::{ + brillig::{BinaryFieldOp, BitSize, MemoryAddress, Opcode as BrilligOpcode}, + AcirField, }; use crate::brillig::brillig_ir::artifact::GeneratedBrillig; @@ -28,7 +28,7 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { BrilligOpcode::Const { destination: zero_const, value: F::from(0_usize), - bit_size: F::max_num_bits(), + bit_size: BitSize::Field, }, BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Equals, @@ -42,7 +42,7 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { BrilligOpcode::Const { destination: one_const, value: F::one(), - bit_size: F::max_num_bits(), + bit_size: BitSize::Field, }, // Divide 1 by the input, and set the result of the division into register (0) BrilligOpcode::BinaryFieldOp { @@ -67,105 +67,47 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { /// (a/b, a-a/b*b) /// } /// ``` -pub(crate) fn directive_quotient(bit_size: u32) -> GeneratedBrillig { +pub(crate) fn directive_quotient() -> GeneratedBrillig { // `a` is (0) (i.e register index 0) // `b` is (1) - // TODO: The only difference between these implementations is the integer version will truncate the input to the `bit_size` via cast. - // Once we deduplicate brillig functions then we can modify this so that fields and integers share the same quotient function. - if bit_size >= F::max_num_bits() { - // Field version - GeneratedBrillig { - byte_code: vec![ - BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress::from(0), - size: 2, - offset: 0, - }, - // No cast, since calldata is typed as field by default - //q = a/b is set into register (2) - BrilligOpcode::BinaryFieldOp { - op: BinaryFieldOp::IntegerDiv, // We want integer division, not field division! - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(2), - }, - //(1)= q*b - BrilligOpcode::BinaryFieldOp { - op: BinaryFieldOp::Mul, - lhs: MemoryAddress::from(2), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(1), - }, - //(1) = a-q*b - BrilligOpcode::BinaryFieldOp { - op: BinaryFieldOp::Sub, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(1), - }, - //(0) = q - BrilligOpcode::Mov { - destination: MemoryAddress::from(0), - source: MemoryAddress::from(2), - }, - BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 2 }, - ], - assert_messages: Default::default(), - locations: Default::default(), - } - } else { - // Integer version - GeneratedBrillig { - byte_code: vec![ - BrilligOpcode::CalldataCopy { - destination_address: MemoryAddress::from(0), - size: 2, - offset: 0, - }, - BrilligOpcode::Cast { - destination: MemoryAddress(0), - source: MemoryAddress(0), - bit_size, - }, - BrilligOpcode::Cast { - destination: MemoryAddress(1), - source: MemoryAddress(1), - bit_size, - }, - //q = a/b is set into register (2) - BrilligOpcode::BinaryIntOp { - op: BinaryIntOp::Div, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(2), - bit_size, - }, - //(1)= q*b - BrilligOpcode::BinaryIntOp { - op: BinaryIntOp::Mul, - lhs: MemoryAddress::from(2), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(1), - bit_size, - }, - //(1) = a-q*b - BrilligOpcode::BinaryIntOp { - op: BinaryIntOp::Sub, - lhs: MemoryAddress::from(0), - rhs: MemoryAddress::from(1), - destination: MemoryAddress::from(1), - bit_size, - }, - //(0) = q - BrilligOpcode::Mov { - destination: MemoryAddress::from(0), - source: MemoryAddress::from(2), - }, - BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 2 }, - ], - assert_messages: Default::default(), - locations: Default::default(), - } + GeneratedBrillig { + byte_code: vec![ + BrilligOpcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: 2, + offset: 0, + }, + // No cast, since calldata is typed as field by default + //q = a/b is set into register (2) + BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::IntegerDiv, // We want integer division, not field division! + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(2), + }, + //(1)= q*b + BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::Mul, + lhs: MemoryAddress::from(2), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(1), + }, + //(1) = a-q*b + BrilligOpcode::BinaryFieldOp { + op: BinaryFieldOp::Sub, + lhs: MemoryAddress::from(0), + rhs: MemoryAddress::from(1), + destination: MemoryAddress::from(1), + }, + //(0) = q + BrilligOpcode::Mov { + destination: MemoryAddress::from(0), + source: MemoryAddress::from(2), + }, + BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 2 }, + ], + assert_messages: Default::default(), + locations: Default::default(), } } diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index 80367d07635..21f8722c116 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -127,7 +127,8 @@ pub(crate) mod tests { use std::vec; use acvm::acir::brillig::{ - ForeignCallParam, ForeignCallResult, HeapArray, HeapVector, MemoryAddress, ValueOrArray, + BitSize, ForeignCallParam, ForeignCallResult, HeapArray, HeapVector, IntegerBitSize, + MemoryAddress, ValueOrArray, }; use acvm::brillig_vm::brillig::HeapValueType; use acvm::brillig_vm::{VMStatus, VM}; @@ -253,9 +254,11 @@ pub(crate) mod tests { context.foreign_call_instruction( "make_number_sequence".into(), &[ValueOrArray::MemoryAddress(r_input_size)], - &[HeapValueType::Simple(32)], + &[HeapValueType::Simple(BitSize::Integer(IntegerBitSize::U32))], &[ValueOrArray::HeapVector(HeapVector { pointer: r_stack, size: r_output_size })], - &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple(32)] }], + &[HeapValueType::Vector { + value_types: vec![HeapValueType::Simple(BitSize::Integer(IntegerBitSize::U32))], + }], ); // push stack frame by r_returned_size context.memory_op_instruction(r_stack, r_output_size, r_stack, BrilligBinaryOp::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 cf1fd555191..3200bd54265 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -1,5 +1,5 @@ use acvm::{ - acir::AcirField, + acir::{brillig::BitSize, AcirField}, brillig_vm::brillig::{HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray}, FieldElement, }; @@ -126,9 +126,9 @@ impl BrilligVariable { pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType { match typ { - Type::Numeric(_) | Type::Reference(_) | Type::Function => { - HeapValueType::Simple(get_bit_size_from_ssa_type(typ)) - } + Type::Numeric(_) | Type::Reference(_) | Type::Function => HeapValueType::Simple( + BitSize::try_from_u32::(get_bit_size_from_ssa_type(typ)).unwrap(), + ), 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, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs index b1cb2b19764..d07b411f5a1 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/codegen_intrinsic.rs @@ -1,8 +1,10 @@ -use acvm::{ - acir::brillig::{BlackBoxOp, HeapArray}, - acir::AcirField, +use acvm::acir::{ + brillig::{BlackBoxOp, HeapArray, IntegerBitSize}, + AcirField, }; +use crate::brillig::brillig_ir::BrilligBinaryOp; + use super::{ brillig_variable::{BrilligVector, SingleAddrVariable}, debug_show::DebugToString, @@ -24,12 +26,39 @@ impl BrilligContext { value_to_truncate.bit_size ); - // We cast back and forth to ensure that the value is truncated. - let intermediate_register = - SingleAddrVariable { address: self.allocate_register(), bit_size }; - self.cast_instruction(intermediate_register, value_to_truncate); - self.cast_instruction(destination_of_truncated_value, intermediate_register); - self.deallocate_single_addr(intermediate_register); + if bit_size == value_to_truncate.bit_size { + self.mov_instruction(destination_of_truncated_value.address, value_to_truncate.address); + return; + } + + // If we are truncating a value down to a natively supported integer, we can just use the cast instruction + if IntegerBitSize::try_from(bit_size).is_ok() { + // We cast back and forth to ensure that the value is truncated. + let intermediate_register = SingleAddrVariable::new(self.allocate_register(), bit_size); + + self.cast_instruction(intermediate_register, value_to_truncate); + self.cast_instruction(destination_of_truncated_value, intermediate_register); + + self.deallocate_single_addr(intermediate_register); + return; + } + + // If the bit size we are truncating down to is not a natively supported integer, we need to use a modulo operation. + + // The modulus is guaranteed to fit, since we are truncating down to a bit size that is strictly less than the value_to_truncate.bit_size + let modulus_var = self.make_constant_instruction( + F::from(2_usize).pow(&F::from(bit_size as u128)), + value_to_truncate.bit_size, + ); + + self.binary_instruction( + value_to_truncate, + modulus_var, + destination_of_truncated_value, + BrilligBinaryOp::Modulo, + ); + + self.deallocate_single_addr(modulus_var); } /// Issues a to_radix instruction. This instruction will write the modulus of the source register diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs index a614f93fa30..69a6b12c9b0 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/instructions.rs @@ -1,9 +1,11 @@ use acvm::{ - acir::brillig::{ - BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapArray, HeapValueType, MemoryAddress, - Opcode as BrilligOpcode, ValueOrArray, + acir::{ + brillig::{ + BinaryFieldOp, BinaryIntOp, BitSize, BlackBoxOp, HeapArray, HeapValueType, + MemoryAddress, Opcode as BrilligOpcode, ValueOrArray, + }, + AcirField, }, - acir::AcirField, FieldElement, }; @@ -99,7 +101,7 @@ impl BrilligContext { self.push_opcode(BrilligOpcode::BinaryIntOp { op: operation.into(), destination: result.address, - bit_size: lhs.bit_size, + bit_size: lhs.bit_size.try_into().unwrap(), lhs: lhs.address, rhs: rhs.address, }); @@ -363,7 +365,7 @@ impl BrilligContext { self.push_opcode(BrilligOpcode::Cast { destination: destination.address, source: source.address, - bit_size: destination.bit_size, + bit_size: BitSize::try_from_u32::(destination.bit_size).unwrap(), }); } @@ -405,7 +407,7 @@ impl BrilligContext { self.push_opcode(BrilligOpcode::Const { destination: result.address, value: constant, - bit_size: result.bit_size, + bit_size: BitSize::try_from_u32::(result.bit_size).unwrap(), }); } } diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs index 9e97fd3bc50..fdad06a520b 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/acir_variable.rs @@ -830,7 +830,7 @@ impl AcirContext { let [q_value, r_value]: [AcirValue; 2] = self .brillig_call( predicate, - &brillig_directive::directive_quotient(bit_size + 1), + &brillig_directive::directive_quotient(), vec![ AcirValue::Var(lhs, AcirType::unsigned(bit_size)), AcirValue::Var(rhs, AcirType::unsigned(bit_size)), @@ -839,7 +839,7 @@ impl AcirContext { true, false, PLACEHOLDER_BRILLIG_INDEX, - Some(BrilligStdlibFunc::Quotient(bit_size + 1)), + Some(BrilligStdlibFunc::Quotient), )? .try_into() .expect("quotient only returns two values"); diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs index 44467677154..1395d04f99e 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/acir_ir/generated_acir.rs @@ -74,17 +74,14 @@ pub(crate) struct GeneratedAcir { #[derive(Debug, Clone, Copy, Hash, PartialEq, Eq)] pub(crate) enum BrilligStdlibFunc { Inverse, - // The Brillig quotient code is different depending upon the bit size. - Quotient(u32), + Quotient, } impl BrilligStdlibFunc { pub(crate) fn get_generated_brillig(&self) -> GeneratedBrillig { match self { BrilligStdlibFunc::Inverse => brillig_directive::directive_invert(), - BrilligStdlibFunc::Quotient(bit_size) => { - brillig_directive::directive_quotient(*bit_size) - } + BrilligStdlibFunc::Quotient => brillig_directive::directive_quotient(), } } } diff --git a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs index d7dd5e5dbce..0e4bbbf759c 100644 --- a/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs +++ b/compiler/noirc_evaluator/src/ssa/acir_gen/mod.rs @@ -3501,7 +3501,7 @@ mod test { if stdlib_func_index == 0 { assert!(matches!(brillig_stdlib_func, BrilligStdlibFunc::Inverse)); } else { - assert!(matches!(brillig_stdlib_func, BrilligStdlibFunc::Quotient(_))); + assert!(matches!(brillig_stdlib_func, BrilligStdlibFunc::Quotient)); } match opcode_location { diff --git a/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs b/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs index 9baeb19206f..06325b31dd0 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/function_inserter.rs @@ -18,11 +18,10 @@ pub(crate) struct FunctionInserter<'f> { pub(crate) function: &'f mut Function, values: HashMap, - /// Map containing repeat array constant so that we do not initialize a new - /// array unnecessarily. An extra bool is included as part of the key to - /// distinguish between Type::Array and Type::Slice, as both are valid - /// types for a Value::Array - const_arrays: HashMap<(im::Vector, bool), ValueId>, + /// Map containing repeat array constants so that we do not initialize a new + /// array unnecessarily. An extra tuple field is included as part of the key to + /// distinguish between array/slice types. + const_arrays: HashMap<(im::Vector, Type), ValueId>, } impl<'f> FunctionInserter<'f> { @@ -44,10 +43,8 @@ impl<'f> FunctionInserter<'f> { let new_array: im::Vector = array.iter().map(|id| self.resolve(*id)).collect(); - // Flag to determine the type of the value's array list - let is_array = matches!(typ, Type::Array { .. }); if let Some(fetched_value) = - self.const_arrays.get(&(new_array.clone(), is_array)) + self.const_arrays.get(&(new_array.clone(), typ.clone())) { // Arrays in ACIR are immutable, but in Brillig arrays are copy-on-write // so for function's with a Brillig runtime we make sure to check that value @@ -60,9 +57,9 @@ impl<'f> FunctionInserter<'f> { }; let new_array_clone = new_array.clone(); - let new_id = self.function.dfg.make_array(new_array, typ); + let new_id = self.function.dfg.make_array(new_array, typ.clone()); self.values.insert(value, new_id); - self.const_arrays.insert((new_array_clone, is_array), new_id); + self.const_arrays.insert((new_array_clone, typ), new_id); new_id } _ => value, diff --git a/noir_stdlib/src/embedded_curve_ops.nr b/noir_stdlib/src/embedded_curve_ops.nr index 9c1a3097217..6b70b6ddef0 100644 --- a/noir_stdlib/src/embedded_curve_ops.nr +++ b/noir_stdlib/src/embedded_curve_ops.nr @@ -88,27 +88,28 @@ impl Eq for EmbeddedCurveScalar { // // The embedded curve being used is decided by the // underlying proof system. -#[foreign(multi_scalar_mul)] // docs:start:multi_scalar_mul pub fn multi_scalar_mul( points: [EmbeddedCurvePoint; N], scalars: [EmbeddedCurveScalar; N] -) -> [Field; 3] +) -> EmbeddedCurvePoint // docs:end:multi_scalar_mul -{} +{ + let point_array = multi_scalar_mul_array_return(points, scalars); + EmbeddedCurvePoint { x: point_array[0], y: point_array[1], is_infinite: point_array[2] as bool } +} + +#[foreign(multi_scalar_mul)] +fn multi_scalar_mul_array_return(points: [EmbeddedCurvePoint; N], scalars: [EmbeddedCurveScalar; N]) -> [Field; 3] {} #[foreign(multi_scalar_mul)] pub(crate) fn multi_scalar_mul_slice(points: [EmbeddedCurvePoint], scalars: [EmbeddedCurveScalar]) -> [Field; 3] {} // docs:start:fixed_base_scalar_mul -pub fn fixed_base_scalar_mul( - scalar_low: Field, - scalar_high: Field -) -> [Field; 3] +pub fn fixed_base_scalar_mul(scalar: EmbeddedCurveScalar) -> EmbeddedCurvePoint // docs:end:fixed_base_scalar_mul { let g1 = EmbeddedCurvePoint { x: 1, y: 17631683881184975370165255887551781615748388533673675138860, is_infinite: false }; - let scalar = EmbeddedCurveScalar { lo: scalar_low, hi: scalar_high }; multi_scalar_mul([g1], [scalar]) } diff --git a/noir_stdlib/src/hash/keccak.nr b/noir_stdlib/src/hash/keccak.nr index a747676731a..bb8a9cc2ce2 100644 --- a/noir_stdlib/src/hash/keccak.nr +++ b/noir_stdlib/src/hash/keccak.nr @@ -24,12 +24,13 @@ pub(crate) fn keccak256(mut input: [u8; N], message_size: u32) -> [u let real_max_blocks = (message_size + BLOCK_SIZE) / BLOCK_SIZE; let real_blocks_bytes = real_max_blocks * BLOCK_SIZE; - let mut block_bytes = Vec::from_slice(input.as_slice()); - for _i in N..N + BLOCK_SIZE { - block_bytes.push(0); + let mut block_bytes = [0; BLOCK_SIZE]; + for i in 0..N { + block_bytes[i] = input[i]; } - block_bytes.set(message_size, 1); - block_bytes.set(real_blocks_bytes - 1, 0x80); + + block_bytes[message_size] = 1; + block_bytes[real_blocks_bytes - 1] = 0x80; // keccak lanes interpret memory as little-endian integers, // means we need to swap our byte ordering @@ -37,10 +38,10 @@ pub(crate) fn keccak256(mut input: [u8; N], message_size: u32) -> [u for i in 0..num_limbs { let mut temp = [0; 8]; for j in 0..8 { - temp[j] = block_bytes.get(8*i+j); + temp[j] = block_bytes[8*i+j]; } for j in 0..8 { - block_bytes.set(8 * i + j, temp[7 - j]); + block_bytes[8 * i + j] = temp[7 - j]; } } let byte_size = max_blocks_length; @@ -56,7 +57,7 @@ pub(crate) fn keccak256(mut input: [u8; N], message_size: u32) -> [u let byte_shift = (WORD_SIZE - slice_size) * 8; let mut v = 1; for k in 0..slice_size { - sliced += v * (block_bytes.get(i * WORD_SIZE+7-k) as Field); + sliced += v * (block_bytes[i * WORD_SIZE+7-k] as Field); v *= 256; } let w = 1 << (byte_shift as u8); @@ -64,7 +65,7 @@ pub(crate) fn keccak256(mut input: [u8; N], message_size: u32) -> [u } else { let mut v = 1; for k in 0..WORD_SIZE { - sliced += v * (block_bytes.get(i * WORD_SIZE+7-k) as Field); + sliced += v * (block_bytes[i * WORD_SIZE+7-k] as Field); v *= 256; } } diff --git a/noir_stdlib/src/hash/mod.nr b/noir_stdlib/src/hash/mod.nr index 40d50abc9e5..320b89353d9 100644 --- a/noir_stdlib/src/hash/mod.nr +++ b/noir_stdlib/src/hash/mod.nr @@ -33,18 +33,30 @@ pub fn pedersen_commitment(input: [Field; N]) -> EmbeddedCurvePoint pedersen_commitment_with_separator(input, 0) } +pub fn pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field { + __pedersen_hash_with_separator(input, separator) +} + fn pedersen_commitment_with_separator(input: [Field; N], separator: u32) -> EmbeddedCurvePoint { + let value = __pedersen_commitment_with_separator(input, separator); + if (value[0] == 0) & (value[1] == 0) { + EmbeddedCurvePoint { x: 0, y: 0, is_infinite: true } + } else { + EmbeddedCurvePoint { x: value[0], y: value[1], is_infinite: false } + } +} + +fn pedersen_commitment_with_separator_noir(input: [Field; N], separator: u32) -> EmbeddedCurvePoint { let mut points = [EmbeddedCurveScalar { lo: 0, hi: 0 }; N]; for i in 0..N { // we use the unsafe version because the multi_scalar_mul will constraint the scalars. points[i] = from_field_unsafe(input[i]); } let generators = derive_generators("DEFAULT_DOMAIN_SEPARATOR".as_bytes(), separator); - let values = multi_scalar_mul(generators, points); - EmbeddedCurvePoint { x: values[0], y: values[1], is_infinite: values[2] as bool } + multi_scalar_mul(generators, points) } -fn pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field { +fn pedersen_hash_with_separator_noir(input: [Field; N], separator: u32) -> Field { let mut scalars: Vec = Vec::from_slice([EmbeddedCurveScalar { lo: 0, hi: 0 }; N].as_slice()); //Vec::new(); for i in 0..N { @@ -62,9 +74,15 @@ fn pedersen_hash_with_separator(input: [Field; N], separator: u32) - pub fn pedersen_hash(input: [Field; N]) -> Field // docs:end:pedersen_hash { - pedersen_hash_with_separator(input, 0) + __pedersen_hash_with_separator(input, 0) } +#[foreign(pedersen_hash)] +fn __pedersen_hash_with_separator(input: [Field; N], separator: u32) -> Field {} + +#[foreign(pedersen_commitment)] +fn __pedersen_commitment_with_separator(input: [Field; N], separator: u32) -> [Field; 2] {} + #[field(bn254)] fn derive_generators(domain_separator_bytes: [u8; M], starting_index: u32) -> [EmbeddedCurvePoint; N] { crate::assert_constant(domain_separator_bytes); diff --git a/scripts/install_bb.sh b/scripts/install_bb.sh index 95dcfdda880..65a449be543 100755 --- a/scripts/install_bb.sh +++ b/scripts/install_bb.sh @@ -1,6 +1,6 @@ #!/bin/bash -VERSION="0.46.1" +VERSION="0.47.1" BBUP_PATH=~/.bb/bbup diff --git a/test_programs/execution_success/embedded_curve_ops/src/main.nr b/test_programs/execution_success/embedded_curve_ops/src/main.nr index 4eeda39c6aa..5372f73df23 100644 --- a/test_programs/execution_success/embedded_curve_ops/src/main.nr +++ b/test_programs/execution_success/embedded_curve_ops/src/main.nr @@ -4,8 +4,8 @@ fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { let scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 }; // Test that multi_scalar_mul correctly derives the public key let res = std::embedded_curve_ops::multi_scalar_mul([g1], [scalar]); - assert(res[0] == pub_x); - assert(res[1] == pub_y); + assert(res.x == pub_x); + assert(res.y == pub_y); // Test that double function calling embedded_curve_add works as expected let pub_point = std::embedded_curve_ops::EmbeddedCurvePoint { x: pub_x, y: pub_y, is_infinite: false }; @@ -18,5 +18,5 @@ fn main(priv_key: Field, pub_x: pub Field, pub_y: pub Field) { let res = std::embedded_curve_ops::multi_scalar_mul([g1, g1], [scalar, scalar]); // The results should be double the g1 point because the scalars are 1 and we pass in g1 twice - assert(double.x == res[0]); + assert(double.x == res.x); } diff --git a/test_programs/execution_success/regression_5045/src/main.nr b/test_programs/execution_success/regression_5045/src/main.nr index cf39b2f97e4..d1bc4f663fd 100644 --- a/test_programs/execution_success/regression_5045/src/main.nr +++ b/test_programs/execution_success/regression_5045/src/main.nr @@ -15,6 +15,6 @@ fn main(is_active: bool) { [a, bad], [EmbeddedCurveScalar { lo: 1, hi: 0 }, EmbeddedCurveScalar { lo: 1, hi: 0 }] ); - assert(e[0] != d.x); + assert(e.x != d.x); } } diff --git a/test_programs/execution_success/schnorr/src/main.nr b/test_programs/execution_success/schnorr/src/main.nr index 5bc0ca9fefb..cf22fd371d1 100644 --- a/test_programs/execution_success/schnorr/src/main.nr +++ b/test_programs/execution_success/schnorr/src/main.nr @@ -50,7 +50,7 @@ pub fn verify_signature_noir(public_key: embedded_curve_ops::EmbeddedCurvePoi let g1 = embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 17631683881184975370165255887551781615748388533673675138860, is_infinite: false }; let r = embedded_curve_ops::multi_scalar_mul([g1, public_key], [sig_s, sig_e]); // compare the _hashes_ rather than field elements modulo r - let pedersen_hash = std::hash::pedersen_hash([r[0], public_key.x, public_key.y]); + let pedersen_hash = std::hash::pedersen_hash([r.x, public_key.x, public_key.y]); let mut hash_input = [0; M]; let pde = pedersen_hash.to_be_bytes(32); @@ -62,7 +62,7 @@ pub fn verify_signature_noir(public_key: embedded_curve_ops::EmbeddedCurvePoi } let result = std::hash::blake2s(hash_input); - is_ok = (r[2] == 0); + is_ok = !r.is_infinite; for i in 0..32 { if result[i] != signature[32 + i] { is_ok = false; @@ -101,7 +101,7 @@ pub fn assert_valid_signature(public_key: embedded_curve_ops::EmbeddedCurvePo let g1 = embedded_curve_ops::EmbeddedCurvePoint { x: 1, y: 17631683881184975370165255887551781615748388533673675138860, is_infinite: false }; let r = embedded_curve_ops::multi_scalar_mul([g1, public_key], [sig_s, sig_e]); // compare the _hashes_ rather than field elements modulo r - let pedersen_hash = std::hash::pedersen_hash([r[0], public_key.x, public_key.y]); + let pedersen_hash = std::hash::pedersen_hash([r.x, public_key.x, public_key.y]); let mut hash_input = [0; M]; let pde = pedersen_hash.to_be_bytes(32); @@ -113,7 +113,7 @@ pub fn assert_valid_signature(public_key: embedded_curve_ops::EmbeddedCurvePo } let result = std::hash::blake2s(hash_input); - assert(r[2] == 0); + assert(!r.is_infinite); for i in 0..32 { assert(result[i] == signature[32 + i]); } diff --git a/test_programs/execution_success/simple_shield/src/main.nr b/test_programs/execution_success/simple_shield/src/main.nr index d84288b9fd6..fd2fc20d08f 100644 --- a/test_programs/execution_success/simple_shield/src/main.nr +++ b/test_programs/execution_success/simple_shield/src/main.nr @@ -10,12 +10,11 @@ fn main( to_pubkey_x: Field, to_pubkey_y: Field ) -> pub [Field; 2] { + let priv_key_as_scalar = std::embedded_curve_ops::EmbeddedCurveScalar { lo: priv_key, hi: 0 }; // Compute public key from private key to show ownership - let pubkey = std::embedded_curve_ops::fixed_base_scalar_mul(priv_key, 0); - let pubkey_x = pubkey[0]; - let pubkey_y = pubkey[1]; + let pubkey = std::embedded_curve_ops::fixed_base_scalar_mul(priv_key_as_scalar); // Compute input note commitment - let note_commitment = std::hash::pedersen_commitment([pubkey_x, pubkey_y]); + let note_commitment = std::hash::pedersen_commitment([pubkey.x, pubkey.y]); // Compute input note nullifier let nullifier = std::hash::pedersen_commitment([note_commitment.x, index, priv_key]); // Compute output note nullifier diff --git a/test_programs/noir_test_success/embedded_curve_ops/src/main.nr b/test_programs/noir_test_success/embedded_curve_ops/src/main.nr index 225e86397fd..0c2c333fa62 100644 --- a/test_programs/noir_test_success/embedded_curve_ops/src/main.nr +++ b/test_programs/noir_test_success/embedded_curve_ops/src/main.nr @@ -10,28 +10,28 @@ use std::embedded_curve_ops::{EmbeddedCurvePoint, EmbeddedCurveScalar, multi_sca let s1 = EmbeddedCurveScalar { lo: 1, hi: 0 }; let a = multi_scalar_mul([g1], [s1]); - assert(a[2] == 0); + assert(!a.is_infinite); assert(g1 + zero == g1); assert(g1 - g1 == zero); assert(g1 - zero == g1); assert(zero + zero == zero); assert( multi_scalar_mul([g1], [s1]) - == [1, 17631683881184975370165255887551781615748388533673675138860, 0] + == EmbeddedCurvePoint { x: 1, y: 17631683881184975370165255887551781615748388533673675138860, is_infinite: false } ); - assert(multi_scalar_mul([g1, g1], [s1, s1]) == [g2.x, g2.y, 0]); + assert(multi_scalar_mul([g1, g1], [s1, s1]) == g2); assert( multi_scalar_mul( [g1, zero], [EmbeddedCurveScalar { lo: 2, hi: 0 }, EmbeddedCurveScalar { lo: 42, hi: 25 }] ) - == [g2.x, g2.y, 0] + == g2 ); assert( multi_scalar_mul( [g1, g1, zero], [s1, s1, EmbeddedCurveScalar { lo: 42, hi: 25 }] ) - == [g2.x, g2.y, 0] + == g2 ); } diff --git a/test_programs/rebuild.sh b/test_programs/rebuild.sh index 13479f58b4b..a70f69d531d 100755 --- a/test_programs/rebuild.sh +++ b/test_programs/rebuild.sh @@ -45,7 +45,7 @@ rm -rf $current_dir/acir_artifacts mkdir -p $current_dir/acir_artifacts # Gather directories to process. -dirs_to_process=() +# dirs_to_process=() for dir in $base_path/*; do if [[ ! -d $dir ]] || [[ " ${excluded_dirs[@]} " =~ " $(basename "$dir") " ]]; then continue diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index d18ec5f0786..7cdbe515649 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -1,4 +1,5 @@ use crate::foreign_calls::DebugForeignCallExecutor; +use acvm::acir::brillig::BitSize; use acvm::acir::circuit::brillig::BrilligBytecode; use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap, WitnessStack}; @@ -708,7 +709,12 @@ impl<'a, B: BlackBoxFunctionSolver> DebugContext<'a, B> { self.brillig_solver.as_ref().map(|solver| solver.get_memory()) } - pub(super) fn write_brillig_memory(&mut self, ptr: usize, value: FieldElement, bit_size: u32) { + pub(super) fn write_brillig_memory( + &mut self, + ptr: usize, + value: FieldElement, + bit_size: BitSize, + ) { if let Some(solver) = self.brillig_solver.as_mut() { solver.write_memory_at( ptr, @@ -847,6 +853,7 @@ mod tests { use crate::foreign_calls::DefaultDebugForeignCallExecutor; use acvm::{ acir::{ + brillig::IntegerBitSize, circuit::{ brillig::{BrilligInputs, BrilligOutputs}, opcodes::{BlockId, BlockType}, @@ -876,7 +883,7 @@ mod tests { BrilligOpcode::Const { destination: MemoryAddress::from(1), value: fe_0, - bit_size: 32, + bit_size: BitSize::Integer(IntegerBitSize::U32), }, BrilligOpcode::ForeignCall { function: "clear_mock".into(), diff --git a/tooling/debugger/src/repl.rs b/tooling/debugger/src/repl.rs index d3462985642..bd9b316331d 100644 --- a/tooling/debugger/src/repl.rs +++ b/tooling/debugger/src/repl.rs @@ -1,9 +1,11 @@ use crate::context::{DebugCommandResult, DebugContext, DebugLocation}; +use acvm::acir::brillig::{BitSize, IntegerBitSize}; use acvm::acir::circuit::brillig::BrilligBytecode; use acvm::acir::circuit::{Circuit, Opcode, OpcodeLocation}; use acvm::acir::native_types::{Witness, WitnessMap, WitnessStack}; use acvm::brillig_vm::brillig::Opcode as BrilligOpcode; +use acvm::brillig_vm::MemoryValue; use acvm::{BlackBoxFunctionSolver, FieldElement}; use nargo::NargoError; use noirc_driver::CompiledProgram; @@ -362,7 +364,11 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { return; }; - for (index, value) in memory.iter().enumerate().filter(|(_, value)| value.bit_size() > 0) { + for (index, value) in memory + .iter() + .enumerate() + .filter(|(_, value)| !matches!(value, MemoryValue::Integer(_, IntegerBitSize::U0))) + { println!("{index} = {}", value); } } @@ -372,6 +378,12 @@ impl<'a, B: BlackBoxFunctionSolver> ReplDebugger<'a, B> { println!("Invalid value: {value}"); return; }; + + let Ok(bit_size) = BitSize::try_from_u32::(bit_size) else { + println!("Invalid bit size: {bit_size}"); + return; + }; + if !self.context.is_executing_brillig() { println!("Not executing a Brillig block"); return; diff --git a/tooling/fuzzer/src/dictionary/mod.rs b/tooling/fuzzer/src/dictionary/mod.rs index a45b9c3abb2..942462c4f37 100644 --- a/tooling/fuzzer/src/dictionary/mod.rs +++ b/tooling/fuzzer/src/dictionary/mod.rs @@ -113,14 +113,18 @@ fn build_dictionary_from_unconstrained_function( for opcode in &function.bytecode { match opcode { BrilligOpcode::Cast { bit_size, .. } => { - let field = 1u128.wrapping_shl(*bit_size); + let bit_size = bit_size.to_u32::(); + + let field = 1u128.wrapping_shl(bit_size); constants.insert(F::from(field)); constants.insert(F::from(field - 1)); } BrilligOpcode::Const { bit_size, value, .. } => { + let bit_size = bit_size.to_u32::(); + constants.insert(*value); - let field = 1u128.wrapping_shl(*bit_size); + let field = 1u128.wrapping_shl(bit_size); constants.insert(F::from(field)); constants.insert(F::from(field - 1)); } diff --git a/tooling/noir_js_backend_barretenberg/package.json b/tooling/noir_js_backend_barretenberg/package.json index 06c40d59a6a..aeca5fe543f 100644 --- a/tooling/noir_js_backend_barretenberg/package.json +++ b/tooling/noir_js_backend_barretenberg/package.json @@ -41,7 +41,7 @@ "lint": "NODE_NO_WARNINGS=1 eslint . --ext .ts --ignore-path ./.eslintignore --max-warnings 0" }, "dependencies": { - "@aztec/bb.js": "0.46.1", + "@aztec/bb.js": "0.47.1", "@noir-lang/types": "workspace:*", "fflate": "^0.8.0" }, diff --git a/tooling/profiler/src/cli/gates_flamegraph_cmd.rs b/tooling/profiler/src/cli/gates_flamegraph_cmd.rs index 154ac38f4bb..98e89e42015 100644 --- a/tooling/profiler/src/cli/gates_flamegraph_cmd.rs +++ b/tooling/profiler/src/cli/gates_flamegraph_cmd.rs @@ -19,6 +19,9 @@ pub(crate) struct GatesFlamegraphCommand { #[clap(long, short)] backend_path: String, + #[arg(trailing_var_arg = true, allow_hyphen_values = true)] + backend_extra_args: Vec, + /// The output folder for the flamegraph svg files #[clap(long, short)] output: String, @@ -27,7 +30,10 @@ pub(crate) struct GatesFlamegraphCommand { pub(crate) fn run(args: GatesFlamegraphCommand) -> eyre::Result<()> { run_with_provider( &PathBuf::from(args.artifact_path), - &BackendGatesProvider { backend_path: PathBuf::from(args.backend_path) }, + &BackendGatesProvider { + backend_path: PathBuf::from(args.backend_path), + extra_args: args.backend_extra_args, + }, &InfernoFlamegraphGenerator { count_name: "gates".to_string() }, &PathBuf::from(args.output), ) diff --git a/tooling/profiler/src/gates_provider.rs b/tooling/profiler/src/gates_provider.rs index caed2666426..f96b1292987 100644 --- a/tooling/profiler/src/gates_provider.rs +++ b/tooling/profiler/src/gates_provider.rs @@ -10,12 +10,20 @@ pub(crate) trait GatesProvider { pub(crate) struct BackendGatesProvider { pub(crate) backend_path: PathBuf, + pub(crate) extra_args: Vec, } impl GatesProvider for BackendGatesProvider { fn get_gates(&self, artifact_path: &Path) -> eyre::Result { - let backend_gates_response = - Command::new(&self.backend_path).arg("gates").arg("-b").arg(artifact_path).output()?; + let mut backend_gates_cmd = Command::new(&self.backend_path); + + backend_gates_cmd.arg("gates").arg("-b").arg(artifact_path); + + for arg in &self.extra_args { + backend_gates_cmd.arg(arg); + } + + let backend_gates_response = backend_gates_cmd.output()?; // Parse the backend gates command stdout as json let backend_gates_response: BackendGatesResponse = diff --git a/yarn.lock b/yarn.lock index 5a442d77b30..40d6ccc55e6 100644 --- a/yarn.lock +++ b/yarn.lock @@ -221,9 +221,9 @@ __metadata: languageName: node linkType: hard -"@aztec/bb.js@npm:0.46.1": - version: 0.46.1 - resolution: "@aztec/bb.js@npm:0.46.1" +"@aztec/bb.js@npm:0.47.1": + version: 0.47.1 + resolution: "@aztec/bb.js@npm:0.47.1" dependencies: comlink: ^4.4.1 commander: ^10.0.1 @@ -231,7 +231,7 @@ __metadata: tslib: ^2.4.0 bin: bb.js: dest/node/main.js - checksum: 9475388f994e430ab3282a2c9769cd116f334358049955ed520f467d1abec8237bfeae7fa2fed9cd292f24c09c466e32e2af2d0a5cec2d10cc0c727728d96b0d + checksum: fa06d2ab58b2a23bacc578df7654f5c7eb90553229fc9730aaaf7479bc96b39f10f24a4f3a7eae8f73df3cdd8a3ffb07627cad61dff9896cabdb275ce5b6f09b languageName: node linkType: hard @@ -4161,7 +4161,7 @@ __metadata: version: 0.0.0-use.local resolution: "@noir-lang/backend_barretenberg@workspace:tooling/noir_js_backend_barretenberg" dependencies: - "@aztec/bb.js": 0.46.1 + "@aztec/bb.js": 0.47.1 "@noir-lang/types": "workspace:*" "@types/node": ^20.6.2 "@types/prettier": ^3