Skip to content
Merged

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,
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 @@ -115,7 +115,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 @@ -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 @@ -67,7 +68,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 @@ -159,7 +160,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 @@ -228,16 +230,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 @@ -255,6 +278,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 @@ -390,7 +414,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 @@ -1136,7 +1161,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(),
revert_code: 0,
min_revertible_side_effect_counter: 0,
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