From f1b91511124df89bbe9e059b87536901bdf0d6f3 Mon Sep 17 00:00:00 2001 From: AztecBot Date: Wed, 7 Feb 2024 15:56:25 +0000 Subject: [PATCH] chore: Sync to noir-lang/noir feat: Allow nested arrays and vectors in Brillig foreign calls (https://github.com/AztecProtocol/aztec-packages/pull/4478) feat: allow brillig to read arrays directly from memory (https://github.com/AztecProtocol/aztec-packages/pull/4460) feat(avm): back in avm context with macro - refactor context (https://github.com/AztecProtocol/aztec-packages/pull/4438) chore!: rename bigint_neg into bigint_sub (https://github.com/AztecProtocol/aztec-packages/pull/4420) chore: add bigint solver in ACVM and add a unit test for bigints in Noir (https://github.com/AztecProtocol/aztec-packages/pull/4415) feat!: Add expression width into acir (https://github.com/AztecProtocol/aztec-packages/pull/4014) feat: Add bit size to const opcode (https://github.com/AztecProtocol/aztec-packages/pull/4385) feat(aztec-nr): initial work for aztec public vm macro (https://github.com/AztecProtocol/aztec-packages/pull/4400) chore: surpress chained macro warning (https://github.com/AztecProtocol/aztec-packages/pull/4396) feat!: init storage macro (https://github.com/AztecProtocol/aztec-packages/pull/4200) chore(acir)!: Move `is_recursive` flag to be part of the circuit definition (https://github.com/AztecProtocol/aztec-packages/pull/4221) --- acvm-repo/acir/codegen/acir.cpp | 1438 +++++++++++------ .../acir/src/circuit/black_box_functions.rs | 6 +- acvm-repo/acir/src/circuit/brillig.rs | 2 + acvm-repo/acir/src/circuit/mod.rs | 22 +- .../opcodes/black_box_function_call.rs | 8 +- .../src/circuit/opcodes/memory_operation.rs | 2 +- acvm-repo/acir/src/lib.rs | 9 +- .../acir/tests/test_program_serialization.rs | 106 +- acvm-repo/acvm/src/compiler/mod.rs | 4 +- .../compiler/optimizers/redundant_range.rs | 4 +- .../acvm/src/compiler/transformers/mod.rs | 9 +- acvm-repo/acvm/src/lib.rs | 25 - acvm-repo/acvm/src/pwg/blackbox/bigint.rs | 120 ++ acvm-repo/acvm/src/pwg/blackbox/mod.rs | 22 +- acvm-repo/acvm/src/pwg/brillig.rs | 18 +- acvm-repo/acvm/src/pwg/memory_op.rs | 4 +- acvm-repo/acvm/src/pwg/mod.rs | 35 +- acvm-repo/acvm/tests/solver.rs | 13 + acvm-repo/acvm_js/test/shared/addition.ts | 10 +- .../test/shared/complex_foreign_call.ts | 13 +- .../test/shared/fixed_base_scalar_mul.ts | 6 +- acvm-repo/acvm_js/test/shared/foreign_call.ts | 8 +- acvm-repo/acvm_js/test/shared/memory_op.ts | 8 +- acvm-repo/acvm_js/test/shared/pedersen.ts | 4 +- .../acvm_js/test/shared/schnorr_verify.ts | 24 +- acvm-repo/brillig/src/black_box.rs | 2 +- acvm-repo/brillig/src/lib.rs | 4 +- acvm-repo/brillig/src/opcodes.rs | 27 + acvm-repo/brillig_vm/src/black_box.rs | 4 +- acvm-repo/brillig_vm/src/lib.rs | 404 ++++- aztec_macros/src/lib.rs | 441 ++++- compiler/noirc_driver/src/lib.rs | 8 +- .../brillig/brillig_gen/brillig_black_box.rs | 4 +- .../src/brillig/brillig_gen/brillig_block.rs | 64 +- .../brillig/brillig_gen/brillig_directive.rs | 11 +- .../brillig/brillig_gen/brillig_slice_ops.rs | 24 +- .../noirc_evaluator/src/brillig/brillig_ir.rs | 58 +- .../brillig/brillig_ir/brillig_variable.rs | 19 +- .../src/brillig/brillig_ir/debug_show.rs | 4 +- .../src/brillig/brillig_ir/entry_point.rs | 21 +- compiler/noirc_evaluator/src/ssa.rs | 3 +- .../src/ssa/acir_gen/acir_ir/acir_variable.rs | 14 +- .../ssa/acir_gen/acir_ir/generated_acir.rs | 6 +- .../src/ssa/ir/instruction/call.rs | 2 +- compiler/noirc_frontend/src/node_interner.rs | 30 +- compiler/wasm/src/compile.rs | 2 +- compiler/wasm/src/compile_new.rs | 4 +- noir_stdlib/src/bigint.nr | 44 +- noir_stdlib/src/lib.nr | 2 +- .../execution_success/bigint/Nargo.toml | 6 + .../execution_success/bigint/Prover.toml | 2 + .../execution_success/bigint/src/main.nr | 21 + .../execution_success/debug_logs/src/main.nr | 6 + tooling/backend_interface/src/cli/info.rs | 3 +- tooling/backend_interface/src/proof_system.rs | 6 +- .../backend_interface/src/smart_contract.rs | 3 +- tooling/debugger/src/context.rs | 5 +- tooling/lsp/src/requests/profile_run.rs | 2 +- tooling/nargo/src/ops/transform.rs | 2 +- tooling/nargo_cli/src/cli/dap_cmd.rs | 7 +- tooling/nargo_cli/src/cli/info_cmd.rs | 2 +- 61 files changed, 2332 insertions(+), 855 deletions(-) create mode 100644 acvm-repo/acvm/src/pwg/blackbox/bigint.rs create mode 100644 test_programs/execution_success/bigint/Nargo.toml create mode 100644 test_programs/execution_success/bigint/Prover.toml create mode 100644 test_programs/execution_success/bigint/src/main.nr diff --git a/acvm-repo/acir/codegen/acir.cpp b/acvm-repo/acir/codegen/acir.cpp index bdee08794e6..b1c0d12272c 100644 --- a/acvm-repo/acir/codegen/acir.cpp +++ b/acvm-repo/acir/codegen/acir.cpp @@ -5,65 +5,172 @@ namespace Circuit { - struct Witness { - uint32_t value; + struct BinaryFieldOp { - friend bool operator==(const Witness&, const Witness&); - std::vector bincodeSerialize() const; - static Witness bincodeDeserialize(std::vector); - }; + struct Add { + friend bool operator==(const Add&, const Add&); + std::vector bincodeSerialize() const; + static Add bincodeDeserialize(std::vector); + }; - struct FunctionInput { - Circuit::Witness witness; - uint32_t num_bits; + struct Sub { + friend bool operator==(const Sub&, const Sub&); + std::vector bincodeSerialize() const; + static Sub bincodeDeserialize(std::vector); + }; - friend bool operator==(const FunctionInput&, const FunctionInput&); + struct Mul { + friend bool operator==(const Mul&, const Mul&); + std::vector bincodeSerialize() const; + static Mul bincodeDeserialize(std::vector); + }; + + struct Div { + friend bool operator==(const Div&, const Div&); + std::vector bincodeSerialize() const; + static Div bincodeDeserialize(std::vector); + }; + + struct Equals { + friend bool operator==(const Equals&, const Equals&); + std::vector bincodeSerialize() const; + static Equals bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static FunctionInput bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct BlackBoxFuncCall { + struct BinaryIntOp { - struct AND { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + struct Add { + friend bool operator==(const Add&, const Add&); + std::vector bincodeSerialize() const; + static Add bincodeDeserialize(std::vector); + }; - friend bool operator==(const AND&, const AND&); + struct Sub { + friend bool operator==(const Sub&, const Sub&); std::vector bincodeSerialize() const; - static AND bincodeDeserialize(std::vector); + static Sub bincodeDeserialize(std::vector); }; - struct XOR { - Circuit::FunctionInput lhs; - Circuit::FunctionInput rhs; - Circuit::Witness output; + struct Mul { + friend bool operator==(const Mul&, const Mul&); + std::vector bincodeSerialize() const; + static Mul bincodeDeserialize(std::vector); + }; - friend bool operator==(const XOR&, const XOR&); + struct SignedDiv { + friend bool operator==(const SignedDiv&, const SignedDiv&); std::vector bincodeSerialize() const; - static XOR bincodeDeserialize(std::vector); + static SignedDiv bincodeDeserialize(std::vector); }; - struct RANGE { - Circuit::FunctionInput input; + struct UnsignedDiv { + friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); + std::vector bincodeSerialize() const; + static UnsignedDiv bincodeDeserialize(std::vector); + }; - friend bool operator==(const RANGE&, const RANGE&); + struct Equals { + friend bool operator==(const Equals&, const Equals&); std::vector bincodeSerialize() const; - static RANGE bincodeDeserialize(std::vector); + static Equals bincodeDeserialize(std::vector); }; - struct SHA256 { - std::vector inputs; - std::vector outputs; + struct LessThan { + friend bool operator==(const LessThan&, const LessThan&); + std::vector bincodeSerialize() const; + static LessThan bincodeDeserialize(std::vector); + }; - friend bool operator==(const SHA256&, const SHA256&); + struct LessThanEquals { + friend bool operator==(const LessThanEquals&, const LessThanEquals&); std::vector bincodeSerialize() const; - static SHA256 bincodeDeserialize(std::vector); + static LessThanEquals bincodeDeserialize(std::vector); + }; + + struct And { + friend bool operator==(const And&, const And&); + std::vector bincodeSerialize() const; + static And bincodeDeserialize(std::vector); + }; + + struct Or { + friend bool operator==(const Or&, const Or&); + std::vector bincodeSerialize() const; + static Or bincodeDeserialize(std::vector); + }; + + struct Xor { + friend bool operator==(const Xor&, const Xor&); + std::vector bincodeSerialize() const; + static Xor bincodeDeserialize(std::vector); + }; + + struct Shl { + friend bool operator==(const Shl&, const Shl&); + std::vector bincodeSerialize() const; + static Shl bincodeDeserialize(std::vector); + }; + + struct Shr { + friend bool operator==(const Shr&, const Shr&); + std::vector bincodeSerialize() const; + static Shr bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); + std::vector bincodeSerialize() const; + static BinaryIntOp bincodeDeserialize(std::vector); + }; + + struct MemoryAddress { + uint64_t value; + + friend bool operator==(const MemoryAddress&, const MemoryAddress&); + std::vector bincodeSerialize() const; + static MemoryAddress bincodeDeserialize(std::vector); + }; + + struct HeapArray { + Circuit::MemoryAddress pointer; + uint64_t size; + + friend bool operator==(const HeapArray&, const HeapArray&); + std::vector bincodeSerialize() const; + static HeapArray bincodeDeserialize(std::vector); + }; + + struct HeapVector { + Circuit::MemoryAddress pointer; + Circuit::MemoryAddress size; + + friend bool operator==(const HeapVector&, const HeapVector&); + std::vector bincodeSerialize() const; + static HeapVector bincodeDeserialize(std::vector); + }; + + struct BlackBoxOp { + + struct Sha256 { + Circuit::HeapVector message; + Circuit::HeapArray output; + + friend bool operator==(const Sha256&, const Sha256&); + std::vector bincodeSerialize() const; + static Sha256 bincodeDeserialize(std::vector); }; struct Blake2s { - std::vector inputs; - std::vector outputs; + Circuit::HeapVector message; + Circuit::HeapArray output; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -71,52 +178,38 @@ namespace Circuit { }; struct Blake3 { - std::vector inputs; - std::vector outputs; + Circuit::HeapVector message; + Circuit::HeapArray output; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; static Blake3 bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Circuit::FunctionInput public_key_x; - Circuit::FunctionInput public_key_y; - std::vector signature; - std::vector message; - Circuit::Witness output; - - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); - std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); - }; - - struct PedersenCommitment { - std::vector inputs; - uint32_t domain_separator; - std::array outputs; + struct Keccak256 { + Circuit::HeapVector message; + Circuit::HeapArray output; - friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); + friend bool operator==(const Keccak256&, const Keccak256&); std::vector bincodeSerialize() const; - static PedersenCommitment bincodeDeserialize(std::vector); + static Keccak256 bincodeDeserialize(std::vector); }; - struct PedersenHash { - std::vector inputs; - uint32_t domain_separator; - Circuit::Witness output; + struct Keccakf1600 { + Circuit::HeapVector message; + Circuit::HeapArray output; - friend bool operator==(const PedersenHash&, const PedersenHash&); + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static PedersenHash bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; struct EcdsaSecp256k1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + Circuit::HeapVector hashed_msg; + Circuit::HeapArray public_key_x; + Circuit::HeapArray public_key_y; + Circuit::HeapArray signature; + Circuit::MemoryAddress result; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -124,102 +217,95 @@ namespace Circuit { }; struct EcdsaSecp256r1 { - std::vector public_key_x; - std::vector public_key_y; - std::vector signature; - std::vector hashed_message; - Circuit::Witness output; + Circuit::HeapVector hashed_msg; + Circuit::HeapArray public_key_x; + Circuit::HeapArray public_key_y; + Circuit::HeapArray signature; + Circuit::MemoryAddress result; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct FixedBaseScalarMul { - Circuit::FunctionInput low; - Circuit::FunctionInput high; - std::array outputs; - - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); - std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); - }; - - struct EmbeddedCurveAdd { - Circuit::FunctionInput input1_x; - Circuit::FunctionInput input1_y; - Circuit::FunctionInput input2_x; - Circuit::FunctionInput input2_y; - std::array outputs; + struct SchnorrVerify { + Circuit::MemoryAddress public_key_x; + Circuit::MemoryAddress public_key_y; + Circuit::HeapVector message; + Circuit::HeapVector signature; + Circuit::MemoryAddress result; - friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); + friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); std::vector bincodeSerialize() const; - static EmbeddedCurveAdd bincodeDeserialize(std::vector); + static SchnorrVerify bincodeDeserialize(std::vector); }; - struct Keccak256 { - std::vector inputs; - std::vector outputs; + struct PedersenCommitment { + Circuit::HeapVector inputs; + Circuit::MemoryAddress domain_separator; + Circuit::HeapArray output; - friend bool operator==(const Keccak256&, const Keccak256&); + friend bool operator==(const PedersenCommitment&, const PedersenCommitment&); std::vector bincodeSerialize() const; - static Keccak256 bincodeDeserialize(std::vector); + static PedersenCommitment bincodeDeserialize(std::vector); }; - struct Keccak256VariableLength { - std::vector inputs; - Circuit::FunctionInput var_message_size; - std::vector outputs; + struct PedersenHash { + Circuit::HeapVector inputs; + Circuit::MemoryAddress domain_separator; + Circuit::MemoryAddress output; - friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); + friend bool operator==(const PedersenHash&, const PedersenHash&); std::vector bincodeSerialize() const; - static Keccak256VariableLength bincodeDeserialize(std::vector); + static PedersenHash bincodeDeserialize(std::vector); }; - struct Keccakf1600 { - std::vector inputs; - std::vector outputs; + struct FixedBaseScalarMul { + Circuit::MemoryAddress low; + Circuit::MemoryAddress high; + Circuit::HeapArray result; - friend bool operator==(const Keccakf1600&, const Keccakf1600&); + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; - static Keccakf1600 bincodeDeserialize(std::vector); + static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - struct RecursiveAggregation { - std::vector verification_key; - std::vector proof; - std::vector public_inputs; - Circuit::FunctionInput key_hash; + struct EmbeddedCurveAdd { + Circuit::MemoryAddress input1_x; + Circuit::MemoryAddress input1_y; + Circuit::MemoryAddress input2_x; + Circuit::MemoryAddress input2_y; + Circuit::HeapArray result; - friend bool operator==(const RecursiveAggregation&, const RecursiveAggregation&); + friend bool operator==(const EmbeddedCurveAdd&, const EmbeddedCurveAdd&); std::vector bincodeSerialize() const; - static RecursiveAggregation bincodeDeserialize(std::vector); + static EmbeddedCurveAdd bincodeDeserialize(std::vector); }; struct BigIntAdd { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; static BigIntAdd bincodeDeserialize(std::vector); }; - struct BigIntNeg { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + struct BigIntSub { + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; - friend bool operator==(const BigIntNeg&, const BigIntNeg&); + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static BigIntNeg bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; struct BigIntMul { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -227,9 +313,9 @@ namespace Circuit { }; struct BigIntDiv { - uint32_t lhs; - uint32_t rhs; - uint32_t output; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + Circuit::MemoryAddress output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -237,9 +323,9 @@ namespace Circuit { }; struct BigIntFromLeBytes { - std::vector inputs; - std::vector modulus; - uint32_t output; + Circuit::HeapVector inputs; + Circuit::HeapVector modulus; + Circuit::MemoryAddress output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -247,8 +333,8 @@ namespace Circuit { }; struct BigIntToLeBytes { - uint32_t input; - std::vector outputs; + Circuit::MemoryAddress input; + Circuit::HeapVector output; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -256,9 +342,9 @@ namespace Circuit { }; struct Poseidon2Permutation { - std::vector inputs; - std::vector outputs; - uint32_t len; + Circuit::HeapVector message; + Circuit::HeapArray output; + Circuit::MemoryAddress len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; @@ -266,231 +352,310 @@ namespace Circuit { }; struct Sha256Compression { - std::vector inputs; - std::vector hash_values; - std::vector outputs; + Circuit::HeapVector input; + Circuit::HeapVector hash_values; + Circuit::HeapArray output; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; - - friend bool operator==(const BlackBoxFuncCall&, const BlackBoxFuncCall&); - std::vector bincodeSerialize() const; - static BlackBoxFuncCall bincodeDeserialize(std::vector); - }; - - struct BlockId { - uint32_t value; - - friend bool operator==(const BlockId&, const BlockId&); - std::vector bincodeSerialize() const; - static BlockId bincodeDeserialize(std::vector); - }; - - struct Expression { - std::vector> mul_terms; - std::vector> linear_combinations; - std::string q_c; + std::variant value; - friend bool operator==(const Expression&, const Expression&); + friend bool operator==(const BlackBoxOp&, const BlackBoxOp&); std::vector bincodeSerialize() const; - static Expression bincodeDeserialize(std::vector); + static BlackBoxOp bincodeDeserialize(std::vector); }; - struct BrilligInputs { + struct HeapValueType; - struct Single { - Circuit::Expression value; + struct HeapValueType { - friend bool operator==(const Single&, const Single&); + struct Simple { + friend bool operator==(const Simple&, const Simple&); std::vector bincodeSerialize() const; - static Single bincodeDeserialize(std::vector); + static Simple bincodeDeserialize(std::vector); }; struct Array { - std::vector value; + std::vector value_types; + uint64_t size; friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; static Array bincodeDeserialize(std::vector); }; - std::variant value; + struct Vector { + std::vector value_types; - friend bool operator==(const BrilligInputs&, const BrilligInputs&); + friend bool operator==(const Vector&, const Vector&); + std::vector bincodeSerialize() const; + static Vector bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const HeapValueType&, const HeapValueType&); std::vector bincodeSerialize() const; - static BrilligInputs bincodeDeserialize(std::vector); + static HeapValueType bincodeDeserialize(std::vector); }; - struct BinaryFieldOp { + struct Value { + std::string inner; - struct Add { - friend bool operator==(const Add&, const Add&); + friend bool operator==(const Value&, const Value&); + std::vector bincodeSerialize() const; + static Value bincodeDeserialize(std::vector); + }; + + struct ValueOrArray { + + struct MemoryAddress { + Circuit::MemoryAddress value; + + friend bool operator==(const MemoryAddress&, const MemoryAddress&); std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); + static MemoryAddress bincodeDeserialize(std::vector); }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + struct HeapArray { + Circuit::HeapArray value; + + friend bool operator==(const HeapArray&, const HeapArray&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static HeapArray bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct HeapVector { + Circuit::HeapVector value; + + friend bool operator==(const HeapVector&, const HeapVector&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static HeapVector bincodeDeserialize(std::vector); }; - struct Div { - friend bool operator==(const Div&, const Div&); + std::variant value; + + friend bool operator==(const ValueOrArray&, const ValueOrArray&); + std::vector bincodeSerialize() const; + static ValueOrArray bincodeDeserialize(std::vector); + }; + + struct BrilligOpcode { + + struct BinaryFieldOp { + Circuit::MemoryAddress destination; + Circuit::BinaryFieldOp op; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + + friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); std::vector bincodeSerialize() const; - static Div bincodeDeserialize(std::vector); + static BinaryFieldOp bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct BinaryIntOp { + Circuit::MemoryAddress destination; + Circuit::BinaryIntOp op; + uint32_t bit_size; + Circuit::MemoryAddress lhs; + Circuit::MemoryAddress rhs; + + friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static BinaryIntOp bincodeDeserialize(std::vector); }; - std::variant value; + struct JumpIfNot { + Circuit::MemoryAddress condition; + uint64_t location; - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); - std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); - }; + friend bool operator==(const JumpIfNot&, const JumpIfNot&); + std::vector bincodeSerialize() const; + static JumpIfNot bincodeDeserialize(std::vector); + }; - struct BinaryIntOp { + struct JumpIf { + Circuit::MemoryAddress condition; + uint64_t location; - struct Add { - friend bool operator==(const Add&, const Add&); + friend bool operator==(const JumpIf&, const JumpIf&); std::vector bincodeSerialize() const; - static Add bincodeDeserialize(std::vector); + static JumpIf bincodeDeserialize(std::vector); }; - struct Sub { - friend bool operator==(const Sub&, const Sub&); + struct Jump { + uint64_t location; + + friend bool operator==(const Jump&, const Jump&); std::vector bincodeSerialize() const; - static Sub bincodeDeserialize(std::vector); + static Jump bincodeDeserialize(std::vector); }; - struct Mul { - friend bool operator==(const Mul&, const Mul&); + struct CalldataCopy { + Circuit::MemoryAddress destination_address; + uint64_t size; + uint64_t offset; + + friend bool operator==(const CalldataCopy&, const CalldataCopy&); std::vector bincodeSerialize() const; - static Mul bincodeDeserialize(std::vector); + static CalldataCopy bincodeDeserialize(std::vector); }; - struct SignedDiv { - friend bool operator==(const SignedDiv&, const SignedDiv&); + struct Call { + uint64_t location; + + friend bool operator==(const Call&, const Call&); std::vector bincodeSerialize() const; - static SignedDiv bincodeDeserialize(std::vector); + static Call bincodeDeserialize(std::vector); }; - struct UnsignedDiv { - friend bool operator==(const UnsignedDiv&, const UnsignedDiv&); + struct Const { + Circuit::MemoryAddress destination; + uint32_t bit_size; + Circuit::Value value; + + friend bool operator==(const Const&, const Const&); std::vector bincodeSerialize() const; - static UnsignedDiv bincodeDeserialize(std::vector); + static Const bincodeDeserialize(std::vector); }; - struct Equals { - friend bool operator==(const Equals&, const Equals&); + struct Return { + friend bool operator==(const Return&, const Return&); std::vector bincodeSerialize() const; - static Equals bincodeDeserialize(std::vector); + static Return bincodeDeserialize(std::vector); }; - struct LessThan { - friend bool operator==(const LessThan&, const LessThan&); + 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 LessThan bincodeDeserialize(std::vector); + static ForeignCall bincodeDeserialize(std::vector); }; - struct LessThanEquals { - friend bool operator==(const LessThanEquals&, const LessThanEquals&); + struct Mov { + Circuit::MemoryAddress destination; + Circuit::MemoryAddress source; + + friend bool operator==(const Mov&, const Mov&); std::vector bincodeSerialize() const; - static LessThanEquals bincodeDeserialize(std::vector); + static Mov bincodeDeserialize(std::vector); }; - struct And { - friend bool operator==(const And&, const And&); + struct Load { + Circuit::MemoryAddress destination; + Circuit::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 { + Circuit::MemoryAddress destination_pointer; + Circuit::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 { + Circuit::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 { + 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 { - Circuit::MemoryAddress pointer; - uint64_t size; + struct FunctionInput { + Circuit::Witness witness; + uint32_t num_bits; - friend bool operator==(const HeapArray&, const HeapArray&); + friend bool operator==(const FunctionInput&, const FunctionInput&); std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); + static FunctionInput bincodeDeserialize(std::vector); }; - struct HeapVector { - Circuit::MemoryAddress pointer; - Circuit::MemoryAddress size; + struct BlackBoxFuncCall { - friend bool operator==(const HeapVector&, const HeapVector&); - std::vector bincodeSerialize() const; - static HeapVector bincodeDeserialize(std::vector); - }; + struct AND { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; - struct BlackBoxOp { + friend bool operator==(const AND&, const AND&); + std::vector bincodeSerialize() const; + static AND bincodeDeserialize(std::vector); + }; - struct Sha256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct XOR { + Circuit::FunctionInput lhs; + Circuit::FunctionInput rhs; + Circuit::Witness output; - friend bool operator==(const Sha256&, const Sha256&); + friend bool operator==(const XOR&, const XOR&); std::vector bincodeSerialize() const; - static Sha256 bincodeDeserialize(std::vector); + static XOR bincodeDeserialize(std::vector); + }; + + struct RANGE { + Circuit::FunctionInput input; + + friend bool operator==(const RANGE&, const RANGE&); + std::vector bincodeSerialize() const; + static RANGE bincodeDeserialize(std::vector); + }; + + struct SHA256 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const SHA256&, const SHA256&); + std::vector bincodeSerialize() const; + static SHA256 bincodeDeserialize(std::vector); }; struct Blake2s { - Circuit::HeapVector message; - Circuit::HeapArray output; + std::vector inputs; + std::vector outputs; friend bool operator==(const Blake2s&, const Blake2s&); std::vector bincodeSerialize() const; @@ -498,38 +663,52 @@ namespace Circuit { }; struct Blake3 { - Circuit::HeapVector message; - Circuit::HeapArray output; + std::vector inputs; + std::vector outputs; friend bool operator==(const Blake3&, const Blake3&); std::vector bincodeSerialize() const; static Blake3 bincodeDeserialize(std::vector); }; - struct Keccak256 { - Circuit::HeapVector message; - Circuit::HeapArray output; + struct SchnorrVerify { + Circuit::FunctionInput public_key_x; + Circuit::FunctionInput public_key_y; + std::vector signature; + std::vector message; + Circuit::Witness output; - friend bool operator==(const 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 { - Circuit::HeapVector message; - Circuit::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; + Circuit::Witness output; + + friend bool operator==(const PedersenHash&, const PedersenHash&); + std::vector bincodeSerialize() const; + static PedersenHash bincodeDeserialize(std::vector); }; struct EcdsaSecp256k1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::MemoryAddress result; + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; friend bool operator==(const EcdsaSecp256k1&, const EcdsaSecp256k1&); std::vector bincodeSerialize() const; @@ -537,95 +716,102 @@ namespace Circuit { }; struct EcdsaSecp256r1 { - Circuit::HeapVector hashed_msg; - Circuit::HeapArray public_key_x; - Circuit::HeapArray public_key_y; - Circuit::HeapArray signature; - Circuit::MemoryAddress result; + std::vector public_key_x; + std::vector public_key_y; + std::vector signature; + std::vector hashed_message; + Circuit::Witness output; friend bool operator==(const EcdsaSecp256r1&, const EcdsaSecp256r1&); std::vector bincodeSerialize() const; static EcdsaSecp256r1 bincodeDeserialize(std::vector); }; - struct SchnorrVerify { - Circuit::MemoryAddress public_key_x; - Circuit::MemoryAddress public_key_y; - Circuit::HeapVector message; - Circuit::HeapVector signature; - Circuit::MemoryAddress result; + struct FixedBaseScalarMul { + Circuit::FunctionInput low; + Circuit::FunctionInput high; + std::array outputs; - friend bool operator==(const SchnorrVerify&, const SchnorrVerify&); + friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); std::vector bincodeSerialize() const; - static SchnorrVerify bincodeDeserialize(std::vector); + static FixedBaseScalarMul bincodeDeserialize(std::vector); }; - struct PedersenCommitment { - Circuit::HeapVector inputs; - Circuit::MemoryAddress domain_separator; - Circuit::HeapArray output; + struct EmbeddedCurveAdd { + Circuit::FunctionInput input1_x; + Circuit::FunctionInput input1_y; + Circuit::FunctionInput input2_x; + Circuit::FunctionInput input2_y; + std::array outputs; - friend bool operator==(const 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 { - Circuit::HeapVector inputs; - Circuit::MemoryAddress domain_separator; - Circuit::MemoryAddress output; + struct Keccak256 { + std::vector inputs; + std::vector 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 FixedBaseScalarMul { - Circuit::MemoryAddress low; - Circuit::MemoryAddress high; - Circuit::HeapArray result; + struct Keccak256VariableLength { + std::vector inputs; + Circuit::FunctionInput var_message_size; + std::vector outputs; + + friend bool operator==(const Keccak256VariableLength&, const Keccak256VariableLength&); + std::vector bincodeSerialize() const; + static Keccak256VariableLength bincodeDeserialize(std::vector); + }; - friend bool operator==(const FixedBaseScalarMul&, const FixedBaseScalarMul&); + struct Keccakf1600 { + std::vector inputs; + std::vector outputs; + + friend bool operator==(const Keccakf1600&, const Keccakf1600&); std::vector bincodeSerialize() const; - static FixedBaseScalarMul bincodeDeserialize(std::vector); + static Keccakf1600 bincodeDeserialize(std::vector); }; - struct EmbeddedCurveAdd { - Circuit::MemoryAddress input1_x; - Circuit::MemoryAddress input1_y; - Circuit::MemoryAddress input2_x; - Circuit::MemoryAddress input2_y; - Circuit::HeapArray result; + struct RecursiveAggregation { + std::vector verification_key; + std::vector proof; + std::vector public_inputs; + Circuit::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 { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntAdd&, const BigIntAdd&); std::vector bincodeSerialize() const; static BigIntAdd bincodeDeserialize(std::vector); }; - struct BigIntNeg { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + struct BigIntSub { + uint32_t lhs; + uint32_t rhs; + uint32_t output; - friend bool operator==(const BigIntNeg&, const BigIntNeg&); + friend bool operator==(const BigIntSub&, const BigIntSub&); std::vector bincodeSerialize() const; - static BigIntNeg bincodeDeserialize(std::vector); + static BigIntSub bincodeDeserialize(std::vector); }; struct BigIntMul { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntMul&, const BigIntMul&); std::vector bincodeSerialize() const; @@ -633,9 +819,9 @@ namespace Circuit { }; struct BigIntDiv { - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - Circuit::MemoryAddress output; + uint32_t lhs; + uint32_t rhs; + uint32_t output; friend bool operator==(const BigIntDiv&, const BigIntDiv&); std::vector bincodeSerialize() const; @@ -643,9 +829,9 @@ namespace Circuit { }; struct BigIntFromLeBytes { - Circuit::HeapVector inputs; - Circuit::HeapVector modulus; - Circuit::MemoryAddress output; + std::vector inputs; + std::vector modulus; + uint32_t output; friend bool operator==(const BigIntFromLeBytes&, const BigIntFromLeBytes&); std::vector bincodeSerialize() const; @@ -653,8 +839,8 @@ namespace Circuit { }; struct BigIntToLeBytes { - Circuit::MemoryAddress input; - Circuit::HeapVector output; + uint32_t input; + std::vector outputs; friend bool operator==(const BigIntToLeBytes&, const BigIntToLeBytes&); std::vector bincodeSerialize() const; @@ -662,9 +848,9 @@ namespace Circuit { }; struct Poseidon2Permutation { - Circuit::HeapVector message; - Circuit::HeapArray output; - Circuit::MemoryAddress len; + std::vector inputs; + std::vector outputs; + uint32_t len; friend bool operator==(const Poseidon2Permutation&, const Poseidon2Permutation&); std::vector bincodeSerialize() const; @@ -672,212 +858,71 @@ namespace Circuit { }; struct Sha256Compression { - Circuit::HeapVector input; - Circuit::HeapVector hash_values; - Circuit::HeapArray output; + std::vector inputs; + std::vector hash_values; + std::vector outputs; friend bool operator==(const Sha256Compression&, const Sha256Compression&); std::vector bincodeSerialize() const; static Sha256Compression bincodeDeserialize(std::vector); }; - std::variant value; + 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 Value { - std::string inner; + struct BlockId { + uint32_t value; - friend bool operator==(const Value&, const Value&); + friend bool operator==(const BlockId&, const BlockId&); std::vector bincodeSerialize() const; - static Value bincodeDeserialize(std::vector); + static BlockId bincodeDeserialize(std::vector); }; - struct ValueOrArray { - - struct MemoryAddress { - Circuit::MemoryAddress value; - - friend bool operator==(const MemoryAddress&, const MemoryAddress&); - std::vector bincodeSerialize() const; - static MemoryAddress bincodeDeserialize(std::vector); - }; - - struct HeapArray { - Circuit::HeapArray value; - - friend bool operator==(const HeapArray&, const HeapArray&); - std::vector bincodeSerialize() const; - static HeapArray bincodeDeserialize(std::vector); - }; - - struct HeapVector { - Circuit::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 BinaryFieldOp { - Circuit::MemoryAddress destination; - Circuit::BinaryFieldOp op; - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - - friend bool operator==(const BinaryFieldOp&, const BinaryFieldOp&); - std::vector bincodeSerialize() const; - static BinaryFieldOp bincodeDeserialize(std::vector); - }; - - struct BinaryIntOp { - Circuit::MemoryAddress destination; - Circuit::BinaryIntOp op; - uint32_t bit_size; - Circuit::MemoryAddress lhs; - Circuit::MemoryAddress rhs; - - friend bool operator==(const BinaryIntOp&, const BinaryIntOp&); - std::vector bincodeSerialize() const; - static BinaryIntOp bincodeDeserialize(std::vector); - }; - - struct JumpIfNot { - Circuit::MemoryAddress condition; - uint64_t location; - - friend bool operator==(const JumpIfNot&, const JumpIfNot&); - std::vector bincodeSerialize() const; - static JumpIfNot bincodeDeserialize(std::vector); - }; - - struct JumpIf { - Circuit::MemoryAddress condition; - uint64_t location; - - friend bool operator==(const JumpIf&, const JumpIf&); - std::vector bincodeSerialize() const; - static JumpIf bincodeDeserialize(std::vector); - }; - - struct Jump { - uint64_t location; - - friend bool operator==(const Jump&, const Jump&); - std::vector bincodeSerialize() const; - static Jump bincodeDeserialize(std::vector); - }; - - struct CalldataCopy { - Circuit::MemoryAddress destination_address; - uint64_t size; - uint64_t offset; - - friend bool operator==(const CalldataCopy&, const CalldataCopy&); - std::vector bincodeSerialize() const; - static CalldataCopy bincodeDeserialize(std::vector); - }; - - struct Call { - uint64_t location; - - friend bool operator==(const Call&, const Call&); - std::vector bincodeSerialize() const; - static Call bincodeDeserialize(std::vector); - }; - - struct Const { - Circuit::MemoryAddress destination; - Circuit::Value value; - - friend bool operator==(const Const&, const Const&); - std::vector bincodeSerialize() const; - static Const bincodeDeserialize(std::vector); - }; - - struct Return { - friend bool operator==(const Return&, const Return&); - std::vector bincodeSerialize() const; - static Return bincodeDeserialize(std::vector); - }; - - struct ForeignCall { - std::string function; - std::vector destinations; - std::vector inputs; - - friend bool operator==(const ForeignCall&, const ForeignCall&); - std::vector bincodeSerialize() const; - static ForeignCall bincodeDeserialize(std::vector); - }; - - struct Mov { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source; - - friend bool operator==(const Mov&, const Mov&); - std::vector bincodeSerialize() const; - static Mov bincodeDeserialize(std::vector); - }; - - struct Load { - Circuit::MemoryAddress destination; - Circuit::MemoryAddress source_pointer; - - friend bool operator==(const Load&, const Load&); - std::vector bincodeSerialize() const; - static Load bincodeDeserialize(std::vector); - }; + struct BrilligInputs { - struct Store { - Circuit::MemoryAddress destination_pointer; - Circuit::MemoryAddress source; + struct Single { + Circuit::Expression value; - friend bool operator==(const Store&, const Store&); + friend bool operator==(const Single&, const Single&); std::vector bincodeSerialize() const; - static Store bincodeDeserialize(std::vector); + static Single bincodeDeserialize(std::vector); }; - struct BlackBox { - Circuit::BlackBoxOp value; - - friend bool operator==(const BlackBox&, const BlackBox&); - std::vector bincodeSerialize() const; - static BlackBox bincodeDeserialize(std::vector); - }; + struct Array { + std::vector value; - struct Trap { - friend bool operator==(const Trap&, const Trap&); + friend bool operator==(const Array&, const Array&); std::vector bincodeSerialize() const; - static Trap bincodeDeserialize(std::vector); + static Array bincodeDeserialize(std::vector); }; - struct Stop { - uint64_t return_data_offset; - uint64_t return_data_size; + struct MemoryArray { + Circuit::BlockId value; - friend bool operator==(const Stop&, const Stop&); + friend bool operator==(const MemoryArray&, const MemoryArray&); std::vector bincodeSerialize() const; - static Stop bincodeDeserialize(std::vector); + static MemoryArray bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; - friend bool operator==(const BrilligOpcode&, const BrilligOpcode&); + friend bool operator==(const BrilligInputs&, const BrilligInputs&); std::vector bincodeSerialize() const; - static BrilligOpcode bincodeDeserialize(std::vector); + static BrilligInputs bincodeDeserialize(std::vector); }; struct BrilligOutputs { @@ -1016,6 +1061,29 @@ namespace Circuit { static Opcode bincodeDeserialize(std::vector); }; + struct ExpressionWidth { + + struct Unbounded { + friend bool operator==(const Unbounded&, const Unbounded&); + std::vector bincodeSerialize() const; + static Unbounded bincodeDeserialize(std::vector); + }; + + struct Bounded { + uint64_t width; + + friend bool operator==(const Bounded&, const Bounded&); + std::vector bincodeSerialize() const; + static Bounded bincodeDeserialize(std::vector); + }; + + std::variant value; + + friend bool operator==(const ExpressionWidth&, const ExpressionWidth&); + std::vector bincodeSerialize() const; + static ExpressionWidth bincodeDeserialize(std::vector); + }; + struct OpcodeLocation { struct Acir { @@ -1053,6 +1121,7 @@ namespace Circuit { struct Circuit { uint32_t current_witness_index; std::vector opcodes; + Circuit::ExpressionWidth expression_width; std::vector private_parameters; Circuit::PublicInputs public_parameters; Circuit::PublicInputs return_values; @@ -2623,22 +2692,22 @@ Circuit::BlackBoxFuncCall::BigIntAdd serde::Deserializable BlackBoxFuncCall::BigIntNeg::bincodeSerialize() const { + inline std::vector BlackBoxFuncCall::BigIntSub::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxFuncCall::BigIntNeg BlackBoxFuncCall::BigIntNeg::bincodeDeserialize(std::vector input) { + inline BlackBoxFuncCall::BigIntSub BlackBoxFuncCall::BigIntSub::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"); } @@ -2649,7 +2718,7 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntNeg &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxFuncCall::BigIntSub &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -2657,8 +2726,8 @@ void serde::Serializable::serialize(const template <> template -Circuit::BlackBoxFuncCall::BigIntNeg serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxFuncCall::BigIntNeg obj; +Circuit::BlackBoxFuncCall::BigIntSub serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxFuncCall::BigIntSub obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); @@ -3551,22 +3620,22 @@ Circuit::BlackBoxOp::BigIntAdd serde::Deserializable BlackBoxOp::BigIntNeg::bincodeSerialize() const { + inline std::vector BlackBoxOp::BigIntSub::bincodeSerialize() const { auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); + serde::Serializable::serialize(*this, serializer); return std::move(serializer).bytes(); } - inline BlackBoxOp::BigIntNeg BlackBoxOp::BigIntNeg::bincodeDeserialize(std::vector input) { + inline BlackBoxOp::BigIntSub BlackBoxOp::BigIntSub::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"); } @@ -3577,7 +3646,7 @@ namespace Circuit { template <> template -void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntNeg &obj, Serializer &serializer) { +void serde::Serializable::serialize(const Circuit::BlackBoxOp::BigIntSub &obj, Serializer &serializer) { serde::Serializable::serialize(obj.lhs, serializer); serde::Serializable::serialize(obj.rhs, serializer); serde::Serializable::serialize(obj.output, serializer); @@ -3585,8 +3654,8 @@ void serde::Serializable::serialize(const Circui template <> template -Circuit::BlackBoxOp::BigIntNeg serde::Deserializable::deserialize(Deserializer &deserializer) { - Circuit::BlackBoxOp::BigIntNeg obj; +Circuit::BlackBoxOp::BigIntSub serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BlackBoxOp::BigIntSub obj; obj.lhs = serde::Deserializable::deserialize(deserializer); obj.rhs = serde::Deserializable::deserialize(deserializer); obj.output = serde::Deserializable::deserialize(deserializer); @@ -4065,6 +4134,44 @@ Circuit::BrilligInputs::Array serde::Deserializable BrilligInputs::MemoryArray::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline BrilligInputs::MemoryArray BrilligInputs::MemoryArray::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::BrilligInputs::MemoryArray &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value, serializer); +} + +template <> +template +Circuit::BrilligInputs::MemoryArray serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::BrilligInputs::MemoryArray obj; + obj.value = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const BrilligOpcode &lhs, const BrilligOpcode &rhs) { @@ -4410,6 +4517,7 @@ namespace Circuit { inline bool operator==(const BrilligOpcode::Const &lhs, const BrilligOpcode::Const &rhs) { if (!(lhs.destination == rhs.destination)) { return false; } + if (!(lhs.bit_size == rhs.bit_size)) { return false; } if (!(lhs.value == rhs.value)) { return false; } return true; } @@ -4435,6 +4543,7 @@ template <> template void serde::Serializable::serialize(const Circuit::BrilligOpcode::Const &obj, Serializer &serializer) { serde::Serializable::serialize(obj.destination, serializer); + serde::Serializable::serialize(obj.bit_size, serializer); serde::Serializable::serialize(obj.value, serializer); } @@ -4443,6 +4552,7 @@ template Circuit::BrilligOpcode::Const serde::Deserializable::deserialize(Deserializer &deserializer) { Circuit::BrilligOpcode::Const obj; obj.destination = serde::Deserializable::deserialize(deserializer); + obj.bit_size = serde::Deserializable::deserialize(deserializer); obj.value = serde::Deserializable::deserialize(deserializer); return obj; } @@ -4487,7 +4597,9 @@ namespace Circuit { inline bool operator==(const BrilligOpcode::ForeignCall &lhs, const BrilligOpcode::ForeignCall &rhs) { if (!(lhs.function == rhs.function)) { return false; } if (!(lhs.destinations == rhs.destinations)) { return false; } + if (!(lhs.destination_value_types == rhs.destination_value_types)) { return false; } if (!(lhs.inputs == rhs.inputs)) { return false; } + if (!(lhs.input_value_types == rhs.input_value_types)) { return false; } return true; } @@ -4513,7 +4625,9 @@ template void serde::Serializable::serialize(const Circuit::BrilligOpcode::ForeignCall &obj, Serializer &serializer) { serde::Serializable::serialize(obj.function, serializer); serde::Serializable::serialize(obj.destinations, serializer); + serde::Serializable::serialize(obj.destination_value_types, serializer); serde::Serializable::serialize(obj.inputs, serializer); + serde::Serializable::serialize(obj.input_value_types, serializer); } template <> @@ -4522,7 +4636,9 @@ Circuit::BrilligOpcode::ForeignCall serde::Deserializable::deserialize(deserializer); obj.destinations = serde::Deserializable::deserialize(deserializer); + obj.destination_value_types = serde::Deserializable::deserialize(deserializer); obj.inputs = serde::Deserializable::deserialize(deserializer); + obj.input_value_types = serde::Deserializable::deserialize(deserializer); return obj; } @@ -4886,6 +5002,7 @@ namespace Circuit { inline bool operator==(const Circuit &lhs, const Circuit &rhs) { if (!(lhs.current_witness_index == rhs.current_witness_index)) { return false; } if (!(lhs.opcodes == rhs.opcodes)) { return false; } + if (!(lhs.expression_width == rhs.expression_width)) { return false; } if (!(lhs.private_parameters == rhs.private_parameters)) { return false; } if (!(lhs.public_parameters == rhs.public_parameters)) { return false; } if (!(lhs.return_values == rhs.return_values)) { return false; } @@ -4917,6 +5034,7 @@ void serde::Serializable::serialize(const Circuit::Circuit &ob serializer.increase_container_depth(); serde::Serializable::serialize(obj.current_witness_index, serializer); serde::Serializable::serialize(obj.opcodes, serializer); + serde::Serializable::serialize(obj.expression_width, serializer); serde::Serializable::serialize(obj.private_parameters, serializer); serde::Serializable::serialize(obj.public_parameters, serializer); serde::Serializable::serialize(obj.return_values, serializer); @@ -4932,6 +5050,7 @@ Circuit::Circuit serde::Deserializable::deserialize(Deserializ Circuit::Circuit obj; obj.current_witness_index = serde::Deserializable::deserialize(deserializer); obj.opcodes = serde::Deserializable::deserialize(deserializer); + obj.expression_width = serde::Deserializable::deserialize(deserializer); obj.private_parameters = serde::Deserializable::deserialize(deserializer); obj.public_parameters = serde::Deserializable::deserialize(deserializer); obj.return_values = serde::Deserializable::deserialize(deserializer); @@ -5122,6 +5241,121 @@ Circuit::Expression serde::Deserializable::deserialize(Dese return obj; } +namespace Circuit { + + inline bool operator==(const ExpressionWidth &lhs, const ExpressionWidth &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector ExpressionWidth::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline ExpressionWidth ExpressionWidth::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::ExpressionWidth &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Circuit::ExpressionWidth serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::ExpressionWidth obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Circuit { + + inline bool operator==(const ExpressionWidth::Unbounded &lhs, const ExpressionWidth::Unbounded &rhs) { + return true; + } + + inline std::vector ExpressionWidth::Unbounded::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline ExpressionWidth::Unbounded ExpressionWidth::Unbounded::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::ExpressionWidth::Unbounded &obj, Serializer &serializer) { +} + +template <> +template +Circuit::ExpressionWidth::Unbounded serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::ExpressionWidth::Unbounded obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const ExpressionWidth::Bounded &lhs, const ExpressionWidth::Bounded &rhs) { + if (!(lhs.width == rhs.width)) { return false; } + return true; + } + + inline std::vector ExpressionWidth::Bounded::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline ExpressionWidth::Bounded ExpressionWidth::Bounded::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::ExpressionWidth::Bounded &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.width, serializer); +} + +template <> +template +Circuit::ExpressionWidth::Bounded serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::ExpressionWidth::Bounded obj; + obj.width = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const FunctionInput &lhs, const FunctionInput &rhs) { @@ -5212,6 +5446,162 @@ Circuit::HeapArray serde::Deserializable::deserialize(Deseri return obj; } +namespace Circuit { + + inline bool operator==(const HeapValueType &lhs, const HeapValueType &rhs) { + if (!(lhs.value == rhs.value)) { return false; } + return true; + } + + inline std::vector HeapValueType::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType HeapValueType::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType &obj, Serializer &serializer) { + serializer.increase_container_depth(); + serde::Serializable::serialize(obj.value, serializer); + serializer.decrease_container_depth(); +} + +template <> +template +Circuit::HeapValueType serde::Deserializable::deserialize(Deserializer &deserializer) { + deserializer.increase_container_depth(); + Circuit::HeapValueType obj; + obj.value = serde::Deserializable::deserialize(deserializer); + deserializer.decrease_container_depth(); + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Simple &lhs, const HeapValueType::Simple &rhs) { + return true; + } + + inline std::vector HeapValueType::Simple::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Simple HeapValueType::Simple::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Simple &obj, Serializer &serializer) { +} + +template <> +template +Circuit::HeapValueType::Simple serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Simple obj; + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Array &lhs, const HeapValueType::Array &rhs) { + if (!(lhs.value_types == rhs.value_types)) { return false; } + if (!(lhs.size == rhs.size)) { return false; } + return true; + } + + inline std::vector HeapValueType::Array::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Array HeapValueType::Array::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Array &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value_types, serializer); + serde::Serializable::serialize(obj.size, serializer); +} + +template <> +template +Circuit::HeapValueType::Array serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Array obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); + obj.size = serde::Deserializable::deserialize(deserializer); + return obj; +} + +namespace Circuit { + + inline bool operator==(const HeapValueType::Vector &lhs, const HeapValueType::Vector &rhs) { + if (!(lhs.value_types == rhs.value_types)) { return false; } + return true; + } + + inline std::vector HeapValueType::Vector::bincodeSerialize() const { + auto serializer = serde::BincodeSerializer(); + serde::Serializable::serialize(*this, serializer); + return std::move(serializer).bytes(); + } + + inline HeapValueType::Vector HeapValueType::Vector::bincodeDeserialize(std::vector input) { + auto deserializer = serde::BincodeDeserializer(input); + auto value = serde::Deserializable::deserialize(deserializer); + if (deserializer.get_buffer_offset() < input.size()) { + throw serde::deserialization_error("Some input bytes were not read"); + } + return value; + } + +} // end of namespace Circuit + +template <> +template +void serde::Serializable::serialize(const Circuit::HeapValueType::Vector &obj, Serializer &serializer) { + serde::Serializable::serialize(obj.value_types, serializer); +} + +template <> +template +Circuit::HeapValueType::Vector serde::Deserializable::deserialize(Deserializer &deserializer) { + Circuit::HeapValueType::Vector obj; + obj.value_types = serde::Deserializable::deserialize(deserializer); + return obj; +} + namespace Circuit { inline bool operator==(const HeapVector &lhs, const HeapVector &rhs) { diff --git a/acvm-repo/acir/src/circuit/black_box_functions.rs b/acvm-repo/acir/src/circuit/black_box_functions.rs index 97b4759d350..0a7ee244a5e 100644 --- a/acvm-repo/acir/src/circuit/black_box_functions.rs +++ b/acvm-repo/acir/src/circuit/black_box_functions.rs @@ -50,7 +50,7 @@ pub enum BlackBoxFunc { /// BigInt addition BigIntAdd, /// BigInt subtraction - BigIntNeg, + BigIntSub, /// BigInt multiplication BigIntMul, /// BigInt division @@ -91,7 +91,7 @@ impl BlackBoxFunc { BlackBoxFunc::RecursiveAggregation => "recursive_aggregation", BlackBoxFunc::EcdsaSecp256r1 => "ecdsa_secp256r1", BlackBoxFunc::BigIntAdd => "bigint_add", - BlackBoxFunc::BigIntNeg => "bigint_neg", + BlackBoxFunc::BigIntSub => "bigint_sub", BlackBoxFunc::BigIntMul => "bigint_mul", BlackBoxFunc::BigIntDiv => "bigint_div", BlackBoxFunc::BigIntFromLeBytes => "bigint_from_le_bytes", @@ -120,7 +120,7 @@ impl BlackBoxFunc { "keccakf1600" => Some(BlackBoxFunc::Keccakf1600), "recursive_aggregation" => Some(BlackBoxFunc::RecursiveAggregation), "bigint_add" => Some(BlackBoxFunc::BigIntAdd), - "bigint_neg" => Some(BlackBoxFunc::BigIntNeg), + "bigint_sub" => Some(BlackBoxFunc::BigIntSub), "bigint_mul" => Some(BlackBoxFunc::BigIntMul), "bigint_div" => Some(BlackBoxFunc::BigIntDiv), "bigint_from_le_bytes" => Some(BlackBoxFunc::BigIntFromLeBytes), diff --git a/acvm-repo/acir/src/circuit/brillig.rs b/acvm-repo/acir/src/circuit/brillig.rs index 63c6ad2a3d4..f394a46ff82 100644 --- a/acvm-repo/acir/src/circuit/brillig.rs +++ b/acvm-repo/acir/src/circuit/brillig.rs @@ -1,3 +1,4 @@ +use super::opcodes::BlockId; use crate::native_types::{Expression, Witness}; use brillig::Opcode as BrilligOpcode; use serde::{Deserialize, Serialize}; @@ -8,6 +9,7 @@ use serde::{Deserialize, Serialize}; pub enum BrilligInputs { Single(Expression), Array(Vec), + MemoryArray(BlockId), } /// Outputs for the Brillig VM. Once the VM has completed diff --git a/acvm-repo/acir/src/circuit/mod.rs b/acvm-repo/acir/src/circuit/mod.rs index ccfb19bbf05..9cbacdc2ab0 100644 --- a/acvm-repo/acir/src/circuit/mod.rs +++ b/acvm-repo/acir/src/circuit/mod.rs @@ -15,12 +15,30 @@ use serde::{de::Error as DeserializationError, Deserialize, Deserializer, Serial use std::collections::BTreeSet; +/// Specifies the maximum width of the expressions which will be constrained. +/// +/// Unbounded Expressions are useful if you are eventually going to pass the ACIR +/// into a proving system which supports R1CS. +/// +/// Bounded Expressions are useful if you are eventually going to pass the ACIR +/// into a proving system which supports PLONK, where arithmetic expressions have a +/// finite fan-in. +#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize, Default)] +pub enum ExpressionWidth { + #[default] + Unbounded, + Bounded { + width: usize, + }, +} + #[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Default)] pub struct Circuit { // current_witness_index is the highest witness index in the circuit. The next witness to be added to this circuit // will take on this value. (The value is cached here as an optimization.) pub current_witness_index: u32, pub opcodes: Vec, + pub expression_width: ExpressionWidth, /// The set of private inputs to the circuit. pub private_parameters: BTreeSet, @@ -240,7 +258,7 @@ mod tests { opcodes::{BlackBoxFuncCall, FunctionInput}, Circuit, Compression, Opcode, PublicInputs, }; - use crate::native_types::Witness; + use crate::{circuit::ExpressionWidth, native_types::Witness}; use acir_field::FieldElement; fn and_opcode() -> Opcode { @@ -318,6 +336,7 @@ mod tests { fn serialization_roundtrip() { let circuit = Circuit { current_witness_index: 5, + expression_width: ExpressionWidth::Unbounded, opcodes: vec![and_opcode(), range_opcode()], private_parameters: BTreeSet::new(), public_parameters: PublicInputs(BTreeSet::from_iter(vec![Witness(2), Witness(12)])), @@ -340,6 +359,7 @@ mod tests { fn test_serialize() { let circuit = Circuit { current_witness_index: 0, + expression_width: ExpressionWidth::Unbounded, opcodes: vec![ Opcode::AssertZero(crate::native_types::Expression { mul_terms: vec![], diff --git a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs index ba4964c8912..f73417a4b5b 100644 --- a/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs +++ b/acvm-repo/acir/src/circuit/opcodes/black_box_function_call.rs @@ -120,7 +120,7 @@ pub enum BlackBoxFuncCall { rhs: u32, output: u32, }, - BigIntNeg { + BigIntSub { lhs: u32, rhs: u32, output: u32, @@ -193,7 +193,7 @@ impl BlackBoxFuncCall { BlackBoxFuncCall::Keccakf1600 { .. } => BlackBoxFunc::Keccakf1600, BlackBoxFuncCall::RecursiveAggregation { .. } => BlackBoxFunc::RecursiveAggregation, BlackBoxFuncCall::BigIntAdd { .. } => BlackBoxFunc::BigIntAdd, - BlackBoxFuncCall::BigIntNeg { .. } => BlackBoxFunc::BigIntNeg, + BlackBoxFuncCall::BigIntSub { .. } => BlackBoxFunc::BigIntSub, BlackBoxFuncCall::BigIntMul { .. } => BlackBoxFunc::BigIntMul, BlackBoxFuncCall::BigIntDiv { .. } => BlackBoxFunc::BigIntDiv, BlackBoxFuncCall::BigIntFromLeBytes { .. } => BlackBoxFunc::BigIntFromLeBytes, @@ -223,7 +223,7 @@ impl BlackBoxFuncCall { vec![*lhs, *rhs] } BlackBoxFuncCall::BigIntAdd { .. } - | BlackBoxFuncCall::BigIntNeg { .. } + | BlackBoxFuncCall::BigIntSub { .. } | BlackBoxFuncCall::BigIntMul { .. } | BlackBoxFuncCall::BigIntDiv { .. } | BlackBoxFuncCall::BigIntToLeBytes { .. } => Vec::new(), @@ -328,7 +328,7 @@ impl BlackBoxFuncCall { | BlackBoxFuncCall::RecursiveAggregation { .. } | BlackBoxFuncCall::BigIntFromLeBytes { .. } | BlackBoxFuncCall::BigIntAdd { .. } - | BlackBoxFuncCall::BigIntNeg { .. } + | BlackBoxFuncCall::BigIntSub { .. } | BlackBoxFuncCall::BigIntMul { .. } | BlackBoxFuncCall::BigIntDiv { .. } => { vec![] diff --git a/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs b/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs index 9e45dc4ee8c..0e94c0f051e 100644 --- a/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs +++ b/acvm-repo/acir/src/circuit/opcodes/memory_operation.rs @@ -1,7 +1,7 @@ use crate::native_types::{Expression, Witness}; use serde::{Deserialize, Serialize}; -#[derive(Clone, PartialEq, Eq, Serialize, Deserialize, Hash, Copy, Default)] +#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Hash, Copy, Default)] pub struct BlockId(pub u32); /// Operation on a block of memory diff --git a/acvm-repo/acir/src/lib.rs b/acvm-repo/acir/src/lib.rs index 0a72cec6070..c7be5026850 100644 --- a/acvm-repo/acir/src/lib.rs +++ b/acvm-repo/acir/src/lib.rs @@ -31,7 +31,10 @@ mod reflection { path::{Path, PathBuf}, }; - use brillig::{BinaryFieldOp, BinaryIntOp, BlackBoxOp, Opcode as BrilligOpcode, ValueOrArray}; + use brillig::{ + BinaryFieldOp, BinaryIntOp, BlackBoxOp, HeapValueType, Opcode as BrilligOpcode, + ValueOrArray, + }; use serde_reflection::{Tracer, TracerConfig}; use crate::{ @@ -39,7 +42,7 @@ mod reflection { brillig::{BrilligInputs, BrilligOutputs}, directives::Directive, opcodes::BlackBoxFuncCall, - Circuit, Opcode, OpcodeLocation, + Circuit, ExpressionWidth, Opcode, OpcodeLocation, }, native_types::{Witness, WitnessMap}, }; @@ -57,6 +60,7 @@ mod reflection { let mut tracer = Tracer::new(TracerConfig::default()); 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(); @@ -68,6 +72,7 @@ mod reflection { tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); tracer.trace_simple_type::().unwrap(); + tracer.trace_simple_type::().unwrap(); let registry = tracer.registry().unwrap(); diff --git a/acvm-repo/acir/tests/test_program_serialization.rs b/acvm-repo/acir/tests/test_program_serialization.rs index c94c5ae66b0..6a73522c822 100644 --- a/acvm-repo/acir/tests/test_program_serialization.rs +++ b/acvm-repo/acir/tests/test_program_serialization.rs @@ -20,7 +20,7 @@ use acir::{ native_types::{Expression, Witness}, }; use acir_field::FieldElement; -use brillig::{HeapArray, MemoryAddress, ValueOrArray}; +use brillig::{HeapArray, HeapValueType, MemoryAddress, ValueOrArray}; #[test] fn addition_circuit() { @@ -45,12 +45,12 @@ fn addition_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 187, 13, 192, 32, 12, 68, 249, 100, 32, 27, - 219, 96, 119, 89, 37, 40, 176, 255, 8, 17, 18, 5, 74, 202, 240, 154, 235, 158, 238, 238, - 112, 206, 121, 247, 37, 206, 60, 103, 194, 63, 208, 111, 116, 133, 197, 69, 144, 153, 91, - 73, 13, 9, 47, 72, 86, 85, 128, 165, 102, 69, 69, 81, 185, 147, 18, 53, 101, 45, 86, 173, - 128, 33, 83, 195, 46, 70, 125, 202, 226, 190, 94, 16, 166, 103, 108, 13, 203, 151, 254, - 245, 233, 224, 1, 1, 52, 166, 127, 120, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 208, 49, 14, 192, 32, 8, 5, 80, 212, 30, 8, 4, 20, + 182, 94, 165, 166, 122, 255, 35, 52, 77, 28, 76, 58, 214, 191, 124, 166, 23, 242, 15, 0, 8, + 240, 77, 154, 125, 206, 198, 127, 161, 176, 209, 138, 139, 197, 88, 68, 122, 205, 157, 152, + 46, 204, 222, 76, 81, 180, 21, 35, 35, 53, 189, 179, 49, 119, 19, 171, 222, 188, 162, 147, + 112, 167, 161, 206, 99, 98, 105, 223, 95, 248, 26, 113, 90, 97, 185, 97, 217, 56, 173, 35, + 63, 243, 81, 87, 163, 125, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -75,9 +75,9 @@ fn fixed_base_scalar_mul_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 215, 46, 189, - 163, 175, 165, 10, 21, 36, 10, 57, 192, 160, 146, 188, 226, 139, 78, 113, 69, 183, 190, 61, - 111, 218, 182, 231, 124, 122, 8, 177, 65, 92, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 32, 16, 2, 109, 171, 175, 46, 221, + 209, 247, 229, 130, 130, 140, 200, 92, 0, 11, 157, 228, 35, 127, 212, 200, 29, 61, 116, 76, + 220, 217, 250, 171, 91, 113, 160, 66, 104, 242, 97, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -102,9 +102,9 @@ fn pedersen_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 9, 10, 0, 64, 8, 2, 103, 15, 232, 255, 31, 142, - 138, 10, 34, 65, 84, 198, 15, 28, 82, 145, 178, 182, 86, 191, 238, 183, 24, 131, 205, 79, - 203, 0, 166, 242, 158, 93, 92, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 135, 9, 0, 48, 8, 75, 171, 224, 255, 15, 139, + 27, 196, 64, 200, 100, 0, 15, 133, 80, 57, 89, 219, 127, 39, 173, 126, 235, 236, 247, 151, + 48, 224, 71, 90, 33, 97, 0, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -143,22 +143,22 @@ fn schnorr_verify_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 87, 78, 2, 1, 20, 134, 209, 177, 247, 222, 123, - 71, 68, 68, 68, 68, 68, 68, 68, 68, 68, 221, 133, 251, 95, 130, 145, 27, 206, 36, 78, 50, - 57, 16, 94, 200, 253, 191, 159, 36, 73, 134, 146, 193, 19, 142, 243, 183, 255, 14, 179, - 233, 247, 145, 254, 59, 217, 127, 71, 57, 198, 113, 78, 48, 125, 167, 56, 205, 25, 206, - 114, 142, 243, 92, 224, 34, 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184, - 205, 29, 238, 114, 143, 251, 60, 224, 33, 143, 120, 204, 19, 158, 242, 140, 25, 158, 51, - 203, 11, 230, 120, 201, 60, 175, 88, 224, 53, 139, 188, 97, 137, 183, 44, 243, 142, 21, - 222, 179, 202, 7, 214, 248, 200, 58, 159, 216, 224, 51, 155, 124, 97, 235, 223, 142, 241, - 188, 250, 222, 230, 27, 59, 124, 103, 151, 31, 236, 241, 147, 95, 252, 246, 57, 158, 104, - 47, 186, 139, 214, 162, 179, 104, 44, 250, 74, 219, 154, 242, 63, 162, 165, 232, 40, 26, - 138, 126, 162, 157, 232, 38, 154, 137, 94, 162, 149, 232, 36, 26, 137, 62, 162, 141, 232, - 34, 154, 136, 30, 162, 133, 232, 32, 26, 136, 253, 99, 251, 195, 100, 176, 121, 236, 29, - 91, 159, 218, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, 182, - 42, 219, 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, 55, 111, 185, 113, - 219, 109, 59, 110, 218, 117, 203, 158, 27, 166, 55, 75, 239, 150, 184, 101, 250, 252, 1, - 55, 204, 92, 74, 220, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 7, 74, 3, 1, 20, 69, 209, 177, 247, 222, 123, + 239, 189, 119, 141, 93, 99, 220, 133, 251, 95, 130, 152, 103, 78, 32, 3, 195, 33, 4, 66, + 248, 239, 254, 20, 69, 209, 84, 212, 158, 216, 206, 223, 234, 219, 204, 146, 239, 91, 170, + 111, 103, 245, 109, 101, 27, 219, 217, 193, 250, 219, 197, 110, 246, 176, 151, 125, 236, + 231, 0, 7, 57, 196, 97, 142, 112, 148, 99, 28, 231, 4, 39, 57, 197, 105, 206, 112, 150, + 115, 156, 231, 2, 23, 185, 196, 101, 174, 112, 149, 107, 92, 231, 6, 55, 185, 197, 109, + 238, 112, 151, 123, 220, 231, 1, 15, 121, 196, 99, 158, 240, 148, 103, 60, 231, 5, 47, 121, + 197, 107, 222, 240, 150, 119, 188, 231, 3, 75, 124, 228, 83, 195, 142, 121, 158, 125, 126, + 225, 43, 223, 248, 206, 15, 126, 178, 204, 47, 86, 248, 237, 119, 43, 76, 127, 105, 47, + 189, 165, 181, 116, 150, 198, 234, 125, 117, 249, 47, 233, 41, 45, 165, 163, 52, 148, 126, + 210, 78, 186, 73, 51, 233, 37, 173, 164, 147, 52, 146, 62, 210, 70, 186, 72, 19, 233, 33, + 45, 164, 131, 52, 144, 253, 23, 139, 218, 238, 217, 60, 123, 103, 235, 236, 156, 141, 179, + 239, 166, 93, 183, 237, 185, 107, 199, 125, 251, 29, 218, 237, 216, 94, 167, 118, 58, 183, + 207, 165, 93, 174, 237, 113, 107, 135, 123, 247, 47, 185, 251, 147, 59, 191, 184, 239, 155, + 187, 126, 184, 103, 217, 29, 235, 55, 171, 223, 173, 104, 184, 231, 255, 243, 7, 236, 52, + 239, 128, 225, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -186,7 +186,9 @@ fn simple_brillig_foreign_call() { brillig::Opcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, brillig::Opcode::Stop { return_data_offset: 0, return_data_size: 1 }, ], @@ -204,11 +206,11 @@ fn simple_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 12, 68, 207, 148, 150, 118, - 234, 175, 216, 63, 232, 207, 116, 232, 210, 161, 136, 223, 175, 98, 132, 27, 212, 69, 31, - 132, 28, 23, 8, 119, 59, 0, 131, 204, 66, 154, 41, 222, 173, 219, 142, 113, 153, 121, 191, - 44, 231, 21, 237, 144, 88, 43, 249, 11, 71, 156, 77, 245, 251, 249, 231, 119, 189, 214, - 204, 89, 187, 11, 25, 130, 54, 1, 36, 1, 124, 242, 107, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 215, 148, 150, 246, + 212, 175, 216, 31, 244, 51, 61, 244, 226, 65, 196, 247, 171, 24, 33, 136, 122, 209, 129, + 144, 176, 132, 101, 247, 4, 160, 144, 217, 196, 45, 41, 218, 203, 91, 207, 241, 168, 117, + 94, 90, 230, 37, 238, 144, 216, 27, 249, 11, 87, 156, 131, 239, 223, 248, 207, 186, 81, + 235, 150, 67, 173, 221, 189, 95, 18, 34, 97, 64, 0, 116, 135, 40, 214, 136, 1, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -258,6 +260,7 @@ fn complex_brillig_foreign_call() { brillig::Opcode::Const { destination: MemoryAddress(0), value: brillig::Value::from(32_usize), + bit_size: 32, }, brillig::Opcode::CalldataCopy { destination_address: MemoryAddress(1), @@ -271,11 +274,20 @@ fn complex_brillig_foreign_call() { ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), ValueOrArray::MemoryAddress(MemoryAddress::from(1)), ], + input_value_types: vec![ + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, + HeapValueType::Simple, + ], destinations: vec![ ValueOrArray::HeapArray(HeapArray { pointer: 0.into(), size: 3 }), ValueOrArray::MemoryAddress(MemoryAddress::from(35)), ValueOrArray::MemoryAddress(MemoryAddress::from(36)), ], + destination_value_types: vec![ + HeapValueType::Array { size: 3, value_types: vec![HeapValueType::Simple] }, + HeapValueType::Simple, + HeapValueType::Simple, + ], }, brillig::Opcode::Stop { return_data_offset: 32, return_data_size: 5 }, ], @@ -293,14 +305,15 @@ fn complex_brillig_foreign_call() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 83, 65, 10, 132, 48, 12, 76, 218, 237, 174, 123, - 242, 11, 130, 62, 160, 250, 2, 255, 34, 222, 20, 61, 250, 124, 11, 78, 49, 4, 193, 131, 21, - 52, 16, 210, 132, 105, 50, 77, 210, 140, 136, 152, 54, 177, 65, 13, 206, 12, 95, 74, 196, - 181, 176, 254, 154, 212, 156, 46, 151, 191, 139, 163, 121, 1, 71, 123, 3, 199, 184, 15, 15, - 157, 119, 202, 185, 36, 237, 159, 61, 248, 63, 159, 160, 46, 232, 23, 254, 15, 54, 67, 156, - 96, 11, 213, 119, 82, 248, 116, 179, 104, 188, 163, 125, 15, 89, 213, 253, 139, 154, 221, - 52, 206, 67, 191, 88, 5, 213, 52, 75, 113, 174, 96, 205, 201, 157, 24, 207, 197, 211, 157, - 6, 50, 18, 233, 158, 72, 89, 1, 53, 215, 75, 175, 196, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 73, 14, 131, 48, 12, 28, 147, 166, 165, 167, + 126, 161, 82, 251, 128, 180, 47, 224, 47, 85, 111, 32, 56, 242, 124, 130, 24, 68, 176, 2, + 23, 130, 4, 35, 89, 206, 50, 137, 71, 182, 147, 28, 128, 96, 128, 241, 150, 113, 44, 156, + 135, 24, 121, 5, 189, 219, 134, 143, 164, 187, 203, 237, 165, 49, 59, 129, 70, 179, 131, + 198, 177, 31, 14, 90, 239, 148, 117, 73, 154, 63, 19, 121, 63, 23, 111, 214, 219, 149, 243, + 27, 125, 206, 117, 208, 63, 85, 222, 161, 248, 32, 167, 72, 162, 245, 235, 44, 166, 94, 20, + 21, 251, 30, 196, 253, 213, 85, 83, 254, 91, 163, 168, 90, 234, 43, 24, 191, 213, 190, 172, + 156, 235, 17, 126, 59, 49, 142, 68, 120, 75, 220, 7, 166, 84, 90, 68, 72, 194, 139, 180, + 136, 25, 58, 46, 103, 45, 188, 25, 5, 0, 0, ]; assert_eq!(bytes, expected_serialization) @@ -332,11 +345,10 @@ fn memory_op_circuit() { let bytes = Circuit::serialize_circuit(&circuit); let expected_serialization: Vec = vec![ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 146, 49, 14, 0, 32, 8, 3, 139, 192, 127, 240, 7, - 254, 255, 85, 198, 136, 9, 131, 155, 48, 216, 165, 76, 77, 57, 80, 0, 140, 45, 117, 111, - 238, 228, 179, 224, 174, 225, 110, 111, 234, 213, 185, 148, 156, 203, 121, 89, 86, 13, 215, - 126, 131, 43, 153, 187, 115, 40, 185, 62, 153, 3, 136, 83, 60, 30, 96, 2, 12, 235, 225, - 124, 14, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 145, 187, 17, 0, 32, 8, 67, 195, 111, 31, 220, 192, + 253, 167, 178, 144, 2, 239, 236, 132, 194, 52, 129, 230, 93, 8, 6, 64, 176, 101, 225, 28, + 78, 49, 43, 238, 154, 225, 254, 166, 209, 205, 165, 98, 174, 212, 177, 188, 187, 92, 255, + 173, 92, 173, 190, 93, 82, 80, 78, 123, 14, 127, 60, 97, 1, 210, 144, 46, 242, 19, 3, 0, 0, ]; assert_eq!(bytes, expected_serialization) diff --git a/acvm-repo/acvm/src/compiler/mod.rs b/acvm-repo/acvm/src/compiler/mod.rs index ccb043914d6..6543c70958b 100644 --- a/acvm-repo/acvm/src/compiler/mod.rs +++ b/acvm-repo/acvm/src/compiler/mod.rs @@ -1,8 +1,6 @@ use std::collections::HashMap; -use acir::circuit::{Circuit, OpcodeLocation}; - -use crate::ExpressionWidth; +use acir::circuit::{Circuit, ExpressionWidth, OpcodeLocation}; // The various passes that we can use over ACIR mod optimizers; diff --git a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs index ecabd98b3b1..64fe5291cc6 100644 --- a/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs +++ b/acvm-repo/acvm/src/compiler/optimizers/redundant_range.rs @@ -148,7 +148,7 @@ mod tests { use acir::{ circuit::{ opcodes::{BlackBoxFuncCall, FunctionInput}, - Circuit, Opcode, PublicInputs, + Circuit, ExpressionWidth, Opcode, PublicInputs, }, native_types::{Expression, Witness}, }; @@ -167,11 +167,13 @@ mod tests { Circuit { current_witness_index: 1, + expression_width: ExpressionWidth::Bounded { width: 3 }, opcodes, private_parameters: BTreeSet::new(), public_parameters: PublicInputs::default(), return_values: PublicInputs::default(), assert_messages: Default::default(), + recursive: false, } } diff --git a/acvm-repo/acvm/src/compiler/transformers/mod.rs b/acvm-repo/acvm/src/compiler/transformers/mod.rs index e184401c5d4..4be2eb7029e 100644 --- a/acvm-repo/acvm/src/compiler/transformers/mod.rs +++ b/acvm-repo/acvm/src/compiler/transformers/mod.rs @@ -1,12 +1,10 @@ use acir::{ - circuit::{brillig::BrilligOutputs, directives::Directive, Circuit, Opcode}, + circuit::{brillig::BrilligOutputs, directives::Directive, Circuit, ExpressionWidth, Opcode}, native_types::{Expression, Witness}, FieldElement, }; use indexmap::IndexMap; -use crate::ExpressionWidth; - mod csat; mod r1cs; @@ -44,11 +42,11 @@ pub(super) fn transform_internal( acir_opcode_positions: Vec, ) -> (Circuit, Vec) { let mut transformer = match &expression_width { - crate::ExpressionWidth::Unbounded => { + ExpressionWidth::Unbounded => { let transformer = R1CSTransformer::new(acir); return (transformer.transform(), acir_opcode_positions); } - crate::ExpressionWidth::Bounded { width } => { + ExpressionWidth::Bounded { width } => { let mut csat = CSatTransformer::new(*width); for value in acir.circuit_arguments() { csat.mark_solvable(value); @@ -159,6 +157,7 @@ pub(super) fn transform_internal( let acir = Circuit { current_witness_index, + expression_width, opcodes: transformed_opcodes, // The transformer does not add new public inputs ..acir diff --git a/acvm-repo/acvm/src/lib.rs b/acvm-repo/acvm/src/lib.rs index 264479d8a12..00a253fde07 100644 --- a/acvm-repo/acvm/src/lib.rs +++ b/acvm-repo/acvm/src/lib.rs @@ -7,7 +7,6 @@ pub mod compiler; pub mod pwg; pub use acvm_blackbox_solver::{BlackBoxFunctionSolver, BlackBoxResolutionError}; -use core::fmt::Debug; use pwg::OpcodeResolutionError; // re-export acir @@ -17,27 +16,3 @@ pub use acir::FieldElement; pub use brillig_vm; // re-export blackbox solver pub use acvm_blackbox_solver as blackbox_solver; - -/// Specifies the maximum width of the expressions which will be constrained. -/// -/// Unbounded Expressions are useful if you are eventually going to pass the ACIR -/// into a proving system which supports R1CS. -/// -/// Bounded Expressions are useful if you are eventually going to pass the ACIR -/// into a proving system which supports PLONK, where arithmetic expressions have a -/// finite fan-in. -#[derive(Debug, Clone, Copy)] -pub enum ExpressionWidth { - Unbounded, - Bounded { width: usize }, -} - -impl From for ExpressionWidth { - fn from(width: usize) -> ExpressionWidth { - if width == 0 { - ExpressionWidth::Unbounded - } else { - ExpressionWidth::Bounded { width } - } - } -} diff --git a/acvm-repo/acvm/src/pwg/blackbox/bigint.rs b/acvm-repo/acvm/src/pwg/blackbox/bigint.rs new file mode 100644 index 00000000000..986afaa3ce7 --- /dev/null +++ b/acvm-repo/acvm/src/pwg/blackbox/bigint.rs @@ -0,0 +1,120 @@ +use std::collections::HashMap; + +use acir::{ + circuit::opcodes::FunctionInput, + native_types::{Witness, WitnessMap}, + BlackBoxFunc, FieldElement, +}; + +use num_bigint::BigUint; + +use crate::pwg::OpcodeResolutionError; + +/// Resolve BigInt opcodes by storing BigInt values (and their moduli) by their ID in a HashMap: +/// - When it encounters a bigint operation opcode, it performs the operation on the stored values +/// and store the result using the provided ID. +/// - When it gets a to_bytes opcode, it simply looks up the value and resolves the output witness accordingly. +#[derive(Default)] +pub(crate) struct BigIntSolver { + bigint_id_to_value: HashMap, + bigint_id_to_modulus: HashMap, +} + +impl BigIntSolver { + pub(crate) fn get_bigint( + &self, + id: u32, + func: BlackBoxFunc, + ) -> Result { + self.bigint_id_to_value + .get(&id) + .ok_or(OpcodeResolutionError::BlackBoxFunctionFailed( + func, + format!("could not find bigint of id {id}"), + )) + .cloned() + } + + pub(crate) fn get_modulus( + &self, + id: u32, + func: BlackBoxFunc, + ) -> Result { + self.bigint_id_to_modulus + .get(&id) + .ok_or(OpcodeResolutionError::BlackBoxFunctionFailed( + func, + format!("could not find bigint of id {id}"), + )) + .cloned() + } + pub(crate) fn bigint_from_bytes( + &mut self, + inputs: &[FunctionInput], + modulus: &[u8], + output: u32, + initial_witness: &mut WitnessMap, + ) -> Result<(), OpcodeResolutionError> { + let bytes = inputs + .iter() + .map(|input| initial_witness.get(&input.witness).unwrap().to_u128() as u8) + .collect::>(); + let bigint = BigUint::from_bytes_le(&bytes); + self.bigint_id_to_value.insert(output, bigint); + let modulus = BigUint::from_bytes_le(modulus); + self.bigint_id_to_modulus.insert(output, modulus); + Ok(()) + } + + pub(crate) fn bigint_to_bytes( + &self, + input: u32, + outputs: &Vec, + initial_witness: &mut WitnessMap, + ) -> Result<(), OpcodeResolutionError> { + let bigint = self.get_bigint(input, BlackBoxFunc::BigIntToLeBytes)?; + + let mut bytes = bigint.to_bytes_le(); + while bytes.len() < outputs.len() { + bytes.push(0); + } + bytes.iter().zip(outputs.iter()).for_each(|(byte, output)| { + initial_witness.insert(*output, FieldElement::from(*byte as u128)); + }); + Ok(()) + } + + pub(crate) fn bigint_op( + &mut self, + lhs: u32, + rhs: u32, + output: u32, + func: BlackBoxFunc, + ) -> Result<(), OpcodeResolutionError> { + let modulus = self.get_modulus(lhs, func)?; + let lhs = self.get_bigint(lhs, func)?; + let rhs = self.get_bigint(rhs, func)?; + let mut result = match func { + BlackBoxFunc::BigIntAdd => lhs + rhs, + BlackBoxFunc::BigIntSub => { + if lhs >= rhs { + &lhs - &rhs + } else { + &lhs + &modulus - &rhs + } + } + BlackBoxFunc::BigIntMul => lhs * rhs, + BlackBoxFunc::BigIntDiv => { + lhs * rhs.modpow(&(&modulus - BigUint::from(1_u32)), &modulus) + } //TODO ensure that modulus is prime + _ => unreachable!("ICE - bigint_op must be called for an operation"), + }; + if result > modulus { + let q = &result / &modulus; + result -= q * &modulus; + } + self.bigint_id_to_value.insert(output, result); + self.bigint_id_to_modulus.insert(output, modulus); + Ok(()) + } +} diff --git a/acvm-repo/acvm/src/pwg/blackbox/mod.rs b/acvm-repo/acvm/src/pwg/blackbox/mod.rs index 0f026cd274a..7146dff87e0 100644 --- a/acvm-repo/acvm/src/pwg/blackbox/mod.rs +++ b/acvm-repo/acvm/src/pwg/blackbox/mod.rs @@ -5,11 +5,12 @@ use acir::{ }; use acvm_blackbox_solver::{blake2s, blake3, keccak256, keccakf1600, sha256}; -use self::pedersen::pedersen_hash; +use self::{bigint::BigIntSolver, pedersen::pedersen_hash}; use super::{insert_value, OpcodeNotSolvable, OpcodeResolutionError}; use crate::{pwg::witness_to_value, BlackBoxFunctionSolver}; +pub(crate) mod bigint; mod fixed_base_scalar_mul; mod hash; mod logic; @@ -53,6 +54,7 @@ pub(crate) fn solve( backend: &impl BlackBoxFunctionSolver, initial_witness: &mut WitnessMap, bb_func: &BlackBoxFuncCall, + bigint_solver: &mut BigIntSolver, ) -> Result<(), OpcodeResolutionError> { let inputs = bb_func.get_inputs_vec(); if !contains_all_inputs(initial_witness, &inputs) { @@ -190,12 +192,18 @@ pub(crate) fn solve( } // Recursive aggregation will be entirely handled by the backend and is not solved by the ACVM BlackBoxFuncCall::RecursiveAggregation { .. } => Ok(()), - BlackBoxFuncCall::BigIntAdd { .. } => todo!(), - BlackBoxFuncCall::BigIntNeg { .. } => todo!(), - BlackBoxFuncCall::BigIntMul { .. } => todo!(), - BlackBoxFuncCall::BigIntDiv { .. } => todo!(), - BlackBoxFuncCall::BigIntFromLeBytes { .. } => todo!(), - BlackBoxFuncCall::BigIntToLeBytes { .. } => todo!(), + BlackBoxFuncCall::BigIntAdd { lhs, rhs, output } + | BlackBoxFuncCall::BigIntSub { lhs, rhs, output } + | BlackBoxFuncCall::BigIntMul { lhs, rhs, output } + | BlackBoxFuncCall::BigIntDiv { lhs, rhs, output } => { + bigint_solver.bigint_op(*lhs, *rhs, *output, bb_func.get_black_box_func()) + } + BlackBoxFuncCall::BigIntFromLeBytes { inputs, modulus, output } => { + bigint_solver.bigint_from_bytes(inputs, modulus, *output, initial_witness) + } + BlackBoxFuncCall::BigIntToLeBytes { input, outputs } => { + bigint_solver.bigint_to_bytes(*input, outputs, initial_witness) + } BlackBoxFuncCall::Poseidon2Permutation { .. } => todo!(), BlackBoxFuncCall::Sha256Compression { .. } => todo!(), } diff --git a/acvm-repo/acvm/src/pwg/brillig.rs b/acvm-repo/acvm/src/pwg/brillig.rs index 4b62f86f0eb..c5a98aaf01c 100644 --- a/acvm-repo/acvm/src/pwg/brillig.rs +++ b/acvm-repo/acvm/src/pwg/brillig.rs @@ -1,7 +1,10 @@ +use std::collections::HashMap; + use acir::{ brillig::{ForeignCallParam, ForeignCallResult, Value}, circuit::{ brillig::{Brillig, BrilligInputs, BrilligOutputs}, + opcodes::BlockId, OpcodeLocation, }, native_types::WitnessMap, @@ -12,7 +15,7 @@ use brillig_vm::{VMStatus, VM}; use crate::{pwg::OpcodeNotSolvable, OpcodeResolutionError}; -use super::{get_value, insert_value}; +use super::{get_value, insert_value, memory_op::MemoryOpSolver}; #[derive(Debug)] pub enum BrilligSolverStatus { @@ -64,6 +67,7 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { /// witness. pub(super) fn new( initial_witness: &WitnessMap, + memory: &HashMap, brillig: &'b Brillig, bb_solver: &'b B, acir_index: usize, @@ -97,6 +101,18 @@ impl<'b, B: BlackBoxFunctionSolver> BrilligSolver<'b, B> { } } } + BrilligInputs::MemoryArray(block_id) => { + let memory_block = memory + .get(block_id) + .ok_or(OpcodeNotSolvable::MissingMemoryBlock(block_id.0))?; + for memory_index in 0..memory_block.block_len { + let memory_value = memory_block + .block_value + .get(&memory_index) + .expect("All memory is initialized on creation"); + calldata.push((*memory_value).into()); + } + } } } diff --git a/acvm-repo/acvm/src/pwg/memory_op.rs b/acvm-repo/acvm/src/pwg/memory_op.rs index c1da2cd95cf..49ec652289e 100644 --- a/acvm-repo/acvm/src/pwg/memory_op.rs +++ b/acvm-repo/acvm/src/pwg/memory_op.rs @@ -14,8 +14,8 @@ type MemoryIndex = u32; /// Maintains the state for solving [`MemoryInit`][`acir::circuit::Opcode::MemoryInit`] and [`MemoryOp`][`acir::circuit::Opcode::MemoryOp`] opcodes. #[derive(Default)] pub(super) struct MemoryOpSolver { - block_value: HashMap, - block_len: u32, + pub(super) block_value: HashMap, + pub(super) block_len: u32, } impl MemoryOpSolver { diff --git a/acvm-repo/acvm/src/pwg/mod.rs b/acvm-repo/acvm/src/pwg/mod.rs index 41b96572658..2ee39a289e7 100644 --- a/acvm-repo/acvm/src/pwg/mod.rs +++ b/acvm-repo/acvm/src/pwg/mod.rs @@ -10,7 +10,10 @@ use acir::{ }; use acvm_blackbox_solver::BlackBoxResolutionError; -use self::{arithmetic::ExpressionSolver, directives::solve_directives, memory_op::MemoryOpSolver}; +use self::{ + arithmetic::ExpressionSolver, blackbox::bigint::BigIntSolver, directives::solve_directives, + memory_op::MemoryOpSolver, +}; use crate::BlackBoxFunctionSolver; use thiserror::Error; @@ -76,6 +79,8 @@ pub enum StepResult<'a, B: BlackBoxFunctionSolver> { pub enum OpcodeNotSolvable { #[error("missing assignment for witness index {0}")] MissingAssignment(u32), + #[error("Attempted to load uninitialized memory block")] + MissingMemoryBlock(u32), #[error("expression has too many unknowns {0}")] ExpressionHasTooManyUnknowns(Expression), } @@ -132,6 +137,8 @@ pub struct ACVM<'a, B: BlackBoxFunctionSolver> { /// Stores the solver for memory operations acting on blocks of memory disambiguated by [block][`BlockId`]. block_solvers: HashMap, + bigint_solver: BigIntSolver, + /// A list of opcodes which are to be executed by the ACVM. opcodes: &'a [Opcode], /// Index of the next opcode to be executed. @@ -149,6 +156,7 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { status, backend, block_solvers: HashMap::default(), + bigint_solver: BigIntSolver::default(), opcodes, instruction_pointer: 0, witness_map: initial_witness, @@ -254,9 +262,12 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { let resolution = match opcode { Opcode::AssertZero(expr) => ExpressionSolver::solve(&mut self.witness_map, expr), - Opcode::BlackBoxFuncCall(bb_func) => { - blackbox::solve(self.backend, &mut self.witness_map, bb_func) - } + Opcode::BlackBoxFuncCall(bb_func) => blackbox::solve( + self.backend, + &mut self.witness_map, + bb_func, + &mut self.bigint_solver, + ), Opcode::Directive(directive) => solve_directives(&mut self.witness_map, directive), Opcode::MemoryInit { block_id, init } => { let solver = self.block_solvers.entry(*block_id).or_default(); @@ -327,7 +338,13 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { // there will be a cached `BrilligSolver` to avoid recomputation. let mut solver: BrilligSolver<'_, B> = match self.brillig_solver.take() { Some(solver) => solver, - None => BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer)?, + None => BrilligSolver::new( + witness, + &self.block_solvers, + brillig, + self.backend, + self.instruction_pointer, + )?, }; match solver.solve()? { BrilligSolverStatus::ForeignCallWait(foreign_call) => { @@ -362,7 +379,13 @@ impl<'a, B: BlackBoxFunctionSolver> ACVM<'a, B> { return StepResult::Status(self.handle_opcode_resolution(resolution)); } - let solver = BrilligSolver::new(witness, brillig, self.backend, self.instruction_pointer); + let solver = BrilligSolver::new( + witness, + &self.block_solvers, + brillig, + self.backend, + self.instruction_pointer, + ); match solver { Ok(solver) => StepResult::IntoBrillig(solver), Err(..) => StepResult::Status(self.handle_opcode_resolution(solver.map(|_| ()))), diff --git a/acvm-repo/acvm/tests/solver.rs b/acvm-repo/acvm/tests/solver.rs index 9ff4a4f4897..b267c3005a8 100644 --- a/acvm-repo/acvm/tests/solver.rs +++ b/acvm-repo/acvm/tests/solver.rs @@ -13,6 +13,7 @@ use acir::{ use acvm::pwg::{ACVMStatus, ErrorLocation, ForeignCallWaitInfo, OpcodeResolutionError, ACVM}; use acvm_blackbox_solver::StubbedBlackBoxSolver; +use brillig_vm::brillig::HeapValueType; // Reenable these test cases once we move the brillig implementation of inversion down into the acvm stdlib. @@ -69,7 +70,9 @@ fn inversion_brillig_oracle_equivalence() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 3 }, ], @@ -196,12 +199,16 @@ fn double_inversion_brillig_oracle() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 5 }, ], @@ -327,12 +334,16 @@ fn oracle_dependent_execution() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(3))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(2))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 4 }, ], @@ -453,7 +464,9 @@ fn brillig_oracle_predicate() { BrilligOpcode::ForeignCall { function: "invert".into(), destinations: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(1))], + destination_value_types: vec![HeapValueType::Simple], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, ], predicate: Some(Expression::default()), diff --git a/acvm-repo/acvm_js/test/shared/addition.ts b/acvm-repo/acvm_js/test/shared/addition.ts index 982b9b685ce..217902bdea6 100644 --- a/acvm-repo/acvm_js/test/shared/addition.ts +++ b/acvm-repo/acvm_js/test/shared/addition.ts @@ -2,11 +2,11 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `addition_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 144, 187, 13, 192, 32, 12, 68, 249, 100, 32, 27, 219, 96, 119, 89, 37, 40, - 176, 255, 8, 17, 18, 5, 74, 202, 240, 154, 235, 158, 238, 238, 112, 206, 121, 247, 37, 206, 60, 103, 194, 63, 208, - 111, 116, 133, 197, 69, 144, 153, 91, 73, 13, 9, 47, 72, 86, 85, 128, 165, 102, 69, 69, 81, 185, 147, 18, 53, 101, 45, - 86, 173, 128, 33, 83, 195, 46, 70, 125, 202, 226, 190, 94, 16, 166, 103, 108, 13, 203, 151, 254, 245, 233, 224, 1, 1, - 52, 166, 127, 120, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 208, 49, 14, 192, 32, 8, 5, 80, 212, 30, 8, 4, 20, 182, 94, 165, 166, 122, + 255, 35, 52, 77, 28, 76, 58, 214, 191, 124, 166, 23, 242, 15, 0, 8, 240, 77, 154, 125, 206, 198, 127, 161, 176, 209, + 138, 139, 197, 88, 68, 122, 205, 157, 152, 46, 204, 222, 76, 81, 180, 21, 35, 35, 53, 189, 179, 49, 119, 19, 171, 222, + 188, 162, 147, 112, 167, 161, 206, 99, 98, 105, 223, 95, 248, 26, 113, 90, 97, 185, 97, 217, 56, 173, 35, 63, 243, 81, + 87, 163, 125, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ 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 faae98bcf47..07c343c5ba0 100644 --- a/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/complex_foreign_call.ts @@ -2,12 +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, 83, 65, 10, 132, 48, 12, 76, 218, 237, 174, 123, 242, 11, 130, 62, 160, 250, - 2, 255, 34, 222, 20, 61, 250, 124, 11, 78, 49, 4, 193, 131, 21, 52, 16, 210, 132, 105, 50, 77, 210, 140, 136, 152, 54, - 177, 65, 13, 206, 12, 95, 74, 196, 181, 176, 254, 154, 212, 156, 46, 151, 191, 139, 163, 121, 1, 71, 123, 3, 199, 184, - 15, 15, 157, 119, 202, 185, 36, 237, 159, 61, 248, 63, 159, 160, 46, 232, 23, 254, 15, 54, 67, 156, 96, 11, 213, 119, - 82, 248, 116, 179, 104, 188, 163, 125, 15, 89, 213, 253, 139, 154, 221, 52, 206, 67, 191, 88, 5, 213, 52, 75, 113, - 174, 96, 205, 201, 157, 24, 207, 197, 211, 157, 6, 50, 18, 233, 158, 72, 89, 1, 53, 215, 75, 175, 196, 4, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 84, 73, 14, 131, 48, 12, 28, 147, 166, 165, 167, 126, 161, 82, 251, 128, 180, + 47, 224, 47, 85, 111, 32, 56, 242, 124, 130, 24, 68, 176, 2, 23, 130, 4, 35, 89, 206, 50, 137, 71, 182, 147, 28, 128, + 96, 128, 241, 150, 113, 44, 156, 135, 24, 121, 5, 189, 219, 134, 143, 164, 187, 203, 237, 165, 49, 59, 129, 70, 179, + 131, 198, 177, 31, 14, 90, 239, 148, 117, 73, 154, 63, 19, 121, 63, 23, 111, 214, 219, 149, 243, 27, 125, 206, 117, + 208, 63, 85, 222, 161, 248, 32, 167, 72, 162, 245, 235, 44, 166, 94, 20, 21, 251, 30, 196, 253, 213, 85, 83, 254, 91, + 163, 168, 90, 234, 43, 24, 191, 213, 190, 172, 156, 235, 17, 126, 59, 49, 142, 68, 120, 75, 220, 7, 166, 84, 90, 68, + 72, 194, 139, 180, 136, 25, 58, 46, 103, 45, 188, 25, 5, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000001'], diff --git a/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts b/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts index 0437bebc369..c0859f50135 100644 --- a/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts +++ b/acvm-repo/acvm_js/test/shared/fixed_base_scalar_mul.ts @@ -1,8 +1,8 @@ // See `fixed_base_scalar_mul_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 48, 12, 194, 178, 215, 215, 46, 189, 163, 175, 165, 10, 21, 36, - 10, 57, 192, 160, 146, 188, 226, 139, 78, 113, 69, 183, 190, 61, 111, 218, 182, 231, 124, 122, 8, 177, 65, 92, 0, 0, - 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 138, 91, 10, 0, 32, 16, 2, 109, 171, 175, 46, 221, 209, 247, 229, 130, 130, + 140, 200, 92, 0, 11, 157, 228, 35, 127, 212, 200, 29, 61, 116, 76, 220, 217, 250, 171, 91, 113, 160, 66, 104, 242, 97, + 0, 0, 0, ]); export const initialWitnessMap = 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 7a65f29117c..cfa7c679b18 100644 --- a/acvm-repo/acvm_js/test/shared/foreign_call.ts +++ b/acvm-repo/acvm_js/test/shared/foreign_call.ts @@ -2,10 +2,10 @@ import { WitnessMap } from '@noir-lang/acvm_js'; // See `simple_brillig_foreign_call` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 177, 10, 192, 32, 12, 68, 207, 148, 150, 118, 234, 175, 216, 63, 232, - 207, 116, 232, 210, 161, 136, 223, 175, 98, 132, 27, 212, 69, 31, 132, 28, 23, 8, 119, 59, 0, 131, 204, 66, 154, 41, - 222, 173, 219, 142, 113, 153, 121, 191, 44, 231, 21, 237, 144, 88, 43, 249, 11, 71, 156, 77, 245, 251, 249, 231, 119, - 189, 214, 204, 89, 187, 11, 25, 130, 54, 1, 36, 1, 124, 242, 107, 1, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 173, 143, 65, 10, 192, 32, 12, 4, 215, 148, 150, 246, 212, 175, 216, 31, 244, 51, + 61, 244, 226, 65, 196, 247, 171, 24, 33, 136, 122, 209, 129, 144, 176, 132, 101, 247, 4, 160, 144, 217, 196, 45, 41, + 218, 203, 91, 207, 241, 168, 117, 94, 90, 230, 37, 238, 144, 216, 27, 249, 11, 87, 156, 131, 239, 223, 248, 207, 186, + 81, 235, 150, 67, 173, 221, 189, 95, 18, 34, 97, 64, 0, 116, 135, 40, 214, 136, 1, 0, 0, ]); export const initialWitnessMap: WitnessMap = new Map([ [1, '0x0000000000000000000000000000000000000000000000000000000000000005'], diff --git a/acvm-repo/acvm_js/test/shared/memory_op.ts b/acvm-repo/acvm_js/test/shared/memory_op.ts index ce88f491893..b5ab64b3447 100644 --- a/acvm-repo/acvm_js/test/shared/memory_op.ts +++ b/acvm-repo/acvm_js/test/shared/memory_op.ts @@ -1,9 +1,9 @@ // See `memory_op_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 146, 49, 14, 0, 32, 8, 3, 139, 192, 127, 240, 7, 254, 255, 85, 198, 136, 9, - 131, 155, 48, 216, 165, 76, 77, 57, 80, 0, 140, 45, 117, 111, 238, 228, 179, 224, 174, 225, 110, 111, 234, 213, 185, - 148, 156, 203, 121, 89, 86, 13, 215, 126, 131, 43, 153, 187, 115, 40, 185, 62, 153, 3, 136, 83, 60, 30, 96, 2, 12, - 235, 225, 124, 14, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 213, 145, 187, 17, 0, 32, 8, 67, 195, 111, 31, 220, 192, 253, 167, 178, 144, 2, + 239, 236, 132, 194, 52, 129, 230, 93, 8, 6, 64, 176, 101, 225, 28, 78, 49, 43, 238, 154, 225, 254, 166, 209, 205, 165, + 98, 174, 212, 177, 188, 187, 92, 255, 173, 92, 173, 190, 93, 82, 80, 78, 123, 14, 127, 60, 97, 1, 210, 144, 46, 242, + 19, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/acvm-repo/acvm_js/test/shared/pedersen.ts b/acvm-repo/acvm_js/test/shared/pedersen.ts index e35893fc355..5150d24131c 100644 --- a/acvm-repo/acvm_js/test/shared/pedersen.ts +++ b/acvm-repo/acvm_js/test/shared/pedersen.ts @@ -1,7 +1,7 @@ // See `pedersen_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 138, 9, 10, 0, 64, 8, 2, 103, 15, 232, 255, 31, 142, 138, 10, 34, 65, 84, 198, - 15, 28, 82, 145, 178, 182, 86, 191, 238, 183, 24, 131, 205, 79, 203, 0, 166, 242, 158, 93, 92, 0, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 93, 74, 135, 9, 0, 48, 8, 75, 171, 224, 255, 15, 139, 27, 196, 64, 200, 100, 0, 15, + 133, 80, 57, 89, 219, 127, 39, 173, 126, 235, 236, 247, 151, 48, 224, 71, 90, 33, 97, 0, 0, 0, ]); export const initialWitnessMap = new Map([[1, '0x0000000000000000000000000000000000000000000000000000000000000001']]); diff --git a/acvm-repo/acvm_js/test/shared/schnorr_verify.ts b/acvm-repo/acvm_js/test/shared/schnorr_verify.ts index 5716cbd30f8..2127de66f69 100644 --- a/acvm-repo/acvm_js/test/shared/schnorr_verify.ts +++ b/acvm-repo/acvm_js/test/shared/schnorr_verify.ts @@ -1,17 +1,17 @@ // See `schnorr_verify_circuit` integration test in `acir/tests/test_program_serialization.rs`. export const bytecode = Uint8Array.from([ - 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 87, 78, 2, 1, 20, 134, 209, 177, 247, 222, 123, 71, 68, 68, 68, 68, 68, - 68, 68, 68, 68, 221, 133, 251, 95, 130, 145, 27, 206, 36, 78, 50, 57, 16, 94, 200, 253, 191, 159, 36, 73, 134, 146, - 193, 19, 142, 243, 183, 255, 14, 179, 233, 247, 145, 254, 59, 217, 127, 71, 57, 198, 113, 78, 48, 125, 167, 56, 205, - 25, 206, 114, 142, 243, 92, 224, 34, 151, 184, 204, 21, 174, 114, 141, 235, 220, 224, 38, 183, 184, 205, 29, 238, 114, - 143, 251, 60, 224, 33, 143, 120, 204, 19, 158, 242, 140, 25, 158, 51, 203, 11, 230, 120, 201, 60, 175, 88, 224, 53, - 139, 188, 97, 137, 183, 44, 243, 142, 21, 222, 179, 202, 7, 214, 248, 200, 58, 159, 216, 224, 51, 155, 124, 97, 235, - 223, 142, 241, 188, 250, 222, 230, 27, 59, 124, 103, 151, 31, 236, 241, 147, 95, 252, 246, 57, 158, 104, 47, 186, 139, - 214, 162, 179, 104, 44, 250, 74, 219, 154, 242, 63, 162, 165, 232, 40, 26, 138, 126, 162, 157, 232, 38, 154, 137, 94, - 162, 149, 232, 36, 26, 137, 62, 162, 141, 232, 34, 154, 136, 30, 162, 133, 232, 32, 26, 136, 253, 99, 251, 195, 100, - 176, 121, 236, 29, 91, 159, 218, 56, 99, 219, 172, 77, 115, 182, 204, 219, 176, 96, 187, 162, 205, 74, 182, 42, 219, - 168, 98, 155, 170, 77, 106, 182, 168, 219, 160, 225, 246, 77, 55, 111, 185, 113, 219, 109, 59, 110, 218, 117, 203, - 158, 27, 166, 55, 75, 239, 150, 184, 101, 250, 252, 1, 55, 204, 92, 74, 220, 3, 0, 0, + 31, 139, 8, 0, 0, 0, 0, 0, 0, 255, 77, 210, 7, 74, 3, 1, 20, 69, 209, 177, 247, 222, 123, 239, 189, 119, 141, 93, 99, + 220, 133, 251, 95, 130, 152, 103, 78, 32, 3, 195, 33, 4, 66, 248, 239, 254, 20, 69, 209, 84, 212, 158, 216, 206, 223, + 234, 219, 204, 146, 239, 91, 170, 111, 103, 245, 109, 101, 27, 219, 217, 193, 250, 219, 197, 110, 246, 176, 151, 125, + 236, 231, 0, 7, 57, 196, 97, 142, 112, 148, 99, 28, 231, 4, 39, 57, 197, 105, 206, 112, 150, 115, 156, 231, 2, 23, + 185, 196, 101, 174, 112, 149, 107, 92, 231, 6, 55, 185, 197, 109, 238, 112, 151, 123, 220, 231, 1, 15, 121, 196, 99, + 158, 240, 148, 103, 60, 231, 5, 47, 121, 197, 107, 222, 240, 150, 119, 188, 231, 3, 75, 124, 228, 83, 195, 142, 121, + 158, 125, 126, 225, 43, 223, 248, 206, 15, 126, 178, 204, 47, 86, 248, 237, 119, 43, 76, 127, 105, 47, 189, 165, 181, + 116, 150, 198, 234, 125, 117, 249, 47, 233, 41, 45, 165, 163, 52, 148, 126, 210, 78, 186, 73, 51, 233, 37, 173, 164, + 147, 52, 146, 62, 210, 70, 186, 72, 19, 233, 33, 45, 164, 131, 52, 144, 253, 23, 139, 218, 238, 217, 60, 123, 103, + 235, 236, 156, 141, 179, 239, 166, 93, 183, 237, 185, 107, 199, 125, 251, 29, 218, 237, 216, 94, 167, 118, 58, 183, + 207, 165, 93, 174, 237, 113, 107, 135, 123, 247, 47, 185, 251, 147, 59, 191, 184, 239, 155, 187, 126, 184, 103, 217, + 29, 235, 55, 171, 223, 173, 104, 184, 231, 255, 243, 7, 236, 52, 239, 128, 225, 3, 0, 0, ]); export const initialWitnessMap = new Map([ diff --git a/acvm-repo/brillig/src/black_box.rs b/acvm-repo/brillig/src/black_box.rs index 9195d8aa6f3..29861d0fd84 100644 --- a/acvm-repo/brillig/src/black_box.rs +++ b/acvm-repo/brillig/src/black_box.rs @@ -85,7 +85,7 @@ pub enum BlackBoxOp { rhs: MemoryAddress, output: MemoryAddress, }, - BigIntNeg { + BigIntSub { lhs: MemoryAddress, rhs: MemoryAddress, output: MemoryAddress, diff --git a/acvm-repo/brillig/src/lib.rs b/acvm-repo/brillig/src/lib.rs index 2e9d80e2f3b..0661e794360 100644 --- a/acvm-repo/brillig/src/lib.rs +++ b/acvm-repo/brillig/src/lib.rs @@ -17,7 +17,9 @@ mod value; pub use black_box::BlackBoxOp; pub use foreign_call::{ForeignCallParam, ForeignCallResult}; -pub use opcodes::{BinaryFieldOp, BinaryIntOp, HeapArray, HeapVector, MemoryAddress, ValueOrArray}; +pub use opcodes::{ + BinaryFieldOp, BinaryIntOp, HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray, +}; pub use opcodes::{BrilligOpcode as Opcode, Label}; pub use value::Typ; pub use value::Value; diff --git a/acvm-repo/brillig/src/opcodes.rs b/acvm-repo/brillig/src/opcodes.rs index 9a6f11c463f..06c8fdc04eb 100644 --- a/acvm-repo/brillig/src/opcodes.rs +++ b/acvm-repo/brillig/src/opcodes.rs @@ -19,6 +19,27 @@ impl From for MemoryAddress { } } +/// Describes the memory layout for an array/vector element +#[derive(Debug, Clone, Eq, PartialEq, Serialize, Deserialize)] +pub enum HeapValueType { + // A single field element is enough to represent the value + Simple, + // The value read should be interpreted as a pointer to a heap array, which + // consists of a pointer to a slice of memory of size elements, and a + // reference count + Array { value_types: Vec, size: usize }, + // The value read should be interpreted as a pointer to a heap vector, which + // consists of a pointer to a slice of memory, a number of elements in that + // slice, and a reference count + Vector { value_types: Vec }, +} + +impl HeapValueType { + pub fn all_simple(types: &[HeapValueType]) -> bool { + types.iter().all(|typ| matches!(typ, HeapValueType::Simple)) + } +} + /// A fixed-sized array starting from a Brillig memory location. #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub struct HeapArray { @@ -104,6 +125,7 @@ pub enum BrilligOpcode { }, Const { destination: MemoryAddress, + bit_size: u32, value: Value, }, Return, @@ -117,8 +139,13 @@ pub enum BrilligOpcode { function: String, /// Destination addresses (may be single values or memory pointers). destinations: Vec, + /// Destination value types + destination_value_types: Vec, /// Input addresses (may be single values or memory pointers). inputs: Vec, + /// Input value types (for heap allocated structures indicates how to + /// retrieve the elements) + input_value_types: Vec, }, Mov { destination: MemoryAddress, diff --git a/acvm-repo/brillig_vm/src/black_box.rs b/acvm-repo/brillig_vm/src/black_box.rs index de20d194dde..04aa2bcf9af 100644 --- a/acvm-repo/brillig_vm/src/black_box.rs +++ b/acvm-repo/brillig_vm/src/black_box.rs @@ -179,7 +179,7 @@ pub(crate) fn evaluate_black_box( Ok(()) } BlackBoxOp::BigIntAdd { .. } => todo!(), - BlackBoxOp::BigIntNeg { .. } => todo!(), + BlackBoxOp::BigIntSub { .. } => todo!(), BlackBoxOp::BigIntMul { .. } => todo!(), BlackBoxOp::BigIntDiv { .. } => todo!(), BlackBoxOp::BigIntFromLeBytes { .. } => todo!(), @@ -204,7 +204,7 @@ fn black_box_function_from_op(op: &BlackBoxOp) -> BlackBoxFunc { BlackBoxOp::FixedBaseScalarMul { .. } => BlackBoxFunc::FixedBaseScalarMul, BlackBoxOp::EmbeddedCurveAdd { .. } => BlackBoxFunc::EmbeddedCurveAdd, BlackBoxOp::BigIntAdd { .. } => BlackBoxFunc::BigIntAdd, - BlackBoxOp::BigIntNeg { .. } => BlackBoxFunc::BigIntNeg, + BlackBoxOp::BigIntSub { .. } => BlackBoxFunc::BigIntSub, BlackBoxOp::BigIntMul { .. } => BlackBoxFunc::BigIntMul, BlackBoxOp::BigIntDiv { .. } => BlackBoxFunc::BigIntDiv, BlackBoxOp::BigIntFromLeBytes { .. } => BlackBoxFunc::BigIntFromLeBytes, diff --git a/acvm-repo/brillig_vm/src/lib.rs b/acvm-repo/brillig_vm/src/lib.rs index 0c90fcb1416..4292a623cdb 100644 --- a/acvm-repo/brillig_vm/src/lib.rs +++ b/acvm-repo/brillig_vm/src/lib.rs @@ -12,8 +12,8 @@ //! [acvm]: https://crates.io/crates/acvm use acir::brillig::{ - BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapVector, - MemoryAddress, Opcode, Value, ValueOrArray, + BinaryFieldOp, BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapArray, HeapValueType, + HeapVector, MemoryAddress, Opcode, Value, ValueOrArray, }; use acir::FieldElement; // Re-export `brillig`. @@ -212,7 +212,16 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.fail("return opcode hit, but callstack already empty".to_string()) } } - Opcode::ForeignCall { function, destinations, inputs } => { + Opcode::ForeignCall { + function, + destinations, + destination_value_types, + inputs, + input_value_types, + } => { + assert!(inputs.len() == input_value_types.len()); + assert!(destinations.len() == destination_value_types.len()); + if self.foreign_call_counter >= self.foreign_call_results.len() { // When this opcode is called, it is possible that the results of a foreign call are // not yet known (not enough entries in `foreign_call_results`). @@ -223,7 +232,8 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { // but has the necessary results to proceed with execution. let resolved_inputs = inputs .iter() - .map(|input| self.get_memory_values(*input)) + .zip(input_value_types) + .map(|(input, input_type)| self.get_memory_values(*input, input_type)) .collect::>(); return self.wait_for_foreign_call(function.clone(), resolved_inputs); } @@ -231,48 +241,69 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { let values = &self.foreign_call_results[self.foreign_call_counter].values; let mut invalid_foreign_call_result = false; - for (destination, output) in destinations.iter().zip(values) { - match destination { - ValueOrArray::MemoryAddress(value_index) => match output { - ForeignCallParam::Single(value) => { - self.memory.write(*value_index, *value); - } - _ => unreachable!( - "Function result size does not match brillig bytecode (expected 1 result)" - ), - }, - ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }) => { + for ((destination, value_type), output) in + destinations.iter().zip(destination_value_types).zip(values) + { + match (destination, value_type) { + (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple) => { match output { - ForeignCallParam::Array(values) => { - if values.len() != *size { - invalid_foreign_call_result = true; - break; - } - // Convert the destination pointer to a usize - let destination = self.memory.read_ref(*pointer_index); - // Write to our destination memory - self.memory.write_slice(destination, values); - } - _ => { - unreachable!("Function result size does not match brillig bytecode size") + ForeignCallParam::Single(value) => { + self.memory.write(*value_index, *value); } + _ => unreachable!( + "Function result size does not match brillig bytecode. Expected 1 result but got {output:?}" + ), } } - ValueOrArray::HeapVector(HeapVector { pointer: pointer_index, size: size_index }) => { - match output { - ForeignCallParam::Array(values) => { - // Set our size in the size address - self.memory.write(*size_index, Value::from(values.len())); - // Convert the destination pointer to a usize - let destination = self.memory.read_ref(*pointer_index); - // Write to our destination memory - self.memory.write_slice(destination, values); + ( + ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), + HeapValueType::Array { value_types, size: type_size }, + ) if size == type_size => { + if HeapValueType::all_simple(value_types) { + match output { + ForeignCallParam::Array(values) => { + if values.len() != *size { + invalid_foreign_call_result = true; + break; + } + // Convert the destination pointer to a usize + let destination = self.memory.read_ref(*pointer_index); + // Write to our destination memory + self.memory.write_slice(destination, values); + } + _ => { + unreachable!("Function result size does not match brillig bytecode size") + } } - _ => { - unreachable!("Function result size does not match brillig bytecode size") + } else { + unimplemented!("deflattening heap arrays from foreign calls"); + } + } + ( + ValueOrArray::HeapVector(HeapVector {pointer: pointer_index, size: size_index }), + HeapValueType::Vector { value_types }, + ) => { + if HeapValueType::all_simple(value_types) { + match output { + ForeignCallParam::Array(values) => { + // Set our size in the size address + self.memory.write(*size_index, Value::from(values.len())); + // Convert the destination pointer to a usize + let destination = self.memory.read_ref(*pointer_index); + // Write to our destination memory + self.memory.write_slice(destination, values); + } + _ => { + unreachable!("Function result size does not match brillig bytecode size") + } } + } else { + unimplemented!("deflattening heap vectors from foreign calls"); } } + _ => { + unreachable!("Unexpected value type {value_type:?} for destination {destination:?}"); + } } } @@ -316,7 +347,7 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.call_stack.push(Value::from(self.program_counter)); self.set_program_counter(*location) } - Opcode::Const { destination, value } => { + Opcode::Const { destination, value, bit_size: _ } => { self.memory.write(*destination, *value); self.increment_program_counter() } @@ -351,21 +382,85 @@ impl<'a, B: BlackBoxFunctionSolver> VM<'a, B> { self.status.clone() } - fn get_memory_values(&self, input: ValueOrArray) -> ForeignCallParam { - match input { - ValueOrArray::MemoryAddress(value_index) => self.memory.read(value_index).into(), - ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }) => { + fn get_memory_values( + &self, + input: ValueOrArray, + value_type: &HeapValueType, + ) -> ForeignCallParam { + match (input, value_type) { + (ValueOrArray::MemoryAddress(value_index), HeapValueType::Simple) => { + self.memory.read(value_index).into() + } + ( + ValueOrArray::HeapArray(HeapArray { pointer: pointer_index, size }), + HeapValueType::Array { value_types, size: type_size }, + ) if *type_size == size => { let start = self.memory.read_ref(pointer_index); - self.memory.read_slice(start, size).to_vec().into() + self.read_slice_of_values_from_memory(start, size, value_types).into() } - ValueOrArray::HeapVector(HeapVector { pointer: pointer_index, size: size_index }) => { + ( + ValueOrArray::HeapVector(HeapVector { pointer: pointer_index, size: size_index }), + HeapValueType::Vector { value_types }, + ) => { let start = self.memory.read_ref(pointer_index); - let size = self.memory.read(size_index); - self.memory.read_slice(start, size.to_usize()).to_vec().into() + let size = self.memory.read(size_index).to_usize(); + self.read_slice_of_values_from_memory(start, size, value_types).into() + } + _ => { + unreachable!("Unexpected value type {value_type:?} for input {input:?}"); } } } + /// Reads an array/vector from memory but recursively reads pointers to + /// nested arrays/vectors according to the sequence of value types. + fn read_slice_of_values_from_memory( + &self, + start: MemoryAddress, + size: usize, + value_types: &[HeapValueType], + ) -> Vec { + if HeapValueType::all_simple(value_types) { + self.memory.read_slice(start, size).to_vec() + } else { + // Check that the sequence of value types fit an integer number of + // times inside the given size. + assert!( + 0 == size % value_types.len(), + "array/vector does not contain a whole number of elements" + ); + (0..size) + .zip(value_types.iter().cycle()) + .flat_map(|(i, value_type)| { + let value_address: MemoryAddress = (start.to_usize() + i).into(); + match value_type { + HeapValueType::Simple => { + let value = self.memory.read(value_address); + vec![value] + } + HeapValueType::Array { value_types, size } => { + let array_address = self.memory.read_ref(value_address); + let array_start = self.memory.read_ref(array_address); + self.read_slice_of_values_from_memory(array_start, *size, value_types) + } + HeapValueType::Vector { value_types } => { + let vector_address = self.memory.read_ref(value_address); + let vector_start = self.memory.read_ref(vector_address); + let size_address: MemoryAddress = + (vector_address.to_usize() + 1).into(); + let vector_size = self.memory.read(size_address).to_usize(); + self.read_slice_of_values_from_memory( + vector_start, + vector_size, + value_types, + ) + } + } + }) + .collect::>() + } + } + /// Process a binary operation. /// This method will not modify the program counter. fn process_binary_field_op( @@ -737,17 +832,21 @@ mod tests { let start = [ // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into() }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, // len = memory.len() (approximation) - Opcode::Const { destination: r_len, value: Value::from(item_count as u128) }, + Opcode::Const { + destination: r_len, + value: Value::from(item_count as u128), + bit_size: 32, + }, // pointer = free_memory_ptr - Opcode::Const { destination: r_pointer, value: 4u128.into() }, + Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size: 32 }, ]; let loop_body = [ // *i = i Opcode::Store { destination_pointer: r_pointer, source: r_i }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into() }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -816,13 +915,17 @@ mod tests { let start = [ // sum = 0 - Opcode::Const { destination: r_sum, value: 0u128.into() }, + Opcode::Const { destination: r_sum, value: 0u128.into(), bit_size: 32 }, // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into() }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, // len = array.len() (approximation) - Opcode::Const { destination: r_len, value: Value::from(memory.len() as u128) }, + Opcode::Const { + destination: r_len, + value: Value::from(memory.len() as u128), + bit_size: 32, + }, // pointer = array_ptr - Opcode::Const { destination: r_pointer, value: 5u128.into() }, + Opcode::Const { destination: r_pointer, value: 5u128.into(), bit_size: 32 }, Opcode::CalldataCopy { destination_address: MemoryAddress(5), size: memory.len(), @@ -841,7 +944,7 @@ mod tests { bit_size, }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into() }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -908,11 +1011,11 @@ mod tests { let start = [ // i = 0 - Opcode::Const { destination: r_i, value: 0u128.into() }, + Opcode::Const { destination: r_i, value: 0u128.into(), bit_size: 32 }, // len = size - Opcode::Const { destination: r_len, value: size.into() }, + Opcode::Const { destination: r_len, value: size.into(), bit_size: 32 }, // pointer = free_memory_ptr - Opcode::Const { destination: r_pointer, value: 4u128.into() }, + Opcode::Const { destination: r_pointer, value: 4u128.into(), bit_size: 32 }, // call recursive_fn Opcode::Call { location: 5, // Call after 'start' @@ -938,7 +1041,7 @@ mod tests { // *i = i Opcode::Store { destination_pointer: r_pointer, source: r_i }, // tmp = 1 - Opcode::Const { destination: r_tmp, value: 1u128.into() }, + Opcode::Const { destination: r_tmp, value: 1u128.into(), bit_size: 32 }, // i = i + 1 (tmp) Opcode::BinaryIntOp { destination: r_i, @@ -1008,12 +1111,14 @@ mod tests { let double_program = vec![ // Load input address with value 5 - Opcode::Const { destination: r_input, value: Value::from(5u128) }, + Opcode::Const { destination: r_input, value: Value::from(5u128), bit_size: 32 }, // 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], inputs: vec![ValueOrArray::MemoryAddress(r_input)], + input_value_types: vec![HeapValueType::Simple], }, ]; @@ -1067,9 +1172,9 @@ mod tests { offset: 0, }, // input = 0 - Opcode::Const { destination: r_input, value: 2_usize.into() }, + Opcode::Const { destination: r_input, value: 2_usize.into(), bit_size: 32 }, // output = 0 - Opcode::Const { destination: r_output, value: 2_usize.into() }, + Opcode::Const { destination: r_output, value: 2_usize.into(), bit_size: 32 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1077,10 +1182,18 @@ mod tests { pointer: r_output, size: initial_matrix.len(), })], + destination_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), })], + input_value_types: vec![HeapValueType::Array { + value_types: vec![HeapValueType::Simple], + size: initial_matrix.len(), + }], }, ]; @@ -1138,18 +1251,24 @@ mod tests { offset: 0, }, // input_pointer = 4 - Opcode::Const { destination: r_input_pointer, value: Value::from(4u128) }, + Opcode::Const { destination: r_input_pointer, value: Value::from(4u128), bit_size: 32 }, // input_size = input_string.len() (constant here) - Opcode::Const { destination: r_input_size, value: Value::from(input_string.len()) }, + Opcode::Const { + destination: r_input_size, + value: Value::from(input_string.len()), + bit_size: 32, + }, // output_pointer = 4 + input_size Opcode::Const { destination: r_output_pointer, value: Value::from(4 + input_string.len()), + bit_size: 32, }, // output_size = input_size * 2 Opcode::Const { destination: r_output_size, value: Value::from(input_string.len() * 2), + bit_size: 32, }, // output_pointer[0..output_size] = string_double(input_pointer[0...input_size]) Opcode::ForeignCall { @@ -1158,10 +1277,16 @@ mod tests { pointer: r_output_pointer, size: r_output_size, })], + destination_value_types: vec![HeapValueType::Vector { + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ValueOrArray::HeapVector(HeapVector { pointer: r_input_pointer, size: r_input_size, })], + input_value_types: vec![HeapValueType::Vector { + value_types: vec![HeapValueType::Simple], + }], }, ]; @@ -1218,9 +1343,9 @@ mod tests { offset: 0, }, // input = 0 - Opcode::Const { destination: r_input, value: Value::from(2u128) }, + Opcode::Const { destination: r_input, value: Value::from(2u128), bit_size: 32 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(6u128) }, + Opcode::Const { destination: r_output, value: Value::from(6u128), bit_size: 32 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1228,10 +1353,18 @@ mod tests { pointer: r_output, size: initial_matrix.len(), })], + destination_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ValueOrArray::HeapArray(HeapArray { pointer: r_input, size: initial_matrix.len(), })], + input_value_types: vec![HeapValueType::Array { + size: initial_matrix.len(), + value_types: vec![HeapValueType::Simple], + }], }, ]; @@ -1299,11 +1432,11 @@ mod tests { offset: 0, }, // input = 3 - Opcode::Const { destination: r_input_a, value: Value::from(3u128) }, + Opcode::Const { destination: r_input_a, value: Value::from(3u128), bit_size: 32 }, // input = 7 - Opcode::Const { destination: r_input_b, value: Value::from(7u128) }, + Opcode::Const { destination: r_input_b, value: Value::from(7u128), bit_size: 32 }, // output = 0 - Opcode::Const { destination: r_output, value: Value::from(0u128) }, + Opcode::Const { destination: r_output, value: Value::from(0u128), bit_size: 32 }, // *output = matrix_2x2_transpose(*input) Opcode::ForeignCall { function: "matrix_2x2_transpose".into(), @@ -1311,10 +1444,24 @@ mod tests { pointer: r_output, size: matrix_a.len(), })], + destination_value_types: vec![HeapValueType::Array { + size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], + }], inputs: vec![ ValueOrArray::HeapArray(HeapArray { pointer: r_input_a, size: matrix_a.len() }), ValueOrArray::HeapArray(HeapArray { pointer: r_input_b, size: matrix_b.len() }), ], + input_value_types: vec![ + HeapValueType::Array { + size: matrix_a.len(), + value_types: vec![HeapValueType::Simple], + }, + HeapValueType::Array { + size: matrix_b.len(), + value_types: vec![HeapValueType::Simple], + }, + ], }, ]; let mut initial_memory = matrix_a.clone(); @@ -1346,4 +1493,121 @@ mod tests { // Ensure the foreign call counter has been incremented assert_eq!(vm.foreign_call_counter, 1); } + + #[test] + fn foreign_call_opcode_nested_arrays_and_slices_input() { + // [(1, <2,3>, [4]), (5, <6,7,8>, [9])] + + let v2 = vec![Value::from(2u128), Value::from(3u128)]; + let a4 = vec![Value::from(4u128)]; + let v6 = vec![Value::from(6u128), Value::from(7u128), Value::from(8u128)]; + let a9 = vec![Value::from(9u128)]; + + // construct memory by declaring all inner arrays/vectors first + let v2_ptr = 0u128; + let mut memory = v2.clone(); + let v2_start = memory.len(); + memory.extend(vec![Value::from(v2_ptr), Value::from(v2.len()), Value::from(1u128)]); + let a4_ptr = memory.len(); + memory.extend(a4.clone()); + let a4_start = memory.len(); + memory.extend(vec![Value::from(a4_ptr), Value::from(1u128)]); + let v6_ptr = memory.len(); + memory.extend(v6.clone()); + let v6_start = memory.len(); + memory.extend(vec![Value::from(v6_ptr), Value::from(v6.len()), Value::from(1u128)]); + let a9_ptr = memory.len(); + memory.extend(a9.clone()); + let a9_start = memory.len(); + memory.extend(vec![Value::from(a9_ptr), Value::from(1u128)]); + // finally we add the contents of the outer array + let outer_ptr = memory.len(); + let outer_array = vec![ + Value::from(1u128), + Value::from(v2.len()), + Value::from(v2_start), + Value::from(a4_start), + Value::from(5u128), + Value::from(v6.len()), + Value::from(v6_start), + Value::from(a9_start), + ]; + memory.extend(outer_array.clone()); + + let input_array_value_types = vec![ + HeapValueType::Simple, + HeapValueType::Simple, // size of following vector + HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }, + HeapValueType::Array { value_types: vec![HeapValueType::Simple], size: 1 }, + ]; + + // memory address of the end of the above data structures + let r_ptr = memory.len(); + + let r_input = MemoryAddress::from(r_ptr); + let r_output = MemoryAddress::from(r_ptr + 1); + + let program = vec![ + Opcode::CalldataCopy { + destination_address: MemoryAddress::from(0), + size: memory.len(), + offset: 0, + }, + // input = 0 + Opcode::Const { destination: r_input, value: Value::from(outer_ptr), bit_size: 32 }, + // some_function(input) + Opcode::ForeignCall { + function: "flat_sum".into(), + destinations: vec![ValueOrArray::MemoryAddress(r_output)], + destination_value_types: vec![HeapValueType::Simple], + inputs: vec![ValueOrArray::HeapArray(HeapArray { + pointer: r_input, + size: outer_array.len(), + })], + input_value_types: vec![HeapValueType::Array { + value_types: input_array_value_types, + size: outer_array.len(), + }], + }, + ]; + + let mut vm = brillig_execute_and_get_vm(memory, &program); + + // Check that VM is waiting + assert_eq!( + vm.status, + VMStatus::ForeignCallWait { + function: "flat_sum".into(), + inputs: vec![ForeignCallParam::Array(vec![ + Value::from(1u128), + Value::from(2u128), // size of following vector + Value::from(2u128), + Value::from(3u128), + Value::from(4u128), + Value::from(5u128), + Value::from(3u128), // size of following vector + Value::from(6u128), + Value::from(7u128), + Value::from(8u128), + Value::from(9u128), + ])], + } + ); + + // Push result we're waiting for + vm.resolve_foreign_call(Value::from(45u128).into()); + + // Resume VM + brillig_execute(&mut vm); + + // Check that VM finished once resumed + assert_eq!(vm.status, VMStatus::Finished { return_data_offset: 0, return_data_size: 0 }); + + // Check result + let result_value = vm.memory.read(r_output); + assert_eq!(result_value, Value::from(45u128)); + + // Ensure the foreign call counter has been incremented + assert_eq!(vm.foreign_call_counter, 1); + } } diff --git a/aztec_macros/src/lib.rs b/aztec_macros/src/lib.rs index 1dbe7631388..138bcafb1d6 100644 --- a/aztec_macros/src/lib.rs +++ b/aztec_macros/src/lib.rs @@ -1,5 +1,7 @@ -use iter_extended::vecmap; +use std::borrow::{Borrow, BorrowMut}; +use std::vec; +use iter_extended::vecmap; use noirc_frontend::macros_api::FieldElement; use noirc_frontend::macros_api::{ BlockExpression, CallExpression, CastExpression, Distinctness, Expression, ExpressionKind, @@ -13,6 +15,8 @@ use noirc_frontend::macros_api::{ use noirc_frontend::macros_api::{CrateId, FileId}; use noirc_frontend::macros_api::{MacroError, MacroProcessor}; use noirc_frontend::macros_api::{ModuleDefId, NodeInterner, SortedModule, StructId}; +use noirc_frontend::node_interner::{TraitId, TraitImplKind}; +use noirc_frontend::Lambda; pub struct AztecMacro; @@ -45,6 +49,8 @@ pub enum AztecMacroError { ContractHasTooManyFunctions { span: Span }, ContractConstructorMissing { span: Span }, UnsupportedFunctionArgumentType { span: Span, typ: UnresolvedTypeData }, + UnsupportedStorageType { span: Option, typ: UnresolvedTypeData }, + CouldNotAssignStorageSlots { secondary_message: Option }, EventError { span: Span, message: String }, } @@ -76,6 +82,16 @@ impl From for MacroError { secondary_message: None, span: Some(span), }, + AztecMacroError::UnsupportedStorageType { span, typ } => MacroError { + primary_message: format!("Provided storage type `{typ:?}` is not directly supported in Aztec. Please provide a custom storage implementation"), + secondary_message: None, + span, + }, + AztecMacroError::CouldNotAssignStorageSlots { secondary_message } => MacroError { + primary_message: "Could not assign storage slots, please provide a custom storage implementation".to_string(), + secondary_message, + span: None, + }, AztecMacroError::EventError { span, message } => MacroError { primary_message: message, secondary_message: None, @@ -166,7 +182,28 @@ fn member_access(lhs: &str, rhs: &str) -> Expression { }))) } +fn return_type(path: Path) -> FunctionReturnType { + let ty = make_type(UnresolvedTypeData::Named(path, vec![])); + FunctionReturnType::Ty(ty) +} + +fn lambda(parameters: Vec<(Pattern, UnresolvedType)>, body: Expression) -> Expression { + expression(ExpressionKind::Lambda(Box::new(Lambda { + parameters, + return_type: UnresolvedType { + typ: UnresolvedTypeData::Unspecified, + span: Some(Span::default()), + }, + body, + }))) +} + macro_rules! chained_path { + ( $base:expr ) => { + { + ident_path($base) + } + }; ( $base:expr $(, $tail:expr)* ) => { { let mut base_path = ident_path($base); @@ -196,7 +233,7 @@ fn cast(lhs: Expression, ty: UnresolvedTypeData) -> Expression { } fn make_type(typ: UnresolvedTypeData) -> UnresolvedType { - UnresolvedType { typ, span: None } + UnresolvedType { typ, span: Some(Span::default()) } } fn index_array(array: Ident, index: &str) -> Expression { @@ -251,7 +288,8 @@ fn transform_hir( crate_id: &CrateId, context: &mut HirContext, ) -> Result<(), (AztecMacroError, FileId)> { - transform_events(crate_id, context) + transform_events(crate_id, context)?; + assign_storage_slots(crate_id, context) } /// Includes an import to the aztec library if it has not been included yet @@ -288,6 +326,16 @@ fn check_for_storage_definition(module: &SortedModule) -> bool { module.types.iter().any(|r#struct| r#struct.name.0.contents == "Storage") } +// Check to see if the user has defined a storage struct +fn check_for_storage_implementation(module: &SortedModule) -> bool { + module.impls.iter().any(|r#impl| match &r#impl.object_type.typ { + UnresolvedTypeData::Named(path, _) => { + path.segments.last().is_some_and(|segment| segment.0.contents == "Storage") + } + _ => false, + }) +} + // Check if "compute_note_hash_and_nullifier(AztecAddress,Field,Field,[Field; N]) -> [Field; 4]" is defined fn check_for_compute_note_hash_and_nullifier_definition(module: &SortedModule) -> bool { module.functions.iter().any(|func| { @@ -343,9 +391,15 @@ fn transform_module( // Check for a user defined storage struct let storage_defined = check_for_storage_definition(module); + let storage_implemented = check_for_storage_implementation(module); + + let crate_graph = &context.crate_graph[crate_id]; + + if storage_defined && !storage_implemented { + generate_storage_implementation(module).map_err(|err| (err, crate_graph.root_file_id))?; + } if storage_defined && !check_for_compute_note_hash_and_nullifier_definition(module) { - let crate_graph = &context.crate_graph[crate_id]; return Err(( AztecMacroError::ComputeNoteHashAndNullifierNotFound { span: Span::default() }, crate_graph.root_file_id, @@ -370,6 +424,10 @@ fn transform_module( transform_function("Public", func, storage_defined) .map_err(|err| (err, crate_graph.root_file_id))?; has_transformed_module = true; + } else if is_custom_attribute(&secondary_attribute, "aztec(public-vm)") { + transform_vm_function(func, storage_defined) + .map_err(|err| (err, crate_graph.root_file_id))?; + has_transformed_module = true; } } // Add the storage struct to the beginning of the function if it is unconstrained in an aztec contract @@ -403,6 +461,134 @@ fn transform_module( Ok(has_transformed_module) } +/// Auxiliary function to generate the storage constructor for a given field, using +/// the Storage definition as a reference. Supports nesting. +fn generate_storage_field_constructor( + (type_ident, unresolved_type): &(Ident, UnresolvedType), + slot: Expression, +) -> Result { + let typ = &unresolved_type.typ; + match typ { + UnresolvedTypeData::Named(path, generics) => { + let mut new_path = path.clone().to_owned(); + new_path.segments.push(ident("new")); + match path.segments.last().unwrap().0.contents.as_str() { + "Map" => Ok(call( + variable_path(new_path), + vec![ + variable("context"), + slot, + lambda( + vec![ + ( + pattern("context"), + make_type(UnresolvedTypeData::Named( + chained_path!("aztec", "context", "Context"), + vec![], + )), + ), + ( + Pattern::Identifier(ident("slot")), + make_type(UnresolvedTypeData::FieldElement), + ), + ], + generate_storage_field_constructor( + &(type_ident.clone(), generics.iter().last().unwrap().clone()), + variable("slot"), + )?, + ), + ], + )), + _ => Ok(call(variable_path(new_path), vec![variable("context"), slot])), + } + } + _ => Err(AztecMacroError::UnsupportedStorageType { + typ: typ.clone(), + span: Some(type_ident.span()), + }), + } +} + +// Generates the Storage implementation block from the Storage struct definition if it does not exist +/// From: +/// +/// struct Storage { +/// a_map: Map>, +/// a_nested_map: Map>>, +/// a_field: SomeStoragePrimitive, +/// } +/// +/// To: +/// +/// impl Storage { +/// fn init(context: Context) -> Self { +/// Storage { +/// a_map: Map::new(context, 0, |context, slot| { +/// SomeStoragePrimitive::new(context, slot) +/// }), +/// a_nested_map: Map::new(context, 0, |context, slot| { +/// Map::new(context, slot, |context, slot| { +/// SomeStoragePrimitive::new(context, slot) +/// }) +/// }), +/// a_field: SomeStoragePrimitive::new(context, 0), +/// } +/// } +/// } +/// +/// Storage slots are generated as 0 and will be populated using the information from the HIR +/// at a later stage. +fn generate_storage_implementation(module: &mut SortedModule) -> Result<(), AztecMacroError> { + let definition = + module.types.iter().find(|r#struct| r#struct.name.0.contents == "Storage").unwrap(); + + let slot_zero = expression(ExpressionKind::Literal(Literal::Integer( + FieldElement::from(i128::from(0)), + false, + ))); + + let field_constructors = definition + .fields + .iter() + .flat_map(|field| { + generate_storage_field_constructor(field, slot_zero.clone()) + .map(|expression| (field.0.clone(), expression)) + }) + .collect(); + + let storage_constructor_statement = make_statement(StatementKind::Expression(expression( + ExpressionKind::constructor((chained_path!("Storage"), field_constructors)), + ))); + + let init = NoirFunction::normal(FunctionDefinition::normal( + &ident("init"), + &vec![], + &[( + ident("context"), + make_type(UnresolvedTypeData::Named( + chained_path!("aztec", "context", "Context"), + vec![], + )), + )], + &BlockExpression(vec![storage_constructor_statement]), + &[], + &return_type(chained_path!("Self")), + )); + + let storage_impl = TypeImpl { + object_type: UnresolvedType { + typ: UnresolvedTypeData::Named(chained_path!("Storage"), vec![]), + span: Some(Span::default()), + }, + type_span: Span::default(), + generics: vec![], + methods: vec![init], + }; + module.impls.push(storage_impl); + + Ok(()) +} + /// If it does, it will insert the following things: /// - A new Input that is provided for a kernel app circuit, named: {Public/Private}ContextInputs /// - Hashes all of the function input variables @@ -454,6 +640,24 @@ fn transform_function( Ok(()) } +/// Transform a function to work with AVM bytecode +fn transform_vm_function( + func: &mut NoirFunction, + _storage_defined: bool, +) -> Result<(), AztecMacroError> { + // Push Avm context creation to the beginning of the function + let create_context = create_avm_context()?; + func.def.body.0.insert(0, create_context); + + // We want the function to be seen as a public function + func.def.is_open = true; + + // NOTE: the line below is a temporary hack to trigger external transpilation tools + // It will be removed once the transpiler is integrated into the Noir compiler + func.def.name.0.contents = format!("avm_{}", func.def.name.0.contents); + Ok(()) +} + /// Transform Unconstrained /// /// Inserts the following code at the beginning of an unconstrained function @@ -484,6 +688,23 @@ fn collect_crate_structs(crate_id: &CrateId, context: &HirContext) -> Vec Vec { + let crates = context.crates(); + crates + .flat_map(|crate_id| context.def_map(&crate_id).map(|def_map| def_map.modules())) + .flatten() + .flat_map(|(_, module)| { + module.type_definitions().filter_map(|typ| { + if let ModuleDefId::TraitId(struct_id) = typ { + Some(struct_id) + } else { + None + } + }) + }) + .collect() +} + /// Substitutes the signature literal that was introduced in the selector method previously with the actual signature. fn transform_event( struct_id: StructId, @@ -576,6 +797,185 @@ fn transform_events( Ok(()) } +/// Obtains the serialized length of a type that implements the Serialize trait. +fn get_serialized_length( + traits: &[TraitId], + typ: &Type, + interner: &NodeInterner, +) -> Result { + let (struct_name, maybe_stored_in_state) = match typ { + Type::Struct(struct_type, generics) => { + Ok((struct_type.borrow().name.0.contents.clone(), generics.get(0))) + } + _ => Err(AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some("State storage variable must be a struct".to_string()), + }), + }?; + let stored_in_state = + maybe_stored_in_state.ok_or(AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some("State storage variable must be generic".to_string()), + })?; + + let is_note = traits.iter().any(|&trait_id| { + let r#trait = interner.get_trait(trait_id); + r#trait.name.0.contents == "NoteInterface" + && !interner.lookup_all_trait_implementations(stored_in_state, trait_id).is_empty() + }); + + // Maps and (private) Notes always occupy a single slot. Someone could store a Note in PublicState for whatever reason though. + if struct_name == "Map" || (is_note && struct_name != "PublicState") { + return Ok(1); + } + + let serialized_trait_impl_kind = traits + .iter() + .filter_map(|&trait_id| { + let r#trait = interner.get_trait(trait_id); + if r#trait.borrow().name.0.contents == "Serialize" + && r#trait.borrow().generics.len() == 1 + { + interner + .lookup_all_trait_implementations(stored_in_state, trait_id) + .into_iter() + .next() + } else { + None + } + }) + .next() + .ok_or(AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some("Stored data must implement Serialize trait".to_string()), + })?; + + let serialized_trait_impl_id = match serialized_trait_impl_kind { + TraitImplKind::Normal(trait_impl_id) => Ok(trait_impl_id), + _ => Err(AztecMacroError::CouldNotAssignStorageSlots { secondary_message: None }), + }?; + + let serialized_trait_impl_shared = interner.get_trait_implementation(*serialized_trait_impl_id); + let serialized_trait_impl = serialized_trait_impl_shared.borrow(); + + match serialized_trait_impl.trait_generics.get(0).unwrap() { + Type::Constant(value) => Ok(*value), + _ => Err(AztecMacroError::CouldNotAssignStorageSlots { secondary_message: None }), + } +} + +/// Assigns storage slots to the storage struct fields based on the serialized length of the types. This automatic assignment +/// will only trigger if the assigned storage slot is invalid (0 as generated by generate_storage_implementation) +fn assign_storage_slots( + crate_id: &CrateId, + context: &mut HirContext, +) -> Result<(), (AztecMacroError, FileId)> { + let traits: Vec<_> = collect_traits(context); + for struct_id in collect_crate_structs(crate_id, context) { + let interner: &mut NodeInterner = context.def_interner.borrow_mut(); + let r#struct = interner.get_struct(struct_id); + let file_id = r#struct.borrow().location.file; + if r#struct.borrow().name.0.contents == "Storage" && r#struct.borrow().id.krate().is_root() + { + let init_id = interner + .lookup_method( + &Type::Struct(interner.get_struct(struct_id), vec![]), + struct_id, + "init", + false, + ) + .ok_or(( + AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some( + "Storage struct must have an init function".to_string(), + ), + }, + file_id, + ))?; + let init_function = interner.function(&init_id).block(interner); + let init_function_statement_id = init_function.statements().first().ok_or(( + AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some("Init storage statement not found".to_string()), + }, + file_id, + ))?; + let storage_constructor_statement = interner.statement(init_function_statement_id); + + let storage_constructor_expression = match storage_constructor_statement { + HirStatement::Expression(expression_id) => { + match interner.expression(&expression_id) { + HirExpression::Constructor(hir_constructor_expression) => { + Ok(hir_constructor_expression) + } + _ => Err((AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some( + "Storage constructor statement must be a constructor expression" + .to_string(), + ), + }, file_id)) + } + } + _ => Err(( + AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some( + "Storage constructor statement must be an expression".to_string(), + ), + }, + file_id, + )), + }?; + + let mut storage_slot: u64 = 1; + for (index, (_, expr_id)) in storage_constructor_expression.fields.iter().enumerate() { + let fields = r#struct.borrow().get_fields(&[]); + let (_, field_type) = fields.get(index).unwrap(); + let new_call_expression = match interner.expression(expr_id) { + HirExpression::Call(hir_call_expression) => Ok(hir_call_expression), + _ => Err(( + AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some( + "Storage field initialization expression is not a call expression" + .to_string(), + ), + }, + file_id, + )), + }?; + + let slot_arg_expression = interner.expression(&new_call_expression.arguments[1]); + + let current_storage_slot = match slot_arg_expression { + HirExpression::Literal(HirLiteral::Integer(slot, _)) => { + Ok(slot.borrow().to_u128()) + } + _ => Err(( + AztecMacroError::CouldNotAssignStorageSlots { + secondary_message: Some( + "Storage slot argument expression must be a literal integer" + .to_string(), + ), + }, + file_id, + )), + }?; + + if current_storage_slot != 0 { + continue; + } + + let type_serialized_len = get_serialized_length(&traits, field_type, interner) + .map_err(|err| (err, file_id))?; + interner.update_expression(new_call_expression.arguments[1], |expr| { + *expr = HirExpression::Literal(HirLiteral::Integer( + FieldElement::from(u128::from(storage_slot)), + false, + )); + }); + + storage_slot += type_serialized_len; + } + } + } + Ok(()) +} + const SIGNATURE_PLACEHOLDER: &str = "SIGNATURE_PLACEHOLDER"; /// Generates the impl for an event selector @@ -762,6 +1162,35 @@ fn create_context(ty: &str, params: &[Param]) -> Result, AztecMac Ok(injected_expressions) } +/// Creates an mutable avm context +/// +/// ```noir +/// /// Before +/// #[aztec(public-vm)] +/// fn foo() -> Field { +/// let mut context = aztec::context::AVMContext::new(); +/// let timestamp = context.timestamp(); +/// // ... +/// } +/// +/// /// After +/// #[aztec(private)] +/// fn foo() -> Field { +/// let mut timestamp = context.timestamp(); +/// // ... +/// } +fn create_avm_context() -> Result { + let let_context = mutable_assignment( + "context", // Assigned to + call( + variable_path(chained_path!("aztec", "context", "AVMContext", "new")), // Path + vec![], // args + ), + ); + + Ok(let_context) +} + /// Abstract Return Type /// /// This function intercepts the function's current return type and replaces it with pushes @@ -969,9 +1398,7 @@ fn make_castable_return_type(expression: Expression) -> Statement { /// } fn create_return_type(ty: &str) -> FunctionReturnType { let return_path = chained_path!("aztec", "abi", ty); - - let ty = make_type(UnresolvedTypeData::Named(return_path, vec![])); - FunctionReturnType::Ty(ty) + return_type(return_path) } /// Create Context Finish diff --git a/compiler/noirc_driver/src/lib.rs b/compiler/noirc_driver/src/lib.rs index 6fd69f8b576..cded514f28c 100644 --- a/compiler/noirc_driver/src/lib.rs +++ b/compiler/noirc_driver/src/lib.rs @@ -3,7 +3,7 @@ #![warn(unreachable_pub)] #![warn(clippy::semicolon_if_nothing_returned)] -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use clap::Args; use fm::{FileId, FileManager}; use iter_extended::vecmap; @@ -87,12 +87,14 @@ pub struct CompileOptions { fn parse_expression_width(input: &str) -> Result { use std::io::{Error, ErrorKind}; - let width = input .parse::() .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?; - Ok(ExpressionWidth::from(width)) + match width { + 0 => Ok(ExpressionWidth::Unbounded), + _ => Ok(ExpressionWidth::Bounded { width }), + } } /// Helper type used to signify where only warnings are expected in file diagnostics diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs index 96d80cb8131..dfe23b45034 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_black_box.rs @@ -244,13 +244,13 @@ pub(crate) fn convert_black_box_call( ) } } - BlackBoxFunc::BigIntNeg => { + BlackBoxFunc::BigIntSub => { if let ( [BrilligVariable::Simple(lhs), BrilligVariable::Simple(rhs)], [BrilligVariable::Simple(output)], ) = (function_arguments, function_results) { - brillig_context.black_box_op_instruction(BlackBoxOp::BigIntNeg { + brillig_context.black_box_op_instruction(BlackBoxOp::BigIntSub { lhs: *lhs, rhs: *rhs, output: *output, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs index ae8adeb10ec..b19ee97bc4e 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_block.rs @@ -1,4 +1,6 @@ -use crate::brillig::brillig_ir::brillig_variable::{BrilligArray, BrilligVariable, BrilligVector}; +use crate::brillig::brillig_ir::brillig_variable::{ + type_to_heap_value_type, BrilligArray, BrilligVariable, BrilligVector, +}; use crate::brillig::brillig_ir::{ BrilligBinaryOp, BrilligContext, BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE, }; @@ -85,10 +87,10 @@ impl<'block> BrilligBlock<'block> { self.convert_ssa_terminator(terminator_instruction, dfg); } - fn get_bit_size_from_ssa_type(typ: Type) -> u32 { + fn get_bit_size_from_ssa_type(typ: &Type) -> u32 { match typ { Type::Numeric(num_type) => match num_type { - NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => bit_size, + NumericType::Signed { bit_size } | NumericType::Unsigned { bit_size } => *bit_size, NumericType::NativeField => FieldElement::max_num_bits(), }, _ => unreachable!("ICE bitwise not on a non numeric type"), @@ -322,7 +324,7 @@ impl<'block> BrilligBlock<'block> { dfg.instruction_results(instruction_id)[0], dfg, ); - let bit_size = Self::get_bit_size_from_ssa_type(dfg.type_of_value(*value)); + let bit_size = Self::get_bit_size_from_ssa_type(&dfg.type_of_value(*value)); self.brillig_context.not_instruction(condition_register, bit_size, result_register); } Instruction::Call { func, arguments } => match &dfg[*func] { @@ -332,13 +334,23 @@ impl<'block> BrilligBlock<'block> { let input_registers = vecmap(arguments, |value_id| { self.convert_ssa_value(*value_id, dfg).to_register_or_memory() }); + let input_value_types = vecmap(arguments, |value_id| { + let value_type = dfg.type_of_value(*value_id); + type_to_heap_value_type(&value_type) + }); let output_registers = vecmap(result_ids, |value_id| { self.allocate_external_call_result(*value_id, dfg).to_register_or_memory() }); + let output_value_types = vecmap(result_ids, |value_id| { + let value_type = dfg.type_of_value(*value_id); + type_to_heap_value_type(&value_type) + }); self.brillig_context.foreign_call_instruction( func_name.to_owned(), &input_registers, + &input_value_types, &output_registers, + &output_value_types, ); for (i, output_register) in output_registers.iter().enumerate() { @@ -499,7 +511,9 @@ impl<'block> BrilligBlock<'block> { BrilligVariable::Simple(..) => unreachable!("ICE: ToBits on non-array"), }; - let radix = self.brillig_context.make_constant(2_usize.into()); + let radix = self + .brillig_context + .make_constant(2_usize.into(), FieldElement::max_num_bits()); // Update the user-facing slice length self.brillig_context.mov_instruction(target_len, limb_count); @@ -596,6 +610,7 @@ impl<'block> BrilligBlock<'block> { self.brillig_context.const_instruction( right, FieldElement::from_be_bytes_reduce(&max.to_bytes_be()).into(), + FieldElement::max_num_bits(), ); let brillig_binary_op = BrilligBinaryOp::Integer { @@ -696,7 +711,7 @@ impl<'block> BrilligBlock<'block> { ) { let (size_as_register, should_deallocate_size) = match array_variable { BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { - (self.brillig_context.make_constant(size.into()), true) + (self.brillig_context.make_usize_constant(size.into()), true) } BrilligVariable::BrilligVector(BrilligVector { size, .. }) => (size, false), _ => unreachable!("ICE: validate array index on non-array"), @@ -763,7 +778,7 @@ impl<'block> BrilligBlock<'block> { let (source_pointer, source_size_as_register) = match source_variable { BrilligVariable::BrilligArray(BrilligArray { size, pointer, rc: _ }) => { let source_size_register = self.brillig_context.allocate_register(); - self.brillig_context.const_instruction(source_size_register, size.into()); + self.brillig_context.usize_const(source_size_register, size.into()); (pointer, source_size_register) } BrilligVariable::BrilligVector(BrilligVector { size, pointer, rc: _ }) => { @@ -774,7 +789,7 @@ impl<'block> BrilligBlock<'block> { _ => unreachable!("ICE: array set on non-array"), }; - let one = self.brillig_context.make_constant(1_usize.into()); + let one = self.brillig_context.make_usize_constant(1_usize.into()); let condition = self.brillig_context.allocate_register(); self.brillig_context.binary_instruction( @@ -802,7 +817,7 @@ impl<'block> BrilligBlock<'block> { match destination_variable { BrilligVariable::BrilligArray(BrilligArray { rc: target_rc, .. }) => { - self.brillig_context.const_instruction(target_rc, 1_usize.into()); + self.brillig_context.usize_const(target_rc, 1_usize.into()); } BrilligVariable::BrilligVector(BrilligVector { size: target_size, @@ -810,7 +825,7 @@ impl<'block> BrilligBlock<'block> { .. }) => { self.brillig_context.mov_instruction(target_size, source_size_as_register); - self.brillig_context.const_instruction(target_rc, 1_usize.into()); + self.brillig_context.usize_const(target_rc, 1_usize.into()); } _ => unreachable!("ICE: array set on non-array"), } @@ -1022,7 +1037,7 @@ impl<'block> BrilligBlock<'block> { // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 let user_index = self.convert_ssa_register_value(arguments[2], dfg); - let converted_index = self.brillig_context.make_constant(element_size.into()); + let converted_index = self.brillig_context.make_usize_constant(element_size.into()); self.brillig_context.memory_op( converted_index, @@ -1065,7 +1080,7 @@ impl<'block> BrilligBlock<'block> { // https://github.com/noir-lang/noir/issues/1889#issuecomment-1668048587 let user_index = self.convert_ssa_register_value(arguments[2], dfg); - let converted_index = self.brillig_context.make_constant(element_size.into()); + let converted_index = self.brillig_context.make_usize_constant(element_size.into()); self.brillig_context.memory_op( converted_index, user_index, @@ -1158,7 +1173,7 @@ impl<'block> BrilligBlock<'block> { // converted to registers so we fetch from the cache. self.variables.get_allocation(self.function_context, value_id, dfg) } - Value::NumericConstant { constant, .. } => { + Value::NumericConstant { constant, typ } => { // Constants might have been converted previously or not, so we get or create and // (re)initialize the value inside. if let Some(variable) = self.variables.get_constant(value_id, dfg) { @@ -1168,7 +1183,11 @@ impl<'block> BrilligBlock<'block> { self.variables.allocate_constant(self.brillig_context, value_id, dfg); let register_index = new_variable.extract_register(); - self.brillig_context.const_instruction(register_index, (*constant).into()); + self.brillig_context.const_instruction( + register_index, + (*constant).into(), + Self::get_bit_size_from_ssa_type(typ), + ); new_variable } } @@ -1184,16 +1203,15 @@ impl<'block> BrilligBlock<'block> { BrilligVariable::BrilligArray(brillig_array) => { self.brillig_context .allocate_fixed_length_array(brillig_array.pointer, array.len()); - self.brillig_context - .const_instruction(brillig_array.rc, 1_usize.into()); + self.brillig_context.usize_const(brillig_array.rc, 1_usize.into()); brillig_array.pointer } BrilligVariable::BrilligVector(vector) => { - self.brillig_context.const_instruction(vector.size, array.len().into()); + self.brillig_context.usize_const(vector.size, array.len().into()); self.brillig_context .allocate_array_instruction(vector.pointer, vector.size); - self.brillig_context.const_instruction(vector.rc, 1_usize.into()); + self.brillig_context.usize_const(vector.rc, 1_usize.into()); vector.pointer } @@ -1205,7 +1223,8 @@ impl<'block> BrilligBlock<'block> { // Write the items // Allocate a register for the iterator - let iterator_register = self.brillig_context.make_constant(0_usize.into()); + let iterator_register = + self.brillig_context.make_usize_constant(0_usize.into()); for element_id in array.iter() { let element_variable = self.convert_ssa_value(*element_id, dfg); @@ -1263,7 +1282,7 @@ impl<'block> BrilligBlock<'block> { ); let array = variable.extract_array(); self.brillig_context.allocate_fixed_length_array(array.pointer, array.size); - self.brillig_context.const_instruction(array.rc, 1_usize.into()); + self.brillig_context.usize_const(array.rc, 1_usize.into()); variable } @@ -1280,7 +1299,7 @@ impl<'block> BrilligBlock<'block> { // The stack pointer will then be updated by the caller of this method // once the external call is resolved and the array size is known self.brillig_context.set_array_pointer(vector.pointer); - self.brillig_context.const_instruction(vector.rc, 1_usize.into()); + self.brillig_context.usize_const(vector.rc, 1_usize.into()); variable } @@ -1304,8 +1323,7 @@ impl<'block> BrilligBlock<'block> { match array_variable { BrilligVariable::BrilligArray(BrilligArray { size, .. }) => { - self.brillig_context - .const_instruction(result_register, (size / element_size).into()); + self.brillig_context.usize_const(result_register, (size / element_size).into()); } BrilligVariable::BrilligVector(BrilligVector { size, .. }) => { self.brillig_context.usize_op( 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 5ac2ecf06be..93c4b1a5042 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_directive.rs @@ -1,5 +1,6 @@ -use acvm::acir::brillig::{ - BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode, Value, +use acvm::{ + acir::brillig::{BinaryFieldOp, BinaryIntOp, MemoryAddress, Opcode as BrilligOpcode, Value}, + FieldElement, }; use crate::brillig::brillig_ir::artifact::GeneratedBrillig; @@ -24,7 +25,11 @@ pub(crate) fn directive_invert() -> GeneratedBrillig { // If the input is zero, then we jump to the stop opcode BrilligOpcode::JumpIfNot { condition: input, location: stop_location }, // Put value one in register (1) - BrilligOpcode::Const { destination: one_const, value: Value::from(1_usize) }, + BrilligOpcode::Const { + destination: one_const, + value: Value::from(1_usize), + bit_size: FieldElement::max_num_bits(), + }, // Divide 1 by the input, and set the result of the division into register (0) BrilligOpcode::BinaryFieldOp { op: BinaryFieldOp::Div, diff --git a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs index 981a16a01b2..3fed8ee91d9 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_gen/brillig_slice_ops.rs @@ -20,7 +20,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we copy the source vector into the target vector self.brillig_context.copy_array_instruction( @@ -30,7 +30,7 @@ impl<'block> BrilligBlock<'block> { ); for (index, variable) in variables_to_insert.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.brillig_context.memory_op( target_index, source_vector.size, @@ -57,7 +57,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we offset the target pointer by variables_to_insert.len() let destination_copy_pointer = self.brillig_context.allocate_register(); @@ -77,7 +77,7 @@ impl<'block> BrilligBlock<'block> { // Then we write the items to insert at the start for (index, variable) in variables_to_insert.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.store_variable_in_array(target_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); } @@ -100,7 +100,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we offset the source pointer by removed_items.len() let source_copy_pointer = self.brillig_context.allocate_register(); @@ -119,7 +119,7 @@ impl<'block> BrilligBlock<'block> { ); for (index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); } @@ -142,7 +142,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Now we copy all elements except the last items into the target vector self.brillig_context.copy_array_instruction( @@ -152,7 +152,7 @@ impl<'block> BrilligBlock<'block> { ); for (index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(index.into()); + let target_index = self.brillig_context.make_usize_constant(index.into()); self.brillig_context.memory_op( target_index, target_vector.size, @@ -180,7 +180,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Copy the elements to the left of the index self.brillig_context.copy_array_instruction( @@ -225,7 +225,7 @@ impl<'block> BrilligBlock<'block> { // Write the items to insert starting at the index for (subitem_index, variable) in items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(subitem_index.into()); + let target_index = self.brillig_context.make_usize_constant(subitem_index.into()); self.brillig_context.memory_op(target_index, index, target_index, BinaryIntOp::Add); self.store_variable_in_array(target_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); @@ -252,7 +252,7 @@ impl<'block> BrilligBlock<'block> { ); self.brillig_context.allocate_array_instruction(target_vector.pointer, target_vector.size); // We initialize the RC of the target vector to 1 - self.brillig_context.const_instruction(target_vector.rc, 1_usize.into()); + self.brillig_context.usize_const(target_vector.rc, 1_usize.into()); // Copy the elements to the left of the index self.brillig_context.copy_array_instruction( @@ -298,7 +298,7 @@ impl<'block> BrilligBlock<'block> { // Get the removed items for (subitem_index, variable) in removed_items.iter().enumerate() { - let target_index = self.brillig_context.make_constant(subitem_index.into()); + let target_index = self.brillig_context.make_usize_constant(subitem_index.into()); self.brillig_context.memory_op(target_index, index, target_index, BinaryIntOp::Add); self.retrieve_variable_from_array(source_vector.pointer, target_index, *variable); self.brillig_context.deallocate_register(target_index); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs index b094ff9c4c0..035b9b01500 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir.rs @@ -23,6 +23,7 @@ use acvm::{ BinaryFieldOp, BinaryIntOp, BlackBoxOp, MemoryAddress, Opcode as BrilligOpcode, Value, ValueOrArray, }, + brillig_vm::brillig::HeapValueType, FieldElement, }; use debug_show::DebugShow; @@ -41,7 +42,7 @@ pub(crate) const BRILLIG_INTEGER_ARITHMETIC_BIT_SIZE: u32 = 127; /// The Brillig VM does not apply a limit to the memory address space, /// As a convention, we take use 64 bits. This means that we assume that /// memory has 2^64 memory slots. -pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 64; +pub(crate) const BRILLIG_MEMORY_ADDRESSING_BIT_SIZE: u32 = 32; // Registers reserved in runtime for special purposes. pub(crate) enum ReservedRegisters { @@ -131,7 +132,7 @@ impl BrilligContext { size: usize, ) { // debug_show handled by allocate_array_instruction - let size_register = self.make_constant(size.into()); + let size_register = self.make_usize_constant(size.into()); self.allocate_array_instruction(pointer_register, size_register); self.deallocate_register(size_register); } @@ -174,7 +175,7 @@ impl BrilligContext { ) { self.debug_show.allocate_instruction(pointer_register); // A variable can be stored in up to three values, so we reserve three values for that. - let size_register = self.make_constant(size.into()); + let size_register = self.make_usize_constant(size.into()); self.push_opcode(BrilligOpcode::Mov { destination: pointer_register, source: ReservedRegisters::stack_pointer(), @@ -286,7 +287,7 @@ impl BrilligContext { where F: FnOnce(&mut BrilligContext, MemoryAddress), { - let iterator_register = self.make_constant(0_u128.into()); + let iterator_register = self.make_usize_constant(0_u128.into()); let (loop_section, loop_label) = self.reserve_next_section_label(); self.enter_section(loop_section); @@ -529,9 +530,18 @@ impl BrilligContext { } /// Stores the value of `constant` in the `result` register - pub(crate) fn const_instruction(&mut self, result: MemoryAddress, constant: Value) { + pub(crate) fn const_instruction( + &mut self, + result: MemoryAddress, + constant: Value, + bit_size: u32, + ) { self.debug_show.const_instruction(result, constant); - self.push_opcode(BrilligOpcode::Const { destination: result, value: constant }); + self.push_opcode(BrilligOpcode::Const { destination: result, value: constant, bit_size }); + } + + pub(crate) fn usize_const(&mut self, result: MemoryAddress, constant: Value) { + self.const_instruction(result, constant, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE); } /// Processes a not instruction. @@ -548,7 +558,7 @@ impl BrilligContext { // Compile !x as ((-1) - x) let u_max = FieldElement::from(2_i128).pow(&FieldElement::from(bit_size as i128)) - FieldElement::one(); - let max = self.make_constant(Value::from(u_max)); + let max = self.make_constant(Value::from(u_max), bit_size); let opcode = BrilligOpcode::BinaryIntOp { destination: result, op: BinaryIntOp::Sub, @@ -568,13 +578,19 @@ impl BrilligContext { &mut self, func_name: String, inputs: &[ValueOrArray], + input_value_types: &[HeapValueType], outputs: &[ValueOrArray], + output_value_types: &[HeapValueType], ) { + assert!(inputs.len() == input_value_types.len()); + assert!(outputs.len() == output_value_types.len()); self.debug_show.foreign_call_instruction(func_name.clone(), inputs, outputs); let opcode = BrilligOpcode::ForeignCall { function: func_name, destinations: outputs.to_vec(), + destination_value_types: output_value_types.to_vec(), inputs: inputs.to_vec(), + input_value_types: input_value_types.to_vec(), }; self.push_opcode(opcode); } @@ -704,7 +720,7 @@ impl BrilligContext { // The brillig VM performs all arithmetic operations modulo 2**bit_size // So to truncate any value to a target bit size we can just issue a no-op arithmetic operation // With bit size equal to target_bit_size - let zero_register = self.make_constant(Value::from(FieldElement::zero())); + let zero_register = self.make_constant(Value::from(FieldElement::zero()), bit_size); self.binary_instruction( value_to_truncate, zero_register, @@ -721,9 +737,16 @@ impl BrilligContext { } /// Returns a register which holds the value of a constant - pub(crate) fn make_constant(&mut self, constant: Value) -> MemoryAddress { + pub(crate) fn make_constant(&mut self, constant: Value, bit_size: u32) -> MemoryAddress { + let register = self.allocate_register(); + self.const_instruction(register, constant, bit_size); + register + } + + /// Returns a register which holds the value of an usize constant + pub(crate) fn make_usize_constant(&mut self, constant: Value) -> MemoryAddress { let register = self.allocate_register(); - self.const_instruction(register, constant); + self.usize_const(register, constant); register } @@ -856,7 +879,7 @@ impl BrilligContext { op: BinaryIntOp, constant: usize, ) { - let const_register = self.make_constant(Value::from(constant)); + let const_register = self.make_usize_constant(Value::from(constant)); self.memory_op(operand, const_register, destination, op); // Mark as no longer used for this purpose, frees for reuse self.deallocate_register(const_register); @@ -926,13 +949,13 @@ impl BrilligContext { /// Utility method to transform a HeapArray to a HeapVector by making a runtime constant with the size. pub(crate) fn array_to_vector(&mut self, array: &BrilligArray) -> BrilligVector { - let size_register = self.make_constant(array.size.into()); + let size_register = self.make_usize_constant(array.size.into()); BrilligVector { size: size_register, pointer: array.pointer, rc: array.rc } } /// Issues a blackbox operation. pub(crate) fn black_box_op_instruction(&mut self, op: BlackBoxOp) { - self.debug_show.black_box_op_instruction(op); + self.debug_show.black_box_op_instruction(&op); self.push_opcode(BrilligOpcode::BlackBox(op)); } @@ -947,7 +970,7 @@ impl BrilligContext { big_endian: bool, ) { self.mov_instruction(target_vector.size, limb_count); - self.const_instruction(target_vector.rc, 1_usize.into()); + self.usize_const(target_vector.rc, 1_usize.into()); self.allocate_array_instruction(target_vector.pointer, target_vector.size); let shifted_register = self.allocate_register(); @@ -1047,6 +1070,7 @@ pub(crate) mod tests { BinaryIntOp, ForeignCallParam, ForeignCallResult, HeapVector, MemoryAddress, Value, ValueOrArray, }; + use acvm::brillig_vm::brillig::HeapValueType; use acvm::brillig_vm::{VMStatus, VM}; use acvm::{BlackBoxFunctionSolver, BlackBoxResolutionError, FieldElement}; @@ -1148,18 +1172,20 @@ pub(crate) mod tests { let mut context = BrilligContext::new(true); let r_stack = ReservedRegisters::stack_pointer(); // Start stack pointer at 0 - context.const_instruction(r_stack, Value::from(ReservedRegisters::len() + 3)); + context.usize_const(r_stack, Value::from(ReservedRegisters::len() + 3)); let r_input_size = MemoryAddress::from(ReservedRegisters::len()); let r_array_ptr = MemoryAddress::from(ReservedRegisters::len() + 1); let r_output_size = MemoryAddress::from(ReservedRegisters::len() + 2); let r_equality = MemoryAddress::from(ReservedRegisters::len() + 3); - context.const_instruction(r_input_size, Value::from(12_usize)); + context.usize_const(r_input_size, Value::from(12_usize)); // copy our stack frame to r_array_ptr context.mov_instruction(r_array_ptr, r_stack); context.foreign_call_instruction( "make_number_sequence".into(), &[ValueOrArray::MemoryAddress(r_input_size)], + &[HeapValueType::Simple], &[ValueOrArray::HeapVector(HeapVector { pointer: r_stack, size: r_output_size })], + &[HeapValueType::Vector { value_types: vec![HeapValueType::Simple] }], ); // push stack frame by r_returned_size context.memory_op(r_stack, r_output_size, r_stack, BinaryIntOp::Add); diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs index b3fe30c40b4..856fb709fa9 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/brillig_variable.rs @@ -1,6 +1,10 @@ -use acvm::brillig_vm::brillig::{HeapArray, HeapVector, MemoryAddress, ValueOrArray}; +use acvm::brillig_vm::brillig::{ + HeapArray, HeapValueType, HeapVector, MemoryAddress, ValueOrArray, +}; use serde::{Deserialize, Serialize}; +use crate::ssa::ir::types::Type; + /// The representation of a noir array in the Brillig IR #[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Copy)] pub(crate) struct BrilligArray { @@ -93,3 +97,16 @@ impl BrilligVariable { } } } + +pub(crate) fn type_to_heap_value_type(typ: &Type) -> HeapValueType { + match typ { + Type::Numeric(_) | Type::Reference(_) | Type::Function => HeapValueType::Simple, + Type::Array(elem_type, size) => HeapValueType::Array { + value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), + size: typ.element_size() * size, + }, + Type::Slice(elem_type) => HeapValueType::Vector { + value_types: elem_type.as_ref().iter().map(type_to_heap_value_type).collect(), + }, + } +} diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs index 28359f8dcea..280cd12e91d 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/debug_show.rs @@ -342,7 +342,7 @@ impl DebugShow { } /// Debug function for black_box_op - pub(crate) fn black_box_op_instruction(&self, op: BlackBoxOp) { + pub(crate) fn black_box_op_instruction(&self, op: &BlackBoxOp) { match op { BlackBoxOp::Sha256 { message, output } => { debug_println!(self.enable_debug_trace, " SHA256 {} -> {}", message, output); @@ -457,7 +457,7 @@ impl DebugShow { output ); } - BlackBoxOp::BigIntNeg { lhs, rhs, output } => { + BlackBoxOp::BigIntSub { lhs, rhs, output } => { debug_println!( self.enable_debug_trace, " BIGINT_NEG {} {} -> {}", diff --git a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs index b9d95788b80..fc4ac36d7fd 100644 --- a/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs +++ b/compiler/noirc_evaluator/src/brillig/brillig_ir/entry_point.rs @@ -3,7 +3,7 @@ use super::{ brillig_variable::{BrilligArray, BrilligVariable}, debug_show::DebugShow, registers::BrilligRegistersContext, - BrilligContext, ReservedRegisters, + BrilligContext, ReservedRegisters, BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }; use acvm::acir::brillig::{MemoryAddress, Opcode as BrilligOpcode}; @@ -48,6 +48,7 @@ impl BrilligContext { self.push_opcode(BrilligOpcode::Const { destination: ReservedRegisters::stack_pointer(), value: (MAX_STACK_SIZE + calldata_size + return_data_size).into(), + bit_size: BRILLIG_MEMORY_ADDRESSING_BIT_SIZE, }); // Copy calldata @@ -72,8 +73,8 @@ impl BrilligContext { } BrilligParameter::Array(_, _) => { let pointer_to_the_array_in_calldata = - self.make_constant(current_calldata_pointer.into()); - let rc_register = self.make_constant(1_usize.into()); + self.make_usize_constant(current_calldata_pointer.into()); + let rc_register = self.make_usize_constant(1_usize.into()); let flattened_size = BrilligContext::flattened_size(argument); let var = BrilligVariable::BrilligArray(BrilligArray { pointer: pointer_to_the_array_in_calldata, @@ -158,10 +159,10 @@ impl BrilligContext { for (subitem_index, subitem) in item_type.iter().enumerate() { let source_index = - self.make_constant((source_item_base_index + source_offset).into()); + self.make_usize_constant((source_item_base_index + source_offset).into()); let target_index = - self.make_constant((target_item_base_index + subitem_index).into()); + self.make_usize_constant((target_item_base_index + subitem_index).into()); match subitem { BrilligParameter::Simple => { @@ -196,7 +197,7 @@ impl BrilligContext { ); let reference = self.allocate_register(); let rc = self.allocate_register(); - self.const_instruction(rc, 1_usize.into()); + self.usize_const(rc, 1_usize.into()); self.allocate_array_reference_instruction(reference); let array_variable = BrilligVariable::BrilligArray(BrilligArray { @@ -280,7 +281,7 @@ impl BrilligContext { } BrilligParameter::Array(item_type, item_count) => { let returned_pointer = returned_variable.extract_array().pointer; - let pointer_to_return_data = self.make_constant(return_data_index.into()); + let pointer_to_return_data = self.make_usize_constant(return_data_index.into()); self.flatten_array( item_type, @@ -324,9 +325,9 @@ impl BrilligContext { for (subitem_index, subitem) in item_type.iter().enumerate() { let source_index = - self.make_constant((source_item_base_index + subitem_index).into()); + self.make_usize_constant((source_item_base_index + subitem_index).into()); let target_index = - self.make_constant((target_item_base_index + target_offset).into()); + self.make_usize_constant((target_item_base_index + target_offset).into()); match subitem { BrilligParameter::Simple => { @@ -405,7 +406,7 @@ impl BrilligContext { self.deallocate_register(movement_register); } else { - let item_count = self.make_constant((item_count * item_type.len()).into()); + let item_count = self.make_usize_constant((item_count * item_type.len()).into()); self.copy_array_instruction( deflattened_array_pointer, flattened_array_pointer, diff --git a/compiler/noirc_evaluator/src/ssa.rs b/compiler/noirc_evaluator/src/ssa.rs index 108737f1f75..e1a2e0d3564 100644 --- a/compiler/noirc_evaluator/src/ssa.rs +++ b/compiler/noirc_evaluator/src/ssa.rs @@ -14,7 +14,7 @@ use crate::{ errors::{RuntimeError, SsaReport}, }; use acvm::acir::{ - circuit::{Circuit, PublicInputs}, + circuit::{Circuit, ExpressionWidth, PublicInputs}, native_types::Witness, }; @@ -107,6 +107,7 @@ pub fn create_circuit( let circuit = Circuit { current_witness_index, + expression_width: ExpressionWidth::Unbounded, opcodes, private_parameters, public_parameters, 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 f1a639de211..94e62e76746 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 @@ -1199,7 +1199,7 @@ impl AcirContext { (vec![state_len], Vec::new()) } BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv => { assert_eq!(inputs.len(), 4, "ICE - bigint operation requires 4 inputs"); @@ -1245,7 +1245,8 @@ impl AcirContext { for i in const_inputs { field_inputs.push(i?); } - let modulus = self.big_int_ctx.modulus(field_inputs[0]); + let bigint = self.big_int_ctx.get(field_inputs[0]); + let modulus = self.big_int_ctx.modulus(bigint.modulus_id()); let bytes_len = ((modulus - BigUint::from(1_u32)).bits() - 1) / 8 + 1; output_count = bytes_len as usize; (field_inputs, vec![FieldElement::from(bytes_len as u128)]) @@ -1452,10 +1453,8 @@ impl AcirContext { } Ok(BrilligInputs::Array(var_expressions)) } - AcirValue::DynamicArray(_) => { - let mut var_expressions = Vec::new(); - self.brillig_array_input(&mut var_expressions, i)?; - Ok(BrilligInputs::Array(var_expressions)) + AcirValue::DynamicArray(AcirDynamicArray { block_id, .. }) => { + Ok(BrilligInputs::MemoryArray(block_id)) } } })?; @@ -1869,6 +1868,9 @@ fn execute_brillig(code: &[BrilligOpcode], inputs: &[BrilligInputs]) -> Option { + return None; + } } } 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 b86fc4eeb5f..4d88a449e1c 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 @@ -252,7 +252,7 @@ impl GeneratedAcir { rhs: constant_inputs[1].to_u128() as u32, output: constant_outputs[0].to_u128() as u32, }, - BlackBoxFunc::BigIntNeg => BlackBoxFuncCall::BigIntNeg { + BlackBoxFunc::BigIntSub => BlackBoxFuncCall::BigIntSub { lhs: constant_inputs[0].to_u128() as u32, rhs: constant_inputs[1].to_u128() as u32, output: constant_outputs[0].to_u128() as u32, @@ -646,7 +646,7 @@ fn black_box_func_expected_input_size(name: BlackBoxFunc) -> Option { // Big integer operations take in 0 inputs. They use constants for their inputs. BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv | BlackBoxFunc::BigIntToLeBytes => Some(0), @@ -696,7 +696,7 @@ fn black_box_expected_output_size(name: BlackBoxFunc) -> Option { // Big integer operations return a big integer BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv | BlackBoxFunc::BigIntFromLeBytes => Some(0), diff --git a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs index 0178ae9dba1..64f81e05f77 100644 --- a/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs +++ b/compiler/noirc_evaluator/src/ssa/ir/instruction/call.rs @@ -434,7 +434,7 @@ fn simplify_black_box_func( SimplifyResult::None } BlackBoxFunc::BigIntAdd - | BlackBoxFunc::BigIntNeg + | BlackBoxFunc::BigIntSub | BlackBoxFunc::BigIntMul | BlackBoxFunc::BigIntDiv | BlackBoxFunc::RecursiveAggregation diff --git a/compiler/noirc_frontend/src/node_interner.rs b/compiler/noirc_frontend/src/node_interner.rs index b856b54f6ca..11ef12ef83e 100644 --- a/compiler/noirc_frontend/src/node_interner.rs +++ b/compiler/noirc_frontend/src/node_interner.rs @@ -1,4 +1,5 @@ use std::collections::HashMap; +use std::ops::Deref; use arena::{Arena, Index}; use fm::FileId; @@ -1042,6 +1043,34 @@ impl NodeInterner { Ok(impl_kind) } + /// Given a `ObjectType: TraitId` pair, find all implementations without taking constraints into account or + /// applying any type bindings. Useful to look for a specific trait in a type that is used in a macro. + pub fn lookup_all_trait_implementations( + &self, + object_type: &Type, + trait_id: TraitId, + ) -> Vec<&TraitImplKind> { + let trait_impl = self.trait_implementation_map.get(&trait_id); + + trait_impl + .map(|trait_impl| { + trait_impl + .iter() + .filter_map(|(typ, impl_kind)| match &typ { + Type::Forall(_, typ) => { + if typ.deref() == object_type { + Some(impl_kind) + } else { + None + } + } + _ => None, + }) + .collect() + }) + .unwrap_or(vec![]) + } + /// Similar to `lookup_trait_implementation` but does not apply any type bindings on success. pub fn try_lookup_trait_implementation( &self, @@ -1263,7 +1292,6 @@ impl NodeInterner { force_type_check: bool, ) -> Option { let methods = self.struct_methods.get(&(id, method_name.to_owned())); - // If there is only one method, just return it immediately. // It will still be typechecked later. if !force_type_check { diff --git a/compiler/wasm/src/compile.rs b/compiler/wasm/src/compile.rs index b39a27a7931..c8b1680bc00 100644 --- a/compiler/wasm/src/compile.rs +++ b/compiler/wasm/src/compile.rs @@ -177,7 +177,7 @@ pub fn compile( let compile_options = CompileOptions::default(); // For now we default to a bounded width of 3, though we can add it as a parameter - let expression_width = acvm::ExpressionWidth::Bounded { width: 3 }; + let expression_width = acvm::acir::circuit::ExpressionWidth::Bounded { width: 3 }; if contracts.unwrap_or_default() { let compiled_contract = compile_contract(&mut context, crate_id, &compile_options) diff --git a/compiler/wasm/src/compile_new.rs b/compiler/wasm/src/compile_new.rs index 4616004ae2b..f8fbed4f470 100644 --- a/compiler/wasm/src/compile_new.rs +++ b/compiler/wasm/src/compile_new.rs @@ -94,7 +94,7 @@ impl CompilerContext { program_width: usize, ) -> Result { let compile_options = CompileOptions::default(); - let np_language = acvm::ExpressionWidth::Bounded { width: program_width }; + let np_language = acvm::acir::circuit::ExpressionWidth::Bounded { width: program_width }; let root_crate_id = *self.context.root_crate_id(); @@ -120,7 +120,7 @@ impl CompilerContext { program_width: usize, ) -> Result { let compile_options = CompileOptions::default(); - let np_language = acvm::ExpressionWidth::Bounded { width: program_width }; + let np_language = acvm::acir::circuit::ExpressionWidth::Bounded { width: program_width }; let root_crate_id = *self.context.root_crate_id(); let compiled_contract = diff --git a/noir_stdlib/src/bigint.nr b/noir_stdlib/src/bigint.nr index 9edd59359c1..11026651207 100644 --- a/noir_stdlib/src/bigint.nr +++ b/noir_stdlib/src/bigint.nr @@ -1,5 +1,20 @@ use crate::ops::{Add, Sub, Mul, Div, Rem,}; + +global bn254_fq = [0x47, 0xFD, 0x7C, 0xD8, 0x16, 0x8C, 0x20, 0x3C, 0x8d, 0xca, 0x71, 0x68, 0x91, 0x6a, 0x81, 0x97, + 0x5d, 0x58, 0x81, 0x81, 0xb6, 0x45, 0x50, 0xb8, 0x29, 0xa0, 0x31, 0xe1, 0x72, 0x4e, 0x64, 0x30]; +global bn254_fr = [0x01, 0x00, 0x00, 0x00, 0x3F, 0x59, 0x1F, 0x43, 0x09, 0x97, 0xB9, 0x79, 0x48, 0xE8, 0x33, 0x28, + 0x5D, 0x58, 0x81, 0x81, 0xB6, 0x45, 0x50, 0xB8, 0x29, 0xA0, 0x31, 0xE1, 0x72, 0x4E, 0x64, 0x30]; +global secpk1_fr = [0x41, 0x41, 0x36, 0xD0, 0x8C, 0x5E, 0xD2, 0xBF, 0x3B, 0xA0, 0x48, 0xAF, 0xE6, 0xDC, 0xAE, 0xBA, + 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; +global secpk1_fq = [0x2F, 0xFC, 0xFF, 0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF]; +global secpr1_fq = [0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF]; +global secpr1_fr = [0x51, 0x25, 0x63, 0xFC, 0xC2, 0xCA, 0xB9, 0xF3, 0x84, 0x9E, 0x17, 0xA7, 0xAD, 0xFA, 0xE6, 0xBC, + 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00,0xFF, 0xFF, 0xFF, 0xFF]; + + struct BigInt { pointer: u32, modulus: u32, @@ -7,21 +22,34 @@ struct BigInt { impl BigInt { #[builtin(bigint_add)] - pub fn bigint_add(self, other: BigInt) -> BigInt { + fn bigint_add(self, other: BigInt) -> BigInt { } - #[builtin(bigint_neg)] - pub fn bigint_neg(self, other: BigInt) -> BigInt { + #[builtin(bigint_sub)] + fn bigint_sub(self, other: BigInt) -> BigInt { } #[builtin(bigint_mul)] - pub fn bigint_mul(self, other: BigInt) -> BigInt { + fn bigint_mul(self, other: BigInt) -> BigInt { } #[builtin(bigint_div)] - pub fn bigint_div(self, other: BigInt) -> BigInt { + fn bigint_div(self, other: BigInt) -> BigInt { } #[builtin(bigint_from_le_bytes)] - pub fn from_le_bytes(bytes: [u8], modulus: [u8]) -> BigInt {} + fn from_le_bytes(bytes: [u8], modulus: [u8]) -> BigInt {} #[builtin(bigint_to_le_bytes)] pub fn to_le_bytes(self) -> [u8] {} + + pub fn bn254_fr_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, bn254_fr) + } + pub fn bn254_fq_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, bn254_fq) + } + pub fn secpk1_fq_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, secpk1_fq) + } + pub fn secpk1_fr_from_le_bytes(bytes: [u8]) -> BigInt { + BigInt::from_le_bytes(bytes, secpk1_fr) + } } impl Add for BigInt { @@ -31,7 +59,7 @@ impl Add for BigInt { } impl Sub for BigInt { fn sub(self: Self, other: BigInt) -> BigInt { - self.bigint_neg(other) + self.bigint_sub(other) } } impl Mul for BigInt { @@ -47,7 +75,7 @@ impl Div for BigInt { impl Rem for BigInt { fn rem(self: Self, other: BigInt) -> BigInt { let quotient = self.bigint_div(other); - self.bigint_neg(quotient.bigint_mul(other)) + self.bigint_sub(quotient.bigint_mul(other)) } } diff --git a/noir_stdlib/src/lib.nr b/noir_stdlib/src/lib.nr index 5165d1ee07b..ebde4b88858 100644 --- a/noir_stdlib/src/lib.nr +++ b/noir_stdlib/src/lib.nr @@ -25,7 +25,7 @@ mod ops; mod default; mod prelude; mod uint128; -// mod bigint; +mod bigint; // Oracle calls are required to be wrapped in an unconstrained function // Thus, the only argument to the `println` oracle is expected to always be an ident diff --git a/test_programs/execution_success/bigint/Nargo.toml b/test_programs/execution_success/bigint/Nargo.toml new file mode 100644 index 00000000000..eee0920f188 --- /dev/null +++ b/test_programs/execution_success/bigint/Nargo.toml @@ -0,0 +1,6 @@ +[package] +name = "bigint" +type = "bin" +authors = [""] + +[dependencies] diff --git a/test_programs/execution_success/bigint/Prover.toml b/test_programs/execution_success/bigint/Prover.toml new file mode 100644 index 00000000000..c50874a8613 --- /dev/null +++ b/test_programs/execution_success/bigint/Prover.toml @@ -0,0 +1,2 @@ +x = [34,3,5,8,4] +y = [44,7,1,8,8] \ No newline at end of file diff --git a/test_programs/execution_success/bigint/src/main.nr b/test_programs/execution_success/bigint/src/main.nr new file mode 100644 index 00000000000..74949a5f785 --- /dev/null +++ b/test_programs/execution_success/bigint/src/main.nr @@ -0,0 +1,21 @@ +use dep::std::bigint; + +fn main(mut x: [u8;5], y: [u8;5]) { + let a = bigint::BigInt::secpk1_fq_from_le_bytes([x[0],x[1],x[2],x[3],x[4]]); + let b = bigint::BigInt::secpk1_fq_from_le_bytes([y[0],y[1],y[2],y[3],y[4]]); + + let a_bytes = a.to_le_bytes(); + let b_bytes = b.to_le_bytes(); + for i in 0..5 { + assert(a_bytes[i] == x[i]); + assert(b_bytes[i] == y[i]); + } + + let d = a*b - b; + let d_bytes = d.to_le_bytes(); + let d1 = bigint::BigInt::secpk1_fq_from_le_bytes(597243850900842442924.to_le_bytes(10)); + let d1_bytes = d1.to_le_bytes(); + for i in 0..32 { + assert(d_bytes[i] == d1_bytes[i]); + } +} diff --git a/test_programs/execution_success/debug_logs/src/main.nr b/test_programs/execution_success/debug_logs/src/main.nr index 52c910065c1..cbce6f15286 100644 --- a/test_programs/execution_success/debug_logs/src/main.nr +++ b/test_programs/execution_success/debug_logs/src/main.nr @@ -50,6 +50,12 @@ fn main(x: Field, y: pub Field) { regression_2906(); + let first_array = [1, 2, 3]; + let second_array = [4, 5, 6]; + let arrays_nested = [first_array, second_array]; + std::println(f"first_array: {first_array}, second_array: {second_array}"); + std::println(f"arrays_nested: {arrays_nested}"); + let free_lambda = |x| x + 1; let sentinel: u32 = 8888; std::println(f"free_lambda: {free_lambda}, sentinel: {sentinel}"); diff --git a/tooling/backend_interface/src/cli/info.rs b/tooling/backend_interface/src/cli/info.rs index 934351dd517..8ca3d4dd0a3 100644 --- a/tooling/backend_interface/src/cli/info.rs +++ b/tooling/backend_interface/src/cli/info.rs @@ -1,4 +1,5 @@ -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; + use serde::Deserialize; use std::path::{Path, PathBuf}; diff --git a/tooling/backend_interface/src/proof_system.rs b/tooling/backend_interface/src/proof_system.rs index 9369c91fa94..485381006df 100644 --- a/tooling/backend_interface/src/proof_system.rs +++ b/tooling/backend_interface/src/proof_system.rs @@ -2,8 +2,10 @@ use std::fs::File; use std::io::Write; use std::path::Path; -use acvm::acir::{circuit::Circuit, native_types::WitnessMap}; -use acvm::ExpressionWidth; +use acvm::acir::{ + circuit::{Circuit, ExpressionWidth}, + native_types::WitnessMap, +}; use acvm::FieldElement; use tempfile::tempdir; use tracing::warn; diff --git a/tooling/backend_interface/src/smart_contract.rs b/tooling/backend_interface/src/smart_contract.rs index 524832c6308..5af75e48389 100644 --- a/tooling/backend_interface/src/smart_contract.rs +++ b/tooling/backend_interface/src/smart_contract.rs @@ -38,7 +38,7 @@ mod tests { use std::collections::BTreeSet; use acvm::acir::{ - circuit::{Circuit, Opcode, PublicInputs}, + circuit::{Circuit, ExpressionWidth, Opcode, PublicInputs}, native_types::{Expression, Witness}, }; @@ -51,6 +51,7 @@ mod tests { let circuit = Circuit { current_witness_index: 4, + expression_width: ExpressionWidth::Bounded { width: 3 }, opcodes: vec![constraint], private_parameters: BTreeSet::from([Witness(1), Witness(2)]), public_parameters: PublicInputs::default(), diff --git a/tooling/debugger/src/context.rs b/tooling/debugger/src/context.rs index 8e5c1dacf2c..9c12794d5dd 100644 --- a/tooling/debugger/src/context.rs +++ b/tooling/debugger/src/context.rs @@ -432,7 +432,7 @@ mod tests { }, blackbox_solver::StubbedBlackBoxSolver, brillig_vm::brillig::{ - BinaryFieldOp, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray, + BinaryFieldOp, HeapValueType, MemoryAddress, Opcode as BrilligOpcode, ValueOrArray, }, }; use nargo::{artifacts::debug::DebugArtifact, ops::DefaultForeignCallExecutor}; @@ -459,11 +459,14 @@ mod tests { BrilligOpcode::Const { destination: MemoryAddress::from(1), value: Value::from(fe_0), + bit_size: 32, }, BrilligOpcode::ForeignCall { function: "clear_mock".into(), destinations: vec![], + destination_value_types: vec![], inputs: vec![ValueOrArray::MemoryAddress(MemoryAddress::from(0))], + input_value_types: vec![HeapValueType::Simple], }, BrilligOpcode::Stop { return_data_offset: 0, return_data_size: 0 }, ], diff --git a/tooling/lsp/src/requests/profile_run.rs b/tooling/lsp/src/requests/profile_run.rs index d866be8988b..917c247410d 100644 --- a/tooling/lsp/src/requests/profile_run.rs +++ b/tooling/lsp/src/requests/profile_run.rs @@ -3,7 +3,7 @@ use std::{ future::{self, Future}, }; -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use async_lsp::{ErrorCode, ResponseError}; use nargo::{artifacts::debug::DebugArtifact, insert_all_files_for_workspace_into_file_manager}; use nargo_toml::{find_package_manifest, resolve_workspace_from_toml, PackageSelection}; diff --git a/tooling/nargo/src/ops/transform.rs b/tooling/nargo/src/ops/transform.rs index f3efd82333e..9267ed7e045 100644 --- a/tooling/nargo/src/ops/transform.rs +++ b/tooling/nargo/src/ops/transform.rs @@ -1,4 +1,4 @@ -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use iter_extended::vecmap; use noirc_driver::{CompiledContract, CompiledProgram}; diff --git a/tooling/nargo_cli/src/cli/dap_cmd.rs b/tooling/nargo_cli/src/cli/dap_cmd.rs index 67322b1873e..f25d0ac212b 100644 --- a/tooling/nargo_cli/src/cli/dap_cmd.rs +++ b/tooling/nargo_cli/src/cli/dap_cmd.rs @@ -1,5 +1,5 @@ +use acvm::acir::circuit::ExpressionWidth; use acvm::acir::native_types::WitnessMap; -use acvm::ExpressionWidth; use backend_interface::Backend; use clap::Args; use nargo::constants::PROVER_INPUT_FILE; @@ -43,7 +43,10 @@ fn parse_expression_width(input: &str) -> Result() .map_err(|err| Error::new(ErrorKind::InvalidInput, err.to_string()))?; - Ok(ExpressionWidth::from(width)) + match width { + 0 => Ok(ExpressionWidth::Unbounded), + _ => Ok(ExpressionWidth::Bounded { width }), + } } struct LoadError(&'static str); diff --git a/tooling/nargo_cli/src/cli/info_cmd.rs b/tooling/nargo_cli/src/cli/info_cmd.rs index 131fd6ad214..ef0df0bf25b 100644 --- a/tooling/nargo_cli/src/cli/info_cmd.rs +++ b/tooling/nargo_cli/src/cli/info_cmd.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use acvm::ExpressionWidth; +use acvm::acir::circuit::ExpressionWidth; use backend_interface::BackendError; use clap::Args; use iter_extended::vecmap;