-
Notifications
You must be signed in to change notification settings - Fork 607
feat(avm): Address derivation gadget #12721
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
Changes from 9 commits
3aa9a5c
ed880cb
df46e1a
238cb52
ea30a85
8d48474
062b4cd
9cd6810
f3d2d6f
215fae5
d8aae85
74d33a6
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,139 @@ | ||
| include "constants_gen.pil"; | ||
| include "ecc.pil"; | ||
| include "poseidon2_hash.pil"; | ||
| include "precomputed.pil"; | ||
| include "scalar_mul.pil"; | ||
|
|
||
| namespace address_derivation; | ||
|
|
||
| pol commit sel; | ||
| sel * (1 - sel) = 0; | ||
|
|
||
| #[skippable_if] | ||
| sel = 0; | ||
|
|
||
| // Address preimage components | ||
| pol commit salt; | ||
| pol commit deployer_addr; | ||
| pol commit class_id; | ||
| pol commit init_hash; | ||
| pol commit nullifier_key_x; | ||
| pol commit nullifier_key_y; | ||
| pol commit incoming_viewing_key_x; | ||
| pol commit incoming_viewing_key_y; | ||
| pol commit outgoing_viewing_key_x; | ||
| pol commit outgoing_viewing_key_y; | ||
| pol commit tagging_key_x; | ||
| pol commit tagging_key_y; | ||
|
|
||
| // Expected derived address | ||
| pol commit address; | ||
|
|
||
|
|
||
| // Computation of salted initialization hash | ||
|
|
||
| pol commit salted_init_hash; | ||
|
|
||
| // It's reused between the partial address and salted initialization hash. Weird. | ||
| pol commit partial_address_domain_separator; | ||
| sel * (partial_address_domain_separator - constants.GENERATOR_INDEX__PARTIAL_ADDRESS) = 0; | ||
|
|
||
| #[SALTED_INITIALIZATION_HASH_POSEIDON2_0] | ||
| sel { partial_address_domain_separator, salt, init_hash, salted_init_hash } | ||
| in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output }; | ||
|
|
||
| #[SALTED_INITIALIZATION_HASH_POSEIDON2_1] | ||
| sel { deployer_addr, precomputed.zero, precomputed.zero, salted_init_hash} | ||
| in poseidon2_hash.end { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output }; | ||
|
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Poseidon2 was changed to propagate the final output on the whole run. It's however still incomplete, I talked with Ilyas about it because we need to lookup also the iteration index. This hash run in poseidon looks like this: In order for it to be safe I need to assert that start is on on the first one and end is on in the second one. However, a malicious prover could still insert more rounds between the two rows, that's why poseidon will need to be improved to include a round_index column, so I can lookup with 0 on start and 1 on end so I can be safe that a malicious prover hasn't inserted more rounds
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Please file an issue to fix poseidon if there's not already one (and to update all callers), assign to ilyas, and add it to this doc since this seems quite important.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Done |
||
|
|
||
|
|
||
| // Computation of partial address | ||
|
|
||
| pol commit partial_address; | ||
|
|
||
| #[PARTIAL_ADDRESS_POSEIDON2] | ||
| sel { partial_address_domain_separator, class_id, salted_init_hash, partial_address } | ||
| in poseidon2_hash.end { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output }; | ||
|
|
||
|
|
||
| // Hash the public keys | ||
|
|
||
| pol commit public_keys_hash; | ||
|
|
||
| pol commit public_keys_hash_domain_separator; | ||
| sel * (public_keys_hash_domain_separator - constants.GENERATOR_INDEX__PUBLIC_KEYS_HASH) = 0; | ||
|
|
||
| // Remove all the 0s for is_infinite when removed from public_keys.nr | ||
| // https://github.com/AztecProtocol/aztec-packages/issues/7529 | ||
| #[PUBLIC_KEYS_HASH_POSEIDON2_0] | ||
| sel { public_keys_hash_domain_separator, nullifier_key_x, nullifier_key_y, public_keys_hash } | ||
| in poseidon2_hash.start { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output }; | ||
|
|
||
| #[PUBLIC_KEYS_HASH_POSEIDON2_1] | ||
| sel { precomputed.zero, incoming_viewing_key_x, incoming_viewing_key_y, public_keys_hash } | ||
| in poseidon2_hash.sel { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output }; | ||
|
|
||
| #[PUBLIC_KEYS_HASH_POSEIDON2_2] | ||
| sel { precomputed.zero, outgoing_viewing_key_x, outgoing_viewing_key_y, public_keys_hash } | ||
| in poseidon2_hash.sel { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output }; | ||
|
|
||
| #[PUBLIC_KEYS_HASH_POSEIDON2_3] | ||
| sel { precomputed.zero, tagging_key_x, tagging_key_y, public_keys_hash } | ||
| in poseidon2_hash.sel { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output }; | ||
|
|
||
| #[PUBLIC_KEYS_HASH_POSEIDON2_4] | ||
| sel { precomputed.zero, precomputed.zero, precomputed.zero, public_keys_hash } | ||
| in poseidon2_hash.end { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output }; | ||
|
|
||
|
|
||
| // Compute the preaddress | ||
|
|
||
| pol commit preaddress; | ||
|
|
||
| pol commit preaddress_domain_separator; | ||
| sel * (preaddress_domain_separator - constants.GENERATOR_INDEX__CONTRACT_ADDRESS_V1) = 0; | ||
|
|
||
| #[PREADDRESS_POSEIDON2] | ||
| sel { preaddress_domain_separator, public_keys_hash, partial_address, preaddress } | ||
| in poseidon2_hash.end { poseidon2_hash.input_0, poseidon2_hash.input_1, poseidon2_hash.input_2, poseidon2_hash.output }; | ||
|
|
||
|
|
||
| // Derive preaddress public key | ||
|
|
||
| pol commit preaddress_public_key_x; | ||
| pol commit preaddress_public_key_y; | ||
|
|
||
| pol commit g1_x; | ||
| sel * (g1_x - 1) = 0; | ||
|
|
||
| pol commit g1_y; | ||
| sel * (g1_y - 17631683881184975370165255887551781615748388533673675138860) = 0; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We could define a constant for this monster literal and add a comment about what it is. |
||
|
|
||
| #[PREADDRESS_SCALAR_MUL] | ||
| sel { | ||
| preaddress, | ||
| g1_x, g1_y, precomputed.zero, | ||
| preaddress_public_key_x, preaddress_public_key_y, precomputed.zero | ||
| } in scalar_mul.start { | ||
| scalar_mul.scalar, | ||
| scalar_mul.point_x, scalar_mul.point_y, scalar_mul.point_inf, | ||
| scalar_mul.res_x, scalar_mul.res_y, scalar_mul.res_inf | ||
| }; | ||
|
|
||
|
|
||
| // Finally, the address must be the x coordinate of preaddress_public_key + incoming_viewing_key | ||
|
|
||
| pol commit address_y; | ||
|
|
||
| #[ADDRESS_ECADD] | ||
| sel { | ||
| preaddress_public_key_x, preaddress_public_key_y, precomputed.zero, | ||
| incoming_viewing_key_x, incoming_viewing_key_y, precomputed.zero, | ||
| address, address_y, precomputed.zero | ||
| } in ecc.sel { | ||
| ecc.p_x, ecc.p_y, ecc.p_is_inf, | ||
| ecc.q_x, ecc.q_y, ecc.q_is_inf, | ||
| ecc.r_x, ecc.r_y, ecc.r_is_inf | ||
| }; | ||
|
|
||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,174 @@ | ||
| #include <gmock/gmock.h> | ||
| #include <gtest/gtest.h> | ||
|
|
||
| #include "barretenberg/crypto/poseidon2/poseidon2.hpp" | ||
| #include "barretenberg/crypto/poseidon2/poseidon2_params.hpp" | ||
| #include "barretenberg/vm2/constraining/testing/check_relation.hpp" | ||
| #include "barretenberg/vm2/generated/columns.hpp" | ||
| #include "barretenberg/vm2/generated/flavor_settings.hpp" | ||
| #include "barretenberg/vm2/generated/relations/address_derivation.hpp" | ||
| #include "barretenberg/vm2/generated/relations/lookups_address_derivation.hpp" | ||
| #include "barretenberg/vm2/simulation/address_derivation.hpp" | ||
| #include "barretenberg/vm2/simulation/events/address_derivation_event.hpp" | ||
| #include "barretenberg/vm2/simulation/events/ecc_events.hpp" | ||
| #include "barretenberg/vm2/simulation/events/event_emitter.hpp" | ||
| #include "barretenberg/vm2/simulation/lib/contract_crypto.hpp" | ||
| #include "barretenberg/vm2/simulation/to_radix.hpp" | ||
| #include "barretenberg/vm2/testing/fixtures.hpp" | ||
| #include "barretenberg/vm2/tracegen/address_derivation_trace.hpp" | ||
| #include "barretenberg/vm2/tracegen/ecc_trace.hpp" | ||
| #include "barretenberg/vm2/tracegen/lib/lookup_builder.hpp" | ||
| #include "barretenberg/vm2/tracegen/poseidon2_trace.hpp" | ||
| #include "barretenberg/vm2/tracegen/test_trace_container.hpp" | ||
| #include "barretenberg/vm2/tracegen/to_radix_trace.hpp" | ||
|
|
||
| namespace bb::avm2::constraining { | ||
| namespace { | ||
|
|
||
| using tracegen::AddressDerivationTraceBuilder; | ||
| using tracegen::EccTraceBuilder; | ||
| using tracegen::LookupIntoDynamicTableSequential; | ||
| using tracegen::Poseidon2TraceBuilder; | ||
| using tracegen::TestTraceContainer; | ||
|
|
||
| using simulation::AddressDerivation; | ||
| using simulation::AddressDerivationEvent; | ||
| using simulation::compute_contract_address; | ||
| using simulation::Ecc; | ||
| using simulation::EccAddEvent; | ||
| using simulation::EventEmitter; | ||
| using simulation::hash_public_keys; | ||
| using simulation::NoopEventEmitter; | ||
| using simulation::Poseidon2; | ||
| using simulation::Poseidon2HashEvent; | ||
| using simulation::Poseidon2PermutationEvent; | ||
| using simulation::ScalarMulEvent; | ||
| using simulation::ToRadix; | ||
| using simulation::ToRadixEvent; | ||
|
|
||
| using FF = AvmFlavorSettings::FF; | ||
| using C = Column; | ||
| using address_derivation_relation = bb::avm2::address_derivation<FF>; | ||
| using poseidon2_relation = bb::avm2::poseidon2_hash<FF>; | ||
| using ecadd_relation = bb::avm2::ecc<FF>; | ||
| using scalar_mul_relation = bb::avm2::scalar_mul<FF>; | ||
| using poseidon2 = crypto::Poseidon2<crypto::Poseidon2Bn254ScalarFieldParams>; | ||
|
|
||
| using lookup_salted_initialization_hash_poseidon2_0 = | ||
| bb::avm2::lookup_address_derivation_salted_initialization_hash_poseidon2_0_relation<FF>; | ||
| using lookup_salted_initialization_hash_poseidon2_1 = | ||
| bb::avm2::lookup_address_derivation_salted_initialization_hash_poseidon2_1_relation<FF>; | ||
| using lookup_partial_address_poseidon2 = bb::avm2::lookup_address_derivation_partial_address_poseidon2_relation<FF>; | ||
| using lookup_public_keys_hash_poseidon2_0 = | ||
| bb::avm2::lookup_address_derivation_public_keys_hash_poseidon2_0_relation<FF>; | ||
| using lookup_public_keys_hash_poseidon2_1 = | ||
| bb::avm2::lookup_address_derivation_public_keys_hash_poseidon2_1_relation<FF>; | ||
| using lookup_public_keys_hash_poseidon2_2 = | ||
| bb::avm2::lookup_address_derivation_public_keys_hash_poseidon2_2_relation<FF>; | ||
| using lookup_public_keys_hash_poseidon2_3 = | ||
| bb::avm2::lookup_address_derivation_public_keys_hash_poseidon2_3_relation<FF>; | ||
| using lookup_public_keys_hash_poseidon2_4 = | ||
| bb::avm2::lookup_address_derivation_public_keys_hash_poseidon2_4_relation<FF>; | ||
| using lookup_public_preaddress_poseidon2 = bb::avm2::lookup_address_derivation_preaddress_poseidon2_relation<FF>; | ||
| using lookup_public_preaddress_scalar_mul = bb::avm2::lookup_address_derivation_preaddress_scalar_mul_relation<FF>; | ||
| using lookup_address_ecadd = bb::avm2::lookup_address_derivation_address_ecadd_relation<FF>; | ||
|
|
||
| TEST(AddressDerivationConstrainingTest, EmptyRow) | ||
| { | ||
| check_relation<address_derivation_relation>(testing::empty_trace()); | ||
| } | ||
|
|
||
| TEST(AddressDerivationConstrainingTest, Basic) | ||
| { | ||
| TestTraceContainer trace; | ||
| AddressDerivationTraceBuilder builder; | ||
|
|
||
| auto instance = testing::random_contract_instance(); | ||
|
|
||
| FF salted_initialization_hash = poseidon2::hash( | ||
| { GENERATOR_INDEX__PARTIAL_ADDRESS, instance.salt, instance.initialisation_hash, instance.deployer_addr }); | ||
|
|
||
| FF partial_address = | ||
| poseidon2::hash({ GENERATOR_INDEX__PARTIAL_ADDRESS, instance.contract_class_id, salted_initialization_hash }); | ||
|
|
||
| FF public_keys_hash = hash_public_keys(instance.public_keys); | ||
| FF preaddress = poseidon2::hash({ GENERATOR_INDEX__CONTRACT_ADDRESS_V1, public_keys_hash, partial_address }); | ||
|
|
||
| EmbeddedCurvePoint g1 = EmbeddedCurvePoint::one(); | ||
| EmbeddedCurvePoint preaddress_public_key = g1 * Fq(preaddress); | ||
| EmbeddedCurvePoint address_point = preaddress_public_key + instance.public_keys.incoming_viewing_key; | ||
|
|
||
| builder.process({ { .address = address_point.x(), | ||
| .instance = instance, | ||
| .salted_initialization_hash = salted_initialization_hash, | ||
| .partial_address = partial_address, | ||
| .public_keys_hash = public_keys_hash, | ||
| .preaddress = preaddress, | ||
| .preaddress_public_key = preaddress_public_key, | ||
| .address_point = address_point } }, | ||
| trace); | ||
|
|
||
| EXPECT_EQ(trace.get_num_rows(), 1); | ||
| check_relation<address_derivation_relation>(trace); | ||
|
sirasistant marked this conversation as resolved.
|
||
| } | ||
|
|
||
| TEST(AddressDerivationConstrainingTest, WithInteractions) | ||
| { | ||
| NoopEventEmitter<ToRadixEvent> to_radix_event_emitter; | ||
| EventEmitter<EccAddEvent> ecadd_event_emitter; | ||
| EventEmitter<ScalarMulEvent> scalar_mul_event_emitter; | ||
| EventEmitter<Poseidon2HashEvent> hash_event_emitter; | ||
| NoopEventEmitter<Poseidon2PermutationEvent> perm_event_emitter; | ||
| EventEmitter<AddressDerivationEvent> address_derivation_event_emitter; | ||
|
|
||
| ToRadix to_radix_simulator(to_radix_event_emitter); | ||
| Ecc ecc_simulator(to_radix_simulator, ecadd_event_emitter, scalar_mul_event_emitter); | ||
| Poseidon2 poseidon2_simulator(hash_event_emitter, perm_event_emitter); | ||
|
|
||
| AddressDerivation address_derivation(poseidon2_simulator, ecc_simulator, address_derivation_event_emitter); | ||
|
|
||
| TestTraceContainer trace = TestTraceContainer::from_rows({ | ||
| { .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); | ||
|
|
||
| LookupIntoDynamicTableSequential<lookup_salted_initialization_hash_poseidon2_0::Settings>().process(trace); | ||
| LookupIntoDynamicTableSequential<lookup_salted_initialization_hash_poseidon2_1::Settings>().process(trace); | ||
| LookupIntoDynamicTableSequential<lookup_partial_address_poseidon2::Settings>().process(trace); | ||
| LookupIntoDynamicTableSequential<lookup_public_keys_hash_poseidon2_0::Settings>().process(trace); | ||
| LookupIntoDynamicTableSequential<lookup_public_keys_hash_poseidon2_1::Settings>().process(trace); | ||
| LookupIntoDynamicTableSequential<lookup_public_keys_hash_poseidon2_2::Settings>().process(trace); | ||
| LookupIntoDynamicTableSequential<lookup_public_keys_hash_poseidon2_3::Settings>().process(trace); | ||
| LookupIntoDynamicTableSequential<lookup_public_keys_hash_poseidon2_4::Settings>().process(trace); | ||
| LookupIntoDynamicTableSequential<lookup_public_preaddress_poseidon2::Settings>().process(trace); | ||
| LookupIntoDynamicTableSequential<lookup_public_preaddress_scalar_mul::Settings>().process(trace); | ||
| LookupIntoDynamicTableSequential<lookup_address_ecadd::Settings>().process(trace); | ||
|
|
||
| check_relation<address_derivation_relation>(trace); | ||
| check_interaction<lookup_salted_initialization_hash_poseidon2_0>(trace); | ||
| check_interaction<lookup_salted_initialization_hash_poseidon2_1>(trace); | ||
| check_interaction<lookup_partial_address_poseidon2>(trace); | ||
| check_interaction<lookup_public_keys_hash_poseidon2_0>(trace); | ||
| check_interaction<lookup_public_keys_hash_poseidon2_1>(trace); | ||
| check_interaction<lookup_public_keys_hash_poseidon2_2>(trace); | ||
| check_interaction<lookup_public_keys_hash_poseidon2_3>(trace); | ||
| check_interaction<lookup_public_keys_hash_poseidon2_4>(trace); | ||
| check_interaction<lookup_public_preaddress_poseidon2>(trace); | ||
| check_interaction<lookup_public_preaddress_scalar_mul>(trace); | ||
| check_interaction<lookup_address_ecadd>(trace); | ||
| } | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. There are no negative tests but not sure what is meaningful to test as it consists mainly in lookups and therefore we would test that lookups are working as expected.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. yes the only relations are trivial constants and lookups |
||
|
|
||
| } // namespace | ||
| } // namespace bb::avm2::constraining | ||
Large diffs are not rendered by default.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
IIRC, we do not support a constant nor alias in a lookup tuple?
Because otherwise, we could inline constants.GENERATOR_INDEX__PARTIAL_ADDRESS in the tuple and get rid of
the above relation.
I suggest to write a TODO so that we can simplify once we support constants in lookups.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'll write a todo, unfortunately we can't, on lookups we need to use real columns ):