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
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 @@ -256,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 @@ -270,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;

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
Original file line number Diff line number Diff line change
Expand Up @@ -72,14 +72,17 @@ TEST(AddressDerivationConstrainingTest, Basic)

auto instance = testing::random_contract_instance();

FF salted_initialization_hash = poseidon2::hash(
{ DOM_SEP__SALTED_INITIALIZATION_HASH, instance.salt, instance.initialization_hash, instance.deployer });
FF salted_initialization_hash = poseidon2::hash({ DOM_SEP__SALTED_INITIALIZATION_HASH,
instance.salt,
instance.initialization_hash,
instance.deployer,
instance.immutables_hash });

FF partial_address =
poseidon2::hash({ DOM_SEP__PARTIAL_ADDRESS, instance.original_contract_class_id, salted_initialization_hash });

FF public_keys_hash = hash_public_keys(instance.public_keys);
FF preaddress = poseidon2::hash({ DOM_SEP__CONTRACT_ADDRESS_V1, public_keys_hash, partial_address });
FF preaddress = poseidon2::hash({ DOM_SEP__CONTRACT_ADDRESS_V2, public_keys_hash, partial_address });

EmbeddedCurvePoint g1 = EmbeddedCurvePoint::one();
EmbeddedCurvePoint preaddress_public_key = g1 * Fq(preaddress);
Expand Down Expand Up @@ -215,6 +218,62 @@ TEST(AddressDerivationConstrainingTest, NegativeWithInteractions)
"Failed.*PREADDRESS_SCALAR_MUL. Could not find tuple in destination.");
}

TEST(AddressDerivationConstrainingTest, NegativeMutateImmutablesHash)
{
EventEmitter<EccAddEvent> ecadd_event_emitter;
EventEmitter<ScalarMulEvent> scalar_mul_event_emitter;
NoopEventEmitter<EccAddMemoryEvent> ecc_add_memory_event_emitter;
EventEmitter<Poseidon2HashEvent> hash_event_emitter;
NoopEventEmitter<Poseidon2PermutationEvent> perm_event_emitter;
NoopEventEmitter<Poseidon2PermutationMemoryEvent> perm_mem_event_emitter;
EventEmitter<AddressDerivationEvent> address_derivation_event_emitter;

StrictMock<MockExecutionIdManager> mock_exec_id_manager;
EXPECT_CALL(mock_exec_id_manager, get_execution_id).WillRepeatedly(Return(0));
StrictMock<MockGreaterThan> mock_gt;
Poseidon2 poseidon2_simulator(
mock_exec_id_manager, mock_gt, hash_event_emitter, perm_event_emitter, perm_mem_event_emitter);

PureToRadix to_radix_simulator;
Ecc ecc_simulator(mock_exec_id_manager,
mock_gt,
to_radix_simulator,
ecadd_event_emitter,
scalar_mul_event_emitter,
ecc_add_memory_event_emitter);

AddressDerivation address_derivation(poseidon2_simulator, ecc_simulator, address_derivation_event_emitter);

TestTraceContainer trace({
{ { C::precomputed_first_row, 1 } },
});

AddressDerivationTraceBuilder builder;
Poseidon2TraceBuilder poseidon2_builder;
EccTraceBuilder ecc_builder;

ContractInstance instance = testing::random_contract_instance();
AztecAddress address = compute_contract_address(instance);
address_derivation.assert_derivation(address, instance);

builder.process(address_derivation_event_emitter.dump_events(), trace);
poseidon2_builder.process_hash(hash_event_emitter.dump_events(), trace);
ecc_builder.process_add(ecadd_event_emitter.dump_events(), trace);
ecc_builder.process_scalar_mul(scalar_mul_event_emitter.dump_events(), trace);

check_all_interactions<AddressDerivationTraceBuilder>(trace);
check_relation<address_derivation_relation>(trace);

// Mutate immutables_hash (the second input of the second poseidon2 round). The salted-init-hash
// round-2 lookup into poseidon2 should now fail because (deployer, mutated_immutables_hash, 0,
// salted_init_hash) no longer exists in the poseidon2 trace.
trace.set(C::address_derivation_immutables_hash, 0, instance.immutables_hash + 1);
EXPECT_THROW_WITH_MESSAGE(
(check_interaction<AddressDerivationTraceBuilder,
lookup_address_derivation_salted_initialization_hash_poseidon2_1_settings>(trace)),
"Failed.*SALTED_INITIALIZATION_HASH_POSEIDON2_1. Could not find tuple in destination.");
}

