Skip to content
Open
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
2 changes: 2 additions & 0 deletions avm-transpiler/src/transpile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1634,6 +1634,7 @@ fn handle_get_contract_instance(
DEPLOYER,
CLASS_ID,
INIT_HASH,
IMMUTABLES_HASH,
}

assert_eq!(inputs.len(), 1);
Expand All @@ -1643,6 +1644,7 @@ fn handle_get_contract_instance(
"aztec_avm_getContractInstanceDeployer" => ContractInstanceMember::DEPLOYER,
"aztec_avm_getContractInstanceClassId" => ContractInstanceMember::CLASS_ID,
"aztec_avm_getContractInstanceInitializationHash" => ContractInstanceMember::INIT_HASH,
"aztec_avm_getContractInstanceImmutablesHash" => ContractInstanceMember::IMMUTABLES_HASH,
_ => panic!("Transpiler doesn't know how to process function {:?}", function),
};

Expand Down
31 changes: 17 additions & 14 deletions barretenberg/cpp/pil/vm2/bytecode/address_derivation.pil
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,14 @@ include "../scalar_mul.pil";
* during contract instance retrieval (contract_instance_retrieval.pil) in our execution flow.
* The address is defined by the following flow, where the hash function H() is Poseidon2, and G1
* is the Grumpkin curve's generator point:
* 1. salted_init_hash = H(DOM_SEP__SALTED_INITIALIZATION_HASH, salt, init_hash, deployer_addr)
* 1. salted_init_hash = H(DOM_SEP__SALTED_INITIALIZATION_HASH, salt, init_hash, deployer_addr, immutables_hash)
* 2. partial_address = H(DOM_SEP__PARTIAL_ADDRESS, class_id, salted_init_hash)
* 3. public_keys_hash = H(DOM_SEP__PUBLIC_KEYS_HASH,
* nullifier_key_x, nullifier_key_y, nullifier_key_is_infinity,
* incoming_viewing_key_x, incoming_viewing_key_y, incoming_viewing_key_is_infinity,
* outgoing_viewing_key_x, outgoing_viewing_key_y, outgoing_viewing_key_is_infinity,
* tagging_key_x, tagging_key_y, tagging_key_is_infinity)
* 4. preaddress = H(DOM_SEP__CONTRACT_ADDRESS_V1, public_keys_hash, partial_address)
* 4. preaddress = H(DOM_SEP__CONTRACT_ADDRESS_V2, public_keys_hash, partial_address)
* 5. preaddress_public_key = preaddress * G1
* 6. address = (preaddress_public_key + incoming_viewing_key).x
*
Expand Down Expand Up @@ -101,6 +101,7 @@ namespace address_derivation;
pol commit deployer_addr;
pol commit class_id; // = original_contract_class_id
pol commit init_hash;
pol commit immutables_hash;
// Public keys, all Grumpkin curve points (see PublicKeys in barretenberg/cpp/src/barretenberg/vm2/common/aztec_types.hpp).
pol commit nullifier_key_x;
pol commit nullifier_key_y;
Expand All @@ -117,14 +118,14 @@ namespace address_derivation;
///////////////////////////////
//
// This trace constrains the result of four Poseidon2 hashes:
// 1. salted_init_hash = H(DOM_SEP__SALTED_INITIALIZATION_HASH, salt, init_hash, deployer_addr)
// 1. salted_init_hash = H(DOM_SEP__SALTED_INITIALIZATION_HASH, salt, init_hash, deployer_addr, immutables_hash)
// 2. partial_address = H(DOM_SEP__PARTIAL_ADDRESS, class_id, salted_init_hash)
// 3. public_keys_hash = H(DOM_SEP__PUBLIC_KEYS_HASH,
// nullifier_key_x, nullifier_key_y, 0,
// incoming_viewing_key_x, incoming_viewing_key_y, 0,
// outgoing_viewing_key_x, outgoing_viewing_key_y, 0,
// tagging_key_x, tagging_key_y, 0)
// 4. preaddress = H(DOM_SEP__CONTRACT_ADDRESS_V1, public_keys_hash, partial_address)
// 4. preaddress = H(DOM_SEP__CONTRACT_ADDRESS_V2, public_keys_hash, partial_address)
//

