Skip to content
Closed
Show file tree
Hide file tree
Changes from all 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

Large diffs are not rendered by default.

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use dep::types::{
abis::private_kernel::private_call_data::PrivateCallData, address::AztecAddress,
constants::MAX_PROTOCOL_CONTRACTS, merkle_tree::root::root_from_sibling_path, traits::ToField,
constants::MAX_PROTOCOL_CONTRACTS, merkle_tree::conditionally_assert_check_membership,
traits::ToField,
};

pub fn validate_contract_address(
Expand All @@ -22,23 +23,28 @@ pub fn validate_contract_address(
private_call_data.public_keys,
);

let protocol_contract_index = contract_address.to_field();

let computed_protocol_contract_tree_root = if (MAX_PROTOCOL_CONTRACTS as Field).lt(
protocol_contract_index,
) {
0
} else {
root_from_sibling_path(
computed_address.to_field(),
protocol_contract_index,
private_call_data.protocol_contract_sibling_path,
)
};
let contract_address_field = contract_address.to_field();
let is_protocol_contract = contract_address_field.lt(MAX_PROTOCOL_CONTRACTS as Field);

// We either have a normal contract address, which must match the calculated address, or
// A computed protocol contract address which exists at the index held in call_context.contract_address.
assert(
computed_address.eq(contract_address)
| computed_protocol_contract_tree_root.eq(protocol_contract_tree_root),
(!is_protocol_contract & computed_address.eq(contract_address))
| (
is_protocol_contract
& private_call_data.protocol_contract_membership_witness.leaf_index.eq(
contract_address_field,
)
),
"computed contract address does not match expected one",
);

// A normal computed contract address
conditionally_assert_check_membership(
computed_address.to_field(),
is_protocol_contract,
private_call_data.protocol_contract_leaf,
private_call_data.protocol_contract_membership_witness,
protocol_contract_tree_root,
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ mod tests {
tx_request: self.tx_request,
private_call,
vk_tree_root: FixtureBuilder::vk_tree_root(),
protocol_contract_tree_root: 0,
protocol_contract_tree_root: self.private_call.protocol_contract_tree_root,
is_private_only: false,
first_nullifier_hint: 0,
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,11 +59,10 @@ fn validate_call_is_static_creating_contract_class_logs_hashes_fails() {

#[test(should_fail_with = "only the class registerer may emit contract class logs")]
fn validate_call_is_from_class_registerer_fails() {
// the default bulder address != REGISTERER_CONTRACT_ADDRESS
let mut builder = PrivateCallDataValidatorBuilder::new();

builder.private_call.add_contract_class_log_hash(1, 2);
// set the contract address to be some msg sender (!= REGISTERER_CONTRACT_ADDRESS)
builder.private_call.contract_address = builder.private_call.msg_sender;

builder.validate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,16 @@ fn validate_contract_address_protocol_contract_succeeds() {
builder.validate();
}

#[test(should_fail)]
fn validate_contract_address_protocol_contract_computed_address_fails() {
let mut builder = PrivateCallDataValidatorBuilder::new_with_protocol_contract();
// Swap the special address (0x01) with the computed address
builder.private_call.contract_address =
AztecAddress { inner: builder.private_call.protocol_contract_leaf.address };
// Validate may fail with either one of the low leaf membership errors
builder.validate();
}

#[test(should_fail_with = "computed contract address does not match expected one")]
fn validate_contract_address_protocol_contract_wrong_index_fails() {
let mut builder = PrivateCallDataValidatorBuilder::new_with_protocol_contract();
Expand All @@ -94,7 +104,7 @@ fn validate_contract_address_protocol_contract_wrong_index_fails() {
builder.validate();
}

#[test(should_fail_with = "computed contract address does not match expected one")]
#[test(should_fail_with = "Key does not match the key of the leaf preimage")]
fn validate_contract_address_protocol_contract_wrong_computed_address_fails() {
let mut builder = PrivateCallDataValidatorBuilder::new_with_protocol_contract();

Expand All @@ -103,6 +113,24 @@ fn validate_contract_address_protocol_contract_wrong_computed_address_fails() {
builder.validate();
}

#[test(should_fail_with = "Key does not match the key of the leaf preimage")]
fn validate_contract_address_protocol_address_wrong_low_leaf_key() {
let mut builder = PrivateCallDataValidatorBuilder::new_with_protocol_contract();

builder.private_call.protocol_contract_leaf.address += 1;

builder.validate();
}

#[test(should_fail_with = "membership check failed")]
fn validate_contract_address_protocol_address_wrong_low_leaf_next_key() {
let mut builder = PrivateCallDataValidatorBuilder::new_with_protocol_contract();

builder.private_call.protocol_contract_leaf.next_address += 1;

builder.validate();
}

#[test(should_fail_with = "Invalid VK hash")]
fn validate_contract_address_wrong_vk_hash_fails() {
let mut builder = PrivateCallDataValidatorBuilder::new_with_regular_contract();
Expand All @@ -124,3 +152,12 @@ fn validate_contract_address_wrong_vk_fails() {

builder.validate();
}

#[test(should_fail_with = "membership check failed")]
fn validate_contract_address_regular_address_wrong_low_leaf() {
let mut builder = PrivateCallDataValidatorBuilder::new_with_regular_contract();

builder.private_call.protocol_contract_leaf.address += 1;

builder.validate();
}
Original file line number Diff line number Diff line change
Expand Up @@ -340,6 +340,8 @@ mod tests {
inputs.constants.global_variables.chain_id = fixtures::CHAIN_ID;
inputs.constants.global_variables.version = fixtures::VERSION;
inputs.constants.vk_tree_root = inputs.tube_data.vk_tree_root;
inputs.constants.protocol_contract_tree_root =
inputs.tube_data.protocol_contract_tree_root;

inputs.pre_existing_blocks[0] = inputs.tube_data.historical_header.hash();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,8 @@ mod tests {
inputs.constants.global_variables.version = fixtures::VERSION;
inputs.avm_data.global_variables = inputs.constants.global_variables;
inputs.constants.vk_tree_root = inputs.tube_data.vk_tree_root;
inputs.constants.protocol_contract_tree_root =
inputs.tube_data.protocol_contract_tree_root;

inputs.pre_existing_blocks[0] = inputs.tube_data.historical_header.hash();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ pub mod function_data;
pub mod global_variables;
pub mod note_hash_leaf_preimage;
pub mod nullifier_leaf_preimage;
pub mod protocol_contract_leaf_preimage;

pub mod tx_constant_data;
pub mod combined_constant_data;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
use crate::{
abis::private_circuit_public_inputs::PrivateCircuitPublicInputs,
abis::{
private_circuit_public_inputs::PrivateCircuitPublicInputs,
protocol_contract_leaf_preimage::ProtocolContractLeafPreimage,
},
address::SaltedInitializationHash,
constants::{
FUNCTION_TREE_HEIGHT, PROOF_TYPE_OINK, PROOF_TYPE_PG, PROTOCOL_CONTRACT_TREE_HEIGHT,
Expand All @@ -19,8 +22,8 @@ pub struct PrivateCallData {
pub contract_class_artifact_hash: Field,
pub contract_class_public_bytecode_commitment: Field,
pub function_leaf_membership_witness: MembershipWitness<FUNCTION_TREE_HEIGHT>,
pub protocol_contract_sibling_path: [Field; PROTOCOL_CONTRACT_TREE_HEIGHT],

pub protocol_contract_membership_witness: MembershipWitness<PROTOCOL_CONTRACT_TREE_HEIGHT>,
pub protocol_contract_leaf: ProtocolContractLeafPreimage,
pub acir_hash: Field,
}

Expand All @@ -44,8 +47,8 @@ pub struct PrivateCallDataWithoutPublicInputs {
pub contract_class_artifact_hash: Field,
pub contract_class_public_bytecode_commitment: Field,
pub function_leaf_membership_witness: MembershipWitness<FUNCTION_TREE_HEIGHT>,
pub protocol_contract_sibling_path: [Field; PROTOCOL_CONTRACT_TREE_HEIGHT],

pub protocol_contract_membership_witness: MembershipWitness<PROTOCOL_CONTRACT_TREE_HEIGHT>,
pub protocol_contract_leaf: ProtocolContractLeafPreimage,
pub acir_hash: Field,
}

Expand All @@ -63,7 +66,8 @@ impl PrivateCallDataWithoutPublicInputs {
contract_class_public_bytecode_commitment: self
.contract_class_public_bytecode_commitment,
function_leaf_membership_witness: self.function_leaf_membership_witness,
protocol_contract_sibling_path: self.protocol_contract_sibling_path,
protocol_contract_membership_witness: self.protocol_contract_membership_witness,
protocol_contract_leaf: self.protocol_contract_leaf,
acir_hash: self.acir_hash,
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
use crate::{
hash::poseidon2_hash,
merkle_tree::leaf_preimage::{IndexedTreeLeafPreimage, LeafPreimage},
traits::Empty,
};

/**
Exists to show:
- Membership of a computed protocol contract address in the tree, or
- Non-membership of a computed non-protocol contract address in the tree
in private_call_data_validator/validate_contract_address.nr.
The tree is created never updated within the kernels, so we don't need the functions which update leaves.
*/

pub struct ProtocolContractLeafPreimage {
pub address: Field,
pub next_address: Field,
}

impl Empty for ProtocolContractLeafPreimage {
fn empty() -> Self {
Self { address: 0, next_address: 0 }
}
}

impl LeafPreimage for ProtocolContractLeafPreimage {
fn get_key(self) -> Field {
self.address
}

fn as_leaf(self) -> Field {
poseidon2_hash([self.address, self.next_address])
}
}

impl IndexedTreeLeafPreimage<Field> for ProtocolContractLeafPreimage {
fn get_next_key(self) -> Field {
self.next_address
}

fn points_to_infinity(self) -> bool {
// Unimplemented, not required
false
}

fn update_pointers(self, _next_key: Field, _next_index: u32) -> Self {
assert(false, "Tried to update a static protocol contract index");
Self::empty()
}

fn update_value(self, _value: Field) -> Self {
assert(false, "Tried to update a static protocol contract address");
Self::empty()
}

fn build_insertion_leaf(_value: Field, _low_leaf: Self) -> Self {
assert(false, "Tried to update a static protocol contract address");
Self::empty()
}
}

impl Eq for ProtocolContractLeafPreimage {
fn eq(self, other: Self) -> bool {
(self.address == other.address) & (self.next_address == other.next_address)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ use crate::{
private_kernel::private_call_data::PrivateCallData,
private_kernel_data::PrivateKernelData,
private_log::PrivateLogData,
protocol_contract_leaf_preimage::ProtocolContractLeafPreimage,
public_call_request::PublicCallRequest,
public_data_write::PublicDataWrite,
public_log::PublicLog,
Expand Down Expand Up @@ -68,7 +69,7 @@ use crate::{
},
public_keys::PublicKeys,
tests::fixtures::{self, contract_functions::ContractFunction, contracts::ContractData},
traits::{Deserialize, Empty, FromField},
traits::{Deserialize, Empty, FromField, ToField},
transaction::{tx_context::TxContext, tx_request::TxRequest},
};

Expand Down Expand Up @@ -160,7 +161,8 @@ pub struct FixtureBuilder {

// Protocol contracts.
pub protocol_contract_tree_root: Field,
pub protocol_contract_sibling_path: [Field; PROTOCOL_CONTRACT_TREE_HEIGHT],
pub protocol_contract_membership_witness: MembershipWitness<PROTOCOL_CONTRACT_TREE_HEIGHT>,
pub protocol_contract_leaf: ProtocolContractLeafPreimage,

// Tree snapshots.
pub archive_tree: AppendOnlyTreeSnapshot,
Expand Down Expand Up @@ -231,16 +233,37 @@ impl FixtureBuilder {
}

pub fn set_protocol_contract_root(&mut self) {
let tree = fixtures::protocol_contract_tree::get_protocol_contract_tree();
let (tree, protocol_contract_leaves) =
fixtures::protocol_contract_tree::get_protocol_contract_tree();
let contract_address_field = self.contract_address.to_field();
self.protocol_contract_tree_root = tree.get_root();
for i in 0..protocol_contract_leaves.len() {
let leaf = protocol_contract_leaves[i];
// The below is true if leaf is a valid low_leaf for self.contract_address
// This is used in validate_contract_address where is_protocol_contract = false.
if (leaf.address != 0)
& (leaf.address.lt(contract_address_field))
& ((contract_address_field.lt(leaf.next_address)) | (leaf.next_address == 0)) {
self.protocol_contract_leaf = leaf;
self.protocol_contract_membership_witness = MembershipWitness {
leaf_index: i as Field,
sibling_path: tree.get_sibling_path(i),
};
}
}
}

pub fn use_protocol_contract(&mut self) -> Self {
let contract_index = 1;

let tree = fixtures::protocol_contract_tree::get_protocol_contract_tree();
let (tree, protocol_contract_leaves) =
fixtures::protocol_contract_tree::get_protocol_contract_tree();
self.protocol_contract_tree_root = tree.get_root();
self.protocol_contract_sibling_path = tree.get_sibling_path(contract_index);
// This is used in validate_contract_address where is_protocol_contract = true.
self.protocol_contract_membership_witness = MembershipWitness {
leaf_index: contract_index as Field,
sibling_path: tree.get_sibling_path(contract_index),
};
self.protocol_contract_leaf = protocol_contract_leaves[contract_index];

let contract_data = fixtures::contracts::get_protocol_contract(contract_index);
let function_data =
Expand All @@ -258,6 +281,7 @@ impl FixtureBuilder {
self.public_keys = contract_data.public_keys;
self.contract_class_artifact_hash = contract_data.artifact_hash;
self.contract_class_public_bytecode_commitment = contract_data.public_bytecode_commitment;
self.set_protocol_contract_root();

*self
}
Expand Down Expand Up @@ -393,7 +417,8 @@ impl FixtureBuilder {
contract_class_artifact_hash: self.contract_class_artifact_hash,
contract_class_public_bytecode_commitment: self
.contract_class_public_bytecode_commitment,
protocol_contract_sibling_path: self.protocol_contract_sibling_path,
protocol_contract_membership_witness: self.protocol_contract_membership_witness,
protocol_contract_leaf: self.protocol_contract_leaf,
acir_hash: self.acir_hash,
}
}
Expand Down Expand Up @@ -1141,7 +1166,8 @@ impl Empty for FixtureBuilder {
vk_path: [0; VK_TREE_HEIGHT],
vk_tree_root: FixtureBuilder::vk_tree_root(),
protocol_contract_tree_root: 0,
protocol_contract_sibling_path: [0; PROTOCOL_CONTRACT_TREE_HEIGHT],
protocol_contract_membership_witness: MembershipWitness::empty(),
protocol_contract_leaf: ProtocolContractLeafPreimage::empty(),
archive_tree: AppendOnlyTreeSnapshot::zero(),
start_snapshots: TreeSnapshots::empty(),
end_snapshots: TreeSnapshots::empty(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ pub global default_private_function: ContractFunction = ContractFunction {
membership_witness: MembershipWitness {
leaf_index: 0,
sibling_path: [
0x1eca11cd2abe68905eab86bc4f207cde29eb7c2b4c2c9b27e3d8c2f8b8234c87,
0x1bf05aedcca6b9682341475d1edb718df1485e4071c6c2f3c4576eeb3f9988a6,
0x233d10e0c959338e062b1c76fb81e17fcf61643da568eac372bb7feac8bfa357,
0x0e1ce4f11f4d51a7d3136abbd625315fff3876d322e46ad8401da96f8e43a614,
0x1a0ca5eecb1430479902264f04e557160a4666fb42bb8b283c6397e3d17ac937,
Expand Down
Loading
Loading