diff --git a/.circleci/config.yml b/.circleci/config.yml index a7864fb23b59..4eca27df8782 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -236,16 +236,16 @@ jobs: command: cond_spot_run_tests barretenberg-x86_64-linux-clang-assert 3 join_split_example_proofs_join_split_tests --gtest_filter=-*full_proof* - *save_logs - bb-bin-tests: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Test" - command: cond_spot_run_test_script ./scripts/bin-test.sh barretenberg-x86_64-linux-clang-assert + # bb-bin-tests: + # docker: + # - image: aztecprotocol/alpine-build-image + # resource_class: small + # steps: + # - *checkout + # - *setup_env + # - run: + # name: "Test" + # command: cond_spot_run_test_script ./scripts/bin-test.sh barretenberg-x86_64-linux-clang-assert barretenberg-benchmark-aggregator: docker: @@ -316,16 +316,17 @@ jobs: name: "Build" command: cond_spot_run_build circuits-wasm-linux-clang-assert 64 - circuits-x86_64-linux-clang-tidy: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Build" - command: cond_spot_run_build circuits-x86_64-linux-clang-tidy 64 + # TODO Disabling until this is 3-10x faster see #1152 + # circuits-x86_64-linux-clang-tidy: + # docker: + # - image: aztecprotocol/alpine-build-image + # resource_class: small + # steps: + # - *checkout + # - *setup_env + # - run: + # name: "Build" + # command: cond_spot_run_build circuits-x86_64-linux-clang-tidy 64 circuits-x86_64-linux-clang: docker: @@ -685,6 +686,18 @@ jobs: name: "Test" command: cond_spot_run_tests end-to-end e2e_deploy_contract.test.ts + e2e-lending-contract: + docker: + - image: aztecprotocol/alpine-build-image + resource_class: small + steps: + - *checkout + - *setup_env + - run: + name: "Test" + command: cond_spot_run_tests end-to-end e2e_lending_contract.test.ts + + e2e-zk-token-contract: docker: - image: aztecprotocol/alpine-build-image @@ -762,7 +775,7 @@ jobs: name: "Test" command: cond_spot_run_tests end-to-end e2e_public_to_private_messaging.test.ts - e2e-account-contract: + e2e-account-contracts: docker: - image: aztecprotocol/alpine-build-image resource_class: small @@ -1008,7 +1021,8 @@ workflows: - barretenberg-stdlib-recursion-turbo-tests: *bb_test - barretenberg-stdlib-recursion-ultra-tests: *bb_test - barretenberg-join-split-tests: *bb_test - - bb-bin-tests: *bb_test + # TODO(#1236): Reinstate this test once Noir support recursion again. + # - bb-bin-tests: *bb_test - barretenberg-benchmark-aggregator: requires: - barretenberg-tests @@ -1037,7 +1051,7 @@ workflows: <<: *defaults - circuits-wasm-linux-clang: *defaults - circuits-wasm-linux-clang-assert: *defaults - - circuits-x86_64-linux-clang-tidy: *defaults + # - circuits-x86_64-linux-clang-tidy: *defaults # TODO #1152 - circuits-x86_64-linux-clang: *defaults - circuits-x86_64-linux-clang-assert: *defaults - circuits-wasm-tests: @@ -1049,7 +1063,7 @@ workflows: requires: - circuits-wasm-linux-clang - circuits-wasm-linux-clang-assert - - circuits-x86_64-linux-clang-tidy + # - circuits-x86_64-linux-clang-tidy # TODO #1152 - circuits-x86_64-linux-clang - circuits-x86_64-linux-clang-assert - circuits-wasm-tests @@ -1115,6 +1129,7 @@ workflows: - e2e-2-rpc-servers: *e2e_test - e2e-deploy-contract: *e2e_test + - e2e-lending-contract: *e2e_test - e2e-zk-token-contract: *e2e_test - e2e-block-building: *e2e_test - e2e-nested-contract: *e2e_test @@ -1124,7 +1139,7 @@ workflows: - e2e-cross-chain-messaging: *e2e_test - e2e-public-cross-chain-messaging: *e2e_test - e2e-public-to-private-messaging: *e2e_test - - e2e-account-contract: *e2e_test + - e2e-account-contracts: *e2e_test - e2e-pending-commitments-contract: *e2e_test - uniswap-trade-on-l1-from-l2: *e2e_test - integration-l1-publisher: *e2e_test @@ -1136,6 +1151,7 @@ workflows: requires: - e2e-2-rpc-servers - e2e-deploy-contract + - e2e-lending-contract - e2e-zk-token-contract - e2e-block-building - e2e-nested-contract @@ -1145,7 +1161,7 @@ workflows: - e2e-cross-chain-messaging - e2e-public-cross-chain-messaging - e2e-public-to-private-messaging - - e2e-account-contract + - e2e-account-contracts - e2e-pending-commitments-contract - uniswap-trade-on-l1-from-l2 - integration-l1-publisher diff --git a/circuits/cpp/barretenberg/.circleci/config.yml b/circuits/cpp/barretenberg/.circleci/config.yml index 2707d12eb524..ab6b49bfe0c7 100644 --- a/circuits/cpp/barretenberg/.circleci/config.yml +++ b/circuits/cpp/barretenberg/.circleci/config.yml @@ -266,16 +266,16 @@ jobs: command: cond_spot_run_tests barretenberg-x86_64-linux-clang-assert 3 join_split_example_proofs_join_split_tests --gtest_filter=-*full_proof* - *save_logs - bb-bin-tests: - docker: - - image: aztecprotocol/alpine-build-image - resource_class: small - steps: - - *checkout - - *setup_env - - run: - name: "Test" - command: cond_spot_run_test_script ./scripts/bin-test.sh barretenberg-x86_64-linux-clang-assert + # bb-bin-tests: + # docker: + # - image: aztecprotocol/alpine-build-image + # resource_class: small + # steps: + # - *checkout + # - *setup_env + # - run: + # name: "Test" + # command: cond_spot_run_test_script ./scripts/bin-test.sh barretenberg-x86_64-linux-clang-assert benchmark-aggregator: docker: @@ -439,7 +439,7 @@ workflows: - stdlib-recursion-turbo-tests: *bb_test - stdlib-recursion-ultra-tests: *bb_test - join-split-tests: *bb_test - - bb-bin-tests: *bb_test + # - bb-bin-tests: *bb_test - benchmark-aggregator: requires: - barretenberg-tests diff --git a/circuits/cpp/barretenberg/.gitrepo b/circuits/cpp/barretenberg/.gitrepo index 121d2275d52d..23fa8b0b25d6 100644 --- a/circuits/cpp/barretenberg/.gitrepo +++ b/circuits/cpp/barretenberg/.gitrepo @@ -6,7 +6,7 @@ [subrepo] remote = https://github.com/AztecProtocol/barretenberg branch = master - commit = d6271b95bc9b0b3ba55ae5c783c48f7903086506 - parent = 5ded7a37b833372982dd888781a708a807100e19 + commit = 970bb073763cc59552cd05dccf7f8fc63f58cef9 + parent = 6743ec1700ea13977ddfdf4817d1a4e2cb8464a8 method = merge cmdver = 0.4.6 diff --git a/circuits/cpp/barretenberg/cpp/bin-test/target/main.json b/circuits/cpp/barretenberg/cpp/bin-test/target/main.json deleted file mode 100644 index 82e0528eb670..000000000000 --- a/circuits/cpp/barretenberg/cpp/bin-test/target/main.json +++ /dev/null @@ -1 +0,0 @@ -{"backend":"acvm-backend-barretenberg","abi":{"parameters":[{"name":"verification_key","type":{"kind":"array","length":114,"type":{"kind":"field"}},"visibility":"private"},{"name":"proof","type":{"kind":"array","length":94,"type":{"kind":"field"}},"visibility":"private"},{"name":"public_inputs","type":{"kind":"array","length":1,"type":{"kind":"field"}},"visibility":"private"},{"name":"key_hash","type":{"kind":"field"},"visibility":"private"},{"name":"input_aggregation_object","type":{"kind":"array","length":16,"type":{"kind":"field"}},"visibility":"private"},{"name":"proof_b","type":{"kind":"array","length":94,"type":{"kind":"field"}},"visibility":"private"}],"param_witnesses":{"input_aggregation_object":[211,212,213,214,215,216,217,218,219,220,221,222,223,224,225,226],"key_hash":[210],"proof":[115,116,117,118,119,120,121,122,123,124,125,126,127,128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,176,177,178,179,180,181,182,183,184,185,186,187,188,189,190,191,192,193,194,195,196,197,198,199,200,201,202,203,204,205,206,207,208],"proof_b":[227,228,229,230,231,232,233,234,235,236,237,238,239,240,241,242,243,244,245,246,247,248,249,250,251,252,253,254,255,256,257,258,259,260,261,262,263,264,265,266,267,268,269,270,271,272,273,274,275,276,277,278,279,280,281,282,283,284,285,286,287,288,289,290,291,292,293,294,295,296,297,298,299,300,301,302,303,304,305,306,307,308,309,310,311,312,313,314,315,316,317,318,319,320],"public_inputs":[209],"verification_key":[1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51,52,53,54,55,56,57,58,59,60,61,62,63,64,65,66,67,68,69,70,71,72,73,74,75,76,77,78,79,80,81,82,83,84,85,86,87,88,89,90,91,92,93,94,95,96,97,98,99,100,101,102,103,104,105,106,107,108,109,110,111,112,113,114]},"return_type":{"kind":"array","length":16,"type":{"kind":"field"}},"return_witnesses":[337,338,339,340,341,342,343,344,345,346,347,348,349,350,351,352]},"bytecode":"H4sIAAAAAAAA/+3V05ObbRjA4WytrW3bdrdr79bWZ6Ofbdu2jdq2+y/UtvmkuXZmp8c96ME+M7+5cieZzJtJ5r2nxEUixSKxEx5G4kNTC80XI7HXoxZnCZZkKZZmGZZlOZZnBcazIiuxMquwKquxOmuwJmuxNuuwLuuxPhuwIRuxMZuwKZuxOVuwJVuxNduwLduxPTuwIzuxM7uwK7uxO3uwJ3uxN/uwL/uxPwdwIAcxgYOZyCQmM4WpTGM6M5jJLGYzh7nMYz6HcCiHcThHcCRHcTTHcCzHcTwncCIncTKn8AbeyJt4M2/hrbyNt/MO3sm7eDfv4b28j/dzaqHrjJ4HzA/yIT7MR/goH+PjfIJP8ik+zWf4LJ/j83yBL/IlvsxX+Cpf4+t8g2/yLb7Nd/gu3+P7/IAf8iN+zE/4KT/j5/yCX/Irfs1v+C2/4/f8gT/yJ/7MX/grf+Pv/IN/8i/+zX/4L//j/5zG6ZzBmZzF2ZzDuZzH+VzAhVzExVzCpVzG5VzBlVzF1VzDtVzH9dzAjdzEzYzuoejZYt7KK4siegaHdySGkkLJoZRQaigtlB7KCGWGskLZoZxQbigvlB9XtPiKFl/MBBYtvpjX2+LbZt7OHdzJXdzNPdzLfdzPAzzIQzzMIzzKYzzOEzzJUzzNMzzLczzPCyzoEqM3oKhxLMbiLMGSLMXSLMOyLMfyrMB4VmQlVmYVVmU1VmcN1mQt1mYd1mU91mcDNmQjNmYTNmUzNmcLtmQrtmYbtmU7tmcHdmQndmYXdmU3dmcP9mQv9mYf9mU/9ucADuQgJhT8/pHYuXrxxRVefNEnEpnEZKYwlWlMZwYzmcVs5jCXecwv+KO4jiFhHhoaFhoeGhEaGRoVGh0aExobGhcaH5oQmhiaFJpc8C2v4eddBhwvtmjWDgAA","proving_key":null,"verification_key":null} \ No newline at end of file diff --git a/circuits/cpp/barretenberg/cpp/bin-test/target/witness.tr b/circuits/cpp/barretenberg/cpp/bin-test/target/witness.tr deleted file mode 100644 index 82e8cf3ff57f..000000000000 Binary files a/circuits/cpp/barretenberg/cpp/bin-test/target/witness.tr and /dev/null differ diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp index 4acabafe5972..b33c935590fc 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/acir_to_constraint_buf.hpp @@ -209,31 +209,6 @@ void handle_blackbox_func_call(Circuit::Opcode::BlackBoxFuncCall const& arg, aci arg.value.value); } -void handle_memory(Circuit::MemoryBlock const& mem_block, bool is_ram, acir_format& af) -{ - std::vector init; - std::vector trace; - auto len = mem_block.len; - for (size_t i = 0; i < len; ++i) { - init.push_back(serialize_arithmetic_gate(mem_block.trace[i].value)); - } - for (size_t i = len; i < mem_block.trace.size(); ++i) { - auto index = serialize_arithmetic_gate(mem_block.trace[i].index); - auto value = serialize_arithmetic_gate(mem_block.trace[i].value); - auto op = mem_block.trace[i].operation; - if (!(op.mul_terms.empty() && op.linear_combinations.empty())) { - throw_or_abort("Expected constant."); - } - bool access_type(uint256_t(op.q_c)); - trace.push_back(MemOp{ - .access_type = static_cast(access_type), - .index = index, - .value = value, - }); - } - af.block_constraints.push_back(BlockConstraint{ .init = init, .trace = trace, .type = (BlockType)is_ram }); -} - BlockConstraint handle_memory_init(Circuit::Opcode::MemoryInit const& mem_init) { BlockConstraint block{ .init = {}, .trace = {}, .type = BlockType::ROM }; @@ -256,10 +231,16 @@ BlockConstraint handle_memory_init(Circuit::Opcode::MemoryInit const& mem_init) return block; } +bool is_rom(Circuit::MemOp const& mem_op) +{ + return mem_op.operation.mul_terms.size() == 0 && mem_op.operation.linear_combinations.size() == 0 && + uint256_t(mem_op.operation.q_c) == 0; +} + void handle_memory_op(Circuit::Opcode::MemoryOp const& mem_op, BlockConstraint& block) { uint8_t access_type = 1; - if (mem_op.op.is_rom()) { + if (is_rom(mem_op.op)) { access_type = 0; } if (block.type == BlockType::ROM && access_type == 1) { @@ -289,10 +270,6 @@ acir_format circuit_buf_to_acir_format(std::vector const& buf) handle_arithmetic(arg, af); } else if constexpr (std::is_same_v) { handle_blackbox_func_call(arg, af); - } else if constexpr (std::is_same_v) { - handle_memory(arg.value, true, af); - } else if constexpr (std::is_same_v) { - handle_memory(arg.value, false, af); } else if constexpr (std::is_same_v) { auto block = handle_memory_init(arg); uint32_t block_id = arg.block_id.value; diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp index 01aef1ef9eff..34e87c391da0 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/dsl/acir_format/serde/acir.hpp @@ -855,22 +855,6 @@ struct MemOp { friend bool operator==(const MemOp&, const MemOp&); std::vector bincodeSerialize() const; static MemOp bincodeDeserialize(std::vector); - - bool is_rom() const - { - return this->operation.mul_terms.size() == 0 && this->operation.linear_combinations.size() == 0 && - uint256_t(this->operation.q_c) == 0; - } -}; - -struct MemoryBlock { - Circuit::BlockId id; - uint32_t len; - std::vector trace; - - friend bool operator==(const MemoryBlock&, const MemoryBlock&); - std::vector bincodeSerialize() const; - static MemoryBlock bincodeDeserialize(std::vector); }; struct Opcode { @@ -899,30 +883,6 @@ struct Opcode { static Directive bincodeDeserialize(std::vector); }; - struct Block { - Circuit::MemoryBlock value; - - friend bool operator==(const Block&, const Block&); - std::vector bincodeSerialize() const; - static Block bincodeDeserialize(std::vector); - }; - - struct ROM { - Circuit::MemoryBlock value; - - friend bool operator==(const ROM&, const ROM&); - std::vector bincodeSerialize() const; - static ROM bincodeDeserialize(std::vector); - }; - - struct RAM { - Circuit::MemoryBlock value; - - friend bool operator==(const RAM&, const RAM&); - std::vector bincodeSerialize() const; - static RAM bincodeDeserialize(std::vector); - }; - struct Brillig { Circuit::Brillig value; @@ -949,7 +909,7 @@ struct Opcode { static MemoryInit bincodeDeserialize(std::vector); }; - std::variant value; + std::variant value; friend bool operator==(const Opcode&, const Opcode&); std::vector bincodeSerialize() const; @@ -967,6 +927,7 @@ struct PublicInputs { struct Circuit { uint32_t current_witness_index; std::vector opcodes; + std::vector private_parameters; PublicInputs public_parameters; PublicInputs return_values; @@ -4459,6 +4420,9 @@ inline bool operator==(const Circuit& lhs, const Circuit& rhs) if (!(lhs.opcodes == rhs.opcodes)) { return false; } + if (!(lhs.private_parameters == rhs.private_parameters)) { + return false; + } if (!(lhs.public_parameters == rhs.public_parameters)) { return false; } @@ -4494,6 +4458,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.private_parameters, serializer); serde::Serializable::serialize(obj.public_parameters, serializer); serde::Serializable::serialize(obj.return_values, serializer); serializer.decrease_container_depth(); @@ -4507,6 +4472,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.private_parameters = serde::Deserializable::deserialize(deserializer); obj.public_parameters = serde::Deserializable::deserialize(deserializer); obj.return_values = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); @@ -5443,65 +5409,6 @@ Circuit::MemOp serde::Deserializable::deserialize(Deserializer& namespace Circuit { -inline bool operator==(const MemoryBlock& lhs, const MemoryBlock& rhs) -{ - if (!(lhs.id == rhs.id)) { - return false; - } - if (!(lhs.len == rhs.len)) { - return false; - } - if (!(lhs.trace == rhs.trace)) { - return false; - } - return true; -} - -inline std::vector MemoryBlock::bincodeSerialize() const -{ - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); -} - -inline MemoryBlock MemoryBlock::bincodeDeserialize(std::vector input) -{ - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw_or_abort("Some input bytes were not read"); - } - return value; -} - -} // end of namespace Circuit - -template <> -template -void serde::Serializable::serialize(const Circuit::MemoryBlock& obj, Serializer& serializer) -{ - serializer.increase_container_depth(); - serde::Serializable::serialize(obj.id, serializer); - serde::Serializable::serialize(obj.len, serializer); - serde::Serializable::serialize(obj.trace, serializer); - serializer.decrease_container_depth(); -} - -template <> -template -Circuit::MemoryBlock serde::Deserializable::deserialize(Deserializer& deserializer) -{ - deserializer.increase_container_depth(); - Circuit::MemoryBlock obj; - obj.id = serde::Deserializable::deserialize(deserializer); - obj.len = serde::Deserializable::deserialize(deserializer); - obj.trace = serde::Deserializable::deserialize(deserializer); - deserializer.decrease_container_depth(); - return obj; -} - -namespace Circuit { - inline bool operator==(const Opcode& lhs, const Opcode& rhs) { if (!(lhs.value == rhs.value)) { @@ -5690,141 +5597,6 @@ Circuit::Opcode::Directive serde::Deserializable::de namespace Circuit { -inline bool operator==(const Opcode::Block& lhs, const Opcode::Block& rhs) -{ - if (!(lhs.value == rhs.value)) { - return false; - } - return true; -} - -inline std::vector Opcode::Block::bincodeSerialize() const -{ - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); -} - -inline Opcode::Block Opcode::Block::bincodeDeserialize(std::vector input) -{ - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw_or_abort("Some input bytes were not read"); - } - return value; -} - -} // end of namespace Circuit - -template <> -template -void serde::Serializable::serialize(const Circuit::Opcode::Block& obj, Serializer& serializer) -{ - serde::Serializable::serialize(obj.value, serializer); -} - -template <> -template -Circuit::Opcode::Block serde::Deserializable::deserialize(Deserializer& deserializer) -{ - Circuit::Opcode::Block obj; - obj.value = serde::Deserializable::deserialize(deserializer); - return obj; -} - -namespace Circuit { - -inline bool operator==(const Opcode::ROM& lhs, const Opcode::ROM& rhs) -{ - if (!(lhs.value == rhs.value)) { - return false; - } - return true; -} - -inline std::vector Opcode::ROM::bincodeSerialize() const -{ - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); -} - -inline Opcode::ROM Opcode::ROM::bincodeDeserialize(std::vector input) -{ - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw_or_abort("Some input bytes were not read"); - } - return value; -} - -} // end of namespace Circuit - -template <> -template -void serde::Serializable::serialize(const Circuit::Opcode::ROM& obj, Serializer& serializer) -{ - serde::Serializable::serialize(obj.value, serializer); -} - -template <> -template -Circuit::Opcode::ROM serde::Deserializable::deserialize(Deserializer& deserializer) -{ - Circuit::Opcode::ROM obj; - obj.value = serde::Deserializable::deserialize(deserializer); - return obj; -} - -namespace Circuit { - -inline bool operator==(const Opcode::RAM& lhs, const Opcode::RAM& rhs) -{ - if (!(lhs.value == rhs.value)) { - return false; - } - return true; -} - -inline std::vector Opcode::RAM::bincodeSerialize() const -{ - auto serializer = serde::BincodeSerializer(); - serde::Serializable::serialize(*this, serializer); - return std::move(serializer).bytes(); -} - -inline Opcode::RAM Opcode::RAM::bincodeDeserialize(std::vector input) -{ - auto deserializer = serde::BincodeDeserializer(input); - auto value = serde::Deserializable::deserialize(deserializer); - if (deserializer.get_buffer_offset() < input.size()) { - throw_or_abort("Some input bytes were not read"); - } - return value; -} - -} // end of namespace Circuit - -template <> -template -void serde::Serializable::serialize(const Circuit::Opcode::RAM& obj, Serializer& serializer) -{ - serde::Serializable::serialize(obj.value, serializer); -} - -template <> -template -Circuit::Opcode::RAM serde::Deserializable::deserialize(Deserializer& deserializer) -{ - Circuit::Opcode::RAM obj; - obj.value = serde::Deserializable::deserialize(deserializer); - return obj; -} - -namespace Circuit { - inline bool operator==(const Opcode::Brillig& lhs, const Opcode::Brillig& rhs) { if (!(lhs.value == rhs.value)) { @@ -6426,4 +6198,4 @@ Circuit::Witness serde::Deserializable::deserialize(Deserializ obj.value = serde::Deserializable::deserialize(deserializer); deserializer.decrease_container_depth(); return obj; -} \ No newline at end of file +} diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp new file mode 100644 index 000000000000..ff4249f37b10 --- /dev/null +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/goblin_ultra_composer.test.cpp @@ -0,0 +1,65 @@ +#include +#include +#include + +#include "barretenberg/common/log.hpp" +#include "barretenberg/honk/composer/ultra_composer.hpp" +#include "barretenberg/honk/proof_system/ultra_prover.hpp" +#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" + +using namespace proof_system::honk; + +namespace test_ultra_honk_composer { + +namespace { +auto& engine = numeric::random::get_debug_engine(); +} + +class GoblinUltraHonkComposerTests : public ::testing::Test { + protected: + static void SetUpTestSuite() { barretenberg::srs::init_crs_factory("../srs_db/ignition"); } +}; + +/** + * @brief Test proof construction/verification for a circuit with ECC op gates, public inputs, and basic arithmetic + * gates + * + */ +TEST_F(GoblinUltraHonkComposerTests, SimpleCircuit) +{ + auto builder = UltraCircuitBuilder(); + + // Define an arbitrary number of operations/gates + size_t num_ecc_ops = 3; + size_t num_conventional_gates = 10; + + // Add some ecc op gates + for (size_t i = 0; i < num_ecc_ops; ++i) { + auto point = g1::affine_one * fr::random_element(); + auto scalar = fr::random_element(); + builder.queue_ecc_mul_accum(point, scalar); + } + + // Add some conventional gates that utlize public inputs + for (size_t i = 0; i < num_conventional_gates; ++i) { + fr a = fr::random_element(); + fr b = fr::random_element(); + fr c = fr::random_element(); + fr d = a + b + c; + uint32_t a_idx = builder.add_public_variable(a); + uint32_t b_idx = builder.add_variable(b); + uint32_t c_idx = builder.add_variable(c); + uint32_t d_idx = builder.add_variable(d); + + builder.create_big_add_gate({ a_idx, b_idx, c_idx, d_idx, fr(1), fr(1), fr(1), fr(-1), fr(0) }); + } + + auto composer = GoblinUltraComposer(); + auto prover = composer.create_prover(builder); + auto verifier = composer.create_verifier(builder); + auto proof = prover.construct_proof(); + bool verified = verifier.verify_proof(proof); + EXPECT_EQ(verified, true); +} + +} // namespace test_ultra_honk_composer diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.cpp index 0a21f5ac121a..2fb01186140c 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.cpp @@ -21,14 +21,16 @@ void UltraComposer_::compute_circuit_size_parameters(CircuitBuilder& cir lookups_size += table.lookup_gates.size(); } + // Get num conventional gates, num public inputs and num Goblin style ECC op gates + const size_t num_gates = circuit_constructor.num_gates; num_public_inputs = circuit_constructor.public_inputs.size(); + num_ecc_op_gates = circuit_constructor.num_ecc_op_gates; // minimum circuit size due to the length of lookups plus tables - const size_t minimum_circuit_size_due_to_lookups = tables_size + lookups_size + zero_row_offset; + const size_t minimum_circuit_size_due_to_lookups = tables_size + lookups_size + num_zero_rows; // number of populated rows in the execution trace - const size_t num_rows_populated_in_execution_trace = - circuit_constructor.num_gates + circuit_constructor.public_inputs.size() + zero_row_offset; + size_t num_rows_populated_in_execution_trace = num_zero_rows + num_ecc_op_gates + num_public_inputs + num_gates; // The number of gates is max(lookup gates + tables, rows already populated in trace) + 1, where the +1 is due to // addition of a "zero row" at top of the execution trace to ensure wires and other polys are shiftable. @@ -48,15 +50,7 @@ template void UltraComposer_::compute_witness(Circu return; } - // At this point, the wires have been populated with as many values as rows in the execution trace. We need to pad - // with zeros up to the full length, i.e. total_num_gates = already populated rows of execution trace + tables_size. - for (size_t i = 0; i < tables_size; ++i) { - circuit_constructor.w_l.emplace_back(circuit_constructor.zero_idx); - circuit_constructor.w_r.emplace_back(circuit_constructor.zero_idx); - circuit_constructor.w_o.emplace_back(circuit_constructor.zero_idx); - circuit_constructor.w_4.emplace_back(circuit_constructor.zero_idx); - } - + // Construct the conventional wire polynomials auto wire_polynomials = construct_wire_polynomials_base(circuit_constructor, dyadic_circuit_size); proving_key->w_l = wire_polynomials[0]; @@ -64,24 +58,23 @@ template void UltraComposer_::compute_witness(Circu proving_key->w_o = wire_polynomials[2]; proving_key->w_4 = wire_polynomials[3]; + // If Goblin, construct the ECC op queue wire polynomials + if constexpr (IsGoblinFlavor) { + construct_ecc_op_wire_polynomials(wire_polynomials); + } + + // Construct the sorted concatenated list polynomials for the lookup argument polynomial s_1(dyadic_circuit_size); polynomial s_2(dyadic_circuit_size); polynomial s_3(dyadic_circuit_size); polynomial s_4(dyadic_circuit_size); - // TODO(luke): The +1 size for z_lookup is not necessary and can lead to confusion. Resolve. - polynomial z_lookup(dyadic_circuit_size + 1); // Only instantiated in this function; nothing assigned. - - // TODO(kesha): Look at this once we figure out how we do ZK (previously we had roots cut out, so just added - // randomness) - // The size of empty space in sorted polynomials - size_t count = dyadic_circuit_size - tables_size - lookups_size; - ASSERT(count > 0); // We need at least 1 row of zeroes for the permutation argument - for (size_t i = 0; i < count; ++i) { - s_1[i] = 0; - s_2[i] = 0; - s_3[i] = 0; - s_4[i] = 0; - } + + // The sorted list polynomials have (tables_size + lookups_size) populated entries. We define the index below so + // that these entries are written into the last indices of the polynomials. The values on the first + // dyadic_circuit_size - (tables_size + lookups_size) indices are automatically initialized to zero via the + // polynomial constructor. + size_t s_index = dyadic_circuit_size - tables_size - lookups_size; + ASSERT(s_index > 0); // We need at least 1 row of zeroes for the permutation argument for (auto& table : circuit_constructor.lookup_tables) { const fr table_index(table.table_index); @@ -120,11 +113,11 @@ template void UltraComposer_::compute_witness(Circu for (const auto& entry : lookup_gates) { const auto components = entry.to_sorted_list_components(table.use_twin_keys); - s_1[count] = components[0]; - s_2[count] = components[1]; - s_3[count] = components[2]; - s_4[count] = table_index; - ++count; + s_1[s_index] = components[0]; + s_2[s_index] = components[1]; + s_3[s_index] = components[2]; + s_4[s_index] = table_index; + ++s_index; } } @@ -137,11 +130,10 @@ template void UltraComposer_::compute_witness(Circu // Copy memory read/write record data into proving key. Prover needs to know which gates contain a read/write // 'record' witness on the 4th wire. This wire value can only be fully computed once the first 3 wire polynomials // have been committed to. The 4th wire on these gates will be a random linear combination of the first 3 wires, - // using the plookup challenge `eta`. We need to update the records with an offset Because we shift the gates by - // the number of public inputs plus an additional offset for a zero row. - auto add_public_inputs_offset = [this](uint32_t gate_index) { - return gate_index + num_public_inputs + zero_row_offset; - }; + // using the plookup challenge `eta`. We need to update the records with an offset Because we shift the gates to + // account for everything that comes before them in the execution trace, e.g. public inputs, a zero row, etc. + size_t offset = num_ecc_op_gates + num_public_inputs + num_zero_rows; + auto add_public_inputs_offset = [offset](uint32_t gate_index) { return gate_index + offset; }; proving_key->memory_read_records = std::vector(); proving_key->memory_write_records = std::vector(); @@ -157,6 +149,38 @@ template void UltraComposer_::compute_witness(Circu computed_witness = true; } +/** + * @brief Construct Goblin style ECC op wire polynomials + * @details The Ecc op wire values are assumed to have already been stored in the corresponding block of the + * conventional wire polynomials. The values for the ecc op wire polynomials are set based on those values. + * + * @tparam Flavor + * @param wire_polynomials + */ +template void UltraComposer_::construct_ecc_op_wire_polynomials(auto& wire_polynomials) +{ + std::array op_wire_polynomials; + for (auto& poly : op_wire_polynomials) { + poly = polynomial(dyadic_circuit_size); + } + + // The ECC op wires are constructed to contain the op data on the appropriate range and to vanish everywhere else. + // The op data is assumed to have already been stored at the correct location in the convetional wires so the data + // can simply be copied over directly. + const size_t op_wire_offset = Flavor::has_zero_row ? 1 : 0; + for (size_t poly_idx = 0; poly_idx < Flavor::NUM_WIRES; ++poly_idx) { + for (size_t i = 0; i < num_ecc_op_gates; ++i) { + size_t idx = i + op_wire_offset; + op_wire_polynomials[poly_idx][idx] = wire_polynomials[poly_idx][idx]; + } + } + + proving_key->ecc_op_wire_1 = op_wire_polynomials[0]; + proving_key->ecc_op_wire_2 = op_wire_polynomials[1]; + proving_key->ecc_op_wire_3 = op_wire_polynomials[2]; + proving_key->ecc_op_wire_4 = op_wire_polynomials[3]; +} + template UltraProver_ UltraComposer_::create_prover(CircuitBuilder& circuit_constructor) { @@ -258,6 +282,10 @@ std::shared_ptr UltraComposer_::compute_pro proving_key->contains_recursive_proof = contains_recursive_proof; + if constexpr (IsGoblinFlavor) { + proving_key->num_ecc_op_gates = num_ecc_op_gates; + } + return proving_key; } @@ -308,6 +336,12 @@ std::shared_ptr UltraComposer_::comput verification_key->lagrange_first = commitment_key->commit(proving_key->lagrange_first); verification_key->lagrange_last = commitment_key->commit(proving_key->lagrange_last); + // TODO(luke): Similar to the lagrange_first/last polynomials, we dont really need to commit to this polynomial due + // to its simple structure. Handling it in the same way as the lagrange polys for now for simplicity. + if constexpr (IsGoblinFlavor) { + verification_key->lagrange_ecc_op = commitment_key->commit(proving_key->lagrange_ecc_op); + } + // // See `add_recusrive_proof()` for how this recursive data is assigned. // verification_key->recursive_proof_public_input_indices = // std::vector(recursive_proof_public_input_indices.begin(), @@ -319,5 +353,6 @@ std::shared_ptr UltraComposer_::comput } template class UltraComposer_; template class UltraComposer_; +template class UltraComposer_; } // namespace proof_system::honk diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.hpp index 7028d2e10564..c58cffec6ff7 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/composer/ultra_composer.hpp @@ -3,6 +3,7 @@ #include "barretenberg/honk/proof_system/ultra_prover.hpp" #include "barretenberg/honk/proof_system/ultra_verifier.hpp" #include "barretenberg/proof_system/composer/composer_lib.hpp" +#include "barretenberg/proof_system/flavor/flavor.hpp" #include "barretenberg/srs/factories/file_crs_factory.hpp" #include @@ -22,7 +23,7 @@ template class UltraComposer_ { using PCSVerificationKey = typename PCSParams::VerificationKey; // offset due to placing zero wires at the start of execution trace - static constexpr size_t zero_row_offset = Flavor::has_zero_row ? 1 : 0; + static constexpr size_t num_zero_rows = Flavor::has_zero_row ? 1 : 0; static constexpr std::string_view NAME_STRING = "UltraHonk"; static constexpr size_t NUM_WIRES = CircuitBuilder::NUM_WIRES; @@ -43,6 +44,7 @@ template class UltraComposer_ { size_t lookups_size = 0; // total number of lookup gates size_t tables_size = 0; // total number of table entries size_t num_public_inputs = 0; + size_t num_ecc_op_gates = 0; UltraComposer_() : crs_factory_(barretenberg::srs::get_crs_factory()){}; @@ -69,6 +71,8 @@ template class UltraComposer_ { void compute_witness(CircuitBuilder& circuit_constructor); + void construct_ecc_op_wire_polynomials(auto&); + UltraProver_ create_prover(CircuitBuilder& circuit_constructor); UltraVerifier_ create_verifier(const CircuitBuilder& circuit_constructor); @@ -81,7 +85,9 @@ template class UltraComposer_ { }; extern template class UltraComposer_; extern template class UltraComposer_; +extern template class UltraComposer_; // TODO(#532): this pattern is weird; is this not instantiating the templates? using UltraComposer = UltraComposer_; using UltraGrumpkinComposer = UltraComposer_; +using GoblinUltraComposer = UltraComposer_; } // namespace proof_system::honk diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp new file mode 100644 index 000000000000..b46613675d6b --- /dev/null +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/flavor/goblin_ultra.hpp @@ -0,0 +1,442 @@ +#pragma once +#include "barretenberg/ecc/curves/bn254/g1.hpp" +#include "barretenberg/honk/pcs/commitment_key.hpp" +#include "barretenberg/honk/pcs/kzg/kzg.hpp" +#include "barretenberg/honk/sumcheck/polynomials/barycentric_data.hpp" +#include "barretenberg/honk/sumcheck/polynomials/univariate.hpp" +#include "barretenberg/honk/sumcheck/relations/auxiliary_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/ecc_op_queue_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/elliptic_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/gen_perm_sort_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/lookup_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/permutation_relation.hpp" +#include "barretenberg/honk/sumcheck/relations/ultra_arithmetic_relation.hpp" +#include "barretenberg/honk/transcript/transcript.hpp" +#include "barretenberg/polynomials/evaluation_domain.hpp" +#include "barretenberg/polynomials/polynomial.hpp" +#include "barretenberg/proof_system/circuit_builder/ultra_circuit_builder.hpp" +#include "barretenberg/proof_system/flavor/flavor.hpp" +#include "barretenberg/srs/factories/crs_factory.hpp" +#include +#include +#include +#include +#include +#include + +namespace proof_system::honk::flavor { + +class GoblinUltra { + public: + using CircuitBuilder = UltraCircuitBuilder; + using FF = barretenberg::fr; + using Polynomial = barretenberg::Polynomial; + using PolynomialHandle = std::span; + using G1 = barretenberg::g1; + using GroupElement = G1::element; + using Commitment = G1::affine_element; + using CommitmentHandle = G1::affine_element; + using PCSParams = pcs::kzg::Params; + using PCS = pcs::kzg::KZG; + + static constexpr size_t NUM_WIRES = CircuitBuilder::NUM_WIRES; + // The number of multivariate polynomials on which a sumcheck prover sumcheck operates (including shifts). We often + // need containers of this size to hold related data, so we choose a name more agnostic than `NUM_POLYNOMIALS`. + // Note: this number does not include the individual sorted list polynomials. + static constexpr size_t NUM_ALL_ENTITIES = 48; // 43 (UH) + 4 op wires + 1 op wire "selector" + // The number of polynomials precomputed to describe a circuit and to aid a prover in constructing a satisfying + // assignment of witnesses. We again choose a neutral name. + static constexpr size_t NUM_PRECOMPUTED_ENTITIES = 26; // 25 (UH) + 1 op wire "selector" + // The total number of witness entities not including shifts. + static constexpr size_t NUM_WITNESS_ENTITIES = 15; // 11 (UH) + 4 op wires + + using GrandProductRelations = std::tuple, sumcheck::LookupRelation>; + + // define the tuple of Relations that comprise the Sumcheck relation + using Relations = std::tuple, + sumcheck::UltraPermutationRelation, + sumcheck::LookupRelation, + sumcheck::GenPermSortRelation, + sumcheck::EllipticRelation, + sumcheck::AuxiliaryRelation, + sumcheck::EccOpQueueRelation>; + + static constexpr size_t MAX_RELATION_LENGTH = get_max_relation_length(); + + // MAX_RANDOM_RELATION_LENGTH = algebraic degree of sumcheck relation *after* multiplying by the `pow_zeta` random + // polynomial e.g. For \sum(x) [A(x) * B(x) + C(x)] * PowZeta(X), relation length = 2 and random relation length = 3 + static constexpr size_t MAX_RANDOM_RELATION_LENGTH = MAX_RELATION_LENGTH + 1; + static constexpr size_t NUM_RELATIONS = std::tuple_size::value; + + // define the container for storing the univariate contribution from each relation in Sumcheck + using RelationUnivariates = decltype(create_relation_univariates_container()); + using RelationValues = decltype(create_relation_values_container()); + + // Whether or not the first row of the execution trace is reserved for 0s to enable shifts + static constexpr bool has_zero_row = true; + + private: + template + /** + * @brief A base class labelling precomputed entities and (ordered) subsets of interest. + * @details Used to build the proving key and verification key. + */ + class PrecomputedEntities : public PrecomputedEntities_ { + public: + DataType& q_m = std::get<0>(this->_data); + DataType& q_c = std::get<1>(this->_data); + DataType& q_l = std::get<2>(this->_data); + DataType& q_r = std::get<3>(this->_data); + DataType& q_o = std::get<4>(this->_data); + DataType& q_4 = std::get<5>(this->_data); + DataType& q_arith = std::get<6>(this->_data); + DataType& q_sort = std::get<7>(this->_data); + DataType& q_elliptic = std::get<8>(this->_data); + DataType& q_aux = std::get<9>(this->_data); + DataType& q_lookup = std::get<10>(this->_data); + DataType& sigma_1 = std::get<11>(this->_data); + DataType& sigma_2 = std::get<12>(this->_data); + DataType& sigma_3 = std::get<13>(this->_data); + DataType& sigma_4 = std::get<14>(this->_data); + DataType& id_1 = std::get<15>(this->_data); + DataType& id_2 = std::get<16>(this->_data); + DataType& id_3 = std::get<17>(this->_data); + DataType& id_4 = std::get<18>(this->_data); + DataType& table_1 = std::get<19>(this->_data); + DataType& table_2 = std::get<20>(this->_data); + DataType& table_3 = std::get<21>(this->_data); + DataType& table_4 = std::get<22>(this->_data); + DataType& lagrange_first = std::get<23>(this->_data); + DataType& lagrange_last = std::get<24>(this->_data); + DataType& lagrange_ecc_op = std::get<25>(this->_data); // indicator poly for ecc op gates + + static constexpr CircuitType CIRCUIT_TYPE = CircuitBuilder::CIRCUIT_TYPE; + + std::vector get_selectors() override + { + return { q_m, q_c, q_l, q_r, q_o, q_4, q_arith, q_sort, q_elliptic, q_aux, q_lookup }; + }; + std::vector get_sigma_polynomials() override { return { sigma_1, sigma_2, sigma_3, sigma_4 }; }; + std::vector get_id_polynomials() override { return { id_1, id_2, id_3, id_4 }; }; + + std::vector get_table_polynomials() { return { table_1, table_2, table_3, table_4 }; }; + }; + + /** + * @brief Container for all witness polynomials used/constructed by the prover. + * @details Shifts are not included here since they do not occupy their own memory. + */ + template + class WitnessEntities : public WitnessEntities_ { + public: + DataType& w_l = std::get<0>(this->_data); + DataType& w_r = std::get<1>(this->_data); + DataType& w_o = std::get<2>(this->_data); + DataType& w_4 = std::get<3>(this->_data); + DataType& sorted_1 = std::get<4>(this->_data); + DataType& sorted_2 = std::get<5>(this->_data); + DataType& sorted_3 = std::get<6>(this->_data); + DataType& sorted_4 = std::get<7>(this->_data); + DataType& sorted_accum = std::get<8>(this->_data); + DataType& z_perm = std::get<9>(this->_data); + DataType& z_lookup = std::get<10>(this->_data); + DataType& ecc_op_wire_1 = std::get<11>(this->_data); + DataType& ecc_op_wire_2 = std::get<12>(this->_data); + DataType& ecc_op_wire_3 = std::get<13>(this->_data); + DataType& ecc_op_wire_4 = std::get<14>(this->_data); + + std::vector get_wires() override { return { w_l, w_r, w_o, w_4 }; }; + std::vector get_ecc_op_wires() + { + return { ecc_op_wire_1, ecc_op_wire_2, ecc_op_wire_3, ecc_op_wire_4 }; + }; + // The sorted concatenations of table and witness data needed for plookup. + std::vector get_sorted_polynomials() { return { sorted_1, sorted_2, sorted_3, sorted_4 }; }; + }; + + /** + * @brief A base class labelling all entities (for instance, all of the polynomials used by the prover during + * sumcheck) in this Honk variant along with particular subsets of interest + * @details Used to build containers for: the prover's polynomial during sumcheck; the sumcheck's folded + * polynomials; the univariates consturcted during during sumcheck; the evaluations produced by sumcheck. + * + * Symbolically we have: AllEntities = PrecomputedEntities + WitnessEntities + "ShiftedEntities". It could be + * implemented as such, but we have this now. + */ + template + class AllEntities : public AllEntities_ { + public: + DataType& q_c = std::get<0>(this->_data); + DataType& q_l = std::get<1>(this->_data); + DataType& q_r = std::get<2>(this->_data); + DataType& q_o = std::get<3>(this->_data); + DataType& q_4 = std::get<4>(this->_data); + DataType& q_m = std::get<5>(this->_data); + DataType& q_arith = std::get<6>(this->_data); + DataType& q_sort = std::get<7>(this->_data); + DataType& q_elliptic = std::get<8>(this->_data); + DataType& q_aux = std::get<9>(this->_data); + DataType& q_lookup = std::get<10>(this->_data); + DataType& sigma_1 = std::get<11>(this->_data); + DataType& sigma_2 = std::get<12>(this->_data); + DataType& sigma_3 = std::get<13>(this->_data); + DataType& sigma_4 = std::get<14>(this->_data); + DataType& id_1 = std::get<15>(this->_data); + DataType& id_2 = std::get<16>(this->_data); + DataType& id_3 = std::get<17>(this->_data); + DataType& id_4 = std::get<18>(this->_data); + DataType& table_1 = std::get<19>(this->_data); + DataType& table_2 = std::get<20>(this->_data); + DataType& table_3 = std::get<21>(this->_data); + DataType& table_4 = std::get<22>(this->_data); + DataType& lagrange_first = std::get<23>(this->_data); + DataType& lagrange_last = std::get<24>(this->_data); + DataType& lagrange_ecc_op = std::get<25>(this->_data); + DataType& w_l = std::get<26>(this->_data); + DataType& w_r = std::get<27>(this->_data); + DataType& w_o = std::get<28>(this->_data); + DataType& w_4 = std::get<29>(this->_data); + DataType& sorted_accum = std::get<30>(this->_data); + DataType& z_perm = std::get<31>(this->_data); + DataType& z_lookup = std::get<32>(this->_data); + DataType& ecc_op_wire_1 = std::get<33>(this->_data); + DataType& ecc_op_wire_2 = std::get<34>(this->_data); + DataType& ecc_op_wire_3 = std::get<35>(this->_data); + DataType& ecc_op_wire_4 = std::get<36>(this->_data); + DataType& table_1_shift = std::get<37>(this->_data); + DataType& table_2_shift = std::get<38>(this->_data); + DataType& table_3_shift = std::get<39>(this->_data); + DataType& table_4_shift = std::get<40>(this->_data); + DataType& w_l_shift = std::get<41>(this->_data); + DataType& w_r_shift = std::get<42>(this->_data); + DataType& w_o_shift = std::get<43>(this->_data); + DataType& w_4_shift = std::get<44>(this->_data); + DataType& sorted_accum_shift = std::get<45>(this->_data); + DataType& z_perm_shift = std::get<46>(this->_data); + DataType& z_lookup_shift = std::get<47>(this->_data); + + std::vector get_wires() override { return { w_l, w_r, w_o, w_4 }; }; + std::vector get_ecc_op_wires() + { + return { ecc_op_wire_1, ecc_op_wire_2, ecc_op_wire_3, ecc_op_wire_4 }; + }; + // Gemini-specific getters. + std::vector get_unshifted() override + { + return { q_c, q_l, + q_r, q_o, + q_4, q_m, + q_arith, q_sort, + q_elliptic, q_aux, + q_lookup, sigma_1, + sigma_2, sigma_3, + sigma_4, id_1, + id_2, id_3, + id_4, table_1, + table_2, table_3, + table_4, lagrange_first, + lagrange_last, lagrange_ecc_op, + w_l, w_r, + w_o, w_4, + sorted_accum, z_perm, + z_lookup, ecc_op_wire_1, + ecc_op_wire_2, ecc_op_wire_3, + ecc_op_wire_4 }; + }; + std::vector get_to_be_shifted() override + { + return { table_1, table_2, table_3, table_4, w_l, w_r, w_o, w_4, sorted_accum, z_perm, z_lookup }; + }; + std::vector get_shifted() override + { + return { table_1_shift, table_2_shift, table_3_shift, table_4_shift, w_l_shift, w_r_shift, + w_o_shift, w_4_shift, sorted_accum_shift, z_perm_shift, z_lookup_shift }; + }; + + AllEntities() = default; + + AllEntities(const AllEntities& other) + : AllEntities_(other){}; + + AllEntities(AllEntities&& other) + : AllEntities_(other){}; + + AllEntities& operator=(const AllEntities& other) + { + if (this == &other) { + return *this; + } + AllEntities_::operator=(other); + return *this; + } + + AllEntities& operator=(AllEntities&& other) + { + AllEntities_::operator=(other); + return *this; + } + + ~AllEntities() = default; + }; + + public: + /** + * @brief The proving key is responsible for storing the polynomials used by the prover. + * @note TODO(Cody): Maybe multiple inheritance is the right thing here. In that case, nothing should eve inherit + * from ProvingKey. + */ + class ProvingKey : public ProvingKey_, + WitnessEntities> { + public: + // Expose constructors on the base class + using Base = ProvingKey_, + WitnessEntities>; + using Base::Base; + + std::vector memory_read_records; + std::vector memory_write_records; + + size_t num_ecc_op_gates; // needed to determine public input offset + + // The plookup wires that store plookup read data. + std::array get_table_column_wires() { return { w_l, w_r, w_o }; }; + }; + + /** + * @brief The verification key is responsible for storing the the commitments to the precomputed (non-witnessk) + * polynomials used by the verifier. + * + * @note Note the discrepancy with what sort of data is stored here vs in the proving key. We may want to resolve + * that, and split out separate PrecomputedPolynomials/Commitments data for clarity but also for portability of our + * circuits. + */ + using VerificationKey = VerificationKey_>; + + /** + * @brief A container for polynomials handles; only stores spans. + */ + using ProverPolynomials = AllEntities; + + /** + * @brief A container for storing the partially evaluated multivariates produced by sumcheck. + */ + class PartiallyEvaluatedMultivariates : public AllEntities { + + public: + PartiallyEvaluatedMultivariates() = default; + PartiallyEvaluatedMultivariates(const size_t circuit_size) + { + // Storage is only needed after the first partial evaluation, hence polynomials of size (n / 2) + for (auto& poly : this->_data) { + poly = Polynomial(circuit_size / 2); + } + } + }; + + /** + * @brief A container for univariates produced during the hot loop in sumcheck. + * @todo TODO(#390): Simplify this by moving MAX_RELATION_LENGTH? + */ + template + using ExtendedEdges = + AllEntities, sumcheck::Univariate>; + + /** + * @brief A container for the polynomials evaluations produced during sumcheck, which are purported to be the + * evaluations of polynomials committed in earlier rounds. + */ + class ClaimedEvaluations : public AllEntities { + public: + using Base = AllEntities; + using Base::Base; + ClaimedEvaluations(std::array _data_in) { this->_data = _data_in; } + }; + + /** + * @brief A container for commitment labels. + * @note It's debatable whether this should inherit from AllEntities. since most entries are not strictly needed. It + * has, however, been useful during debugging to have these labels available. + * + */ + class CommitmentLabels : public AllEntities { + public: + CommitmentLabels() + { + w_l = "W_L"; + w_r = "W_R"; + w_o = "W_O"; + w_4 = "W_4"; + z_perm = "Z_PERM"; + z_lookup = "Z_LOOKUP"; + sorted_accum = "SORTED_ACCUM"; + ecc_op_wire_1 = "ECC_OP_WIRE_1"; + ecc_op_wire_2 = "ECC_OP_WIRE_2"; + ecc_op_wire_3 = "ECC_OP_WIRE_3"; + ecc_op_wire_4 = "ECC_OP_WIRE_4"; + + // The ones beginning with "__" are only used for debugging + q_c = "__Q_C"; + q_l = "__Q_L"; + q_r = "__Q_R"; + q_o = "__Q_O"; + q_4 = "__Q_4"; + q_m = "__Q_M"; + q_arith = "__Q_ARITH"; + q_sort = "__Q_SORT"; + q_elliptic = "__Q_ELLIPTIC"; + q_aux = "__Q_AUX"; + q_lookup = "__Q_LOOKUP"; + sigma_1 = "__SIGMA_1"; + sigma_2 = "__SIGMA_2"; + sigma_3 = "__SIGMA_3"; + sigma_4 = "__SIGMA_4"; + id_1 = "__ID_1"; + id_2 = "__ID_2"; + id_3 = "__ID_3"; + id_4 = "__ID_4"; + table_1 = "__TABLE_1"; + table_2 = "__TABLE_2"; + table_3 = "__TABLE_3"; + table_4 = "__TABLE_4"; + lagrange_first = "__LAGRANGE_FIRST"; + lagrange_last = "__LAGRANGE_LAST"; + lagrange_ecc_op = "__Q_ECC_OP_QUEUE"; + }; + }; + + class VerifierCommitments : public AllEntities { + public: + VerifierCommitments(std::shared_ptr verification_key, VerifierTranscript transcript) + { + static_cast(transcript); + q_m = verification_key->q_m; + q_l = verification_key->q_l; + q_r = verification_key->q_r; + q_o = verification_key->q_o; + q_4 = verification_key->q_4; + q_c = verification_key->q_c; + q_arith = verification_key->q_arith; + q_sort = verification_key->q_sort; + q_elliptic = verification_key->q_elliptic; + q_aux = verification_key->q_aux; + q_lookup = verification_key->q_lookup; + sigma_1 = verification_key->sigma_1; + sigma_2 = verification_key->sigma_2; + sigma_3 = verification_key->sigma_3; + sigma_4 = verification_key->sigma_4; + id_1 = verification_key->id_1; + id_2 = verification_key->id_2; + id_3 = verification_key->id_3; + id_4 = verification_key->id_4; + table_1 = verification_key->table_1; + table_2 = verification_key->table_2; + table_3 = verification_key->table_3; + table_4 = verification_key->table_4; + lagrange_first = verification_key->lagrange_first; + lagrange_last = verification_key->lagrange_last; + lagrange_ecc_op = verification_key->lagrange_ecc_op; + } + }; +}; + +} // namespace proof_system::honk::flavor diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/prover_library.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/prover_library.cpp index a8163aad6256..27da4a422ec0 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/prover_library.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/prover_library.cpp @@ -1,4 +1,5 @@ #include "prover_library.hpp" +#include "barretenberg/honk/flavor/goblin_ultra.hpp" #include "barretenberg/honk/flavor/standard.hpp" #include "barretenberg/honk/flavor/standard_grumpkin.hpp" #include "barretenberg/honk/flavor/ultra.hpp" @@ -86,12 +87,16 @@ void add_plookup_memory_records_to_wire_4(std::shared_ptr( std::shared_ptr& key, typename honk::flavor::Ultra::FF eta); template void add_plookup_memory_records_to_wire_4( std::shared_ptr& key, typename honk::flavor::Ultra::FF eta); +// flavor::UltraGrumpkin + template typename honk::flavor::UltraGrumpkin::Polynomial compute_sorted_list_accumulator( std::shared_ptr& key, typename honk::flavor::UltraGrumpkin::FF eta); @@ -100,4 +105,12 @@ template void add_plookup_memory_records_to_wire_4( std::shared_ptr& key, typename honk::flavor::UltraGrumpkin::FF eta); -} // namespace proof_system::honk::prover_library +// flavor::GoblinUltra + +template typename honk::flavor::GoblinUltra::Polynomial compute_sorted_list_accumulator( + std::shared_ptr& key, typename honk::flavor::GoblinUltra::FF eta); + +template void add_plookup_memory_records_to_wire_4( + std::shared_ptr& key, typename honk::flavor::GoblinUltra::FF eta); + +} // namespace proof_system::honk::prover_library \ No newline at end of file diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp index 9e584a152a2f..2022fac763b7 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.cpp @@ -74,30 +74,28 @@ UltraProver_::UltraProver_(std::shared_ptr prover_polynomials.w_r_shift = key->w_r.shifted(); prover_polynomials.w_o_shift = key->w_o.shifted(); - // Add public inputs to transcript from the second wire polynomial; The PI have been written into the wires at the - // 0th or 1st index depending on whether or not a zero row is utilized. + if constexpr (IsGoblinFlavor) { + prover_polynomials.ecc_op_wire_1 = key->ecc_op_wire_1; + prover_polynomials.ecc_op_wire_2 = key->ecc_op_wire_2; + prover_polynomials.ecc_op_wire_3 = key->ecc_op_wire_3; + prover_polynomials.ecc_op_wire_4 = key->ecc_op_wire_4; + prover_polynomials.lagrange_ecc_op = key->lagrange_ecc_op; + } + + // Add public inputs to transcript from the second wire polynomial; This requires determination of the offset at + // which the PI have been written into the wires relative to the 0th index. std::span public_wires_source = prover_polynomials.w_r; - const size_t pub_input_offset = Flavor::has_zero_row ? 1 : 0; + pub_inputs_offset = Flavor::has_zero_row ? 1 : 0; + if constexpr (IsGoblinFlavor) { + pub_inputs_offset += key->num_ecc_op_gates; + } for (size_t i = 0; i < key->num_public_inputs; ++i) { - size_t idx = i + pub_input_offset; + size_t idx = i + pub_inputs_offset; public_inputs.emplace_back(public_wires_source[idx]); } } -/** - * @brief Commit to the first three wires only - * - */ -template void UltraProver_::compute_wire_commitments() -{ - auto wire_polys = key->get_wires(); - auto labels = commitment_labels.get_wires(); - for (size_t idx = 0; idx < 3; ++idx) { - queue.add_commitment(wire_polys[idx], labels[idx]); - } -} - /** * @brief Add circuit size, public input size, and public inputs to transcript * @@ -109,6 +107,7 @@ template void UltraProver_::execute_preamble_round( transcript.send_to_verifier("circuit_size", circuit_size); transcript.send_to_verifier("public_input_size", num_public_inputs); + transcript.send_to_verifier("pub_inputs_offset", static_cast(pub_inputs_offset)); for (size_t i = 0; i < key->num_public_inputs; ++i) { auto public_input_i = public_inputs[i]; @@ -122,11 +121,21 @@ template void UltraProver_::execute_preamble_round( */ template void UltraProver_::execute_wire_commitments_round() { + // Commit to the first three wire polynomials; the fourth is committed to after the addition of memory records. auto wire_polys = key->get_wires(); auto labels = commitment_labels.get_wires(); for (size_t idx = 0; idx < 3; ++idx) { queue.add_commitment(wire_polys[idx], labels[idx]); } + + // If Goblin, commit to the ECC op wire polynomials + if constexpr (IsGoblinFlavor) { + auto op_wire_polys = key->get_ecc_op_wires(); + auto labels = commitment_labels.get_ecc_op_wires(); + for (size_t idx = 0; idx < Flavor::NUM_WIRES; ++idx) { + queue.add_commitment(op_wire_polys[idx], labels[idx]); + } + } } /** @@ -162,7 +171,8 @@ template void UltraProver_::execute_grand_product_c // Compute and store parameters required by relations in Sumcheck auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); - auto public_input_delta = compute_public_input_delta(public_inputs, beta, gamma, key->circuit_size); + auto public_input_delta = + compute_public_input_delta(public_inputs, beta, gamma, key->circuit_size, pub_inputs_offset); auto lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, key->circuit_size); relation_parameters.beta = beta; @@ -338,5 +348,6 @@ template plonk::proof& UltraProver_::construct_proo template class UltraProver_; template class UltraProver_; +template class UltraProver_; } // namespace proof_system::honk diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp index f848a9a67272..953d41b919ca 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_prover.hpp @@ -1,4 +1,5 @@ #pragma once +#include "barretenberg/honk/flavor/goblin_ultra.hpp" #include "barretenberg/honk/flavor/ultra.hpp" #include "barretenberg/honk/flavor/ultra_grumpkin.hpp" #include "barretenberg/honk/pcs/gemini/gemini.hpp" @@ -38,14 +39,13 @@ template class UltraProver_ { void execute_shplonk_partial_evaluation_round(); void execute_final_pcs_round(); - void compute_wire_commitments(); - plonk::proof& export_proof(); plonk::proof& construct_proof(); ProverTranscript transcript; std::vector public_inputs; + size_t pub_inputs_offset; // offset of the PI relative to 0th index in the wire polynomials sumcheck::RelationParameters relation_parameters; @@ -80,6 +80,7 @@ template class UltraProver_ { extern template class UltraProver_; extern template class UltraProver_; +extern template class UltraProver_; using UltraProver = UltraProver_; diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp index 0a149ac79183..7fbdcd932dd9 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.cpp @@ -54,6 +54,7 @@ template bool UltraVerifier_::verify_proof(const plonk // TODO(Adrian): Change the initialization of the transcript to take the VK hash? const auto circuit_size = transcript.template receive_from_prover("circuit_size"); const auto public_input_size = transcript.template receive_from_prover("public_input_size"); + const auto pub_inputs_offset = transcript.template receive_from_prover("pub_inputs_offset"); if (circuit_size != key->circuit_size) { return false; @@ -68,11 +69,23 @@ template bool UltraVerifier_::verify_proof(const plonk public_inputs.emplace_back(public_input_i); } - // Get commitments to first three wires + // Get commitments to first three wire polynomials commitments.w_l = transcript.template receive_from_prover(commitment_labels.w_l); commitments.w_r = transcript.template receive_from_prover(commitment_labels.w_r); commitments.w_o = transcript.template receive_from_prover(commitment_labels.w_o); + // If Goblin, get commitments to ECC op wire polynomials + if constexpr (IsGoblinFlavor) { + commitments.ecc_op_wire_1 = + transcript.template receive_from_prover(commitment_labels.ecc_op_wire_1); + commitments.ecc_op_wire_2 = + transcript.template receive_from_prover(commitment_labels.ecc_op_wire_2); + commitments.ecc_op_wire_3 = + transcript.template receive_from_prover(commitment_labels.ecc_op_wire_3); + commitments.ecc_op_wire_4 = + transcript.template receive_from_prover(commitment_labels.ecc_op_wire_4); + } + // Get challenge for sorted list batching and wire four memory records auto eta = transcript.get_challenge("eta"); relation_parameters.eta = eta; @@ -84,7 +97,8 @@ template bool UltraVerifier_::verify_proof(const plonk // Get permutation challenges auto [beta, gamma] = transcript.get_challenges("beta", "gamma"); - const FF public_input_delta = compute_public_input_delta(public_inputs, beta, gamma, circuit_size); + const FF public_input_delta = + compute_public_input_delta(public_inputs, beta, gamma, circuit_size, pub_inputs_offset); const FF lookup_grand_product_delta = compute_lookup_grand_product_delta(beta, gamma, circuit_size); relation_parameters.beta = beta; @@ -159,5 +173,6 @@ template bool UltraVerifier_::verify_proof(const plonk template class UltraVerifier_; template class UltraVerifier_; +template class UltraVerifier_; } // namespace proof_system::honk diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp index 39de3ebaf919..9800497ba295 100644 --- a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/proof_system/ultra_verifier.hpp @@ -1,4 +1,5 @@ #pragma once +#include "barretenberg/honk/flavor/goblin_ultra.hpp" #include "barretenberg/honk/flavor/ultra.hpp" #include "barretenberg/honk/flavor/ultra_grumpkin.hpp" #include "barretenberg/honk/sumcheck/sumcheck.hpp" @@ -29,6 +30,7 @@ template class UltraVerifier_ { extern template class UltraVerifier_; extern template class UltraVerifier_; +extern template class UltraVerifier_; using UltraVerifier = UltraVerifier_; diff --git a/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/sumcheck/relations/ecc_op_queue_relation.hpp b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/sumcheck/relations/ecc_op_queue_relation.hpp new file mode 100644 index 000000000000..20ce470587f4 --- /dev/null +++ b/circuits/cpp/barretenberg/cpp/src/barretenberg/honk/sumcheck/relations/ecc_op_queue_relation.hpp @@ -0,0 +1,116 @@ +#pragma once +#include +#include + +#include "../polynomials/univariate.hpp" +#include "relation_parameters.hpp" +#include "relation_types.hpp" + +namespace proof_system::honk::sumcheck { + +template class EccOpQueueRelationBase { + public: + // 1 + polynomial degree of this relation + static constexpr size_t RELATION_LENGTH = 3; // degree(q * (w - w_op_queue)) = 2 + + static constexpr size_t LEN_1 = 3; // wire - op-queue-wire consistency sub-relation 1 + static constexpr size_t LEN_2 = 3; // wire - op-queue-wire consistency sub-relation 2 + static constexpr size_t LEN_3 = 3; // wire - op-queue-wire consistency sub-relation 3 + static constexpr size_t LEN_4 = 3; // wire - op-queue-wire consistency sub-relation 4 + static constexpr size_t LEN_5 = 3; // op-queue-wire vanishes sub-relation 1 + static constexpr size_t LEN_6 = 3; // op-queue-wire vanishes sub-relation 2 + static constexpr size_t LEN_7 = 3; // op-queue-wire vanishes sub-relation 3 + static constexpr size_t LEN_8 = 3; // op-queue-wire vanishes sub-relation 4 + template