// Lookup constant support: Can be removed when we support constants in lookups.
Expand All @@ -134,6 +135,8 @@ namespace address_derivation;
sel * (const_three - 3) = 0;
pol commit const_four;
sel * (const_four - 4) = 0;
pol commit const_five; // Used for the salted initialization hash
sel * (const_five - 5) = 0;
pol commit const_thirteen;
sel * (const_thirteen - 13) = 0;
pol commit salted_init_hash_domain_separator;
Expand All @@ -143,25 +146,25 @@ namespace address_derivation;
pol commit public_keys_hash_domain_separator;
sel * (public_keys_hash_domain_separator - constants.DOM_SEP__PUBLIC_KEYS_HASH) = 0;
pol commit preaddress_domain_separator;
sel * (preaddress_domain_separator - constants.DOM_SEP__CONTRACT_ADDRESS_V1) = 0;
sel * (preaddress_domain_separator - constants.DOM_SEP__CONTRACT_ADDRESS_V2) = 0;

// 1. Computation of salted initialization hash
pol commit salted_init_hash;

// Since Poseidon2 processes inputs in chunks of 3, we need 2 permutation rounds to cover our 4 inputs:
// salted_init_hash = H(DOM_SEP__SALTED_INITIALIZATION_HASH, salt, init_hash, deployer_addr)
// Round 1 (start, input_len=4): (DOM_SEP__SALTED_INITIALIZATION_HASH, salt, init_hash)
// Round 2 (end): (deployer_addr, 0, 0)
// Since Poseidon2 processes inputs in chunks of 3, we need 2 permutation rounds to cover our 5 inputs:
// salted_init_hash = H(DOM_SEP__SALTED_INITIALIZATION_HASH, salt, init_hash, deployer_addr, immutables_hash)
// Round 1 (start, input_len=5): (DOM_SEP__SALTED_INITIALIZATION_HASH, salt, init_hash)
// Round 2 (end): (deployer_addr, immutables_hash, 0)

// Enforces the first round of salted_init_hash. Note that we must lookup poseidon2_hash.input_len == 4
// Enforces the first round of salted_init_hash. Note that we must lookup poseidon2_hash.input_len == 5
// here since it is constrained in the poseidon trace on the start row.
#[SALTED_INITIALIZATION_HASH_POSEIDON2_0]
sel { salted_init_hash_domain_separator, salt, init_hash, salted_init_hash, const_four }
sel { salted_init_hash_domain_separator, salt, init_hash, salted_init_hash, const_five }
in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output, poseidon2_hash.input_len };

// Enforces the second and final round of salted_init_hash. Note that we must enforce the padded values are zero here.
#[SALTED_INITIALIZATION_HASH_POSEIDON2_1]
sel { deployer_addr, precomputed.zero, precomputed.zero, salted_init_hash }
sel { deployer_addr, immutables_hash, precomputed.zero, salted_init_hash }
in poseidon2_hash.end { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output };

// 2. Computation of partial address
Expand Down Expand Up @@ -234,8 +237,8 @@ namespace address_derivation;
pol commit preaddress;

// We have 3 inputs, hence a single Poseidon2 round:
// preaddress = H(DOM_SEP__CONTRACT_ADDRESS_V1, public_keys_hash, partial_address)
// Round 1 (start, input_len=3): (DOM_SEP__CONTRACT_ADDRESS_V1, public_keys_hash, partial_address)
// preaddress = H(DOM_SEP__CONTRACT_ADDRESS_V2, public_keys_hash, partial_address)
// Round 1 (start, input_len=3): (DOM_SEP__CONTRACT_ADDRESS_V2, public_keys_hash, partial_address)

