Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: contract inclusion proof #3680

Merged
merged 12 commits into from
Dec 15, 2023
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions yarn-project/aztec-node/src/aztec-node/server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -339,7 +339,7 @@ export class AztecNodeService implements AztecNode {
* @param leafIndex - The index of the leaf for which the sibling path is required.
* @returns The sibling path for the leaf index.
*/
public async getNullifierTreeSiblingPath(
public async getNullifierSiblingPath(
blockNumber: number | 'latest',
leafIndex: bigint,
): Promise<SiblingPath<typeof NULLIFIER_TREE_HEIGHT>> {
Expand Down Expand Up @@ -408,7 +408,7 @@ export class AztecNodeService implements AztecNode {
* @param leafIndex - Index of the leaf in the tree.
* @returns The sibling path.
*/
public async getPublicDataTreeSiblingPath(
public async getPublicDataSiblingPath(
blockNumber: number | 'latest',
leafIndex: bigint,
): Promise<SiblingPath<typeof PUBLIC_DATA_TREE_HEIGHT>> {
Expand Down
1 change: 1 addition & 0 deletions yarn-project/aztec-nr/aztec/src/history.nr
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
mod contract_inclusion;
mod note_inclusion;
mod note_validity;
mod nullifier_inclusion;
Expand Down
62 changes: 62 additions & 0 deletions yarn-project/aztec-nr/aztec/src/history/contract_inclusion.nr
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use dep::protocol_types::{
abis::{
complete_address::CompleteAddress,
new_contract_data::NewContractData as ContractLeafPreimage,
},
address::{AztecAddress, EthAddress},
point::Point,
};
use dep::std::merkle::compute_merkle_root;

use crate::{
context::PrivateContext,
oracle::get_membership_witness::get_contract_membership_witness,
};

// Proves that a contract exists at block `block_number` and returns its address.
// Note: This can be used to approximate a factory pattern --> a factory contract could perform this proof and that
benesjan marked this conversation as resolved.
Show resolved Hide resolved
// way verify that a contract at a given address is what it expects. Then it could store it in an internal
// map of contracts (like what Uniswap Factory does with pool contracts - it stores them in a mapping).
// By passing in the construct hash the factory can also verify that the contract was constructed with the
// correct constructor arguments. Typically the factory would store the expected construct hash and assert that
// it is what it expects. The constructor param check is the reason of why we pass in the preimage of contract's
// aztec address instead of just the address.
pub fn prove_contract_inclusion(
deployer_public_key: Point,
contract_address_salt: Field,
function_tree_root: Field,
constructor_hash: Field,
portal_contract_address: EthAddress,
block_number: u32, // The block at which we'll prove that the public value exists
context: PrivateContext
) -> AztecAddress {
// 1) Get block header from oracle and ensure that the block is included in the archive.
let block_header = context.get_block_header(block_number);

// 2) Compute the contract address
let contract_address = CompleteAddress::compute(
deployer_public_key,
contract_address_salt,
function_tree_root,
constructor_hash
).address;

// 3) Form the contract tree leaf preimage
let preimage = ContractLeafPreimage { contract_address, portal_contract_address, function_tree_root };

// 4) Get the contract tree leaf by hashing the preimage
let contract_leaf = preimage.hash();

// 5) Get the membership witness of the leaf in the contract tree
let witness = get_contract_membership_witness(block_number, contract_leaf);

// 6) Prove that the leaf is in the contract tree
assert(
block_header.contract_tree_root
== compute_merkle_root(contract_leaf, witness.index, witness.path), "Proving contract inclusion failed"
);

// --> Now we have traversed the trees all the way up to archive root.

contract_address
}
4 changes: 2 additions & 2 deletions yarn-project/aztec.js/src/contract_deployer/deploy_method.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas

const { chainId, protocolVersion } = await this.pxe.getNodeInfo();

const { completeAddress, constructorHash, functionTreeRoot } = getContractDeploymentInfo(
const { completeAddress, constructorVkHash, functionTreeRoot } = getContractDeploymentInfo(
this.artifact,
this.args,
contractAddressSalt,
Expand All @@ -78,7 +78,7 @@ export class DeployMethod<TContract extends ContractBase = Contract> extends Bas

const contractDeploymentData = new ContractDeploymentData(
this.publicKey,
constructorHash,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For my mental image, it still made more sense to me that it was the constructor hash actually combining all the things and not just the vk hash. Bu as @iAmMichaelConnor mentioned they he desire to change how contracts are deployed anyway, don't seem worth it to look deeper into that now.

Copy link
Contributor Author

@benesjan benesjan Dec 15, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it still made more sense to me that it was the constructor hash actually combining all the things and not just the vk hash.

Maybe I misunderstood but the constructor hash is actually "combining all the things" since part of its preimage is the constructor vk hash (see this code).

This change I did didn't break anything because wherever the incorrectly named constructorHash value was used it actually represented the constructorVkHash. Here is where the value is assigned.

constructorVkHash,
functionTreeRoot,
contractAddressSalt,
portalContract,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,8 @@ export function getContractDeploymentInfo(

return {
completeAddress,
constructorHash: constructorVkHash,
constructorHash,
constructorVkHash,
functionTreeRoot,
};
}
4 changes: 4 additions & 0 deletions yarn-project/circuits.js/src/types/deployment_info.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,10 @@ export type DeploymentInfo = {
* The complete address of the deployed contract.
*/
completeAddress: CompleteAddress;
/**
* The contract's constructor verification key hash.
*/
constructorVkHash: Fr;
/**
* The contract's constructor hash.
*/
Expand Down
Loading