TEST(AddressDerivationConstrainingTest, NegativeIVKNotOnCurve)
{
TestTraceContainer trace;
Expand All @@ -232,7 +291,7 @@ TEST(AddressDerivationConstrainingTest, NegativeIVKNotOnCurve)
poseidon2::hash({ DOM_SEP__PARTIAL_ADDRESS, instance.original_contract_class_id, salted_initialization_hash });

FF public_keys_hash = hash_public_keys(instance.public_keys);
FF preaddress = poseidon2::hash({ DOM_SEP__CONTRACT_ADDRESS_V1, public_keys_hash, partial_address });
FF preaddress = poseidon2::hash({ DOM_SEP__CONTRACT_ADDRESS_V2, public_keys_hash, partial_address });

EmbeddedCurvePoint g1 = EmbeddedCurvePoint::one();
EmbeddedCurvePoint preaddress_public_key = g1 * Fq(preaddress);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -472,6 +472,7 @@ TEST(ContractInstanceRetrievalConstrainingTest, IntegrationTracegenValidInstance
{ C::address_derivation_deployer_addr, contract_instance_data.deployer },
{ C::address_derivation_class_id, contract_instance_data.original_contract_class_id },
{ C::address_derivation_init_hash, contract_instance_data.initialization_hash },
{ C::address_derivation_immutables_hash, contract_instance_data.immutables_hash },
{ C::address_derivation_nullifier_key_x, contract_instance_data.public_keys.nullifier_key.x },
{ C::address_derivation_nullifier_key_y, contract_instance_data.public_keys.nullifier_key.y },
{ C::address_derivation_incoming_viewing_key_x, contract_instance_data.public_keys.incoming_viewing_key.x },
Expand Down Expand Up @@ -547,10 +548,11 @@ TEST(ContractInstanceRetrievalConstrainingTest, IntegrationTracegenNonExistentIn
// For address derivation lookup
{ C::address_derivation_sel, 0 }, // Not selected since nullifier doesn't exist
{ C::address_derivation_address, contract_address },
{ C::address_derivation_salt, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_deployer_addr, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_class_id, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_init_hash, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_salt, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_deployer_addr, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_class_id, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_init_hash, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_immutables_hash, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_nullifier_key_x, 0 },
{ C::address_derivation_nullifier_key_y, 0 },
{ C::address_derivation_incoming_viewing_key_x, 0 },
Expand Down Expand Up @@ -628,10 +630,11 @@ TEST(ContractInstanceRetrievalConstrainingTest, IntegrationTracegenAddressZero)
// For address derivation lookup
{ C::address_derivation_sel, 0 }, // Not selected since nullifier doesn't exist
{ C::address_derivation_address, contract_address },
{ C::address_derivation_salt, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_deployer_addr, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_class_id, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_init_hash, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_salt, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_deployer_addr, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_class_id, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_init_hash, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_immutables_hash, 0 }, // zero since nullifier doesn't exist
{ C::address_derivation_nullifier_key_x, 0 },
{ C::address_derivation_nullifier_key_y, 0 },
{ C::address_derivation_incoming_viewing_key_x, 0 },
Expand Down Expand Up @@ -722,6 +725,7 @@ TEST(ContractInstanceRetrievalConstrainingTest, IntegrationTracegenMultipleInsta
{ C::address_derivation_deployer_addr, contract_instance_data.deployer },
{ C::address_derivation_class_id, contract_instance_data.original_contract_class_id },
{ C::address_derivation_init_hash, contract_instance_data.initialization_hash },
{ C::address_derivation_immutables_hash, contract_instance_data.immutables_hash },
{ C::address_derivation_nullifier_key_x, contract_instance_data.public_keys.nullifier_key.x },
{ C::address_derivation_nullifier_key_y, contract_instance_data.public_keys.nullifier_key.y },
{ C::address_derivation_incoming_viewing_key_x,
Expand Down
Loading
Loading