// Enforces the single round of preaddress. Since input_len=3 fills exactly one permutation,
// this start lookup is also the final round and no separate end lookup is needed (the poseidon trace
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,18 +53,20 @@ include "update_check.pil";
* caller.exists,
* caller.deployer_addr, // situational - only if caller needs it
* caller.current_class_id,
* caller.init_hash // situational - only if caller needs it
* caller.init_hash, // situational - only if caller needs it
* caller.immutables_hash // situational - only if caller needs it
* } in contract_instance_retrieval.sel {
* contract_instance_retrieval.address,
* contract_instance_retrieval.nullifier_tree_root,
* contract_instance_retrieval.public_data_tree_root,
* contract_instance_retrieval.exists,
* contract_instance_retrieval.deployer_addr,
* contract_instance_retrieval.current_class_id,
* contract_instance_retrieval.init_hash
* contract_instance_retrieval.init_hash,
* contract_instance_retrieval.immutables_hash
* };
*
* Situational columns (deployer_addr, init_hash) can be omitted if the caller doesn't need
* Situational columns (deployer_addr, init_hash, immutables_hash) can be omitted if the caller doesn't need
* them. When omitted, they are only hinted for address derivation. This is secure because
* incorrect values would break derivation of the given address.
*
Expand Down Expand Up @@ -103,6 +105,7 @@ namespace contract_instance_retrieval;
pol commit current_class_id;
pol commit original_class_id; // HINTED!
pol commit init_hash;
pol commit immutables_hash;

// Current state — these should be looked up and constrained by the caller.
pol commit nullifier_tree_root;
Expand Down Expand Up @@ -242,6 +245,8 @@ namespace contract_instance_retrieval;
sel * (1 - exists) * original_class_id = 0; // technically not needed since original_class_id is hinted, but good for consistency
#[INSTANCE_MEMBER_INIT_HASH_IS_ZERO_IF_DNE]
sel * (1 - exists) * init_hash = 0;
#[INSTANCE_MEMBER_IMMUTABLES_HASH_IS_ZERO_IF_DNE]
sel * (1 - exists) * immutables_hash = 0;

// Address derivation lookup (only if the nullifier exists or for protocol contract instances).
#[ADDRESS_DERIVATION]
Expand All @@ -251,6 +256,7 @@ namespace contract_instance_retrieval;
deployer_addr,
original_class_id,
init_hash,
immutables_hash,
nullifier_key_x,
nullifier_key_y,
incoming_viewing_key_x,
Expand All @@ -265,6 +271,7 @@ namespace contract_instance_retrieval;
address_derivation.deployer_addr,
address_derivation.class_id,
address_derivation.init_hash,
address_derivation.immutables_hash,
address_derivation.nullifier_key_x,
address_derivation.nullifier_key_y,
address_derivation.incoming_viewing_key_x,
Expand Down
2 changes: 1 addition & 1 deletion barretenberg/cpp/pil/vm2/constants_gen.pil
Original file line number Diff line number Diff line change
Expand Up @@ -181,6 +181,6 @@ namespace constants;
pol DOM_SEP__SALTED_INITIALIZATION_HASH = 2763052992;
pol DOM_SEP__PUBLIC_KEYS_HASH = 777457226;
pol DOM_SEP__PARTIAL_ADDRESS = 2103633018;
pol DOM_SEP__CONTRACT_ADDRESS_V1 = 1788365517;
pol DOM_SEP__CONTRACT_ADDRESS_V2 = 4099338721;
pol DOM_SEP__PUBLIC_CALLDATA = 2760353947;

