diff --git a/docs/docs/misc/migration_notes.md b/docs/docs/misc/migration_notes.md index 902eae67a4d0..7f9907385908 100644 --- a/docs/docs/misc/migration_notes.md +++ b/docs/docs/misc/migration_notes.md @@ -12,9 +12,22 @@ Aztec is in full-speed development. Literally every version breaks compatibility The type signature for `SharedMutable` changed from `SharedMutable` to `SharedMutable`. The behavior is the same as before, except the delay can now be changed after deployment by calling `schedule_delay_change`. +### [Aztec.nr] get_public_key oracle replaced with get_ivpk_m + +When implementing changes according to a [new key scheme](https://yp-aztec.netlify.app/docs/addresses-and-keys/keys) we had to change oracles. +What used to be called encryption public key is now master incoming viewing public key. + +```diff +- use dep::aztec::oracles::get_public_key::get_public_key; ++ use dep::aztec::keys::getters::get_ivpk_m; + +- let encryption_pub_key = get_public_key(self.owner); ++ let ivpk_m = get_ivpk_m(context, self.owner); +``` + ## 0.38.0 -### [Aztec.nr] Emmiting encrypted logs +### [Aztec.nr] Emitting encrypted logs The `emit_encrypted_log` function is now a context method. diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index d784a0fb7e76..002c56de9348 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -1,7 +1,8 @@ use dep::aztec::{ + keys::getters::get_ivpk_m, protocol_types::{address::AztecAddress, traits::Empty, constants::GENERATOR_INDEX__NOTE_NULLIFIER}, note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key}, + oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key}, context::PrivateContext, hash::poseidon2_hash }; @@ -40,13 +41,13 @@ impl NoteInterface for AddressNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { - let encryption_pub_key = get_public_key(self.owner); + let ivpk_m = get_ivpk_m(context, self.owner); // docs:start:encrypted context.emit_encrypted_log( (*context).this_address(), slot, Self::get_note_type_id(), - encryption_pub_key, + ivpk_m, self.serialize_content(), ); // docs:end:encrypted diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index f6fe853c1237..f18b33f0f110 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -286,7 +286,7 @@ impl PrivateContext { contract_address: AztecAddress, storage_slot: Field, note_type_id: Field, - encryption_pub_key: GrumpkinPoint, + ivpk_m: GrumpkinPoint, preimage: [Field; N] ) where [Field; N]: LensForEncryptedLog { // TODO(1139): perform encryption in the circuit @@ -296,7 +296,7 @@ impl PrivateContext { contract_address, storage_slot, note_type_id, - encryption_pub_key, + ivpk_m, preimage, counter ); diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/body.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/body.nr index 4393d9da16c5..9f490c768e05 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/body.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/body.nr @@ -67,7 +67,7 @@ mod test { use crate::{ note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key}, + oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key}, context::PrivateContext, hash::poseidon2_hash }; diff --git a/noir-projects/aztec-nr/aztec/src/keys/getters.nr b/noir-projects/aztec-nr/aztec/src/keys/getters.nr index b6fc2759fb7b..0e531da10286 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/getters.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/getters.nr @@ -1,4 +1,7 @@ -use dep::protocol_types::{address::AztecAddress, constants::CANONICAL_KEY_REGISTRY_ADDRESS, grumpkin_point::GrumpkinPoint}; +use dep::protocol_types::{ + address::{AztecAddress, PublicKeysHash}, constants::CANONICAL_KEY_REGISTRY_ADDRESS, + grumpkin_point::GrumpkinPoint +}; use crate::{ context::PrivateContext, oracle::keys::get_public_keys_and_partial_address, state_vars::{ @@ -80,20 +83,15 @@ fn fetch_key_from_registry( fn fetch_and_constrain_keys(address: AztecAddress) -> [GrumpkinPoint; 4] { let (public_keys, partial_address) = get_public_keys_and_partial_address(address); - let nullifier_pub_key = public_keys[0]; - let incoming_pub_key = public_keys[1]; - let outgoing_pub_key = public_keys[2]; - let tagging_pub_key = public_keys[3]; + let npk_m = public_keys[0]; + let ivpk_m = public_keys[1]; + let ovpk_m = public_keys[2]; + let tpk_m = public_keys[3]; - let computed_address = AztecAddress::compute_from_public_keys_and_partial_address( - nullifier_pub_key, - incoming_pub_key, - outgoing_pub_key, - tagging_pub_key, - partial_address - ); + let public_keys_hash = PublicKeysHash::compute(npk_m, ivpk_m, ovpk_m, tpk_m); + let computed_address = AztecAddress::compute(public_keys_hash, partial_address); assert(computed_address.eq(address)); - [nullifier_pub_key, incoming_pub_key, outgoing_pub_key, tagging_pub_key] + [npk_m, ivpk_m, ovpk_m, tpk_m] } diff --git a/noir-projects/aztec-nr/aztec/src/oracle.nr b/noir-projects/aztec-nr/aztec/src/oracle.nr index 64c449d61f85..59031fcdb9f7 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle.nr @@ -10,7 +10,6 @@ mod get_l1_to_l2_membership_witness; mod get_nullifier_membership_witness; mod get_public_data_witness; mod get_membership_witness; -mod get_public_key; mod keys; mod nullifier_key; mod get_sibling_path; diff --git a/noir-projects/aztec-nr/aztec/src/oracle/get_public_key.nr b/noir-projects/aztec-nr/aztec/src/oracle/get_public_key.nr deleted file mode 100644 index a509e8c1b54f..000000000000 --- a/noir-projects/aztec-nr/aztec/src/oracle/get_public_key.nr +++ /dev/null @@ -1,20 +0,0 @@ -use dep::protocol_types::{address::{AztecAddress, PartialAddress, PublicKeysHash}, grumpkin_point::GrumpkinPoint}; - -#[oracle(getPublicKeyAndPartialAddress)] -fn get_public_key_and_partial_address_oracle(_address: AztecAddress) -> [Field; 3] {} - -unconstrained fn get_public_key_and_partial_address_internal(address: AztecAddress) -> [Field; 3] { - get_public_key_and_partial_address_oracle(address) -} - -pub fn get_public_key(address: AztecAddress) -> GrumpkinPoint { - let result = get_public_key_and_partial_address_internal(address); - let pub_key = GrumpkinPoint::new(result[0], result[1]); - let partial_address = PartialAddress::from_field(result[2]); - - // TODO(#5830): disabling the following constraint until we update the oracle according to the new key scheme - // let calculated_address = AztecAddress::compute(PublicKeysHash::compute(pub_key), partial_address); - // assert(calculated_address.eq(address)); - - pub_key -} diff --git a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr index a985e385e811..173ad34aad2c 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr @@ -1,7 +1,5 @@ use dep::protocol_types::{address::{AztecAddress, PartialAddress}, grumpkin_point::GrumpkinPoint}; -use crate::hash::poseidon2_hash; - #[oracle(getPublicKeysAndPartialAddress)] fn get_public_keys_and_partial_address_oracle(_address: AztecAddress) -> [Field; 9] {} diff --git a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr index d692329a82f5..a1d933915eed 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/logs.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/logs.nr @@ -17,7 +17,7 @@ unconstrained pub fn emit_encrypted_log( contract_address: AztecAddress, storage_slot: Field, note_type_id: Field, - encryption_pub_key: GrumpkinPoint, + ivpk_m: GrumpkinPoint, preimage: [Field; N], counter: u32 ) -> [Field; M] { @@ -25,7 +25,7 @@ unconstrained pub fn emit_encrypted_log( contract_address, storage_slot, note_type_id, - encryption_pub_key, + ivpk_m, preimage, counter ) diff --git a/noir-projects/aztec-nr/value-note/src/utils.nr b/noir-projects/aztec-nr/value-note/src/utils.nr index 5cb4b75b6c78..66f9b9983888 100644 --- a/noir-projects/aztec-nr/value-note/src/utils.nr +++ b/noir-projects/aztec-nr/value-note/src/utils.nr @@ -1,6 +1,6 @@ use dep::aztec::prelude::{AztecAddress, PrivateContext, PrivateSet, NoteGetterOptions}; use dep::aztec::note::note_getter_options::SortOrder; -use dep::aztec::oracle::get_public_key::get_public_key; +use dep::aztec::keys::getters::get_ivpk_m; use crate::{filter::filter_notes_min_sum, value_note::{ValueNote, VALUE_NOTE_LEN}}; // Sort the note values (0th field) in descending order. diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index 019ea4bf543b..ac790864aa85 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -1,7 +1,8 @@ use dep::aztec::{ + keys::getters::get_ivpk_m, protocol_types::{address::AztecAddress, traits::{Deserialize, Serialize}, constants::GENERATOR_INDEX__NOTE_NULLIFIER}, note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key}, + oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key}, hash::poseidon2_hash, context::PrivateContext }; @@ -43,12 +44,12 @@ impl NoteInterface for ValueNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { - let encryption_pub_key = get_public_key(self.owner); + let ivpk_m = get_ivpk_m(context, self.owner); context.emit_encrypted_log( (*context).this_address(), slot, Self::get_note_type_id(), - encryption_pub_key, + ivpk_m, self.serialize_content(), ); } diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr index e05320079374..6da684947bf1 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/main.nr @@ -12,7 +12,7 @@ contract AppSubscription { use dep::aztec::protocol_types::traits::is_empty; - use dep::aztec::{context::Context, oracle::get_public_key::get_public_key}; + use dep::aztec::{context::Context, keys::getters::get_ivpk_m}; use dep::authwit::{account::AccountActions, auth_witness::get_auth_witness, auth::assert_current_call_valid_authwit}; use crate::subscription_note::{SubscriptionNote, SUBSCRIPTION_NOTE_LEN}; diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index c2543a14707f..665393b166fe 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -1,8 +1,8 @@ use dep::aztec::prelude::{AztecAddress, PrivateContext, NoteHeader, NoteInterface}; use dep::aztec::{ - protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER, + keys::getters::get_ivpk_m, protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER, note::utils::compute_note_hash_for_consumption, hash::poseidon2_hash, - oracle::{nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key} + oracle::{nullifier_key::get_app_nullifier_secret_key} }; global SUBSCRIPTION_NOTE_LEN: Field = 3; @@ -39,12 +39,12 @@ impl NoteInterface for SubscriptionNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { - let encryption_pub_key = get_public_key(self.owner); + let ivpk_m = get_ivpk_m(context, self.owner); context.emit_encrypted_log( (*context).this_address(), slot, Self::get_note_type_id(), - encryption_pub_key, + ivpk_m, self.serialize_content(), ); } diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 3f952146c2bf..aa2fea463d4e 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -1,8 +1,8 @@ use dep::aztec::prelude::{AztecAddress, NoteInterface, NoteHeader, PrivateContext}; use dep::aztec::{ - note::{utils::compute_note_hash_for_consumption}, - oracle::{nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key}, - hash::poseidon2_hash, protocol_types::{traits::Empty, constants::GENERATOR_INDEX__NOTE_NULLIFIER} + keys::getters::get_ivpk_m, note::{utils::compute_note_hash_for_consumption}, + oracle::nullifier_key::get_app_nullifier_secret_key, hash::poseidon2_hash, + protocol_types::{traits::Empty, constants::GENERATOR_INDEX__NOTE_NULLIFIER} }; // Shows how to create a custom note @@ -47,12 +47,12 @@ impl NoteInterface for CardNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { - let encryption_pub_key = get_public_key(self.owner); + let ivpk_m = get_ivpk_m(context, self.owner); context.emit_encrypted_log( (*context).this_address(), slot, Self::get_note_type_id(), - encryption_pub_key, + ivpk_m, self.serialize_content(), ); } diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index 20fd400e9679..eaadbbc60ace 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -1,9 +1,9 @@ use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, NoteInterface, NoteGetterOptions, PrivateContext}; use dep::aztec::{ - note::utils::compute_note_hash_for_consumption, - oracle::{nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key}, - hash::poseidon2_hash, protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER + keys::getters::get_ivpk_m, note::utils::compute_note_hash_for_consumption, + oracle::nullifier_key::get_app_nullifier_secret_key, hash::poseidon2_hash, + protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER }; global ECDSA_PUBLIC_KEY_NOTE_LEN: Field = 5; @@ -85,12 +85,12 @@ impl NoteInterface for EcdsaPublicKeyNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { - let encryption_pub_key = get_public_key(self.owner); + let ivpk_m = get_ivpk_m(context, self.owner); context.emit_encrypted_log( (*context).this_address(), slot, Self::get_note_type_id(), - encryption_pub_key, + ivpk_m, self.serialize_content(), ); } diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr index 25f96128b9df..d992251604db 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/main.nr @@ -8,7 +8,7 @@ contract EcdsaAccount { use dep::aztec::protocol_types::abis::call_context::CallContext; use dep::std; - use dep::aztec::{context::{PublicContext, Context}, oracle::get_public_key::get_public_key}; + use dep::aztec::context::Context; use dep::authwit::{ entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, auth_witness::get_auth_witness diff --git a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr index c1ec425486b4..bc17776d83d1 100644 --- a/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/escrow_contract/src/main.nr @@ -2,7 +2,7 @@ contract Escrow { use dep::aztec::prelude::{AztecAddress, EthAddress, FunctionSelector, NoteHeader, PrivateContext, PrivateImmutable}; - use dep::aztec::{context::{PublicContext, Context}, oracle::get_public_key::get_public_key}; + use dep::aztec::context::{PublicContext, Context}; use dep::address_note::address_note::AddressNote; diff --git a/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr b/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr index b985c829d269..9c07a53865ec 100644 --- a/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/key_registry_contract/src/main.nr @@ -3,7 +3,7 @@ contract KeyRegistry { use dep::aztec::{ state_vars::{SharedMutable, Map}, - protocol_types::{grumpkin_point::GrumpkinPoint, address::{AztecAddress, PartialAddress}} + protocol_types::{grumpkin_point::GrumpkinPoint, address::{AztecAddress, PartialAddress, PublicKeysHash}} }; global KEY_ROTATION_DELAY = 5; @@ -54,13 +54,13 @@ contract KeyRegistry { outgoing_public_key: GrumpkinPoint, tagging_public_key: GrumpkinPoint ) { - let computed_address = AztecAddress::compute_from_public_keys_and_partial_address( + let public_keys_hash = PublicKeysHash::compute( nullifier_public_key, incoming_public_key, outgoing_public_key, - tagging_public_key, - partial_address + tagging_public_key ); + let computed_address = AztecAddress::compute(public_keys_hash, partial_address); assert(computed_address.eq(address), "Computed address does not match supplied address"); diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr index d42ee2119d68..39cc3384b3b0 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/main.nr @@ -7,7 +7,7 @@ contract SchnorrAccount { use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, PrivateContext, PrivateImmutable}; use dep::aztec::state_vars::{Map, PublicMutable}; - use dep::aztec::{context::Context, oracle::get_public_key::get_public_key}; + use dep::aztec::context::Context; use dep::authwit::{ entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, auth_witness::get_auth_witness diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index 95fbe422f78e..74812ec7465b 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -1,7 +1,7 @@ use dep::aztec::prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}; use dep::aztec::{ - note::utils::compute_note_hash_for_consumption, hash::poseidon2_hash, - oracle::{nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key}, + keys::getters::get_ivpk_m, note::utils::compute_note_hash_for_consumption, hash::poseidon2_hash, + oracle::{nullifier_key::get_app_nullifier_secret_key}, protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER }; @@ -39,12 +39,12 @@ impl NoteInterface for PublicKeyNote { // Broadcasts the note as an encrypted log on L1. fn broadcast(self, context: &mut PrivateContext, slot: Field) { - let encryption_pub_key = get_public_key(self.owner); + let ivpk_m = get_ivpk_m(context, self.owner); context.emit_encrypted_log( (*context).this_address(), slot, Self::get_note_type_id(), - encryption_pub_key, + ivpk_m, self.serialize_content(), ); } diff --git a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr index bb6aad4b7874..5c75c095d2fb 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/main.nr @@ -6,7 +6,8 @@ contract SchnorrSingleKeyAccount { use dep::authwit::{entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions}; - use crate::{util::recover_address, auth_oracle::get_auth_witness}; + // use crate::{util::recover_address, auth_oracle::get_auth_witness}; + use crate::auth_oracle::get_auth_witness; global ACCOUNT_ACTIONS_STORAGE_SLOT = 1; diff --git a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/util.nr b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/util.nr index f337d688bbd1..89f7e2e9b4d5 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/util.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_single_key_account_contract/src/util.nr @@ -3,18 +3,19 @@ use dep::aztec::protocol_types::address::PublicKeysHash; use dep::std::{schnorr::verify_signature_slice}; use crate::auth_oracle::AuthWitness; -pub fn recover_address(message_hash: Field, witness: AuthWitness) -> AztecAddress { - let message_bytes = message_hash.to_be_bytes(32); - let verification = verify_signature_slice( - witness.owner.x, - witness.owner.y, - witness.signature, - message_bytes - ); - assert(verification == true); +// TODO(#5830): the following is currently broken because we are no longer able to compute public keys hash +// pub fn recover_address(message_hash: Field, witness: AuthWitness) -> AztecAddress { +// let message_bytes = message_hash.to_be_bytes(32); +// let verification = verify_signature_slice( +// witness.owner.x, +// witness.owner.y, +// witness.signature, +// message_bytes +// ); +// assert(verification == true); - AztecAddress::compute( - PublicKeysHash::compute(witness.owner), - witness.partial_address - ) -} +// AztecAddress::compute( +// PublicKeysHash::compute(witness.owner), +// witness.partial_address +// ) +// } diff --git a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr index aba898225ff8..2a248a7eaf2a 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -23,18 +23,15 @@ contract Test { use dep::aztec::state_vars::{shared_mutable::SharedMutablePrivateGetter, map::derive_storage_slot_in_map}; use dep::aztec::{ - keys::getters::get_npk_m, + keys::getters::{get_npk_m, get_ivpk_m}, context::{Context, inputs::private_context_inputs::PrivateContextInputs}, - hash::{pedersen_hash, poseidon2_hash, compute_secret_hash, ArgsHasher}, + hash::{pedersen_hash, compute_secret_hash, ArgsHasher}, note::{ lifecycle::{create_note, destroy_note}, note_getter::{get_notes, view_notes}, note_getter_options::NoteStatus }, deploy::deploy_contract as aztec_deploy_contract, - oracle::{ - encryption::aes128_encrypt, get_public_key::get_public_key as get_public_key_oracle, - unsafe_rand::unsafe_rand - } + oracle::{encryption::aes128_encrypt, unsafe_rand::unsafe_rand} }; use dep::token_portal_content_hash_lib::{get_mint_private_content_hash, get_mint_public_content_hash}; use dep::value_note::value_note::ValueNote; @@ -53,8 +50,8 @@ contract Test { } #[aztec(private)] - fn get_public_key(address: AztecAddress) -> [Field; 2] { - let pub_key = get_public_key_oracle(address); + fn get_master_incoming_viewing_public_key(address: AztecAddress) -> [Field; 2] { + let pub_key = get_ivpk_m(&mut context, address); [pub_key.x, pub_key.y] } diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index 798a9cfe174d..8492b92a1fca 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -1,8 +1,8 @@ use dep::aztec::{ - prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}, + keys::getters::get_ivpk_m, prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}, protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER, note::utils::compute_note_hash_for_consumption, hash::poseidon2_hash, - oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key} + oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key} }; trait OwnedNote { @@ -52,12 +52,12 @@ impl NoteInterface for TokenNote { fn broadcast(self, context: &mut PrivateContext, slot: Field) { // We only bother inserting the note if non-empty to save funds on gas. if !(self.amount == U128::from_integer(0)) { - let encryption_pub_key = get_public_key(self.owner); + let ivpk_m = get_ivpk_m(context, self.owner); context.emit_encrypted_log( (*context).this_address(), slot, Self::get_note_type_id(), - encryption_pub_key, + ivpk_m, self.serialize_content(), ); } diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 798a9cfe174d..8492b92a1fca 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -1,8 +1,8 @@ use dep::aztec::{ - prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}, + keys::getters::get_ivpk_m, prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}, protocol_types::constants::GENERATOR_INDEX__NOTE_NULLIFIER, note::utils::compute_note_hash_for_consumption, hash::poseidon2_hash, - oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key, get_public_key::get_public_key} + oracle::{unsafe_rand::unsafe_rand, nullifier_key::get_app_nullifier_secret_key} }; trait OwnedNote { @@ -52,12 +52,12 @@ impl NoteInterface for TokenNote { fn broadcast(self, context: &mut PrivateContext, slot: Field) { // We only bother inserting the note if non-empty to save funds on gas. if !(self.amount == U128::from_integer(0)) { - let encryption_pub_key = get_public_key(self.owner); + let ivpk_m = get_ivpk_m(context, self.owner); context.emit_encrypted_log( (*context).this_address(), slot, Self::get_note_type_id(), - encryption_pub_key, + ivpk_m, self.serialize_content(), ); } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr index 6413bedf15ee..6c91a609990c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr @@ -59,25 +59,6 @@ impl AztecAddress { ) } - pub fn compute_from_public_keys_and_partial_address( - nullifier_public_key: GrumpkinPoint, - incoming_public_key: GrumpkinPoint, - outgoing_public_key: GrumpkinPoint, - tagging_public_key: GrumpkinPoint, - partial_address: PartialAddress - ) -> AztecAddress { - let public_keys_hash = PublicKeysHash::compute_new( - nullifier_public_key, - incoming_public_key, - outgoing_public_key, - tagging_public_key - ); - - let computed_address = AztecAddress::compute(public_keys_hash, partial_address); - - computed_address - } - pub fn is_zero(self) -> bool { self.inner == 0 } @@ -93,7 +74,7 @@ impl AztecAddress { } #[test] -fn compute_address_from_partial_and_pubkey() { +fn compute_address_from_partial_and_pub_keys_hash() { let pub_keys_hash = PublicKeysHash::from_field(1); let partial_address = PartialAddress::from_field(2); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr index f91d1383a19f..09ad9ba1a155 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr @@ -38,37 +38,18 @@ impl PublicKeysHash { Self { inner: field } } - // TODO(#5830): When we do this refactor, rename compute_new -> compute - pub fn compute(public_key: GrumpkinPoint) -> Self { - PublicKeysHash::from_field( - pedersen_hash( - [ - public_key.x, - public_key.y - ], - GENERATOR_INDEX__PARTIAL_ADDRESS - ) - ) - } - - // TODO(#5830): When we do this refactor, rename compute_new -> compute - pub fn compute_new( - nullifier_public_key: GrumpkinPoint, - incoming_public_key: GrumpkinPoint, - outgoing_public_key: GrumpkinPoint, - tagging_public_key: GrumpkinPoint - ) -> Self { + pub fn compute(npk_m: GrumpkinPoint, ivpk_m: GrumpkinPoint, ovpk_m: GrumpkinPoint, tpk_m: GrumpkinPoint) -> Self { PublicKeysHash::from_field( poseidon2_hash( [ - nullifier_public_key.x, - nullifier_public_key.y, - incoming_public_key.x, - incoming_public_key.y, - outgoing_public_key.x, - outgoing_public_key.y, - tagging_public_key.x, - tagging_public_key.y, + npk_m.x, + npk_m.y, + ivpk_m.x, + ivpk_m.y, + ovpk_m.x, + ovpk_m.y, + tpk_m.x, + tpk_m.y, GENERATOR_INDEX__PUBLIC_KEYS_HASH ] ) @@ -84,11 +65,14 @@ impl PublicKeysHash { } } -// TODO(#5830): re-enable this test once the compute function is updated -// #[test] -// fn compute_public_keys_hash() { -// let point = GrumpkinPoint { x: 1, y: 2 }; -// let actual = PublicKeysHash::compute(point); -// let expected_public_keys_hash = 0x22d83a089d7650514c2de24cd30185a414d943eaa19817c67bffe2c3183006a3; -// assert(actual.to_field() == expected_public_keys_hash); -// } +#[test] +fn compute_public_keys_hash() { + let npk_m = GrumpkinPoint { x: 1, y: 2 }; + let ivpk_m = GrumpkinPoint { x: 3, y: 4 }; + let ovpk_m = GrumpkinPoint { x: 5, y: 6 }; + let tpk_m = GrumpkinPoint { x: 7, y: 8 }; + + let actual = PublicKeysHash::compute(npk_m, ivpk_m, ovpk_m, tpk_m); + let expected_public_keys_hash = 0x1936abe4f6a920d16a9f6917f10a679507687e2cd935dd1f1cdcb1e908c027f3; + assert(actual.to_field() == expected_public_keys_hash); +} diff --git a/yarn-project/accounts/src/defaults/account_contract.ts b/yarn-project/accounts/src/defaults/account_contract.ts index dc3b23300593..f2842c9ac0f6 100644 --- a/yarn-project/accounts/src/defaults/account_contract.ts +++ b/yarn-project/accounts/src/defaults/account_contract.ts @@ -1,6 +1,5 @@ import { type AccountContract, type AccountInterface, type AuthWitnessProvider } from '@aztec/aztec.js/account'; import { type CompleteAddress } from '@aztec/circuit-types'; -import { type Fr } from '@aztec/circuits.js'; import { type ContractArtifact } from '@aztec/foundation/abi'; import { type NodeInfo } from '@aztec/types/interfaces'; @@ -20,7 +19,7 @@ export abstract class DefaultAccountContract implements AccountContract { return this.artifact; } - getInterface(address: CompleteAddress, publicKeysHash: Fr, nodeInfo: NodeInfo): AccountInterface { - return new DefaultAccountInterface(this.getAuthWitnessProvider(address), address, publicKeysHash, nodeInfo); + getInterface(address: CompleteAddress, nodeInfo: NodeInfo): AccountInterface { + return new DefaultAccountInterface(this.getAuthWitnessProvider(address), address, nodeInfo); } } diff --git a/yarn-project/accounts/src/defaults/account_interface.ts b/yarn-project/accounts/src/defaults/account_interface.ts index f32e96aa208e..5d7fa311c6e9 100644 --- a/yarn-project/accounts/src/defaults/account_interface.ts +++ b/yarn-project/accounts/src/defaults/account_interface.ts @@ -17,7 +17,6 @@ export class DefaultAccountInterface implements AccountInterface { constructor( private authWitnessProvider: AuthWitnessProvider, private address: CompleteAddress, - private publicKeysHash: Fr, nodeInfo: Pick, ) { this.entrypoint = new DefaultAccountEntrypoint( @@ -38,10 +37,6 @@ export class DefaultAccountInterface implements AccountInterface { return this.authWitnessProvider.createAuthWit(messageHash); } - getPublicKeysHash(): Fr { - return this.publicKeysHash; - } - getCompleteAddress(): CompleteAddress { return this.address; } diff --git a/yarn-project/accounts/src/testing/configuration.ts b/yarn-project/accounts/src/testing/configuration.ts index 7fc376ddd707..cc37380d93f6 100644 --- a/yarn-project/accounts/src/testing/configuration.ts +++ b/yarn-project/accounts/src/testing/configuration.ts @@ -45,7 +45,9 @@ export async function getDeployedTestAccountsWallets(pxe: PXE): Promise { const initialEncryptionKey = sha512ToGrumpkinScalar([initialSecretKey, GeneratorIndex.IVSK_M]); const publicKey = generatePublicKey(initialEncryptionKey); - return registeredAccounts.find(registered => registered.publicKey.equals(publicKey)) != undefined; + return ( + registeredAccounts.find(registered => registered.masterIncomingViewingPublicKey.equals(publicKey)) != undefined + ); }).map(secretKey => { const signingKey = sha512ToGrumpkinScalar([secretKey, GeneratorIndex.IVSK_M]); // TODO(#5726): use actual salt here instead of hardcoding Fr.ZERO diff --git a/yarn-project/aztec.js/src/account/contract.ts b/yarn-project/aztec.js/src/account/contract.ts index 6ae607d386b0..6c49a3b5cf03 100644 --- a/yarn-project/aztec.js/src/account/contract.ts +++ b/yarn-project/aztec.js/src/account/contract.ts @@ -1,5 +1,4 @@ import { type CompleteAddress } from '@aztec/circuit-types'; -import { type Fr } from '@aztec/circuits.js'; import { type ContractArtifact } from '@aztec/foundation/abi'; import { type NodeInfo } from '@aztec/types/interfaces'; @@ -26,11 +25,10 @@ export interface AccountContract { * The account interface is responsible for assembling tx requests given requested function calls, and * for creating signed auth witnesses given action identifiers (message hashes). * @param address - Address where this account contract is deployed. - * @param publicKeysHash - Hash of the public keys used to authorize actions. * @param nodeInfo - Info on the chain where it is deployed. * @returns An account interface instance for creating tx requests and authorizing actions. */ - getInterface(address: CompleteAddress, publicKeysHash: Fr, nodeInfo: NodeInfo): AccountInterface; + getInterface(address: CompleteAddress, nodeInfo: NodeInfo): AccountInterface; /** * Returns the auth witness provider for the given address. diff --git a/yarn-project/aztec.js/src/account/interface.ts b/yarn-project/aztec.js/src/account/interface.ts index 555fce8cbbc5..5a5ab2cf28ea 100644 --- a/yarn-project/aztec.js/src/account/interface.ts +++ b/yarn-project/aztec.js/src/account/interface.ts @@ -42,9 +42,6 @@ export interface AccountInterface extends AuthWitnessProvider, EntrypointInterfa /** Returns the complete address for this account. */ getCompleteAddress(): CompleteAddress; - /** Returns the public keys hash for this account. */ - getPublicKeysHash(): Fr; - /** Returns the address for this account. */ getAddress(): AztecAddress; diff --git a/yarn-project/aztec.js/src/account_manager/index.ts b/yarn-project/aztec.js/src/account_manager/index.ts index 549855a4d978..842236286a13 100644 --- a/yarn-project/aztec.js/src/account_manager/index.ts +++ b/yarn-project/aztec.js/src/account_manager/index.ts @@ -51,7 +51,7 @@ export class AccountManager { public async getAccount(): Promise { const nodeInfo = await this.pxe.getNodeInfo(); const completeAddress = this.getCompleteAddress(); - return this.accountContract.getInterface(completeAddress, this.getPublicKeysHash(), nodeInfo); + return this.accountContract.getInterface(completeAddress, nodeInfo); } /** diff --git a/yarn-project/aztec.js/src/utils/account.ts b/yarn-project/aztec.js/src/utils/account.ts index c128d8e227e1..b9cc606b9b6e 100644 --- a/yarn-project/aztec.js/src/utils/account.ts +++ b/yarn-project/aztec.js/src/utils/account.ts @@ -14,7 +14,7 @@ export async function waitForAccountSynch( address: CompleteAddress, { interval, timeout }: WaitOpts = DefaultWaitOpts, ): Promise { - const publicKey = address.publicKey.toString(); + const publicKey = address.masterIncomingViewingPublicKey.toString(); await retryUntil( async () => { const status = await pxe.getSyncStatus(); diff --git a/yarn-project/aztec.js/src/wallet/account_wallet.ts b/yarn-project/aztec.js/src/wallet/account_wallet.ts index a1f7cea1848a..803d07010eba 100644 --- a/yarn-project/aztec.js/src/wallet/account_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/account_wallet.ts @@ -16,10 +16,6 @@ export class AccountWallet extends BaseWallet { super(pxe); } - getPublicKeysHash(): Fr { - return this.account.getPublicKeysHash(); - } - createTxExecutionRequest(exec: ExecutionRequestInit): Promise { return this.account.createTxExecutionRequest(exec); } diff --git a/yarn-project/aztec.js/src/wallet/base_wallet.ts b/yarn-project/aztec.js/src/wallet/base_wallet.ts index eeacdb4f23af..200ad930deec 100644 --- a/yarn-project/aztec.js/src/wallet/base_wallet.ts +++ b/yarn-project/aztec.js/src/wallet/base_wallet.ts @@ -32,8 +32,6 @@ export abstract class BaseWallet implements Wallet { abstract getCompleteAddress(): CompleteAddress; - abstract getPublicKeysHash(): Fr; - abstract getChainId(): Fr; abstract getVersion(): Fr; @@ -80,9 +78,6 @@ export abstract class BaseWallet implements Wallet { getRegisteredAccount(address: AztecAddress): Promise { return this.pxe.getRegisteredAccount(address); } - getRegisteredAccountPublicKeysHash(address: AztecAddress): Promise { - return this.pxe.getRegisteredAccountPublicKeysHash(address); - } getRecipients(): Promise { return this.pxe.getRecipients(); } diff --git a/yarn-project/aztec.js/src/wallet/index.ts b/yarn-project/aztec.js/src/wallet/index.ts index ad92b67fdd0c..08e8cb27c416 100644 --- a/yarn-project/aztec.js/src/wallet/index.ts +++ b/yarn-project/aztec.js/src/wallet/index.ts @@ -25,11 +25,7 @@ export async function getWallet( if (!completeAddress) { throw new Error(`Account ${address} not found`); } - const publicKeysHash = await pxe.getRegisteredAccountPublicKeysHash(address); - if (!publicKeysHash) { - throw new Error(`Public keys hash for account ${address} not found`); - } const nodeInfo = await pxe.getNodeInfo(); - const entrypoint = accountContract.getInterface(completeAddress, publicKeysHash, nodeInfo); + const entrypoint = accountContract.getInterface(completeAddress, nodeInfo); return new AccountWallet(pxe, entrypoint); } diff --git a/yarn-project/aztec/src/cli/util.ts b/yarn-project/aztec/src/cli/util.ts index db16f546c7b5..844fbb1fc835 100644 --- a/yarn-project/aztec/src/cli/util.ts +++ b/yarn-project/aztec/src/cli/util.ts @@ -126,7 +126,14 @@ export async function createAccountLogs( accountLogStrings.push(` Address: ${completeAddress.address.toString()}\n`); accountLogStrings.push(` Partial Address: ${completeAddress.partialAddress.toString()}\n`); accountLogStrings.push(` Secret Key: ${account.secretKey.toString()}\n`); - accountLogStrings.push(` Public Key: ${completeAddress.publicKey.toString()}\n\n`); + accountLogStrings.push(` Master nullifier public key: ${completeAddress.masterNullifierPublicKey.toString()}\n`); + accountLogStrings.push( + ` Master incoming viewing public key: ${completeAddress.masterIncomingViewingPublicKey.toString()}\n\n`, + ); + accountLogStrings.push( + ` Master outgoing viewing public key: ${completeAddress.masterOutgoingViewingPublicKey.toString()}\n\n`, + ); + accountLogStrings.push(` Master tagging public key: ${completeAddress.masterTaggingPublicKey.toString()}\n\n`); } } return accountLogStrings; diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 0e95d0247272..9e01820e4f79 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -1,4 +1,4 @@ -import { type AztecAddress, type CompleteAddress, type Fr, type PartialAddress, type Point } from '@aztec/circuits.js'; +import { type AztecAddress, type CompleteAddress, type Fr, type PartialAddress } from '@aztec/circuits.js'; import { type ContractArtifact } from '@aztec/foundation/abi'; import { type ContractClassWithId, type ContractInstanceWithAddress } from '@aztec/types/contracts'; import { type NodeInfo } from '@aztec/types/interfaces'; @@ -73,8 +73,7 @@ export interface PXE { * the recipient's notes. We can send notes to this account because we can encrypt them with the recipient's * public key. */ - // TODO: #5834: Nuke publicKeys optional parameter after `CompleteAddress` refactor. - registerRecipient(recipient: CompleteAddress, publicKeys?: Point[]): Promise; + registerRecipient(recipient: CompleteAddress): Promise; /** * Retrieves the user accounts registered on this PXE Service. @@ -91,15 +90,6 @@ export interface PXE { */ getRegisteredAccount(address: AztecAddress): Promise; - /** - * Retrieves the public keys hash of the account corresponding to the provided aztec address. - * - * @param address - The address of account. - * @returns The public keys hash of the requested account if found. - * TODO(#5834): refactor complete address and merge with getRegisteredAccount? - */ - getRegisteredAccountPublicKeysHash(address: AztecAddress): Promise; - /** * Retrieves the recipients added to this PXE Service. * @returns An array of recipients registered on this PXE Service. diff --git a/yarn-project/circuit-types/src/keys/key_store.ts b/yarn-project/circuit-types/src/keys/key_store.ts index 168ec8d5f04d..b4a0d7ce300a 100644 --- a/yarn-project/circuit-types/src/keys/key_store.ts +++ b/yarn-project/circuit-types/src/keys/key_store.ts @@ -1,9 +1,9 @@ import { type AztecAddress, + type CompleteAddress, type Fr, type GrumpkinPrivateKey, type PartialAddress, - type Point, type PublicKey, } from '@aztec/circuits.js'; @@ -13,17 +13,17 @@ import { export interface KeyStore { /** * Creates a new account from a randomly generated secret key. - * @returns A promise that resolves to the newly created account's AztecAddress. + * @returns A promise that resolves to the newly created account's CompleteAddress. */ - createAccount(): Promise; + createAccount(): Promise; /** * Adds an account to the key store from the provided secret key. * @param sk - The secret key of the account. * @param partialAddress - The partial address of the account. - * @returns The account's address. + * @returns The account's complete address. */ - addAccount(sk: Fr, partialAddress: PartialAddress): Promise; + addAccount(sk: Fr, partialAddress: PartialAddress): Promise; /** * Retrieves addresses of accounts stored in the key store. @@ -117,21 +117,4 @@ export interface KeyStore { * @returns A Promise that resolves to the public keys hash. */ getPublicKeysHash(account: AztecAddress): Promise; - - /** - * This is used to register a recipient / for storing public keys of an address - * @param accountAddress - The account address to store keys for. - * @param masterNullifierPublicKey - The stored master nullifier public key - * @param masterIncomingViewingPublicKey - The stored incoming viewing public key - * @param masterOutgoingViewingPublicKey - The stored outgoing viewing public key - * @param masterTaggingPublicKey - The stored master tagging public key - */ - // TODO(#5834): Move this function out of here. Key store should only be used for accounts, not recipients - addPublicKeysForAccount( - accountAddress: AztecAddress, - masterNullifierPublicKey: Point, - masterIncomingViewingPublicKey: Point, - masterOutgoingViewingPublicKey: Point, - masterTaggingPublicKey: Point, - ): Promise; } diff --git a/yarn-project/circuits.js/src/contract/contract_address.test.ts b/yarn-project/circuits.js/src/contract/contract_address.test.ts index 6199e69a25dd..a9c10a16243c 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.test.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.test.ts @@ -69,14 +69,6 @@ describe('ContractAddress', () => { }).toString(); expect(address).toMatchSnapshot(); - - // TODO(#5834): the following was removed from aztec_address.nr, should it be re-introduced? - // // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data - // updateInlineTestData( - // 'noir-projects/noir-protocol-circuits/crates/types/src/address/aztec_address.nr', - // 'expected_computed_address_from_preimage', - // address.toString(), - // ); }); it('Public key hash matches Noir', () => { diff --git a/yarn-project/circuits.js/src/contract/contract_address.ts b/yarn-project/circuits.js/src/contract/contract_address.ts index 11c4dade226d..b8582471d713 100644 --- a/yarn-project/circuits.js/src/contract/contract_address.ts +++ b/yarn-project/circuits.js/src/contract/contract_address.ts @@ -1,12 +1,12 @@ import { type FunctionAbi, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; -import { AztecAddress } from '@aztec/foundation/aztec-address'; -import { pedersenHash, poseidon2Hash } from '@aztec/foundation/crypto'; +import { type AztecAddress } from '@aztec/foundation/aztec-address'; +import { pedersenHash } from '@aztec/foundation/crypto'; import { Fr } from '@aztec/foundation/fields'; import { type ContractInstance } from '@aztec/types/contracts'; import { GeneratorIndex } from '../constants.gen.js'; import { computeVarArgsHash } from '../hash/hash.js'; -import { deriveKeys } from '../keys/index.js'; +import { computeAddress, deriveKeys } from '../keys/index.js'; // TODO(@spalladino): Review all generator indices in this file @@ -65,8 +65,7 @@ export function computeContractAddressFromPartial( args: ({ publicKeysHash: Fr } | { secretKey: Fr }) & { partialAddress: Fr }, ): AztecAddress { const publicKeysHash = 'secretKey' in args ? deriveKeys(args.secretKey).publicKeysHash : args.publicKeysHash; - const result = poseidon2Hash([publicKeysHash, args.partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]); - return AztecAddress.fromField(result); + return computeAddress(publicKeysHash, args.partialAddress); } /** diff --git a/yarn-project/circuits.js/src/keys/index.test.ts b/yarn-project/circuits.js/src/keys/index.test.ts new file mode 100644 index 000000000000..77fd26df220b --- /dev/null +++ b/yarn-project/circuits.js/src/keys/index.test.ts @@ -0,0 +1,30 @@ +import { Fr, Point } from '@aztec/foundation/fields'; +import { updateInlineTestData } from '@aztec/foundation/testing'; + +import { computePublicKeysHash } from './index.js'; + +describe('🔑', () => { + it('computing public keys hash matches Noir', () => { + const masterNullifierPublicKey = new Point(new Fr(1), new Fr(2)); + const masterIncomingViewingPublicKey = new Point(new Fr(3), new Fr(4)); + const masterOutgoingViewingPublicKey = new Point(new Fr(5), new Fr(6)); + const masterTaggingPublicKey = new Point(new Fr(7), new Fr(8)); + + const expected = Fr.fromString('0x1936abe4f6a920d16a9f6917f10a679507687e2cd935dd1f1cdcb1e908c027f3'); + expect( + computePublicKeysHash( + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + ), + ).toEqual(expected); + + // Run with AZTEC_GENERATE_TEST_DATA=1 to update noir test data + updateInlineTestData( + 'noir-projects/noir-protocol-circuits/crates/types/src/address/public_keys_hash.nr', + 'expected_public_keys_hash', + expected.toString(), + ); + }); +}); diff --git a/yarn-project/circuits.js/src/keys/index.ts b/yarn-project/circuits.js/src/keys/index.ts index f8da77fcba5a..11fd962e75ea 100644 --- a/yarn-project/circuits.js/src/keys/index.ts +++ b/yarn-project/circuits.js/src/keys/index.ts @@ -1,4 +1,4 @@ -import { type AztecAddress } from '@aztec/foundation/aztec-address'; +import { AztecAddress } from '@aztec/foundation/aztec-address'; import { poseidon2Hash, sha512ToGrumpkinScalar } from '@aztec/foundation/crypto'; import { type Fr, type GrumpkinScalar } from '@aztec/foundation/fields'; @@ -39,6 +39,11 @@ export function computePublicKeysHash( ]); } +export function computeAddress(publicKeysHash: Fr, partialAddress: Fr) { + const addressFr = poseidon2Hash([publicKeysHash, partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]); + return AztecAddress.fromField(addressFr); +} + /** * Computes secret and public keys and public keys hash from a secret key. * @param secretKey - The secret key to derive keys from. diff --git a/yarn-project/circuits.js/src/structs/complete_address.test.ts b/yarn-project/circuits.js/src/structs/complete_address.test.ts index e8ce620e5e4c..70c006ed2b2e 100644 --- a/yarn-project/circuits.js/src/structs/complete_address.test.ts +++ b/yarn-project/circuits.js/src/structs/complete_address.test.ts @@ -4,16 +4,29 @@ import { Fr, Point } from '@aztec/foundation/fields'; import { CompleteAddress } from './complete_address.js'; describe('CompleteAddress', () => { - // TODO(#5834): re-enable or remove this test - it.skip('refuses to add an account with incorrect address for given partial address and pubkey', () => { - expect(() => CompleteAddress.create(AztecAddress.random(), Point.random(), Fr.random())).toThrow( - /cannot be derived/, - ); + it('refuses to add an account with incorrect address for given partial address and pubkey', () => { + expect(() => + CompleteAddress.create( + AztecAddress.random(), + Point.random(), + Point.random(), + Point.random(), + Point.random(), + Fr.random(), + ), + ).toThrow(/cannot be derived/); }); it('equals returns true when 2 instances are equal', () => { const address1 = CompleteAddress.random(); - const address2 = CompleteAddress.create(address1.address, address1.publicKey, address1.partialAddress); + const address2 = CompleteAddress.create( + address1.address, + address1.masterNullifierPublicKey, + address1.masterIncomingViewingPublicKey, + address1.masterOutgoingViewingPublicKey, + address1.masterTaggingPublicKey, + address1.partialAddress, + ); expect(address1.equals(address2)).toBe(true); }); diff --git a/yarn-project/circuits.js/src/structs/complete_address.ts b/yarn-project/circuits.js/src/structs/complete_address.ts index f4465685ca0b..7b7d46d2b20b 100644 --- a/yarn-project/circuits.js/src/structs/complete_address.ts +++ b/yarn-project/circuits.js/src/structs/complete_address.ts @@ -3,7 +3,7 @@ import { Fr, Point } from '@aztec/foundation/fields'; import { BufferReader } from '@aztec/foundation/serialize'; import { computeContractAddressFromPartial, computePartialAddress } from '../contract/contract_address.js'; -import { deriveKeys } from '../keys/index.js'; +import { computeAddress, computePublicKeysHash, deriveKeys } from '../keys/index.js'; import { type PartialAddress } from '../types/partial_address.js'; import { type PublicKey } from '../types/public_key.js'; @@ -22,8 +22,14 @@ export class CompleteAddress { public constructor( /** Contract address (typically of an account contract) */ public address: AztecAddress, - /** Public key corresponding to the address (used during note encryption). */ - public publicKey: PublicKey, + /** Master nullifier public key */ + public masterNullifierPublicKey: PublicKey, + /** Master incoming viewing public key */ + public masterIncomingViewingPublicKey: PublicKey, + /** Master outgoing viewing public key */ + public masterOutgoingViewingPublicKey: PublicKey, + /** Master tagging viewing public key */ + public masterTaggingPublicKey: PublicKey, /** Partial key corresponding to the public key to the address. */ public partialAddress: PartialAddress, ) {} @@ -31,32 +37,46 @@ export class CompleteAddress { /** Size in bytes of an instance */ static readonly SIZE_IN_BYTES = 32 * 4; - static create(address: AztecAddress, publicKey: PublicKey, partialAddress: PartialAddress) { - const completeAddress = new CompleteAddress(address, publicKey, partialAddress); - // TODO(#5834): re-enable validation - // completeAddress.validate(); + static create( + address: AztecAddress, + masterNullifierPublicKey: PublicKey, + masterIncomingViewingPublicKey: PublicKey, + masterOutgoingViewingPublicKey: PublicKey, + masterTaggingPublicKey: PublicKey, + partialAddress: PartialAddress, + ): CompleteAddress { + const completeAddress = new CompleteAddress( + address, + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + partialAddress, + ); + completeAddress.validate(); return completeAddress; } - static random() { - // TODO(#5834): the following should be cleaned up - const secretKey = Fr.random(); - const partialAddress = Fr.random(); - const address = computeContractAddressFromPartial({ secretKey, partialAddress }); - const publicKey = deriveKeys(secretKey).masterIncomingViewingPublicKey; - return new CompleteAddress(address, publicKey, partialAddress); - } - - static fromRandomSecretKey() { - const secretKey = Fr.random(); - const partialAddress = Fr.random(); - return { secretKey, completeAddress: CompleteAddress.fromSecretKeyAndPartialAddress(secretKey, partialAddress) }; + static random(): CompleteAddress { + return this.fromSecretKeyAndPartialAddress(Fr.random(), Fr.random()); } static fromSecretKeyAndPartialAddress(secretKey: Fr, partialAddress: Fr): CompleteAddress { const address = computeContractAddressFromPartial({ secretKey, partialAddress }); - const publicKey = deriveKeys(secretKey).masterIncomingViewingPublicKey; - return new CompleteAddress(address, publicKey, partialAddress); + const { + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + } = deriveKeys(secretKey); + return new CompleteAddress( + address, + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + partialAddress, + ); } static fromSecretKeyAndInstance( @@ -64,29 +84,31 @@ export class CompleteAddress { instance: Parameters[0], ): CompleteAddress { const partialAddress = computePartialAddress(instance); - const address = computeContractAddressFromPartial({ secretKey, partialAddress }); - const publicKey = deriveKeys(secretKey).masterIncomingViewingPublicKey; - return new CompleteAddress(address, publicKey, partialAddress); + return CompleteAddress.fromSecretKeyAndPartialAddress(secretKey, partialAddress); } - // TODO(#5834): re-enable validation - // /** Throws if the address is not correctly derived from the public key and partial address.*/ - // public validate() { - // const expectedAddress = computeContractAddressFromPartial(this); - // const address = this.address; - // if (!expectedAddress.equals(address)) { - // throw new Error( - // `Address cannot be derived from pubkey and partial address (received ${address.toString()}, derived ${expectedAddress.toString()})`, - // ); - // } - // } + /** Throws if the address is not correctly derived from the public key and partial address.*/ + public validate() { + const publicKeysHash = computePublicKeysHash( + this.masterNullifierPublicKey, + this.masterIncomingViewingPublicKey, + this.masterOutgoingViewingPublicKey, + this.masterTaggingPublicKey, + ); + const expectedAddress = computeAddress(publicKeysHash, this.partialAddress); + if (!expectedAddress.equals(this.address)) { + throw new Error( + `Address cannot be derived from public keys and partial address (received ${this.address.toString()}, derived ${expectedAddress.toString()})`, + ); + } + } /** - * Gets a readable string representation of a the complete address. + * Gets a readable string representation of the complete address. * @returns A readable string representation of the complete address. */ public toReadableString(): string { - return ` Address: ${this.address.toString()}\n Public Key: ${this.publicKey.toString()}\n Partial Address: ${this.partialAddress.toString()}\n`; + return `Address: ${this.address.toString()}\nMaster Nullifier Public Key: ${this.masterNullifierPublicKey.toString()}\nMaster Incoming Viewing Public Key: ${this.masterIncomingViewingPublicKey.toString()}\nMaster Outgoing Viewing Public Key: ${this.masterOutgoingViewingPublicKey.toString()}\nMaster Tagging Public Key: ${this.masterTaggingPublicKey.toString()}\nPartial Address: ${this.partialAddress.toString()}\n`; } /** @@ -96,10 +118,13 @@ export class CompleteAddress { * @param other - The CompleteAddress instance to compare against. * @returns True if the buffers of both instances are equal, false otherwise. */ - equals(other: CompleteAddress) { + equals(other: CompleteAddress): boolean { return ( this.address.equals(other.address) && - this.publicKey.equals(other.publicKey) && + this.masterNullifierPublicKey.equals(other.masterNullifierPublicKey) && + this.masterIncomingViewingPublicKey.equals(other.masterIncomingViewingPublicKey) && + this.masterOutgoingViewingPublicKey.equals(other.masterOutgoingViewingPublicKey) && + this.masterTaggingPublicKey.equals(other.masterTaggingPublicKey) && this.partialAddress.equals(other.partialAddress) ); } @@ -110,8 +135,15 @@ export class CompleteAddress { * * @returns A Buffer representation of the CompleteAddress instance. */ - toBuffer() { - return Buffer.concat([this.address.toBuffer(), this.publicKey.toBuffer(), this.partialAddress.toBuffer()]); + toBuffer(): Buffer { + return Buffer.concat([ + this.address.toBuffer(), + this.masterNullifierPublicKey.toBuffer(), + this.masterIncomingViewingPublicKey.toBuffer(), + this.masterOutgoingViewingPublicKey.toBuffer(), + this.masterTaggingPublicKey.toBuffer(), + this.partialAddress.toBuffer(), + ]); } /** @@ -122,12 +154,22 @@ export class CompleteAddress { * @param buffer - The input buffer or BufferReader containing the address data. * @returns - A new CompleteAddress instance with the extracted address data. */ - static fromBuffer(buffer: Buffer | BufferReader) { + static fromBuffer(buffer: Buffer | BufferReader): CompleteAddress { const reader = BufferReader.asReader(buffer); const address = reader.readObject(AztecAddress); - const publicKey = reader.readObject(Point); + const masterNullifierPublicKey = reader.readObject(Point); + const masterIncomingViewingPublicKey = reader.readObject(Point); + const masterOutgoingViewingPublicKey = reader.readObject(Point); + const masterTaggingPublicKey = reader.readObject(Point); const partialAddress = reader.readObject(Fr); - return new this(address, publicKey, partialAddress); + return new CompleteAddress( + address, + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + partialAddress, + ); } /** @@ -151,4 +193,13 @@ export class CompleteAddress { toString(): string { return `0x${this.toBuffer().toString('hex')}`; } + + get publicKeysHash(): Fr { + return computePublicKeysHash( + this.masterNullifierPublicKey, + this.masterIncomingViewingPublicKey, + this.masterOutgoingViewingPublicKey, + this.masterTaggingPublicKey, + ); + } } diff --git a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts index 8697c01cbdda..03c228469109 100644 --- a/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts +++ b/yarn-project/circuits.js/src/structs/private_circuit_public_inputs.ts @@ -39,7 +39,6 @@ import { TxContext } from './tx_context.js'; /** * Public inputs to a private circuit. - * @see abis/private_circuit_public_inputs.hpp. */ export class PrivateCircuitPublicInputs { constructor( diff --git a/yarn-project/end-to-end/src/benchmarks/utils.ts b/yarn-project/end-to-end/src/benchmarks/utils.ts index 0dbbe2d61624..1072040b1ce6 100644 --- a/yarn-project/end-to-end/src/benchmarks/utils.ts +++ b/yarn-project/end-to-end/src/benchmarks/utils.ts @@ -127,7 +127,8 @@ export async function waitNewPXESynced( */ export async function waitRegisteredAccountSynced(pxe: PXE, secretKey: Fr, partialAddress: PartialAddress) { const l2Block = await pxe.getBlockNumber(); - const { publicKey } = await pxe.registerAccount(secretKey, partialAddress); - const isAccountSynced = async () => (await pxe.getSyncStatus()).notes[publicKey.toString()] === l2Block; + const { masterIncomingViewingPublicKey } = await pxe.registerAccount(secretKey, partialAddress); + const isAccountSynced = async () => + (await pxe.getSyncStatus()).notes[masterIncomingViewingPublicKey.toString()] === l2Block; await retryUntil(isAccountSynced, 'pxe-notes-sync'); } diff --git a/yarn-project/end-to-end/src/client_prover_integration/client_prover_test.ts b/yarn-project/end-to-end/src/client_prover_integration/client_prover_test.ts index 0303dcecdab2..54318e1702c3 100644 --- a/yarn-project/end-to-end/src/client_prover_integration/client_prover_test.ts +++ b/yarn-project/end-to-end/src/client_prover_integration/client_prover_test.ts @@ -130,7 +130,6 @@ export class ClientProverTest { this.logger.debug(`Main setup completed, initializing full prover PXE...`); ({ pxe: this.fullProverPXE, teardown: this.provenPXETeardown } = await setupPXEService( - 0, this.aztecNode, { proverEnabled: false, diff --git a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts index 7e185f169e04..ebb1ec71e14d 100644 --- a/yarn-project/end-to-end/src/e2e_2_pxes.test.ts +++ b/yarn-project/end-to-end/src/e2e_2_pxes.test.ts @@ -1,4 +1,5 @@ import { getUnsafeSchnorrAccount } from '@aztec/accounts/single_key'; +import { createAccounts } from '@aztec/accounts/testing'; import { type AztecAddress, type AztecNode, @@ -40,11 +41,9 @@ describe('e2e_2_pxes', () => { teardown: teardownA, } = await setup(1)); - ({ - pxe: pxeB, - wallets: [walletB], - teardown: teardownB, - } = await setupPXEService(1, aztecNode!, {}, undefined, true)); + ({ pxe: pxeB, teardown: teardownB } = await setupPXEService(aztecNode!, {}, undefined, true)); + + [walletB] = await createAccounts(pxeB, 1); }); afterEach(async () => { diff --git a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts index e5f8f0743a55..68ac9c89e28f 100644 --- a/yarn-project/end-to-end/src/e2e_account_contracts.test.ts +++ b/yarn-project/end-to-end/src/e2e_account_contracts.test.ts @@ -74,11 +74,7 @@ describe('e2e_account_contracts', () => { const walletAt = async (pxe: PXE, accountContract: AccountContract, address: CompleteAddress) => { const nodeInfo = await pxe.getNodeInfo(); - const publicKeysHash = await pxe.getRegisteredAccountPublicKeysHash(address.address); - if (!publicKeysHash) { - throw new Error(`Public keys hash for account ${address.address} not found`); - } - const entrypoint = accountContract.getInterface(address, publicKeysHash, nodeInfo); + const entrypoint = accountContract.getInterface(address, nodeInfo); return new AccountWallet(pxe, entrypoint); }; diff --git a/yarn-project/end-to-end/src/e2e_card_game.test.ts b/yarn-project/end-to-end/src/e2e_card_game.test.ts index f0949b166635..743ff3a38b36 100644 --- a/yarn-project/end-to-end/src/e2e_card_game.test.ts +++ b/yarn-project/end-to-end/src/e2e_card_game.test.ts @@ -105,7 +105,7 @@ describe('e2e_card_game', () => { const publicKey = deriveKeys(key).masterIncomingViewingPublicKey; return ( preRegisteredAccounts.find(preRegisteredAccount => { - return preRegisteredAccount.publicKey.equals(publicKey); + return preRegisteredAccount.masterIncomingViewingPublicKey.equals(publicKey); }) == undefined ); }); diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract/deploy_test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract/deploy_test.ts index 05b314228286..ffafbb038e76 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract/deploy_test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract/deploy_test.ts @@ -3,11 +3,10 @@ import { type AccountWallet, type AztecAddress, type AztecNode, - CompleteAddress, type ContractArtifact, type ContractBase, type DebugLogger, - type Fr, + Fr, type PXE, type Wallet, createDebugLogger, @@ -81,10 +80,8 @@ export class DeployTest { } async registerRandomAccount(): Promise { - const pxe = this.pxe; - const { completeAddress: owner, secretKey } = CompleteAddress.fromRandomSecretKey(); - await pxe.registerAccount(secretKey, owner.partialAddress); - return owner.address; + const completeAddress = await this.pxe.registerAccount(Fr.random(), Fr.random()); + return completeAddress.address; } } diff --git a/yarn-project/end-to-end/src/e2e_deploy_contract/legacy.test.ts b/yarn-project/end-to-end/src/e2e_deploy_contract/legacy.test.ts index 403da38154cb..25c96999fffc 100644 --- a/yarn-project/end-to-end/src/e2e_deploy_contract/legacy.test.ts +++ b/yarn-project/end-to-end/src/e2e_deploy_contract/legacy.test.ts @@ -33,7 +33,7 @@ describe('e2e_deploy_contract legacy', () => { */ it('should deploy a test contract', async () => { const salt = Fr.random(); - const publicKeysHash = wallet.getPublicKeysHash(); + const publicKeysHash = wallet.getCompleteAddress().publicKeysHash; const deploymentData = getContractInstanceFromDeployParams(TestContractArtifact, { salt, publicKeysHash, @@ -68,7 +68,7 @@ describe('e2e_deploy_contract legacy', () => { logger.info(`Deploying contract ${index + 1}...`); const receipt = await deployer.deploy().send({ contractAddressSalt: Fr.random() }).wait({ wallet }); logger.info(`Sending TX to contract ${index + 1}...`); - await receipt.contract.methods.get_public_key(wallet.getAddress()).send().wait(); + await receipt.contract.methods.get_master_incoming_viewing_public_key(wallet.getAddress()).send().wait(); } }); diff --git a/yarn-project/end-to-end/src/e2e_key_registry.test.ts b/yarn-project/end-to-end/src/e2e_key_registry.test.ts index c770ceaf9dd7..d187fb7cfc5c 100644 --- a/yarn-project/end-to-end/src/e2e_key_registry.test.ts +++ b/yarn-project/end-to-end/src/e2e_key_registry.test.ts @@ -1,6 +1,5 @@ import { type AccountWallet, AztecAddress, Fr, type PXE } from '@aztec/aztec.js'; -import { CompleteAddress, GeneratorIndex, type PartialAddress, Point, deriveKeys } from '@aztec/circuits.js'; -import { poseidon2Hash } from '@aztec/foundation/crypto'; +import { CompleteAddress, Point } from '@aztec/circuits.js'; import { KeyRegistryContract, TestContract } from '@aztec/noir-contracts.js'; import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry'; @@ -23,16 +22,7 @@ describe('Key Registry', () => { let teardown: () => Promise; - // TODO(#5834): use AztecAddress.compute or smt - const { - masterNullifierPublicKey, - masterIncomingViewingPublicKey, - masterOutgoingViewingPublicKey, - masterTaggingPublicKey, - publicKeysHash, - } = deriveKeys(Fr.random()); - const partialAddress: PartialAddress = Fr.random(); - let account: AztecAddress; + const account = CompleteAddress.random(); beforeAll(async () => { ({ teardown, pxe, wallets } = await setup(3)); @@ -41,11 +31,6 @@ describe('Key Registry', () => { testContract = await TestContract.deploy(wallets[0]).send().deployed(); await publicDeployAccounts(wallets[0], wallets.slice(0, 2)); - - // TODO(#5834): use AztecAddress.compute or smt - account = AztecAddress.fromField( - poseidon2Hash([publicKeysHash, partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]), - ); }); const crossDelay = async () => { @@ -60,10 +45,10 @@ describe('Key Registry', () => { describe('failure cases', () => { it('throws when address preimage check fails', async () => { const keys = [ - masterNullifierPublicKey, - masterIncomingViewingPublicKey, - masterOutgoingViewingPublicKey, - masterTaggingPublicKey, + account.masterNullifierPublicKey, + account.masterIncomingViewingPublicKey, + account.masterOutgoingViewingPublicKey, + account.masterTaggingPublicKey, ]; // We randomly invalidate some of the keys @@ -72,7 +57,7 @@ describe('Key Registry', () => { await expect( keyRegistry .withWallet(wallets[0]) - .methods.register(AztecAddress.fromField(account), partialAddress, keys[0], keys[1], keys[2], keys[3]) + .methods.register(account, account.partialAddress, keys[0], keys[1], keys[2], keys[3]) .send() .wait(), ).rejects.toThrow('Computed address does not match supplied address'); @@ -96,33 +81,20 @@ describe('Key Registry', () => { await expect( testContract.methods.test_nullifier_key_freshness(randomAddress, randomMasterNullifierPublicKey).send().wait(), - ).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); + ).rejects.toThrow(/No public key registered for address/); }); }); it('fresh key lib succeeds for non-registered account available in PXE', async () => { - // TODO(#5834): Make this not disgusting - const newAccountKeys = deriveKeys(Fr.random()); - const newAccountPartialAddress = Fr.random(); - const newAccount = AztecAddress.fromField( - poseidon2Hash([newAccountKeys.publicKeysHash, newAccountPartialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]), - ); - const newAccountCompleteAddress = CompleteAddress.create( - newAccount, - newAccountKeys.masterIncomingViewingPublicKey, - newAccountPartialAddress, - ); - - await pxe.registerRecipient(newAccountCompleteAddress, [ - newAccountKeys.masterNullifierPublicKey, - newAccountKeys.masterIncomingViewingPublicKey, - newAccountKeys.masterOutgoingViewingPublicKey, - newAccountKeys.masterTaggingPublicKey, - ]); + const newAccountCompleteAddress = CompleteAddress.random(); + await pxe.registerRecipient(newAccountCompleteAddress); // Should succeed as the account is now registered as a recipient in PXE await testContract.methods - .test_nullifier_key_freshness(newAccount, newAccountKeys.masterNullifierPublicKey) + .test_nullifier_key_freshness( + newAccountCompleteAddress.address, + newAccountCompleteAddress.masterNullifierPublicKey, + ) .send() .wait(); }); @@ -133,11 +105,11 @@ describe('Key Registry', () => { .withWallet(wallets[0]) .methods.register( account, - partialAddress, - masterNullifierPublicKey, - masterIncomingViewingPublicKey, - masterOutgoingViewingPublicKey, - masterTaggingPublicKey, + account.partialAddress, + account.masterNullifierPublicKey, + account.masterIncomingViewingPublicKey, + account.masterOutgoingViewingPublicKey, + account.masterTaggingPublicKey, ) .send() .wait(); @@ -157,13 +129,13 @@ describe('Key Registry', () => { .test_shared_mutable_private_getter_for_registry_contract(1, account) .simulate(); - expect(new Fr(nullifierPublicKeyX)).toEqual(masterNullifierPublicKey.x); + expect(new Fr(nullifierPublicKeyX)).toEqual(account.masterNullifierPublicKey.x); }); // Note: This test case is dependent on state from the previous one it('key lib succeeds for registered account', async () => { // Should succeed as the account is registered in key registry from tests before - await testContract.methods.test_nullifier_key_freshness(account, masterNullifierPublicKey).send().wait(); + await testContract.methods.test_nullifier_key_freshness(account, account.masterNullifierPublicKey).send().wait(); }); }); diff --git a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts index a8b0ed53439f..6aaae7545f73 100644 --- a/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts +++ b/yarn-project/end-to-end/src/e2e_multiple_accounts_1_enc_key.test.ts @@ -50,7 +50,7 @@ describe('e2e_multiple_accounts_1_enc_key', () => { const encryptionPublicKey = deriveKeys(encryptionPrivateKey).masterIncomingViewingPublicKey; for (const account of accounts) { - expect(account.publicKey).toEqual(encryptionPublicKey); + expect(account.masterIncomingViewingPublicKey).toEqual(encryptionPublicKey); } logger.info(`Deploying Token...`); diff --git a/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts b/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts index 72651f79e278..7129a268eb9c 100644 --- a/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts +++ b/yarn-project/end-to-end/src/fixtures/snapshot_manager.ts @@ -8,9 +8,11 @@ import { EthCheatCodes, Fr, GrumpkinPrivateKey, + SignerlessWallet, type Wallet, } from '@aztec/aztec.js'; import { deployInstance, registerContractClass } from '@aztec/aztec.js/deployment'; +import { DefaultMultiCallEntrypoint } from '@aztec/aztec.js/entrypoint'; import { asyncMap } from '@aztec/foundation/async-map'; import { type Logger, createDebugLogger } from '@aztec/foundation/log'; import { makeBackoff, retry } from '@aztec/foundation/retry'; @@ -27,6 +29,7 @@ import { mnemonicToAccount } from 'viem/accounts'; import { MNEMONIC } from './fixtures.js'; import { getACVMConfig } from './get_acvm_config.js'; import { setupL1Contracts } from './setup_l1_contracts.js'; +import { deployCanonicalKeyRegistry } from './utils.js'; export type SubsystemsContext = { anvil: Anvil; @@ -264,6 +267,11 @@ async function setupFromFresh(statePath: string | undefined, logger: Logger): Pr pxeConfig.dataDirectory = statePath; const pxe = await createPXEService(aztecNode, pxeConfig); + logger.verbose('Deploying key registry...'); + await deployCanonicalKeyRegistry( + new SignerlessWallet(pxe, new DefaultMultiCallEntrypoint(aztecNodeConfig.chainId, aztecNodeConfig.version)), + ); + if (statePath) { writeFileSync(`${statePath}/aztec_node_config.json`, JSON.stringify(aztecNodeConfig)); } diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 93439822fec8..725d35a6ab61 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -153,7 +153,6 @@ async function initGasBridge({ walletClient, l1ContractAddresses }: DeployL1Cont /** * Sets up Private eXecution Environment (PXE). - * @param numberOfAccounts - The number of new accounts to be created once the PXE is initiated. * @param aztecNode - An instance of Aztec Node. * @param opts - Partial configuration for the PXE service. * @param firstPrivKey - The private key of the first account to be created. @@ -163,7 +162,6 @@ async function initGasBridge({ walletClient, l1ContractAddresses }: DeployL1Cont * @returns Private eXecution Environment (PXE), accounts, wallets and logger. */ export async function setupPXEService( - numberOfAccounts: number, aztecNode: AztecNode, opts: Partial = {}, logger = getLogger(), @@ -174,10 +172,6 @@ export async function setupPXEService( * The PXE instance. */ pxe: PXEService; - /** - * The wallets to be used. - */ - wallets: AccountWalletWithSecretKey[]; /** * Logger instance named as the current test. */ @@ -190,15 +184,12 @@ export async function setupPXEService( const pxeServiceConfig = { ...getPXEServiceConfig(), ...opts }; const pxe = await createPXEService(aztecNode, pxeServiceConfig, useLogSuffix, proofCreator); - const wallets = await createAccounts(pxe, numberOfAccounts); - const teardown = async () => { await pxe.stop(); }; return { pxe, - wallets, logger, teardown, }; @@ -230,14 +221,6 @@ async function setupWithRemoteEnvironment( logger.verbose('JSON RPC client connected to PXE'); logger.verbose(`Retrieving contract addresses from ${PXE_URL}`); const l1Contracts = (await pxeClient.getNodeInfo()).l1ContractAddresses; - logger.verbose('PXE created, constructing available wallets from already registered accounts...'); - const wallets = await getDeployedTestAccountsWallets(pxeClient); - - if (wallets.length < numberOfAccounts) { - const numNewAccounts = numberOfAccounts - wallets.length; - logger.verbose(`Deploying ${numNewAccounts} accounts...`); - wallets.push(...(await createAccounts(pxeClient, numNewAccounts))); - } const walletClient = createWalletClient({ account, @@ -269,6 +252,15 @@ async function setupWithRemoteEnvironment( ); } + logger.verbose('Constructing available wallets from already registered accounts...'); + const wallets = await getDeployedTestAccountsWallets(pxeClient); + + if (wallets.length < numberOfAccounts) { + const numNewAccounts = numberOfAccounts - wallets.length; + logger.verbose(`Deploying ${numNewAccounts} accounts...`); + wallets.push(...(await createAccounts(pxeClient, numNewAccounts))); + } + return { aztecNode, sequencer: undefined, @@ -400,7 +392,8 @@ export async function setup( const prover = aztecNode.getProver(); logger.verbose('Creating a pxe...'); - const { pxe, wallets } = await setupPXEService(numberOfAccounts, aztecNode!, pxeOpts, logger); + + const { pxe } = await setupPXEService(aztecNode!, pxeOpts, logger); logger.verbose('Deploying key registry...'); await deployCanonicalKeyRegistry( @@ -414,6 +407,7 @@ export async function setup( ); } + const wallets = await createAccounts(pxe, numberOfAccounts); const cheatCodes = CheatCodes.create(config.rpcUrl, pxe!); const teardown = async () => { @@ -616,7 +610,7 @@ export async function deployCanonicalGasToken(deployer: Wallet) { await expect(deployer.isContractPubliclyDeployed(gasToken.address)).resolves.toBe(true); } -async function deployCanonicalKeyRegistry(deployer: Wallet) { +export async function deployCanonicalKeyRegistry(deployer: Wallet) { const canonicalKeyRegistry = getCanonicalKeyRegistry(); // We check to see if there exists a contract at the canonical Key Registry address with the same contract class id as we expect. This means that diff --git a/yarn-project/key-store/src/test_key_store.test.ts b/yarn-project/key-store/src/test_key_store.test.ts index 61647e0097c7..2395dbf1472c 100644 --- a/yarn-project/key-store/src/test_key_store.test.ts +++ b/yarn-project/key-store/src/test_key_store.test.ts @@ -11,7 +11,7 @@ describe('TestKeyStore', () => { const sk = new Fr(8923n); const partialAddress = new Fr(243523n); - const accountAddress = await keyStore.addAccount(sk, partialAddress); + const { address: accountAddress } = await keyStore.addAccount(sk, partialAddress); expect(accountAddress.toString()).toMatchInlineSnapshot( `"0x1a8a9a1d91cbb353d8df4f1bbfd0283f7fc63766f671edd9443a1270a7b2a954"`, ); diff --git a/yarn-project/key-store/src/test_key_store.ts b/yarn-project/key-store/src/test_key_store.ts index a3c0d4b239b4..a21763ebf832 100644 --- a/yarn-project/key-store/src/test_key_store.ts +++ b/yarn-project/key-store/src/test_key_store.ts @@ -1,12 +1,14 @@ import { type KeyStore, type PublicKey } from '@aztec/circuit-types'; import { AztecAddress, + CompleteAddress, Fr, GeneratorIndex, type GrumpkinPrivateKey, GrumpkinScalar, type PartialAddress, Point, + computeAddress, computeAppNullifierSecretKey, deriveKeys, } from '@aztec/circuits.js'; @@ -26,9 +28,9 @@ export class TestKeyStore implements KeyStore { /** * Creates a new account from a randomly generated secret key. - * @returns A promise that resolves to the newly created account's AztecAddress. + * @returns A promise that resolves to the newly created account's CompleteAddress. */ - public createAccount(): Promise { + public createAccount(): Promise { const sk = Fr.random(); const partialAddress = Fr.random(); return this.addAccount(sk, partialAddress); @@ -38,9 +40,9 @@ export class TestKeyStore implements KeyStore { * Adds an account to the key store from the provided secret key. * @param sk - The secret key of the account. * @param partialAddress - The partial address of the account. - * @returns The account's address. + * @returns The account's complete address. */ - public async addAccount(sk: Fr, partialAddress: PartialAddress): Promise { + public async addAccount(sk: Fr, partialAddress: PartialAddress): Promise { const { publicKeysHash, masterNullifierSecretKey, @@ -53,10 +55,7 @@ export class TestKeyStore implements KeyStore { masterTaggingPublicKey, } = deriveKeys(sk); - // We hash the partial address and the public keys hash to get the account address - // TODO(#5726): Move the following line to AztecAddress class? - const accountAddressFr = poseidon2Hash([publicKeysHash, partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]); - const accountAddress = AztecAddress.fromField(accountAddressFr); + const accountAddress = computeAddress(publicKeysHash, partialAddress); // We save the keys to db await this.#keys.set(`${accountAddress.toString()}-public_keys_hash`, publicKeysHash.toBuffer()); @@ -72,7 +71,16 @@ export class TestKeyStore implements KeyStore { await this.#keys.set(`${accountAddress.toString()}-tpk_m`, masterTaggingPublicKey.toBuffer()); // At last, we return the newly derived account address - return Promise.resolve(accountAddress); + return Promise.resolve( + CompleteAddress.create( + accountAddress, + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + partialAddress, + ), + ); } /** @@ -292,18 +300,4 @@ export class TestKeyStore implements KeyStore { } return Promise.resolve(Fr.fromBuffer(publicKeysHashBuffer)); } - - // TODO(#5834): Re-add separation between recipients and accounts in keystore. - public async addPublicKeysForAccount( - accountAddress: AztecAddress, - masterNullifierPublicKey: Point, - masterIncomingViewingPublicKey: Point, - masterOutgoingViewingPublicKey: Point, - masterTaggingPublicKey: Point, - ): Promise { - await this.#keys.set(`${accountAddress.toString()}-npk_m`, masterNullifierPublicKey.toBuffer()); - await this.#keys.set(`${accountAddress.toString()}-ivpk_m`, masterIncomingViewingPublicKey.toBuffer()); - await this.#keys.set(`${accountAddress.toString()}-ovpk_m`, masterOutgoingViewingPublicKey.toBuffer()); - await this.#keys.set(`${accountAddress.toString()}-tpk_m`, masterTaggingPublicKey.toBuffer()); - } } diff --git a/yarn-project/pxe/src/database/kv_pxe_database.ts b/yarn-project/pxe/src/database/kv_pxe_database.ts index c07a29219dea..7452f98f5b93 100644 --- a/yarn-project/pxe/src/database/kv_pxe_database.ts +++ b/yarn-project/pxe/src/database/kv_pxe_database.ts @@ -209,7 +209,7 @@ export class KVPxeDatabase implements PxeDatabase { #getNotes(filter: NoteFilter): NoteDao[] { const publicKey: PublicKey | undefined = filter.owner - ? this.#getCompleteAddress(filter.owner)?.publicKey + ? this.#getCompleteAddress(filter.owner)?.masterIncomingViewingPublicKey : undefined; filter.status = filter.status ?? NoteStatus.ACTIVE; diff --git a/yarn-project/pxe/src/database/pxe_database_test_suite.ts b/yarn-project/pxe/src/database/pxe_database_test_suite.ts index 9a1fbbe46f81..440df3db400b 100644 --- a/yarn-project/pxe/src/database/pxe_database_test_suite.ts +++ b/yarn-project/pxe/src/database/pxe_database_test_suite.ts @@ -92,7 +92,10 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { [() => ({ txHash: notes[0].txHash }), () => [notes[0]]], [() => ({ txHash: randomTxHash() }), () => []], - [() => ({ owner: owners[0].address }), () => notes.filter(note => note.publicKey.equals(owners[0].publicKey))], + [ + () => ({ owner: owners[0].address }), + () => notes.filter(note => note.publicKey.equals(owners[0].masterIncomingViewingPublicKey)), + ], [ () => ({ contractAddress: contractAddresses[0], storageSlot: storageSlots[0] }), @@ -113,7 +116,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { randomNoteDao({ contractAddress: contractAddresses[i % contractAddresses.length], storageSlot: storageSlots[i % storageSlots.length], - publicKey: owners[i % owners.length].publicKey, + publicKey: owners[i % owners.length].masterIncomingViewingPublicKey, index: BigInt(i), }), ); @@ -142,9 +145,11 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { // Nullify all notes and use the same filter as other test cases for (const owner of owners) { - const notesToNullify = notes.filter(note => note.publicKey.equals(owner.publicKey)); + const notesToNullify = notes.filter(note => note.publicKey.equals(owner.masterIncomingViewingPublicKey)); const nullifiers = notesToNullify.map(note => note.siloedNullifier); - await expect(database.removeNullifiedNotes(nullifiers, owner.publicKey)).resolves.toEqual(notesToNullify); + await expect( + database.removeNullifiedNotes(nullifiers, owner.masterIncomingViewingPublicKey), + ).resolves.toEqual(notesToNullify); } await expect(database.getNotes({ ...getFilter(), status: NoteStatus.ACTIVE_OR_NULLIFIED })).resolves.toEqual( @@ -155,7 +160,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { it('skips nullified notes by default or when requesting active', async () => { await database.addNotes(notes); - const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey)); + const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].masterIncomingViewingPublicKey)); const nullifiers = notesToNullify.map(note => note.siloedNullifier); await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual( notesToNullify, @@ -171,7 +176,7 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { it('returns active and nullified notes when requesting either', async () => { await database.addNotes(notes); - const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].publicKey)); + const notesToNullify = notes.filter(note => note.publicKey.equals(owners[0].masterIncomingViewingPublicKey)); const nullifiers = notesToNullify.map(note => note.siloedNullifier); await expect(database.removeNullifiedNotes(nullifiers, notesToNullify[0].publicKey)).resolves.toEqual( notesToNullify, @@ -215,7 +220,14 @@ export function describePxeDatabase(getDatabase: () => PxeDatabase) { it.skip('refuses to overwrite an address with a different public key', async () => { const address = CompleteAddress.random(); - const otherAddress = new CompleteAddress(address.address, Point.random(), address.partialAddress); + const otherAddress = new CompleteAddress( + address.address, + Point.random(), + Point.random(), + Point.random(), + Point.random(), + address.partialAddress, + ); await database.addCompleteAddress(address); await expect(database.addCompleteAddress(otherAddress)).rejects.toThrow(); diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 3ed4fa30cf4e..c918ffaafa95 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -25,7 +25,7 @@ import { type TxPXEProcessingStats } from '@aztec/circuit-types/stats'; import { AztecAddress, CallRequest, - CompleteAddress, + type CompleteAddress, FunctionData, MAX_PUBLIC_CALL_STACK_LENGTH_PER_TX, type PartialAddress, @@ -37,7 +37,7 @@ import { import { computeNoteHashNonce, siloNullifier } from '@aztec/circuits.js/hash'; import { type ContractArtifact, type DecodedReturn, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; import { arrayNonEmptyLength, padArrayEnd } from '@aztec/foundation/collection'; -import { Fr, type Point } from '@aztec/foundation/fields'; +import { Fr } from '@aztec/foundation/fields'; import { SerialQueue } from '@aztec/foundation/fifo'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; @@ -115,12 +115,12 @@ export class PXEService implements PXE { let count = 0; for (const address of registeredAddresses) { - if (!publicKeysSet.has(address.publicKey.toString())) { + if (!publicKeysSet.has(address.masterIncomingViewingPublicKey.toString())) { continue; } count++; - this.synchronizer.addAccount(address.publicKey, this.keyStore, this.config.l2StartingBlock); + this.synchronizer.addAccount(address.masterIncomingViewingPublicKey, this.keyStore, this.config.l2StartingBlock); } if (count > 0) { @@ -170,24 +170,21 @@ export class PXEService implements PXE { public async registerAccount(secretKey: Fr, partialAddress: PartialAddress): Promise { const accounts = await this.keyStore.getAccounts(); - const account = await this.keyStore.addAccount(secretKey, partialAddress); - const completeAddress = new CompleteAddress( - account, - await this.keyStore.getMasterIncomingViewingPublicKey(account), - partialAddress, - ); - if (accounts.includes(account)) { - this.log.info(`Account:\n "${completeAddress.address.toString()}"\n already registered.`); - return completeAddress; + const accountCompleteAddress = await this.keyStore.addAccount(secretKey, partialAddress); + if (accounts.includes(accountCompleteAddress.address)) { + this.log.info(`Account:\n "${accountCompleteAddress.address.toString()}"\n already registered.`); + return accountCompleteAddress; } else { - const masterIncomingViewingPublicKey = await this.keyStore.getMasterIncomingViewingPublicKey(account); + const masterIncomingViewingPublicKey = await this.keyStore.getMasterIncomingViewingPublicKey( + accountCompleteAddress.address, + ); this.synchronizer.addAccount(masterIncomingViewingPublicKey, this.keyStore, this.config.l2StartingBlock); - this.log.info(`Registered account ${completeAddress.address.toString()}`); - this.log.debug(`Registered account\n ${completeAddress.toReadableString()}`); + this.log.info(`Registered account ${accountCompleteAddress.address.toString()}`); + this.log.debug(`Registered account\n ${accountCompleteAddress.toReadableString()}`); } - await this.db.addCompleteAddress(completeAddress); - return completeAddress; + await this.db.addCompleteAddress(accountCompleteAddress); + return accountCompleteAddress; } public async getRegisteredAccounts(): Promise { @@ -214,20 +211,9 @@ export class PXEService implements PXE { return this.keyStore.getPublicKeysHash(address); } - public async registerRecipient(recipient: CompleteAddress, publicKeys: Point[] = []): Promise { + public async registerRecipient(recipient: CompleteAddress): Promise { const wasAdded = await this.db.addCompleteAddress(recipient); - // TODO #5834: This should be refactored to be okay with only adding complete address - if (publicKeys.length !== 0) { - await this.keyStore.addPublicKeysForAccount( - recipient.address, - publicKeys[0], - publicKeys[1], - publicKeys[2], - publicKeys[3], - ); - } - if (wasAdded) { this.log.info(`Added recipient:\n ${recipient.toReadableString()}`); } else { @@ -306,7 +292,7 @@ export class PXEService implements PXE { let owner = filter.owner; if (owner === undefined) { const completeAddresses = (await this.db.getCompleteAddresses()).find(address => - address.publicKey.equals(dao.publicKey), + address.masterIncomingViewingPublicKey.equals(dao.publicKey), ); if (completeAddresses === undefined) { throw new Error(`Cannot find complete address for public key ${dao.publicKey.toString()}`); @@ -319,8 +305,8 @@ export class PXEService implements PXE { } public async addNote(note: ExtendedNote) { - const { publicKey } = (await this.db.getCompleteAddress(note.owner)) ?? {}; - if (!publicKey) { + const { masterIncomingViewingPublicKey } = (await this.db.getCompleteAddress(note.owner)) ?? {}; + if (!masterIncomingViewingPublicKey) { throw new Error('Unknown account.'); } @@ -360,7 +346,7 @@ export class PXEService implements PXE { innerNoteHash, siloedNullifier, index, - publicKey, + masterIncomingViewingPublicKey, ), ); } diff --git a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts index 75d2f11b1422..cf9e7d6c4c47 100644 --- a/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts +++ b/yarn-project/pxe/src/pxe_service/test/pxe_test_suite.ts @@ -70,7 +70,14 @@ export const pxeTestSuite = (testName: string, pxeSetup: () => Promise) => it('cannot register a recipient with the same aztec address but different pub key or partial address', async () => { const recipient1 = CompleteAddress.random(); - const recipient2 = new CompleteAddress(recipient1.address, Point.random(), Fr.random()); + const recipient2 = new CompleteAddress( + recipient1.address, + Point.random(), + Point.random(), + Point.random(), + Point.random(), + Fr.random(), + ); await pxe.registerRecipient(recipient1); await expect(() => pxe.registerRecipient(recipient2)).rejects.toThrow( diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 12e540148b76..ac9ee3566efa 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -15,7 +15,6 @@ import { type FunctionSelector, type Header, type L1_TO_L2_MSG_TREE_HEIGHT, - type Point, } from '@aztec/circuits.js'; import { computeL1ToL2MessageNullifier } from '@aztec/circuits.js/hash'; import { type FunctionArtifact, getFunctionArtifact } from '@aztec/foundation/abi'; @@ -44,7 +43,6 @@ export class SimulatorOracle implements DBOracle { return { masterNullifierPublicKey, appNullifierSecretKey }; } - // TODO: #5834 async getCompleteAddress(address: AztecAddress): Promise { const completeAddress = await this.db.getCompleteAddress(address); if (!completeAddress) { @@ -79,16 +77,6 @@ export class SimulatorOracle implements DBOracle { return capsule; } - // TODO: #5834 - async getPublicKeysForAddress(address: AztecAddress): Promise { - const nullifierPublicKey = await this.keyStore.getMasterNullifierPublicKey(address); - const incomingViewingPublicKey = await this.keyStore.getMasterIncomingViewingPublicKey(address); - const outgoingViewingPublicKey = await this.keyStore.getMasterOutgoingViewingPublicKey(address); - const taggingPublicKey = await this.keyStore.getMasterTaggingPublicKey(address); - - return [nullifierPublicKey, incomingViewingPublicKey, outgoingViewingPublicKey, taggingPublicKey]; - } - async getNotes(contractAddress: AztecAddress, storageSlot: Fr, status: NoteStatus) { const noteDaos = await this.db.getNotes({ contractAddress, diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts index f8deb8b8ca3f..1c145eb3302d 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.test.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.test.ts @@ -1,5 +1,5 @@ import { type AztecNode, L2Block } from '@aztec/circuit-types'; -import { CompleteAddress, Fr, type Header, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; +import { Fr, type Header, INITIAL_L2_BLOCK_NUM } from '@aztec/circuits.js'; import { makeHeader } from '@aztec/circuits.js/testing'; import { randomInt } from '@aztec/foundation/crypto'; import { SerialQueue } from '@aztec/foundation/fifo'; @@ -130,12 +130,9 @@ describe('Synchronizer', () => { const addAddress = async (startingBlockNum: number) => { const secretKey = Fr.random(); const partialAddress = Fr.random(); - const accountAddress = await keyStore.addAccount(secretKey, partialAddress); - const masterIncomingViewingPublicKey = await keyStore.getMasterIncomingViewingPublicKey(accountAddress); - - const completeAddress = new CompleteAddress(accountAddress, masterIncomingViewingPublicKey, partialAddress); + const completeAddress = await keyStore.addAccount(secretKey, partialAddress); await database.addCompleteAddress(completeAddress); - synchronizer.addAccount(completeAddress.publicKey, keyStore, startingBlockNum); + synchronizer.addAccount(completeAddress.masterIncomingViewingPublicKey, keyStore, startingBlockNum); return completeAddress; }; diff --git a/yarn-project/pxe/src/synchronizer/synchronizer.ts b/yarn-project/pxe/src/synchronizer/synchronizer.ts index dc7f1890877e..d7da26c991e8 100644 --- a/yarn-project/pxe/src/synchronizer/synchronizer.ts +++ b/yarn-project/pxe/src/synchronizer/synchronizer.ts @@ -285,7 +285,8 @@ export class Synchronizer { if (!completeAddress) { throw new Error(`Checking if account is synched is not possible for ${account} because it is not registered.`); } - const findByPublicKey = (x: NoteProcessor) => x.masterIncomingViewingPublicKey.equals(completeAddress.publicKey); + const findByPublicKey = (x: NoteProcessor) => + x.masterIncomingViewingPublicKey.equals(completeAddress.masterIncomingViewingPublicKey); const processor = this.noteProcessors.find(findByPublicKey) ?? this.noteProcessorsToCatchUp.find(findByPublicKey); if (!processor) { throw new Error( diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 415f8c3e84ed..7df1704f4271 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -1,5 +1,5 @@ import { MerkleTreeId, UnencryptedL2Log } from '@aztec/circuit-types'; -import { type PartialAddress, acvmFieldMessageToString, oracleDebugCallToFormattedStr } from '@aztec/circuits.js'; +import { acvmFieldMessageToString, oracleDebugCallToFormattedStr } from '@aztec/circuits.js'; import { EventSelector, FunctionSelector } from '@aztec/foundation/abi'; import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr, Point } from '@aztec/foundation/fields'; @@ -53,14 +53,6 @@ export class Oracle { ]; } - // TODO: #5834 Nuke this - async getPublicKeyAndPartialAddress([address]: ACVMField[]) { - const { publicKey, partialAddress } = await this.typedOracle.getCompleteAddress( - AztecAddress.fromField(fromACVMField(address)), - ); - return [publicKey.x, publicKey.y, partialAddress].map(toACVMField); - } - async getContractInstance([address]: ACVMField[]) { const instance = await this.typedOracle.getContractInstance(AztecAddress.fromField(fromACVMField(address))); @@ -173,25 +165,22 @@ export class Oracle { } async getPublicKeysAndPartialAddress([address]: ACVMField[]): Promise { - let publicKeys: Point[] | undefined; - let partialAddress: PartialAddress; - - // TODO #5834: This should be reworked to return the public keys as well - try { - ({ partialAddress } = await this.typedOracle.getCompleteAddress(AztecAddress.fromField(fromACVMField(address)))); - } catch (err) { - partialAddress = Fr.ZERO; - } + const parsedAddress = AztecAddress.fromField(fromACVMField(address)); + const { + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + partialAddress, + } = await this.typedOracle.getCompleteAddress(parsedAddress); - try { - publicKeys = await this.typedOracle.getPublicKeysForAddress(AztecAddress.fromField(fromACVMField(address))); - } catch (err) { - publicKeys = Array(4).fill(Point.ZERO); - } - - const acvmPublicKeys = publicKeys.flatMap(key => key.toFields()); - - return [...acvmPublicKeys, partialAddress].map(toACVMField); + return [ + ...masterNullifierPublicKey.toFields(), + ...masterIncomingViewingPublicKey.toFields(), + ...masterOutgoingViewingPublicKey.toFields(), + ...masterTaggingPublicKey.toFields(), + partialAddress, + ].map(toACVMField); } async getNotes( diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 171ccb4d757c..231d8cd99d1c 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -17,7 +17,7 @@ import { } from '@aztec/circuits.js'; import { type FunctionSelector } from '@aztec/foundation/abi'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; -import { Fr, type Point } from '@aztec/foundation/fields'; +import { Fr } from '@aztec/foundation/fields'; import { type ContractInstance } from '@aztec/types/contracts'; /** Nullifier keys which both correspond to the same master nullifier secret key. */ @@ -93,10 +93,6 @@ export abstract class TypedOracle { throw new OracleMethodNotAvailableError('getNullifierKeys'); } - getPublicKeyAndPartialAddress(_address: AztecAddress): Promise { - throw new OracleMethodNotAvailableError('getPublicKeyAndPartialAddress'); - } - getContractInstance(_address: AztecAddress): Promise { throw new OracleMethodNotAvailableError('getContractInstance'); } @@ -140,10 +136,6 @@ export abstract class TypedOracle { throw new OracleMethodNotAvailableError('popCapsule'); } - getPublicKeysForAddress(_address: AztecAddress): Promise { - throw new OracleMethodNotAvailableError('getPublicKeysForAddress'); - } - getNotes( _storageSlot: Fr, _numSelects: number, diff --git a/yarn-project/simulator/src/client/db_oracle.ts b/yarn-project/simulator/src/client/db_oracle.ts index a7e78619eb16..0fbdbd643645 100644 --- a/yarn-project/simulator/src/client/db_oracle.ts +++ b/yarn-project/simulator/src/client/db_oracle.ts @@ -8,7 +8,7 @@ import { import { type CompleteAddress, type Header } from '@aztec/circuits.js'; import { type FunctionArtifact, type FunctionSelector } from '@aztec/foundation/abi'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; -import { type Fr, type Point } from '@aztec/foundation/fields'; +import { type Fr } from '@aztec/foundation/fields'; import { type ContractInstance } from '@aztec/types/contracts'; import { type NoteData, type NullifierKeys } from '../acvm/index.js'; @@ -64,14 +64,6 @@ export interface DBOracle extends CommitmentsDB { */ popCapsule(): Promise; - /** - * Gets public keys for an address. - * @param The address to look up - * @returns The public keys for a specific address - * TODO(#5834): Replace with `getCompleteAddress`. - */ - getPublicKeysForAddress(address: AztecAddress): Promise; - /** * Retrieve nullifier keys associated with a specific account and app/contract address. * diff --git a/yarn-project/simulator/src/client/private_execution.test.ts b/yarn-project/simulator/src/client/private_execution.test.ts index 1037f15109e9..3f152e2e7bdf 100644 --- a/yarn-project/simulator/src/client/private_execution.test.ts +++ b/yarn-project/simulator/src/client/private_execution.test.ts @@ -4,6 +4,8 @@ import { type L1ToL2Message, Note, PackedValues, + PublicDataWitness, + SiblingPath, TxExecutionRequest, } from '@aztec/circuit-types'; import { @@ -17,9 +19,10 @@ import { Header, L1_TO_L2_MSG_TREE_HEIGHT, NOTE_HASH_TREE_HEIGHT, + PUBLIC_DATA_TREE_HEIGHT, PartialStateReference, PublicCallRequest, - type PublicKey, + PublicDataTreeLeafPreimage, StateReference, TxContext, computeAppNullifierSecretKey, @@ -39,7 +42,7 @@ import { Fr } from '@aztec/foundation/fields'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { type FieldsOf } from '@aztec/foundation/types'; import { openTmpStore } from '@aztec/kv-store/utils'; -import { type AppendOnlyTree, Pedersen, StandardTree, newTree } from '@aztec/merkle-tree'; +import { type AppendOnlyTree, INITIAL_LEAF, Pedersen, StandardTree, newTree } from '@aztec/merkle-tree'; import { ChildContractArtifact, ImportTestContractArtifact, @@ -79,14 +82,13 @@ describe('Private Execution test suite', () => { let ownerCompleteAddress: CompleteAddress; let recipientCompleteAddress: CompleteAddress; - let ownerMasterNullifierPublicKey: PublicKey; - let recipientMasterNullifierPublicKey: PublicKey; let ownerMasterNullifierSecretKey: GrumpkinPrivateKey; let recipientMasterNullifierSecretKey: GrumpkinPrivateKey; const treeHeights: { [name: string]: number } = { noteHash: NOTE_HASH_TREE_HEIGHT, l1ToL2Messages: L1_TO_L2_MSG_TREE_HEIGHT, + publicData: PUBLIC_DATA_TREE_HEIGHT, }; let trees: { [name: keyof typeof treeHeights]: AppendOnlyTree } = {}; @@ -139,7 +141,7 @@ describe('Private Execution test suite', () => { // Create a new snapshot. const newSnap = new AppendOnlyTreeSnapshot(Fr.fromBuffer(tree.getRoot(true)), Number(tree.getNumLeaves(true))); - if (name === 'noteHash' || name === 'l1ToL2Messages') { + if (name === 'noteHash' || name === 'l1ToL2Messages' || 'publicData') { header = new Header( header.lastArchive, header.contentCommitment, @@ -148,7 +150,7 @@ describe('Private Execution test suite', () => { new PartialStateReference( name === 'noteHash' ? newSnap : header.state.partial.noteHashTree, header.state.partial.nullifierTree, - header.state.partial.publicDataTree, + name === 'publicData' ? newSnap : header.state.partial.publicDataTree, ), ), header.globalVariables, @@ -175,42 +177,60 @@ describe('Private Execution test suite', () => { const ownerPartialAddress = Fr.random(); ownerCompleteAddress = CompleteAddress.fromSecretKeyAndPartialAddress(ownerSk, ownerPartialAddress); - - const allOwnerKeys = deriveKeys(ownerSk); - ownerMasterNullifierPublicKey = allOwnerKeys.masterNullifierPublicKey; - ownerMasterNullifierSecretKey = allOwnerKeys.masterNullifierSecretKey; + ownerMasterNullifierSecretKey = deriveKeys(ownerSk).masterNullifierSecretKey; const recipientPartialAddress = Fr.random(); recipientCompleteAddress = CompleteAddress.fromSecretKeyAndPartialAddress(recipientSk, recipientPartialAddress); - - const allRecipientKeys = deriveKeys(recipientSk); - recipientMasterNullifierPublicKey = allRecipientKeys.masterNullifierPublicKey; - recipientMasterNullifierSecretKey = allRecipientKeys.masterNullifierSecretKey; + recipientMasterNullifierSecretKey = deriveKeys(recipientSk).masterNullifierSecretKey; owner = ownerCompleteAddress.address; recipient = recipientCompleteAddress.address; }); - beforeEach(() => { + beforeEach(async () => { trees = {}; oracle = mock(); oracle.getNullifierKeys.mockImplementation((accountAddress: AztecAddress, contractAddress: AztecAddress) => { if (accountAddress.equals(ownerCompleteAddress.address)) { return Promise.resolve({ - masterNullifierPublicKey: ownerMasterNullifierPublicKey, + masterNullifierPublicKey: ownerCompleteAddress.masterNullifierPublicKey, appNullifierSecretKey: computeAppNullifierSecretKey(ownerMasterNullifierSecretKey, contractAddress), }); } if (accountAddress.equals(recipientCompleteAddress.address)) { return Promise.resolve({ - masterNullifierPublicKey: recipientMasterNullifierPublicKey, + masterNullifierPublicKey: recipientCompleteAddress.masterNullifierPublicKey, appNullifierSecretKey: computeAppNullifierSecretKey(recipientMasterNullifierSecretKey, contractAddress), }); } throw new Error(`Unknown address ${accountAddress}`); }); + + // We call insertLeaves here with no leaves to populate empty public data tree root --> this is necessary to be + // able to get ivpk_m during execution + await insertLeaves([], 'publicData'); oracle.getHeader.mockResolvedValue(header); + oracle.getCompleteAddress.mockImplementation((address: AztecAddress) => { + if (address.equals(owner)) { + return Promise.resolve(ownerCompleteAddress); + } + if (address.equals(recipient)) { + return Promise.resolve(recipientCompleteAddress); + } + throw new Error(`Unknown address ${address}`); + }); + // This oracle gets called when reading ivpk_m from key registry --> we return zero witness indicating that + // the keys were not registered. This triggers non-registered keys flows in which getCompleteAddress oracle + // gets called and we constrain the result by hashing address preimage and checking it matches. + oracle.getPublicDataTreeWitness.mockResolvedValue( + new PublicDataWitness( + 0n, + PublicDataTreeLeafPreimage.empty(), + SiblingPath.ZERO(PUBLIC_DATA_TREE_HEIGHT, INITIAL_LEAF, new Pedersen()), + ), + ); + acirSimulator = new AcirSimulator(oracle, node); }); @@ -286,16 +306,6 @@ describe('Private Execution test suite', () => { }; beforeEach(() => { - oracle.getCompleteAddress.mockImplementation((address: AztecAddress) => { - if (address.equals(owner)) { - return Promise.resolve(ownerCompleteAddress); - } - if (address.equals(recipient)) { - return Promise.resolve(recipientCompleteAddress); - } - throw new Error(`Unknown address ${address}`); - }); - oracle.getFunctionArtifactByName.mockImplementation((_, functionName: string) => Promise.resolve(getFunctionArtifact(StatefulTestContractArtifact, functionName)), ); @@ -555,15 +565,6 @@ describe('Private Execution test suite', () => { describe('consuming messages', () => { const contractAddress = defaultContractAddress; - beforeEach(() => { - oracle.getCompleteAddress.mockImplementation((address: AztecAddress) => { - if (address.equals(recipient)) { - return Promise.resolve(recipientCompleteAddress); - } - throw new Error(`Unknown address ${address}`); - }); - }); - describe('L1 to L2', () => { const artifact = getFunctionArtifact(TestContractArtifact, 'consume_mint_private_message'); let bridgedAmount = 100n; @@ -865,15 +866,6 @@ describe('Private Execution test suite', () => { }); describe('pending note hashes contract', () => { - beforeEach(() => { - oracle.getCompleteAddress.mockImplementation((address: AztecAddress) => { - if (address.equals(owner)) { - return Promise.resolve(ownerCompleteAddress); - } - throw new Error(`Unknown address ${address}`); - }); - }); - beforeEach(() => { oracle.getFunctionArtifact.mockImplementation((_, selector) => Promise.resolve(getFunctionArtifact(PendingNoteHashesContractArtifact, selector)), @@ -1045,15 +1037,15 @@ describe('Private Execution test suite', () => { }); }); - describe('get public key', () => { + describe('get master incoming viewing public key', () => { it('gets the public key for an address', async () => { // Tweak the contract artifact so we can extract return values - const artifact = getFunctionArtifact(TestContractArtifact, 'get_public_key'); + const artifact = getFunctionArtifact(TestContractArtifact, 'get_master_incoming_viewing_public_key'); // Generate a partial address, pubkey, and resulting address const completeAddress = CompleteAddress.random(); const args = [completeAddress.address]; - const pubKey = completeAddress.publicKey; + const pubKey = completeAddress.masterIncomingViewingPublicKey; oracle.getCompleteAddress.mockResolvedValue(completeAddress); const result = await runSimulator({ artifact, args }); diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index 50dc2552c25c..b4c020391752 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -166,16 +166,6 @@ export class ViewDataOracle extends TypedOracle { return this.db.popCapsule(); } - /** - * Gets public keys for an address. - * @param The address to look up - * @returns The public keys for a specific address - * TODO(#5834): Replace with `getCompleteAddress`. - */ - public override getPublicKeysForAddress(address: AztecAddress) { - return this.db.getPublicKeysForAddress(address); - } - /** * Gets some notes for a contract address and storage slot. * Returns a flattened array containing filtered notes.