diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp index 81f84e0407c..a8f2f2cff87 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.cpp @@ -16,6 +16,7 @@ #include "rollup/root/root_rollup_public_inputs.hpp" #include "aztec3/circuits/abis/combined_accumulated_data.hpp" +#include "aztec3/circuits/abis/complete_address.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/packers.hpp" #include "aztec3/circuits/abis/point.hpp" @@ -30,10 +31,11 @@ namespace { +using aztec3::circuits::compute_complete_contract_address; using aztec3::circuits::compute_constructor_hash; -using aztec3::circuits::compute_contract_address; using aztec3::circuits::compute_partial_address; using aztec3::circuits::abis::CallStackItem; +using aztec3::circuits::abis::CompleteAddress; using aztec3::circuits::abis::ConstantsPacker; using aztec3::circuits::abis::FunctionData; using aztec3::circuits::abis::FunctionLeafPreimage; @@ -287,39 +289,9 @@ WASM_EXPORT void abis__hash_constructor(uint8_t const* function_data_buf, } /** - * @brief Compute a contract address - * This is a WASM-export that can be called from Typescript. - * - * @details Computes a contract address by hashing the deployers public key along with the previously computed partial - * address Return the serialized results in the `output` buffer. - * - * @param point_data_buf point data struct as a buffer of bytes - * @param contract_address_salt_buf salt value for the contract address - * @param function_tree_root_buf root value of the contract's function tree - * @param constructor_hash_buf the hash of the contract constructor's verification key - * @param output buffer that will contain the output. The serialized contract address. + * @brief Compute a complete address. */ -WASM_EXPORT void abis__compute_contract_address(uint8_t const* point_data_buf, - uint8_t const* contract_address_salt_buf, - uint8_t const* function_tree_root_buf, - uint8_t const* constructor_hash_buf, - uint8_t* output) -{ - Point deployer_public_key; - NT::fr contract_address_salt; - NT::fr function_tree_root; - NT::fr constructor_hash; - - serialize::read(point_data_buf, deployer_public_key); - read(contract_address_salt_buf, contract_address_salt); - read(function_tree_root_buf, function_tree_root); - read(constructor_hash_buf, constructor_hash); - - NT::fr const contract_address = - compute_contract_address(deployer_public_key, contract_address_salt, function_tree_root, constructor_hash); - - NT::fr::serialize_to_buffer(contract_address, output); -} +CBIND(abis__compute_complete_contract_address, aztec3::circuits::compute_complete_contract_address); /** * @brief Compute a contract address from deployer public key and partial address. @@ -398,7 +370,7 @@ WASM_EXPORT void abis__compute_var_args_hash(uint8_t const* args_buf, uint8_t* o * @brief Generates a function tree leaf from its preimage. * This is a WASM-export that can be called from Typescript. * - * @details given a `uint8_t const*` buffer representing a function leaf's prieimage, + * @details given a `uint8_t const*` buffer representing a function leaf's preimage, * construct a NewContractData instance, hash, and return the serialized results * in the `output` buffer. * diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h index 94bcc904792..9cf7d61d9e0 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.h +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.h @@ -23,11 +23,7 @@ WASM_EXPORT void abis__hash_constructor(uint8_t const* func_data_buf, uint8_t const* constructor_vk_hash_buf, uint8_t* output); -WASM_EXPORT void abis__compute_contract_address(uint8_t const* point_data_buf, - uint8_t const* contract_address_salt_buf, - uint8_t const* function_tree_root_buf, - uint8_t const* constructor_hash_buf, - uint8_t* output); +CBIND_DECL(abis__compute_complete_contract_address); WASM_EXPORT void abis__compute_partial_address(uint8_t const* contract_address_salt_buf, uint8_t const* function_tree_root_buf, diff --git a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp index 3cd4a1f0c6c..b9d9202a06a 100644 --- a/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp +++ b/circuits/cpp/src/aztec3/circuits/abis/c_bind.test.cpp @@ -2,6 +2,7 @@ #include "function_leaf_preimage.hpp" #include "tx_request.hpp" +#include "aztec3/circuits/abis/complete_address.hpp" #include "aztec3/circuits/abis/new_contract_data.hpp" #include "aztec3/circuits/abis/tx_request.hpp" #include "aztec3/circuits/hash.hpp" @@ -71,14 +72,14 @@ TEST(abi_tests, compute_partial_address) EXPECT_EQ(actual, expected); } -TEST(abi_tests, compute_contract_address) +TEST(abi_tests, compute_complete_contract_address) { Point const point = { .x = 1, .y = 3 }; auto const contract_address_salt = NT::fr(5); auto const function_tree_root = NT::fr(6); auto const constructor_hash = NT::fr(7); - NT::fr const expected = - compute_contract_address(point, contract_address_salt, function_tree_root, constructor_hash); + CompleteAddress const expected = + compute_complete_contract_address(point, contract_address_salt, function_tree_root, constructor_hash); std::array output = { 0 }; std::vector contract_address_salt_buf; @@ -89,11 +90,11 @@ TEST(abi_tests, compute_contract_address) write(function_tree_root_buf, function_tree_root); write(constructor_hash_buf, constructor_hash); serialize::write(point_buf, point); - abis__compute_contract_address(point_buf.data(), - contract_address_salt_buf.data(), - function_tree_root_buf.data(), - constructor_hash_buf.data(), - output.data()); + abis__compute_complete_contract_address(point_buf.data(), + contract_address_salt_buf.data(), + function_tree_root_buf.data(), + constructor_hash_buf.data(), + output.data()); // Convert buffer to `fr` for comparison to in-test calculated hash NT::fr const actual = NT::fr::serialize_from_buffer(output.data()); diff --git a/circuits/cpp/src/aztec3/circuits/abis/complete_address.hpp b/circuits/cpp/src/aztec3/circuits/abis/complete_address.hpp new file mode 100644 index 00000000000..d03de7ec069 --- /dev/null +++ b/circuits/cpp/src/aztec3/circuits/abis/complete_address.hpp @@ -0,0 +1,70 @@ +#pragma once +#include "aztec3/circuits/abis/coordinate.hpp" +#include "aztec3/circuits/abis/point.hpp" +#include "aztec3/utils/types/circuit_types.hpp" +#include "aztec3/utils/types/convert.hpp" +#include "aztec3/utils/types/native_types.hpp" + +#include + +namespace aztec3::circuits::abis { + +using aztec3::utils::types::CircuitTypes; +using aztec3::utils::types::NativeTypes; + +template struct CompleteAddress { + using fr = typename NCT::fr; + using boolean = typename NCT::boolean; + + fr address; + Point public_key; + fr partial_address; + + // for serialization, update with new fields + MSGPACK_FIELDS(address, public_key, partial_address); + bool operator==(CompleteAddress const&) const = default; + + template CompleteAddress> to_circuit_type(Builder& builder) const + { + static_assert((std::is_same::value)); + + auto to_ct = [&](auto& e) { return aztec3::utils::types::to_ct(builder, e); }; + + CompleteAddress> complete_address = { to_ct(address), + to_ct(public_key), + to_ct(partial_address) }; + + return complete_address; + }; + + template CompleteAddress to_native_type() const + { + static_assert((std::is_same, NCT>::value)); + + auto to_nt = [&](auto& e) { return aztec3::utils::types::to_nt(e); }; + + CompleteAddress complete_address = { to_nt(address), to_nt(public_key), to_nt(partial_address) }; + + return complete_address; + }; + + void set_public() + { + static_assert(!(std::is_same::value)); + + address.set_public(); + public_key.set_public(); + partial_address.set_public(); + } + + void assert_is_zero() + { + static_assert(!(std::is_same::value)); + + address.assert_is_zero(); + public_key.assert_is_zero(); + partial_address.assert_is_zero(); + } +}; + +} // namespace aztec3::circuits::abis diff --git a/circuits/cpp/src/aztec3/circuits/hash.hpp b/circuits/cpp/src/aztec3/circuits/hash.hpp index 92f3c1a79f7..53cd1f3c5f7 100644 --- a/circuits/cpp/src/aztec3/circuits/hash.hpp +++ b/circuits/cpp/src/aztec3/circuits/hash.hpp @@ -1,5 +1,6 @@ #pragma once +#include "aztec3/circuits/abis/complete_address.hpp" #include "aztec3/circuits/abis/function_data.hpp" #include "aztec3/circuits/abis/function_leaf_preimage.hpp" #include "aztec3/circuits/abis/function_selector.hpp" @@ -16,6 +17,7 @@ namespace aztec3::circuits { +using abis::CompleteAddress; using abis::FunctionData; using abis::FunctionSelector; using abis::Point; @@ -72,17 +74,20 @@ typename NCT::address compute_contract_address_from_partial(Point const& po return { NCT::hash(inputs, aztec3::GeneratorIndex::CONTRACT_ADDRESS) }; } -template typename NCT::address compute_contract_address(Point const& point, - typename NCT::fr const& contract_address_salt, - typename NCT::fr const& function_tree_root, - typename NCT::fr const& constructor_hash) +template +typename NCT::CompleteAddress compute_complete_contract_address(Point const& point, + typename NCT::fr const& contract_address_salt, + typename NCT::fr const& function_tree_root, + typename NCT::fr const& constructor_hash) { using fr = typename NCT::fr; + using CompleteAddress = typename NCT::CompleteAddress; const fr partial_address = compute_partial_address(contract_address_salt, function_tree_root, constructor_hash); - - return compute_contract_address_from_partial(point, partial_address); + const fr contract_address = compute_contract_address_from_partial(point, partial_address); + const CompleteAddress complete_address = { contract_address, point, partial_address }; + return complete_address; } template typename NCT::fr compute_commitment_nonce(typename NCT::fr const& first_nullifier, diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp index a1b028a0409..893a29b74af 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/common.cpp @@ -340,10 +340,11 @@ void common_contract_logic(DummyBuilder& builder, auto constructor_hash = compute_constructor_hash(function_data, private_call_public_inputs.args_hash, private_call_vk_hash); - auto const new_contract_address = compute_contract_address(contract_dep_data.deployer_public_key, - contract_dep_data.contract_address_salt, - contract_dep_data.function_tree_root, - constructor_hash); + auto const new_contract_address = compute_complete_contract_address(contract_dep_data.deployer_public_key, + contract_dep_data.contract_address_salt, + contract_dep_data.function_tree_root, + constructor_hash) + .address; // Add new contract data if its a contract deployment function NewContractData const native_new_contract_data{ new_contract_address, diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp index 77a6f9549a6..2d08b134368 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/private_kernel_circuit.cpp @@ -20,8 +20,8 @@ using plonk::stdlib::array_push; using plonk::stdlib::is_array_empty; using plonk::stdlib::push_array_to_array; +using aztec3::circuits::compute_complete_contract_address; using aztec3::circuits::compute_constructor_hash; -using aztec3::circuits::compute_contract_address; using aztec3::circuits::silo_commitment; using aztec3::circuits::silo_nullifier; @@ -113,10 +113,11 @@ void update_end_values(PrivateKernelInputsInner const& private_inputs, Kerne "constructor_vk_hash does not match private call vk hash"); // compute the contract address (only valid if this is a contract deployment) - auto contract_address = compute_contract_address(contract_deployment_data.deployer_public_key, - contract_deployment_data.contract_address_salt, - contract_deployment_data.function_tree_root, - constructor_hash); + auto contract_address = compute_complete_contract_address(contract_deployment_data.deployer_public_key, + contract_deployment_data.contract_address_salt, + contract_deployment_data.function_tree_root, + constructor_hash) + .address; // must imply == derived address is_contract_deployment.must_imply( diff --git a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp index fb3f08202ab..3be1642acd8 100644 --- a/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp +++ b/circuits/cpp/src/aztec3/circuits/kernel/private/testing_harness.cpp @@ -225,10 +225,10 @@ std::pair, ContractDeploymentData> create_private_call_d auto constructor_hash = compute_constructor_hash(function_data, args_hash, private_circuit_vk_hash); // Derive contract address so that it can be used inside the constructor itself - contract_address = compute_contract_address( + const auto complete_contract_address = compute_complete_contract_address( msg_sender_pub_key, contract_address_salt, contract_deployment_data.function_tree_root, constructor_hash); // update the contract address in the call context now that it is known - call_context.storage_contract_address = contract_address; + call_context.storage_contract_address = complete_contract_address.address; } else { const NT::fr& function_tree_root = function_tree_root_from_siblings(function_data.selector, function_data.is_internal, @@ -529,7 +529,7 @@ bool validate_deployed_contract_address(PrivateKernelInputsInit const& priva auto expected_constructor_hash = compute_constructor_hash( private_inputs.private_call.call_stack_item.function_data, tx_request.args_hash, private_circuit_vk_hash); - NT::fr const expected_contract_address = compute_contract_address( + NT::fr const expected_contract_address = compute_complete_contract_address( cdd.deployer_public_key, cdd.contract_address_salt, cdd.function_tree_root, expected_constructor_hash); return (public_inputs.end.new_contracts[0].contract_address.to_field() == expected_contract_address); diff --git a/yarn-project/aztec-rpc/src/contract_tree/index.ts b/yarn-project/aztec-rpc/src/contract_tree/index.ts index 8bb6166266f..6acbcb7313c 100644 --- a/yarn-project/aztec-rpc/src/contract_tree/index.ts +++ b/yarn-project/aztec-rpc/src/contract_tree/index.ts @@ -17,7 +17,7 @@ import { isConstructor, } from '@aztec/circuits.js'; import { - computeContractAddress, + computeCompleteContractAddress, computeContractLeaf, computeFunctionTreeRoot, computePartialAddress, @@ -98,7 +98,7 @@ export class ContractTree { // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/1873: create computeCompleteAddress // function --> The following is wasteful as it computes partial address twice const partialAddress = computePartialAddress(wasm, contractAddressSalt, root, constructorHash); - const address = computeContractAddress(wasm, from, contractAddressSalt, root, constructorHash); + const address = computeCompleteContractAddress(wasm, from, contractAddressSalt, root, constructorHash); const completeAddress = await CompleteAddress.create(address, from, partialAddress); const contractDao: ContractDao = { diff --git a/yarn-project/circuits.js/src/abis/abis.test.ts b/yarn-project/circuits.js/src/abis/abis.test.ts index 564777d086d..c061b3e9810 100644 --- a/yarn-project/circuits.js/src/abis/abis.test.ts +++ b/yarn-project/circuits.js/src/abis/abis.test.ts @@ -5,7 +5,7 @@ import { makeAztecAddress, makeEthAddress, makePoint, makeTxRequest, makeVerific import { CircuitsWasm } from '../wasm/circuits_wasm.js'; import { computeCommitmentNonce, - computeContractAddress, + computeCompleteContractAddress, computeContractLeaf, computeFunctionLeaf, computeFunctionSelector, @@ -67,7 +67,7 @@ describe('abis wasm bindings', () => { const contractAddrSalt = new Fr(2n); const treeRoot = new Fr(3n); const constructorHash = new Fr(4n); - const res = computeContractAddress(wasm, deployerPubKey, contractAddrSalt, treeRoot, constructorHash); + const res = computeCompleteContractAddress(wasm, deployerPubKey, contractAddrSalt, treeRoot, constructorHash); expect(res).toMatchSnapshot(); }); diff --git a/yarn-project/circuits.js/src/abis/abis.ts b/yarn-project/circuits.js/src/abis/abis.ts index b9acda0c2de..0fef3761f95 100644 --- a/yarn-project/circuits.js/src/abis/abis.ts +++ b/yarn-project/circuits.js/src/abis/abis.ts @@ -17,6 +17,7 @@ import { } from '../cbind/circuits.gen.js'; import { AztecAddress, + CompleteAddress, FUNCTION_SELECTOR_NUM_BYTES, Fr, FunctionData, @@ -182,53 +183,29 @@ export function hashConstructor( } /** - * Computes a contract address. + * Computes a complete contract address. * @param wasm - A module providing low-level wasm access. * @param deployerPubKey - The pubkey of the contract deployer. * @param contractAddrSalt - The salt used as one of the inputs of the contract address computation. * @param fnTreeRoot - The function tree root of the contract being deployed. * @param constructorHash - The hash of the constructor. - * @returns The contract address. + * @returns The complete contract address. */ -export function computeContractAddress( +export function computeCompleteContractAddress( wasm: IWasmModule, deployerPubKey: PublicKey, contractAddrSalt: Fr, fnTreeRoot: Fr, constructorHash: Fr, -): AztecAddress { +): CompleteAddress { wasm.call('pedersen__init'); const result = inputBuffersToOutputBuffer( wasm, - 'abis__compute_contract_address', + 'abis__compute_complete_contract_address', [deployerPubKey.toBuffer(), contractAddrSalt.toBuffer(), fnTreeRoot.toBuffer(), constructorHash.toBuffer()], 32, ); - return new AztecAddress(result); -} - -/** - * Computes a partial address. Consists of all contract address components except the deployer public key. - * @param wasm - A module providing low-level wasm access. - * @param contractAddrSalt - The salt used as one of the inputs of the contract address computation. - * @param fnTreeRoot - The function tree root of the contract being deployed. - * @param constructorHash - The hash of the constructor. - * @returns The partially constructed contract address. - */ -export function computePartialAddress( - wasm: IWasmModule, - contractAddrSalt: Fr, - fnTreeRoot: Fr, - constructorHash: Fr, -): Fr { - wasm.call('pedersen__init'); - const result = inputBuffersToOutputBuffer( - wasm, - 'abis__compute_partial_address', - [contractAddrSalt.toBuffer(), fnTreeRoot.toBuffer(), constructorHash.toBuffer()], - 32, - ); - return Fr.fromBuffer(result); + return CompleteAddress.fromBuffer(result); } /** diff --git a/yarn-project/circuits.js/src/contract/contract_deployment_info.ts b/yarn-project/circuits.js/src/contract/contract_deployment_info.ts index 1f3d3ed9e93..7c6effd3e97 100644 --- a/yarn-project/circuits.js/src/contract/contract_deployment_info.ts +++ b/yarn-project/circuits.js/src/contract/contract_deployment_info.ts @@ -1,5 +1,5 @@ import { - computeContractAddress, + computeCompleteContractAddress, computeFunctionTreeRoot, computePartialAddress, computeVarArgsHash, @@ -49,7 +49,7 @@ export async function getContractDeploymentInfo( // TODO(benesjan) https://github.com/AztecProtocol/aztec-packages/issues/1873: create computeCompleteAddress // function --> The following is wasteful as it computes partial address twice const partialAddress = computePartialAddress(wasm, contractAddressSalt, functionTreeRoot, constructorHash); - const contractAddress = computeContractAddress( + const contractAddress = computeCompleteContractAddress( wasm, publicKey, contractAddressSalt,