39 changes: 23 additions & 16 deletions barretenberg/cpp/pil/vm2/opcodes/get_contract_instance.pil
Original file line number Diff line number Diff line change
Expand Up @@ -11,16 +11,17 @@ include "../precomputed.pil";
* - Bounds-check dst_offset+1 via #[WRITE_OUT_OF_BOUNDS_CHECK]. If dst_offset is the
* maximum valid address, dst_offset+1 would be out of bounds.
* - Look up member_enum in the precomputed table (#[PRECOMPUTED_INFO]) to determine
* validity and which member is selected (deployer, class_id, or init_hash).
* validity and which member is selected (deployer, class_id, init_hash or immutables_hash).
* The precomputed table covers the full 8-bit range:
* +-------+----------------------+-------------+-------------+--------------+
* | idx | is_valid_member_enum | is_deployer | is_class_id | is_init_hash |
* +-------+----------------------+-------------+-------------+--------------+
* | 0 | 1 | 1 | 0 | 0 |
* | 1 | 1 | 0 | 1 | 0 |
* | 2 | 1 | 0 | 0 | 1 |
* | 3+ | 0 | 0 | 0 | 0 |
* +-------+----------------------+-------------+-------------+--------------+
* +-------+----------------------+-------------+-------------+--------------+--------------------+
* | idx | is_valid_member_enum | is_deployer | is_class_id | is_init_hash | is_immutables_hash |
* +-------+----------------------+-------------+-------------+--------------+--------------------+
* | 0 | 1 | 1 | 0 | 0 | 0 |
* | 1 | 1 | 0 | 1 | 0 | 0 |
* | 2 | 1 | 0 | 0 | 1 | 0 |
* | 3 | 1 | 0 | 0 | 0 | 1 |
* | 4+ | 0 | 0 | 0 | 0 | 0 |
* +-------+----------------------+-------------+-------------+--------------+--------------------+
* - Aggregate errors via #[ERROR_AGGREGATION]. sel_error is set when either
* is_valid_writes_in_bounds or is_valid_member_enum is false.
* - [no error only] Retrieve contract instance via the ContractInstanceRetrieval gadget
Expand Down Expand Up @@ -72,7 +73,7 @@ include "../precomputed.pil";
* ERROR HANDLING:
* Two error conditions, which are NOT mutually exclusive:
* - Write out-of-bounds: dst_offset == AVM_HIGHEST_MEM_ADDRESS (dst_offset+1 overflows).
* - Invalid member enum: member_enum >= 3 (precomputed table returns is_valid_member_enum=0).
* - Invalid member enum: member_enum >= 4 (precomputed table returns is_valid_member_enum=0).
* On error, the row has sel_error=1. The contract instance retrieval lookup and memory
* write permutations are disabled (their selectors is_valid_member_enum / is_valid_writes_in_bounds
* are 0), so no destination interactions fire for error rows.
Expand Down Expand Up @@ -121,13 +122,14 @@ namespace get_contract_instance;
// (from precomputed.pil's GETCONTRACTINSTANCE opcode precomputed columns)
// These are constrained only via the #[PRECOMPUTED_INFO] lookup when is_valid_writes_in_bounds == 1.
// When the lookup is disabled (writes out of bounds), is_valid_member_enum is forced to 0 by
// #[IS_VALID_MEMBER_ENUM_ONLY_SET_BY_PRECOMPUTED_LOOKUP]. is_deployer/is_class_id/is_init_hash
// #[IS_VALID_MEMBER_ENUM_ONLY_SET_BY_PRECOMPUTED_LOOKUP]. is_deployer/is_class_id/is_init_hash/is_immutables_hash
// are free in that case, but safe: they are only consumed in #[SELECTED_MEMBER] and the memory
// write permutations, all of which are gated on is_valid_member_enum (which is 0).
pol commit is_valid_member_enum; // @boolean (by lookup when is_valid_writes_in_bounds == 1)
pol commit is_deployer; // @boolean (by lookup when is_valid_writes_in_bounds == 1)
pol commit is_class_id; // @boolean (by lookup when is_valid_writes_in_bounds == 1)
pol commit is_init_hash; // @boolean (by lookup when is_valid_writes_in_bounds == 1)
pol commit is_immutables_hash; // @boolean (by lookup when is_valid_writes_in_bounds == 1)
// Note: member_enum is guaranteed to be 8 bits by execution (as a U8 immediate operand),
// and the precomputed table is populated for the entire 8-bit range (256 rows).
#[PRECOMPUTED_INFO]
Expand All @@ -138,15 +140,17 @@ namespace get_contract_instance;
is_valid_member_enum,
is_deployer,
is_class_id,
is_init_hash
is_init_hash,
is_immutables_hash
} in precomputed.sel_range_8 {
// inputs
precomputed.idx,
// outputs
precomputed.is_valid_member_enum,
precomputed.is_deployer,
precomputed.is_class_id,
precomputed.is_init_hash
precomputed.is_init_hash,
precomputed.is_immutables_hash
};
// Do not allow is_valid_member_enum to be 1 if the precomputed lookup is disabled.
#[IS_VALID_MEMBER_ENUM_ONLY_SET_BY_PRECOMPUTED_LOOKUP]
Expand All @@ -171,6 +175,7 @@ namespace get_contract_instance;
pol commit retrieved_deployer_addr;
pol commit retrieved_class_id;
pol commit retrieved_init_hash;
pol commit retrieved_immutables_hash;

#[CONTRACT_INSTANCE_RETRIEVAL]
is_valid_member_enum {
Expand All @@ -182,7 +187,8 @@ namespace get_contract_instance;
instance_exists,
retrieved_deployer_addr,
retrieved_class_id,
retrieved_init_hash
retrieved_init_hash,
retrieved_immutables_hash
} in contract_instance_retrieval.sel {
// inputs
contract_instance_retrieval.address,
Expand All @@ -192,14 +198,15 @@ namespace get_contract_instance;
contract_instance_retrieval.exists,
contract_instance_retrieval.deployer_addr,
contract_instance_retrieval.current_class_id,
contract_instance_retrieval.init_hash
contract_instance_retrieval.init_hash,
contract_instance_retrieval.immutables_hash
};

// Select the member indicated by the enum for writing to memory
// Note: is_* selectors are guaranteed to be mutually exclusive booleans by the precomputed table.
pol commit selected_member;
#[SELECTED_MEMBER]
selected_member = is_deployer * retrieved_deployer_addr + is_class_id * retrieved_class_id + is_init_hash * retrieved_init_hash;
selected_member = is_deployer * retrieved_deployer_addr + is_class_id * retrieved_class_id + is_init_hash * retrieved_init_hash + is_immutables_hash * retrieved_immutables_hash;

// Compute memory offsets for writing to
pol commit member_write_offset;
Expand Down
3 changes: 2 additions & 1 deletion barretenberg/cpp/pil/vm2/precomputed.pil
Original file line number Diff line number Diff line change
Expand Up @@ -435,7 +435,7 @@ pol constant out_tag;

// ===== Section 14: GETCONTRACTINSTANCE opcode columns =====
// Maps contract instance member enum values to selectors indicating which field
// (deployer, class_id, init_hash) is being accessed.
// (deployer, class_id, init_hash, immutables_hash) is being accessed.
// Used by the GETCONTRACTINSTANCE opcode.
//
// see opcodes/get_contract_instance.pil for ascii table
Expand All @@ -444,3 +444,4 @@ pol constant is_valid_member_enum;
pol constant is_deployer;
pol constant is_class_id;
pol constant is_init_hash;
pol constant is_immutables_hash;
Original file line number Diff line number Diff line change
Expand Up @@ -273,6 +273,6 @@
#define DOM_SEP__SALTED_INITIALIZATION_HASH 2763052992UL
#define DOM_SEP__PUBLIC_KEYS_HASH 777457226UL
#define DOM_SEP__PARTIAL_ADDRESS 2103633018UL
#define DOM_SEP__CONTRACT_ADDRESS_V1 1788365517UL
#define DOM_SEP__CONTRACT_ADDRESS_V2 4099338721UL
#define DOM_SEP__BLOCK_HEADER_HASH 4195546849UL
#define DOM_SEP__PUBLIC_CALLDATA 2760353947UL
2 changes: 2 additions & 0 deletions barretenberg/cpp/src/barretenberg/vm2/common/avm_io.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,7 @@ struct ContractInstanceHint {
ContractClassId current_contract_class_id;
ContractClassId original_contract_class_id;
FF initialization_hash;
FF immutables_hash;
PublicKeysHint public_keys;

bool operator==(const ContractInstanceHint& other) const = default;
Expand All @@ -146,6 +147,7 @@ struct ContractInstanceHint {
current_contract_class_id,
original_contract_class_id,
initialization_hash,
immutables_hash,
public_keys);
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,8 @@ enum class ContractInstanceMember : uint8_t {
DEPLOYER = 0,
CLASS_ID = 1,
INIT_HASH = 2,
MAX = INIT_HASH,
IMMUTABLES_HASH = 3,
MAX = IMMUTABLES_HASH,
};

////////////////////////////////////////////////////////////////////////////
Expand Down Expand Up @@ -119,7 +120,8 @@ struct ContractInstance {
ContractClassId current_contract_class_id = 0;
ContractClassId original_contract_class_id = 0;
FF initialization_hash = 0;
PublicKeys public_keys;
FF immutables_hash = 0;
PublicKeys public_keys{};

bool operator==(const ContractInstance& other) const = default;

Expand All @@ -136,6 +138,8 @@ struct ContractInstance {
original_contract_class_id,
"initializationHash",
initialization_hash,
"immutablesHash",
immutables_hash,
"publicKeys",
public_keys);
}
Expand Down
Loading
Loading