From 3acc686698853c8add5af6602411bed798922783 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Mon, 22 Apr 2024 17:11:28 +0000 Subject: [PATCH 01/23] Initial --- noir-projects/aztec-nr/aztec/src/keys.nr | 3 + .../src/keys/assert_public_key_freshness.nr | 90 +++++++++++++++++++ noir-projects/aztec-nr/aztec/src/lib.nr | 1 + noir-projects/aztec-nr/aztec/src/oracle.nr | 1 + .../aztec-nr/aztec/src/oracle/keys.nr | 24 +++++ .../contracts/test_contract/src/main.nr | 2 +- .../pxe/src/simulator_oracle/index.ts | 10 +++ .../simulator/src/acvm/oracle/oracle.ts | 9 ++ .../simulator/src/acvm/oracle/typed_oracle.ts | 8 +- .../simulator/src/client/db_oracle.ts | 4 +- .../simulator/src/client/view_data_oracle.ts | 6 ++ 11 files changed, 155 insertions(+), 3 deletions(-) create mode 100644 noir-projects/aztec-nr/aztec/src/keys.nr create mode 100644 noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr create mode 100644 noir-projects/aztec-nr/aztec/src/oracle/keys.nr diff --git a/noir-projects/aztec-nr/aztec/src/keys.nr b/noir-projects/aztec-nr/aztec/src/keys.nr new file mode 100644 index 00000000000..ae78c653dd0 --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/keys.nr @@ -0,0 +1,3 @@ +mod assert_public_key_freshness; + +use crate::keys::assert_public_key_freshness::Map; diff --git a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr new file mode 100644 index 00000000000..f94806c935d --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr @@ -0,0 +1,90 @@ +use dep::protocol_types::{constants::{GENERATOR_INDEX__PUBLIC_KEYS_HASH, GENERATOR_INDEX__CONTRACT_ADDRESS_V1}, address::AztecAddress}; +use crate::context::PrivateContext; +use crate::note::{ + constants::{GET_NOTE_ORACLE_RETURN_LENGTH, MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH}, + note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus, PropertySelector}, + note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, + utils::compute_note_hash_for_consumption, +}; +use crate::state_vars::shared_mutable::shared_mutable_private_getter::SharedMutablePrivateGetter; +use crate::hash::pedersen_hash; +use dep::std::hash::poseidon2::Poseidon2::hash as poseidon2_hash; +use crate::oracle; + + +fn assert_nullifier_public_key_fresh( + context: &mut PrivateContext, + address: AztecAddress, + nullifier_public_key_to_test: Field +) { + // Canonical Key Registry + let contract_address_to_read = AztecAddress::from_field(123); + let storage_slot_of_nullifier_public_key = 1; + // We have to derive this slot to get the location of the shared mutable inside the Map + let derived_slot = pedersen_hash( + [storage_slot_of_nullifier_public_key, address.to_field()], + 0 + ); + + // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly + let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(*context, contract_address_to_read, derived_slot); + let nullifier_public_key = registry_private_getter.get_current_value_in_private(); + + if (nullifier_public_key == 0) { + check_key(address, 1, nullifier_public_key_to_test); + } else { + assert(nullifier_public_key == nullifier_public_key_to_test); + } +} + +fn check_key(address: AztecAddress, key_type: Field, key: Field) { + let mut keys = check_key_internal(address); + + keys[key_type] = key; + + _check_key_constrain_check_key_internal( + address, + keys[0], + keys[1], + keys[2], + keys[3], + keys[4], + ); +} + +unconstrained fn check_key_internal(address: AztecAddress) -> [Field; 5] { + let keys = oracle::keys::get_public_keys_for_address(address); + + keys +} + +fn _check_key_constrain_check_key_internal( + address: AztecAddress, + partial_address: Field, + nullifier_public_key: Field, + incoming_public_key: Field, + outgoing_public_key: Field, + tagging_public_key: Field + ) { + let public_keys_hash = poseidon2_hash([ + nullifier_public_key, + incoming_public_key, + outgoing_public_key, + tagging_public_key, + GENERATOR_INDEX__PUBLIC_KEYS_HASH, + ], + 5 + ); + + let computed_address = AztecAddress::from_field( + poseidon2_hash([ + partial_address.to_field(), + public_keys_hash.to_field(), + GENERATOR_INDEX__CONTRACT_ADDRESS_V1 as Field, + ], + 3 + ) + ); + + assert(computed_address.eq(address), "Computed address does not match supplied address"); +} diff --git a/noir-projects/aztec-nr/aztec/src/lib.nr b/noir-projects/aztec-nr/aztec/src/lib.nr index 81390fb52eb..67a3c8c55b4 100644 --- a/noir-projects/aztec-nr/aztec/src/lib.nr +++ b/noir-projects/aztec-nr/aztec/src/lib.nr @@ -3,6 +3,7 @@ mod deploy; mod hash; mod history; mod initializer; +mod keys; mod log; mod messaging; mod note; diff --git a/noir-projects/aztec-nr/aztec/src/oracle.nr b/noir-projects/aztec-nr/aztec/src/oracle.nr index 57415dc9575..41c6e37adfb 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle.nr @@ -10,6 +10,7 @@ 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; mod unsafe_rand; diff --git a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr new file mode 100644 index 00000000000..6894ccab3b0 --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr @@ -0,0 +1,24 @@ +use dep::protocol_types::address::AztecAddress; + +#[oracle(getPublicKeysForAddress)] +fn get_public_keys_for_address_oracle( + address: AztecAddress, +) -> [Field; 4] {} + +unconstrained fn get_public_keys_for_address_oracle_wrapper( + address: AztecAddress +) -> [Field; 4] { + get_public_keys_for_address_oracle( + address, + ) +} + +unconstrained pub fn get_public_keys_for_address( + address: AztecAddress, +) -> [Field; 4] { + let public_keys = get_public_keys_for_address_oracle_wrapper( + address, + ); + + public_keys +} 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 43a0d80c528..d03ef87095d 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -389,7 +389,7 @@ contract Test { 0 ); // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly - let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(context, contract_address_to_read, derived_slot); + let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(context, contract_address_to_read, derived_slot); let nullifier_public_key = registry_private_getter.get_current_value_in_private(); context.emit_unencrypted_log(nullifier_public_key); diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index da0891190f6..ea9b08a033e 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -9,6 +9,7 @@ import { type SiblingPath, } from '@aztec/circuit-types'; import { + Point, type AztecAddress, type CompleteAddress, type EthAddress, @@ -78,6 +79,15 @@ export class SimulatorOracle implements DBOracle { return capsule; } + 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/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index f1271b791dd..fa0dbc6a149 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -172,6 +172,15 @@ export class Oracle { return capsule.map(toACVMField); } + async getPublicKeysForAddress( + [address]: ACVMField[], + ): Promise { + const keys = await this.typedOracle.getPublicKeysForAddress(AztecAddress.fromField(fromACVMField(address))); + const acvmKeys = keys?.flatMap(key => key.toFields().map(f => toACVMField(f))) ?? Array(8).fill(toACVMField(0)); + + return acvmKeys; + } + async getNotes( [storageSlot]: ACVMField[], [numSelects]: ACVMField[], diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 70f57233af1..28ed6f9d4a1 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 } from '@aztec/foundation/fields'; +import { Fr, Point } from '@aztec/foundation/fields'; import { type ContractInstance } from '@aztec/types/contracts'; /** Nullifier keys which both correspond to the same master nullifier secret key. */ @@ -140,6 +140,12 @@ 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 3c3d5126814..3e193b56472 100644 --- a/yarn-project/simulator/src/client/db_oracle.ts +++ b/yarn-project/simulator/src/client/db_oracle.ts @@ -9,7 +9,7 @@ import { type CompleteAddress, type Header } from '@aztec/circuits.js'; import { type FunctionArtifactWithDebugMetadata, type FunctionSelector } from '@aztec/foundation/abi'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; import { type EthAddress } from '@aztec/foundation/eth-address'; -import { type Fr } from '@aztec/foundation/fields'; +import { Point, type Fr } from '@aztec/foundation/fields'; import { type ContractInstance } from '@aztec/types/contracts'; import { type NoteData, type NullifierKeys } from '../acvm/index.js'; @@ -65,6 +65,8 @@ export interface DBOracle extends CommitmentsDB { */ popCapsule(): Promise; + getPublicKeysForAddress(address: AztecAddress): Promise; + /** * Retrieve nullifier keys associated with a specific account and app/contract address. * diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index b4c02039175..00bb685e8c8 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -166,6 +166,12 @@ export class ViewDataOracle extends TypedOracle { return this.db.popCapsule(); } + 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. From 177445f1b16b6e9d1a0c31c30c9d588b9c1ad62a Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Mon, 22 Apr 2024 19:09:35 +0000 Subject: [PATCH 02/23] fix --- .../src/keys/assert_public_key_freshness.nr | 43 +++++++++++-------- .../aztec-nr/aztec/src/oracle/keys.nr | 31 +++++++++++-- 2 files changed, 51 insertions(+), 23 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr index f94806c935d..a48175d30ce 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::{constants::{GENERATOR_INDEX__PUBLIC_KEYS_HASH, GENERATOR_INDEX__CONTRACT_ADDRESS_V1}, address::AztecAddress}; +use dep::protocol_types::{constants::{GENERATOR_INDEX__PUBLIC_KEYS_HASH, GENERATOR_INDEX__CONTRACT_ADDRESS_V1}, address::AztecAddress, grumpkin_point::GrumpkinPoint}; use crate::context::PrivateContext; use crate::note::{ constants::{GET_NOTE_ORACLE_RETURN_LENGTH, MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH}, @@ -15,7 +15,7 @@ use crate::oracle; fn assert_nullifier_public_key_fresh( context: &mut PrivateContext, address: AztecAddress, - nullifier_public_key_to_test: Field + nullifier_public_key_to_test: GrumpkinPoint, ) { // Canonical Key Registry let contract_address_to_read = AztecAddress::from_field(123); @@ -28,52 +28,57 @@ fn assert_nullifier_public_key_fresh( // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(*context, contract_address_to_read, derived_slot); - let nullifier_public_key = registry_private_getter.get_current_value_in_private(); + let hashed_nullifier_public_key = registry_private_getter.get_current_value_in_private(); - if (nullifier_public_key == 0) { + if (hashed_nullifier_public_key == 0) { check_key(address, 1, nullifier_public_key_to_test); } else { - assert(nullifier_public_key == nullifier_public_key_to_test); + assert(hashed_nullifier_public_key == pedersen_hash(nullifier_public_key_to_test.serialize(), 0)); } } -fn check_key(address: AztecAddress, key_type: Field, key: Field) { - let mut keys = check_key_internal(address); +fn check_key(address: AztecAddress, key_type: Field, key: GrumpkinPoint) { + let mut (partial_address, keys) = check_key_internal(address); keys[key_type] = key; _check_key_constrain_check_key_internal( address, + partial_address, keys[0], keys[1], keys[2], keys[3], - keys[4], ); } -unconstrained fn check_key_internal(address: AztecAddress) -> [Field; 5] { +unconstrained fn check_key_internal(address: AztecAddress) -> (Field, [GrumpkinPoint; 4]) { let keys = oracle::keys::get_public_keys_for_address(address); + let partial_address = oracle::keys::get_address_metadata(address); - keys + (partial_address, keys) } fn _check_key_constrain_check_key_internal( address: AztecAddress, partial_address: Field, - nullifier_public_key: Field, - incoming_public_key: Field, - outgoing_public_key: Field, - tagging_public_key: Field + nullifier_public_key: GrumpkinPoint, + incoming_public_key: GrumpkinPoint, + outgoing_public_key: GrumpkinPoint, + tagging_public_key: GrumpkinPoint ) { let public_keys_hash = poseidon2_hash([ - nullifier_public_key, - incoming_public_key, - outgoing_public_key, - tagging_public_key, + nullifier_public_key.serialize()[0], + nullifier_public_key.serialize()[1], + incoming_public_key.serialize()[0], + incoming_public_key.serialize()[1], + outgoing_public_key.serialize()[0], + outgoing_public_key.serialize()[1], + tagging_public_key.serialize()[0], + tagging_public_key.serialize()[1], GENERATOR_INDEX__PUBLIC_KEYS_HASH, ], - 5 + 9 ); let computed_address = AztecAddress::from_field( diff --git a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr index 6894ccab3b0..44bb1cf5b96 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr @@ -1,13 +1,13 @@ -use dep::protocol_types::address::AztecAddress; +use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}; #[oracle(getPublicKeysForAddress)] fn get_public_keys_for_address_oracle( address: AztecAddress, -) -> [Field; 4] {} +) -> [GrumpkinPoint; 4] {} unconstrained fn get_public_keys_for_address_oracle_wrapper( address: AztecAddress -) -> [Field; 4] { +) -> [GrumpkinPoint; 4] { get_public_keys_for_address_oracle( address, ) @@ -15,10 +15,33 @@ unconstrained fn get_public_keys_for_address_oracle_wrapper( unconstrained pub fn get_public_keys_for_address( address: AztecAddress, -) -> [Field; 4] { +) -> [GrumpkinPoint; 4] { let public_keys = get_public_keys_for_address_oracle_wrapper( address, ); public_keys } + +#[oracle(getAddressMetadata)] +fn get_address_metadata_oracle( + address: AztecAddress, +) -> [Field; 1] {} + +unconstrained fn get_address_metadata_oracle_wrapper( + address: AztecAddress +) -> [Field; 1] { + get_address_metadata_oracle( + address, + ) +} + +unconstrained pub fn get_address_metadata( + address: AztecAddress, +) -> Field { + let partial_address = get_address_metadata_oracle_wrapper( + address, + ); + + partial_address[0] +} From fdbb60a11942d5c8472f73e5e596ef48a5657cc3 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Mon, 22 Apr 2024 20:55:26 +0000 Subject: [PATCH 03/23] good --- noir-projects/aztec-nr/aztec/src/keys.nr | 2 +- .../src/keys/assert_public_key_freshness.nr | 13 ++++--- .../aztec-nr/aztec/src/oracle/keys.nr | 36 +++++++++---------- yarn-project/circuit-types/src/keys/index.ts | 1 + yarn-project/key-store/src/address_book.ts | 25 +++++++++++++ yarn-project/key-store/src/index.ts | 1 + .../pxe/src/simulator_oracle/index.ts | 2 +- .../simulator/src/acvm/oracle/oracle.ts | 15 ++++---- .../simulator/src/acvm/oracle/typed_oracle.ts | 6 ++++ .../simulator/src/client/db_oracle.ts | 2 ++ 10 files changed, 70 insertions(+), 33 deletions(-) create mode 100644 yarn-project/key-store/src/address_book.ts diff --git a/noir-projects/aztec-nr/aztec/src/keys.nr b/noir-projects/aztec-nr/aztec/src/keys.nr index ae78c653dd0..7e83884a099 100644 --- a/noir-projects/aztec-nr/aztec/src/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/keys.nr @@ -1,3 +1,3 @@ mod assert_public_key_freshness; -use crate::keys::assert_public_key_freshness::Map; +use crate::keys::assert_public_key_freshness::assert_nullifier_public_key_fresh; diff --git a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr index a48175d30ce..80f218ce3bd 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::{constants::{GENERATOR_INDEX__PUBLIC_KEYS_HASH, GENERATOR_INDEX__CONTRACT_ADDRESS_V1}, address::AztecAddress, grumpkin_point::GrumpkinPoint}; +use dep::protocol_types::{constants::{GENERATOR_INDEX__PUBLIC_KEYS_HASH, GENERATOR_INDEX__CONTRACT_ADDRESS_V1}, address::{AztecAddress, PartialAddress}, grumpkin_point::GrumpkinPoint}; use crate::context::PrivateContext; use crate::note::{ constants::{GET_NOTE_ORACLE_RETURN_LENGTH, MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH}, @@ -40,7 +40,7 @@ fn assert_nullifier_public_key_fresh( fn check_key(address: AztecAddress, key_type: Field, key: GrumpkinPoint) { let mut (partial_address, keys) = check_key_internal(address); - keys[key_type] = key; + assert(keys[key_type].eq(key)); _check_key_constrain_check_key_internal( address, @@ -52,16 +52,15 @@ fn check_key(address: AztecAddress, key_type: Field, key: GrumpkinPoint) { ); } -unconstrained fn check_key_internal(address: AztecAddress) -> (Field, [GrumpkinPoint; 4]) { - let keys = oracle::keys::get_public_keys_for_address(address); - let partial_address = oracle::keys::get_address_metadata(address); +unconstrained fn check_key_internal(address: AztecAddress) -> (PartialAddress, [GrumpkinPoint; 4]) { + let (partial_address, public_keys) = oracle::keys::get_public_keys_and_partial_address(address); - (partial_address, keys) + (partial_address, public_keys) } fn _check_key_constrain_check_key_internal( address: AztecAddress, - partial_address: Field, + partial_address: PartialAddress, nullifier_public_key: GrumpkinPoint, incoming_public_key: GrumpkinPoint, outgoing_public_key: GrumpkinPoint, diff --git a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr index 44bb1cf5b96..4ff757be4d4 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr @@ -1,4 +1,4 @@ -use dep::protocol_types::{address::AztecAddress, grumpkin_point::GrumpkinPoint}; +use dep::protocol_types::{address::{AztecAddress, PartialAddress, PublicKeysHash}, grumpkin_point::GrumpkinPoint}; #[oracle(getPublicKeysForAddress)] fn get_public_keys_for_address_oracle( @@ -23,25 +23,25 @@ unconstrained pub fn get_public_keys_for_address( public_keys } -#[oracle(getAddressMetadata)] -fn get_address_metadata_oracle( - address: AztecAddress, -) -> [Field; 1] {} -unconstrained fn get_address_metadata_oracle_wrapper( - address: AztecAddress -) -> [Field; 1] { - get_address_metadata_oracle( - address, - ) +#[oracle(getPublicKeysAndPartialAddress)] +fn get_public_keys_and_partial_address_oracle(_address: AztecAddress) -> [Field; 9] {} + +unconstrained fn get_public_keys_and_partial_address_oracle_wrapper(address: AztecAddress) -> [Field; 9] { + get_public_keys_and_partial_address_oracle(address) } -unconstrained pub fn get_address_metadata( - address: AztecAddress, -) -> Field { - let partial_address = get_address_metadata_oracle_wrapper( - address, - ); +pub fn get_public_keys_and_partial_address(address: AztecAddress) -> (PartialAddress, [GrumpkinPoint; 4]) { + let result = get_public_keys_and_partial_address_oracle_wrapper(address); + let partial_address = PartialAddress::from_field(result[0]); + let nullifier_pub_key = GrumpkinPoint::new(result[1], result[2]); + let incoming_pub_key = GrumpkinPoint::new(result[3], result[4]); + let outgoing_pub_key = GrumpkinPoint::new(result[5], result[6]); + let tagging_pub_key = GrumpkinPoint::new(result[7], result[8]); + + // 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)); - partial_address[0] + (partial_address, [nullifier_pub_key, incoming_pub_key, outgoing_pub_key, tagging_pub_key]) } diff --git a/yarn-project/circuit-types/src/keys/index.ts b/yarn-project/circuit-types/src/keys/index.ts index f137b0d567a..02ea81b3bcc 100644 --- a/yarn-project/circuit-types/src/keys/index.ts +++ b/yarn-project/circuit-types/src/keys/index.ts @@ -1,2 +1,3 @@ export * from './key_pair.js'; export * from './key_store.js'; +export * from './address_book.js'; diff --git a/yarn-project/key-store/src/address_book.ts b/yarn-project/key-store/src/address_book.ts new file mode 100644 index 00000000000..8264007f396 --- /dev/null +++ b/yarn-project/key-store/src/address_book.ts @@ -0,0 +1,25 @@ +import { + Fr, + type AztecAddress, + type PartialAddress, +} from '@aztec/circuits.js'; +import { type AddressBook } from '@aztec/circuit-types'; +import { AztecKVStore, AztecMap } from '@aztec/kv-store'; + + +export class KVAddressBook implements AddressBook { + #addressMetadata: AztecMap; + + constructor(database: AztecKVStore) { + this.#addressMetadata = database.openMap('address_book'); + } + + public async addPartialAddress(partialAddress: PartialAddress, address: AztecAddress) { + await this.#addressMetadata.set(address.toString(), partialAddress.toBuffer()); + } + + getPartialAddress(address: AztecAddress): PartialAddress | undefined { + const partialBuf = this.#addressMetadata.get(address.toString()); + return partialBuf === undefined ? undefined : Fr.fromBuffer(partialBuf); + }; +} \ No newline at end of file diff --git a/yarn-project/key-store/src/index.ts b/yarn-project/key-store/src/index.ts index e4ae5ce271c..4f06a44db34 100644 --- a/yarn-project/key-store/src/index.ts +++ b/yarn-project/key-store/src/index.ts @@ -1 +1,2 @@ export * from './test_key_store.js'; +export * from './address_book.js'; diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index ea9b08a033e..56c53a2d806 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -9,11 +9,11 @@ import { type SiblingPath, } from '@aztec/circuit-types'; import { + Fr, Point, type AztecAddress, type CompleteAddress, type EthAddress, - type Fr, type FunctionSelector, type Header, type L1_TO_L2_MSG_TREE_HEIGHT, diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index fa0dbc6a149..02f820666fd 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -53,6 +53,7 @@ export class Oracle { ]; } + // TODO (ek): Nuke this async getPublicKeyAndPartialAddress([address]: ACVMField[]) { const { publicKey, partialAddress } = await this.typedOracle.getCompleteAddress( AztecAddress.fromField(fromACVMField(address)), @@ -172,13 +173,15 @@ export class Oracle { return capsule.map(toACVMField); } - async getPublicKeysForAddress( - [address]: ACVMField[], - ): Promise { - const keys = await this.typedOracle.getPublicKeysForAddress(AztecAddress.fromField(fromACVMField(address))); - const acvmKeys = keys?.flatMap(key => key.toFields().map(f => toACVMField(f))) ?? Array(8).fill(toACVMField(0)); + async getPublicKeysAndPartialAddress([address]: ACVMField[]): Promise { + const { partialAddress } = await this.typedOracle.getCompleteAddress( + AztecAddress.fromField(fromACVMField(address)), + ); + + const publicKeys = await this.typedOracle.getPublicKeysForAddress(AztecAddress.fromField(fromACVMField(address))); + const acvmKeys = publicKeys?.flatMap(key => key.toFields()) ?? Array(8).fill(toACVMField(0)); - return acvmKeys; + return [partialAddress, ...acvmKeys].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 28ed6f9d4a1..86b3d5d6439 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -146,6 +146,12 @@ export abstract class TypedOracle { throw new OracleMethodNotAvailableError('getPublicKeysForAddress'); } + async getAddressMetadata( + _address: AztecAddress, + ): Promise { + throw new OracleMethodNotAvailableError('getAddressMetadata'); + } + 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 3e193b56472..b8d56098703 100644 --- a/yarn-project/simulator/src/client/db_oracle.ts +++ b/yarn-project/simulator/src/client/db_oracle.ts @@ -67,6 +67,8 @@ export interface DBOracle extends CommitmentsDB { getPublicKeysForAddress(address: AztecAddress): Promise; + getAddressMetadata(address: AztecAddress): Promise; + /** * Retrieve nullifier keys associated with a specific account and app/contract address. * From 2d3a95f66de8c88538480f8f1bb1a75223490f90 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Mon, 22 Apr 2024 20:58:38 +0000 Subject: [PATCH 04/23] asdf --- yarn-project/circuit-types/src/keys/index.ts | 1 - yarn-project/key-store/src/address_book.ts | 25 -------------------- yarn-project/key-store/src/index.ts | 1 - 3 files changed, 27 deletions(-) delete mode 100644 yarn-project/key-store/src/address_book.ts diff --git a/yarn-project/circuit-types/src/keys/index.ts b/yarn-project/circuit-types/src/keys/index.ts index 02ea81b3bcc..f137b0d567a 100644 --- a/yarn-project/circuit-types/src/keys/index.ts +++ b/yarn-project/circuit-types/src/keys/index.ts @@ -1,3 +1,2 @@ export * from './key_pair.js'; export * from './key_store.js'; -export * from './address_book.js'; diff --git a/yarn-project/key-store/src/address_book.ts b/yarn-project/key-store/src/address_book.ts deleted file mode 100644 index 8264007f396..00000000000 --- a/yarn-project/key-store/src/address_book.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { - Fr, - type AztecAddress, - type PartialAddress, -} from '@aztec/circuits.js'; -import { type AddressBook } from '@aztec/circuit-types'; -import { AztecKVStore, AztecMap } from '@aztec/kv-store'; - - -export class KVAddressBook implements AddressBook { - #addressMetadata: AztecMap; - - constructor(database: AztecKVStore) { - this.#addressMetadata = database.openMap('address_book'); - } - - public async addPartialAddress(partialAddress: PartialAddress, address: AztecAddress) { - await this.#addressMetadata.set(address.toString(), partialAddress.toBuffer()); - } - - getPartialAddress(address: AztecAddress): PartialAddress | undefined { - const partialBuf = this.#addressMetadata.get(address.toString()); - return partialBuf === undefined ? undefined : Fr.fromBuffer(partialBuf); - }; -} \ No newline at end of file diff --git a/yarn-project/key-store/src/index.ts b/yarn-project/key-store/src/index.ts index 4f06a44db34..e4ae5ce271c 100644 --- a/yarn-project/key-store/src/index.ts +++ b/yarn-project/key-store/src/index.ts @@ -1,2 +1 @@ export * from './test_key_store.js'; -export * from './address_book.js'; From 58f9650f88539f852a1c5e029743e958b42fdd3e Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Tue, 23 Apr 2024 15:13:24 +0000 Subject: [PATCH 05/23] working tests --- .../src/keys/assert_public_key_freshness.nr | 54 ++- .../key_registry_contract/src/main.nr | 46 +- .../contracts/test_contract/src/main.nr | 13 +- .../types/src/address/partial_address.nr | 4 + .../circuit-types/src/interfaces/pxe.ts | 5 +- .../circuit-types/src/keys/key_store.ts | 12 + .../end-to-end/src/e2e_key_registry.test.ts | 417 +++++++++++------- yarn-project/key-store/src/test_key_store.ts | 13 + .../pxe/src/pxe_service/pxe_service.ts | 9 +- .../simulator/src/acvm/oracle/oracle.ts | 26 +- .../simulator/src/acvm/oracle/typed_oracle.ts | 8 +- .../simulator/src/client/db_oracle.ts | 2 - 12 files changed, 382 insertions(+), 227 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr index 80f218ce3bd..5390a2b7848 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr @@ -1,4 +1,7 @@ -use dep::protocol_types::{constants::{GENERATOR_INDEX__PUBLIC_KEYS_HASH, GENERATOR_INDEX__CONTRACT_ADDRESS_V1}, address::{AztecAddress, PartialAddress}, grumpkin_point::GrumpkinPoint}; +use dep::protocol_types::{ + constants::{ + GENERATOR_INDEX__PUBLIC_KEYS_HASH, GENERATOR_INDEX__CONTRACT_ADDRESS_V1}, + address::{AztecAddress, PartialAddress}, grumpkin_point::GrumpkinPoint}; use crate::context::PrivateContext; use crate::note::{ constants::{GET_NOTE_ORACLE_RETURN_LENGTH, MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH}, @@ -7,18 +10,28 @@ use crate::note::{ utils::compute_note_hash_for_consumption, }; use crate::state_vars::shared_mutable::shared_mutable_private_getter::SharedMutablePrivateGetter; -use crate::hash::pedersen_hash; -use dep::std::hash::poseidon2::Poseidon2::hash as poseidon2_hash; +use crate::hash::{pedersen_hash, poseidon2_hash}; use crate::oracle; +struct PublicKeyTypeEnum { + NULLIFIER: u8, + INCOMING: u8, +} + +global PublicKeyType = PublicKeyTypeEnum { + NULLIFIER: 0, + INCOMING: 1, +}; -fn assert_nullifier_public_key_fresh( +pub fn assert_nullifier_public_key_fresh( context: &mut PrivateContext, address: AztecAddress, nullifier_public_key_to_test: GrumpkinPoint, + // remove after + registry_contract_address: AztecAddress, ) { // Canonical Key Registry - let contract_address_to_read = AztecAddress::from_field(123); + let contract_address_to_read = registry_contract_address; let storage_slot_of_nullifier_public_key = 1; // We have to derive this slot to get the location of the shared mutable inside the Map let derived_slot = pedersen_hash( @@ -31,15 +44,22 @@ fn assert_nullifier_public_key_fresh( let hashed_nullifier_public_key = registry_private_getter.get_current_value_in_private(); if (hashed_nullifier_public_key == 0) { - check_key(address, 1, nullifier_public_key_to_test); + check_key(address, PublicKeyType.NULLIFIER, nullifier_public_key_to_test); } else { - assert(hashed_nullifier_public_key == pedersen_hash(nullifier_public_key_to_test.serialize(), 0)); + assert(hashed_nullifier_public_key == poseidon2_hash(nullifier_public_key_to_test.serialize())); } } -fn check_key(address: AztecAddress, key_type: Field, key: GrumpkinPoint) { +fn check_key(address: AztecAddress, key_type: u8, key: GrumpkinPoint) { let mut (partial_address, keys) = check_key_internal(address); + crate::oracle::debug_log::debug_log_array_with_prefix("partial", [partial_address]); + crate::oracle::debug_log::debug_log_array_with_prefix("ACTUAL NULLIFIER", key.serialize()); + crate::oracle::debug_log::debug_log_array_with_prefix("nullifier", keys[0].serialize()); + crate::oracle::debug_log::debug_log_array_with_prefix("incoming", keys[1].serialize()); + crate::oracle::debug_log::debug_log_array_with_prefix("outgoing", keys[2].serialize()); + crate::oracle::debug_log::debug_log_array_with_prefix("tagging", keys[3].serialize()); + assert(keys[key_type].eq(key)); _check_key_constrain_check_key_internal( @@ -49,7 +69,7 @@ fn check_key(address: AztecAddress, key_type: Field, key: GrumpkinPoint) { keys[1], keys[2], keys[3], - ); + ) } unconstrained fn check_key_internal(address: AztecAddress) -> (PartialAddress, [GrumpkinPoint; 4]) { @@ -76,19 +96,15 @@ fn _check_key_constrain_check_key_internal( tagging_public_key.serialize()[0], tagging_public_key.serialize()[1], GENERATOR_INDEX__PUBLIC_KEYS_HASH, - ], - 9 - ); + ]); let computed_address = AztecAddress::from_field( poseidon2_hash([ - partial_address.to_field(), - public_keys_hash.to_field(), - GENERATOR_INDEX__CONTRACT_ADDRESS_V1 as Field, - ], - 3 - ) + partial_address.to_field(), + public_keys_hash.to_field(), + GENERATOR_INDEX__CONTRACT_ADDRESS_V1, + ]) ); - assert(computed_address.eq(address), "Computed address does not match supplied address"); + assert(computed_address.eq(address)); } 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 d4ed6addd03..c0e2ff7e8af 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 @@ -10,6 +10,7 @@ contract KeyRegistry { protocol_types::{ abis::function_selector::FunctionSelector, contract_class_id::ContractClassId, + grumpkin_point::GrumpkinPoint, address::{ AztecAddress, EthAddress, @@ -34,19 +35,19 @@ contract KeyRegistry { struct Storage { // We are not supporting rotating / changing keys other than the nullifier public in the registry at the moment, but will in the future. // Uncomment lines below to enable that functionality - nullifier_public_key_registry: Map>, + nullifier_public_key_hash_registry: Map>, // incoming_public_key_registry: Map>, // outgoing_public_key_registry: Map>, // tagging_public_key_registry: Map>, } #[aztec(public)] - fn rotate_nullifier_public_key( + fn rotate_nullifier_public_key_hash( address: AztecAddress, - new_nullifier_public_key: Field, + new_nullifier_public_key_hash: Field, ) { assert( - new_nullifier_public_key != 0, + new_nullifier_public_key_hash != 0, "New nullifier public key must be non-zero" ); @@ -54,25 +55,26 @@ contract KeyRegistry { assert_current_call_valid_authwit_public(&mut context, address); } - let nullifier_key_registry = storage.nullifier_public_key_registry.at(address); + let nullifier_key_registry = storage.nullifier_public_key_hash_registry.at(address); - nullifier_key_registry.schedule_value_change(new_nullifier_public_key); + nullifier_key_registry.schedule_value_change(new_nullifier_public_key_hash); } #[aztec(public)] fn register( address: AztecAddress, partial_address: PartialAddress, - nullifier_public_key: Field, - incoming_public_key: Field, - outgoing_public_key: Field, - tagging_public_key: Field, + nullifier_public_key: GrumpkinPoint, + incoming_public_key: GrumpkinPoint, + outgoing_public_key: GrumpkinPoint, + tagging_public_key: GrumpkinPoint, ) { assert( - (nullifier_public_key != 0) & - (incoming_public_key != 0) & - (outgoing_public_key != 0) & - (tagging_public_key != 0), + !partial_address.is_zero() & + !nullifier_public_key.is_zero() & + !incoming_public_key.is_zero() & + !outgoing_public_key.is_zero() & + !tagging_public_key.is_zero(), "All public keys must be non-zero" ); @@ -81,10 +83,14 @@ contract KeyRegistry { // let address = AztecAddress::compute(public_keys_hash, partial_address); // We could also pass in original_public_keys_hash instead of computing it here, if all we need the original one is for being able to prove ownership of address let public_keys_hash = poseidon2_hash([ - nullifier_public_key, - incoming_public_key, - outgoing_public_key, - tagging_public_key, + nullifier_public_key.serialize()[0], + nullifier_public_key.serialize()[1], + incoming_public_key.serialize()[0], + incoming_public_key.serialize()[1], + outgoing_public_key.serialize()[0], + outgoing_public_key.serialize()[1], + tagging_public_key.serialize()[0], + tagging_public_key.serialize()[1], GENERATOR_INDEX__PUBLIC_KEYS_HASH, ] ); @@ -100,14 +106,14 @@ contract KeyRegistry { assert(computed_address.eq(address), "Computed address does not match supplied address"); - let nullifier_key_registry = storage.nullifier_public_key_registry.at(address); + let nullifier_key_hash_registry = storage.nullifier_public_key_hash_registry.at(address); // We are not supporting rotating / changing keys other than the nullifier public in the registry at the moment, but will in the future. // Uncomment lines below to enable that functionality // let incoming_key_registry = storage.incoming_public_key_registry.at(address); // let outgoing_key_registry = storage.outgoing_public_key_registry.at(address); // let tagging_key_registry = storage.taggin_public_key_registry.at(address); - nullifier_key_registry.schedule_value_change(nullifier_public_key); + nullifier_key_hash_registry.schedule_value_change(poseidon2_hash(nullifier_public_key.serialize())); // We are not supporting rotating / changing keys other than the nullifier public in the registry at the moment, but will in the future. // Uncomment lines below to enable that functionality // incoming_key_registry.schedule_value_change(new_incoming_public_key); // outgoing_key_registry.schedule_value_change(new_outgoing_public_key); 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 d03ef87095d..982a6b36e79 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -7,7 +7,8 @@ contract Test { use dep::aztec::protocol_types::{ abis::private_circuit_public_inputs::PrivateCircuitPublicInputs, - constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, traits::Serialize + constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, traits::Serialize, + grumpkin_point::GrumpkinPoint }; use dep::aztec::note::constants::MAX_NOTES_PER_PAGE; @@ -15,6 +16,7 @@ contract Test { use dep::aztec::state_vars::shared_mutable::SharedMutablePrivateGetter; use dep::aztec::{ + keys::assert_public_key_freshness::assert_nullifier_public_key_fresh, context::{Context, inputs::private_context_inputs::PrivateContextInputs}, hash::{pedersen_hash, compute_secret_hash, ArgsHasher}, note::{ @@ -411,6 +413,15 @@ contract Test { context.emit_unencrypted_log(authorized); } + #[aztec(private)] + fn test_nullifier_key_freshness( + address: AztecAddress, + public_nullifying_key: GrumpkinPoint, + key_registry_contract: AztecAddress, + ) { + assert_nullifier_public_key_fresh(&mut context, address, public_nullifying_key, key_registry_contract); + } + #[aztec(public)] fn delay() { // We use this as a util function to "mine a block" diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr b/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr index 359fae794ba..b7b6b7caec1 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/address/partial_address.nr @@ -69,6 +69,10 @@ impl PartialAddress { self.inner } + pub fn is_zero(self) -> bool { + self.to_field() == 0 + } + pub fn assert_is_zero(self) { assert(self.to_field() == 0); } diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 0eba3e00512..b1f0fb0327c 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 } from '@aztec/circuits.js'; +import { Point, 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,7 +73,8 @@ 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. */ - registerRecipient(recipient: CompleteAddress): Promise; + // TODO: FIX THIS AFTER THE COMPLETE ADDRESS REFACTOR + registerRecipient(recipient: CompleteAddress, publicKeys?: Point[]): Promise; /** * Retrieves the user accounts 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 55c69f0facb..f670683d905 100644 --- a/yarn-project/circuit-types/src/keys/key_store.ts +++ b/yarn-project/circuit-types/src/keys/key_store.ts @@ -1,4 +1,5 @@ import { + Point, type AztecAddress, type Fr, type GrumpkinPrivateKey, @@ -116,4 +117,15 @@ export interface KeyStore { * @returns A Promise that resolves to the public keys hash. */ getPublicKeysHash(account: AztecAddress): Promise; + + /** + * + */ + addPublicKeysForAccount( + accountAddress: AztecAddress, + masterNullifierPublicKey: Point, + masterIncomingViewingPublicKey: Point, + masterOutgoingViewingPublicKey: Point, + masterTaggingPublicKey: Point, + ): Promise; } 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 37f6ac8cea5..6418d9924e1 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,5 +1,5 @@ import { type AccountWallet, AztecAddress, Fr, type PXE } from '@aztec/aztec.js'; -import { GeneratorIndex } from '@aztec/circuits.js'; +import { CompleteAddress, GeneratorIndex, PartialAddress, Point } from '@aztec/circuits.js'; import { poseidon2Hash } from '@aztec/foundation/crypto'; import { KeyRegistryContract, TestContract } from '@aztec/noir-contracts.js'; @@ -35,102 +35,245 @@ describe('SharedMutablePrivateGetter', () => { afterAll(() => teardown()); - describe('failure cases', () => { - let accountAddedToRegistry: AztecAddress; - - describe('should fail registering with bad input', () => { - const partialAddress = new Fr(69); - - const masterNullifierPublicKey = new Fr(12); - const masterIncomingViewingPublicKey = new Fr(34); - const masterOutgoingViewingPublicKey = new Fr(56); - const masterTaggingPublicKey = new Fr(78); - - // TODO(#5726): use computePublicKeysHash function - const publicKeysHash = poseidon2Hash([ - masterNullifierPublicKey, - masterIncomingViewingPublicKey, - masterOutgoingViewingPublicKey, - masterTaggingPublicKey, - GeneratorIndex.PUBLIC_KEYS_HASH, - ]); - - // We hash the partial address and the public keys hash to get the account address - // TODO(#5726): Move the following line to AztecAddress class? - accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); - - it('should fail registering with mismatched address', async () => { - const mismatchedAddress = Fr.random(); - - await expect( - keyRegistry - .withWallet(wallets[0]) - .methods.register( - AztecAddress.fromField(mismatchedAddress), - partialAddress, - masterNullifierPublicKey, - masterIncomingViewingPublicKey, - masterOutgoingViewingPublicKey, - masterTaggingPublicKey, - ) - .send() - .wait(), - ).rejects.toThrow('Computed address does not match supplied address'); - }); - - it('should fail registering with mismatched nullifier public key', async () => { - const mismatchedMasterNullifierPublicKey = Fr.random(); - - await expect( - keyRegistry - .withWallet(wallets[0]) - .methods.register( - AztecAddress.fromField(accountAddedToRegistry), - partialAddress, - mismatchedMasterNullifierPublicKey, - masterIncomingViewingPublicKey, - masterOutgoingViewingPublicKey, - masterTaggingPublicKey, - ) - .send() - .wait(), - ).rejects.toThrow('Computed address does not match supplied address'); - }); - }); - - describe('should fail when rotating keys with bad input', () => { - it('should fail when trying to rotate setting a 0 key', async () => { - await expect( - keyRegistry - .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), new Fr(0)) - .send() - .wait(), - ).rejects.toThrow('New nullifier public key must be non-zero'); - }); - - it('should fail when trying to rotate for another address without authwit', async () => { - await expect( - keyRegistry - .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[1].getAddress(), new Fr(2)) - .send() - .wait(), - ).rejects.toThrow('Assertion failed: Message not authorized by account'); - }); - }); - }); + // describe('failure cases', () => { + // let accountAddedToRegistry: AztecAddress; + + // describe('should fail registering with bad input', () => { + // const partialAddress = new Fr(69); + + // const masterNullifierPublicKey = new Fr(12); + // const masterIncomingViewingPublicKey = new Fr(34); + // const masterOutgoingViewingPublicKey = new Fr(56); + // const masterTaggingPublicKey = new Fr(78); + + // // TODO(#5726): use computePublicKeysHash function + // const publicKeysHash = poseidon2Hash([ + // masterNullifierPublicKey, + // masterIncomingViewingPublicKey, + // masterOutgoingViewingPublicKey, + // masterTaggingPublicKey, + // GeneratorIndex.PUBLIC_KEYS_HASH, + // ]); + + // // We hash the partial address and the public keys hash to get the account address + // // TODO(#5726): Move the following line to AztecAddress class? + // accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); + + // it('should fail registering with mismatched address', async () => { + // const mismatchedAddress = Fr.random(); + + // await expect( + // keyRegistry + // .withWallet(wallets[0]) + // .methods.register( + // AztecAddress.fromField(mismatchedAddress), + // partialAddress, + // masterNullifierPublicKey, + // masterIncomingViewingPublicKey, + // masterOutgoingViewingPublicKey, + // masterTaggingPublicKey, + // ) + // .send() + // .wait(), + // ).rejects.toThrow('Computed address does not match supplied address'); + // }); + + // it('should fail registering with mismatched nullifier public key', async () => { + // const mismatchedMasterNullifierPublicKey = Fr.random(); + + // await expect( + // keyRegistry + // .withWallet(wallets[0]) + // .methods.register( + // AztecAddress.fromField(accountAddedToRegistry), + // partialAddress, + // mismatchedMasterNullifierPublicKey, + // masterIncomingViewingPublicKey, + // masterOutgoingViewingPublicKey, + // masterTaggingPublicKey, + // ) + // .send() + // .wait(), + // ).rejects.toThrow('Computed address does not match supplied address'); + // }); + // }); + + // describe('should fail when rotating keys with bad input', () => { + // it('should fail when trying to rotate setting a 0 key', async () => { + // await expect( + // keyRegistry + // .withWallet(wallets[0]) + // .methods.rotate_nullifier_public_key(wallets[0].getAddress(), new Fr(0)) + // .send() + // .wait(), + // ).rejects.toThrow('New nullifier public key must be non-zero'); + // }); + + // it('should fail when trying to rotate for another address without authwit', async () => { + // await expect( + // keyRegistry + // .withWallet(wallets[0]) + // .methods.rotate_nullifier_public_key(wallets[1].getAddress(), new Fr(2)) + // .send() + // .wait(), + // ).rejects.toThrow('Assertion failed: Message not authorized by account'); + // }); + // }); + // }); + + // describe('key registration flow', () => { + // let accountAddedToRegistry: AztecAddress; + + // it('should generate and register with original keys', async () => { + // const partialAddress = new Fr(69); + + // const masterNullifierPublicKey = new Fr(12); + // const masterIncomingViewingPublicKey = new Fr(34); + // const masterOutgoingViewingPublicKey = new Fr(56); + // const masterTaggingPublicKey = new Fr(78); + + // const publicKeysHash = poseidon2Hash([ + // masterNullifierPublicKey, + // masterIncomingViewingPublicKey, + // masterOutgoingViewingPublicKey, + // masterTaggingPublicKey, + // GeneratorIndex.PUBLIC_KEYS_HASH, + // ]); + + // // We hash the partial address and the public keys hash to get the account address + // // TODO(#5726): Move the following line to AztecAddress class? + // accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); + + // await keyRegistry + // .withWallet(wallets[0]) + // .methods.register( + // AztecAddress.fromField(accountAddedToRegistry), + // partialAddress, + // masterNullifierPublicKey, + // masterIncomingViewingPublicKey, + // masterOutgoingViewingPublicKey, + // masterTaggingPublicKey, + // ) + // .send() + // .wait(); + // }); + + // it('checks our registry contract from test contract and fails because the address has not been registered yet', async () => { + // const { txHash } = await testContract.methods + // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) + // .send() + // .wait(); + + // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(Fr.ZERO); + // }); + + // it('checks our registry contract from test contract and finds the address and associated nullifier public key after a delay', async () => { + // await delay(5); + + // const { txHash } = await testContract.methods + // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) + // .send() + // .wait(); + + // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + + // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(12)); + // }); + // }); + + // describe('key rotation flow', () => { + // it('we rotate the nullifier key', async () => { + // // This changes + // const newMasterNullifierPublicKey = new Fr(910); + + // await keyRegistry + // .withWallet(wallets[0]) + // .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey) + // .send() + // .wait(); + // }); + + // it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { + // const { txHash } = await testContract.methods + // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + // .send() + // .wait(); + + // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(0)); + // }); + + // it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { + // await delay(5); + + // const { txHash } = await testContract.methods + // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + // .send() + // .wait(); + + // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + + // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(910)); + // }); + // }); + + // describe('key rotation flow with authwit', () => { + // it('wallet 0 lets wallet 1 call rotate_nullifier_public_key on his behalf with a pre-defined new public key', async () => { + // // This changes + // const newMasterNullifierPublicKey = new Fr(420); + + // const action = keyRegistry + // .withWallet(wallets[1]) + // .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey); + + // await wallets[0] + // .setPublicAuthWit({ caller: wallets[1].getCompleteAddress().address, action }, true) + // .send() + // .wait(); + + // await action.send().wait(); + // }); + + // it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { + // const { txHash } = await testContract.methods + // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + // .send() + // .wait(); + + // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(910)); + // }); + + // it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { + // await delay(5); + + // const { txHash } = await testContract.methods + // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + // .send() + // .wait(); + + // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + + // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(420)); + // }); + // }); describe('key registration flow', () => { let accountAddedToRegistry: AztecAddress; + let masterNullifierPublicKey: Point; + let masterIncomingViewingPublicKey: Point; + let masterOutgoingViewingPublicKey: Point; + let masterTaggingPublicKey: Point; + let partialAddress: PartialAddress; it('should generate and register with original keys', async () => { - const partialAddress = new Fr(69); + partialAddress = new Fr(69); - const masterNullifierPublicKey = new Fr(12); - const masterIncomingViewingPublicKey = new Fr(34); - const masterOutgoingViewingPublicKey = new Fr(56); - const masterTaggingPublicKey = new Fr(78); + masterNullifierPublicKey = new Point(new Fr(1), new Fr(2)); + masterIncomingViewingPublicKey = new Point(new Fr(3), new Fr(4)); + masterOutgoingViewingPublicKey = new Point(new Fr(5), new Fr(6)); + masterTaggingPublicKey = new Point(new Fr(7), new Fr(8)); const publicKeysHash = poseidon2Hash([ masterNullifierPublicKey, @@ -166,96 +309,34 @@ describe('SharedMutablePrivateGetter', () => { const rawLogs = await pxe.getUnencryptedLogs({ txHash }); expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(Fr.ZERO); - }); - - it('checks our registry contract from test contract and finds the address and associated nullifier public key after a delay', async () => { - await delay(5); - - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) - .send() - .wait(); - - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(12)); - }); - }); - - describe('key rotation flow', () => { - it('we rotate the nullifier key', async () => { - // This changes - const newMasterNullifierPublicKey = new Fr(910); - - await keyRegistry - .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey) - .send() - .wait(); + // Checks freshness of newly added keys, but the change hasn't been affected yet + await expect(testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey, keyRegistry.address).send().wait()).rejects.toThrow(); }); - it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); - - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(0)); - }); + it('', async () => { + // FIX THIS + await pxe.registerRecipient(CompleteAddress.create(accountAddedToRegistry, Point.ZERO, partialAddress), [ + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey]); + await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey, keyRegistry.address).send().wait(); + }) - it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { + it('checks our registry contract from test contract and finds the address and associated nullifier public key after a delay', async () => { await delay(5); const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); - - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(910)); - }); - }); - - describe('key rotation flow with authwit', () => { - it('wallet 0 lets wallet 1 call rotate_nullifier_public_key on his behalf with a pre-defined new public key', async () => { - // This changes - const newMasterNullifierPublicKey = new Fr(420); - - const action = keyRegistry - .withWallet(wallets[1]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey); - - await wallets[0] - .setPublicAuthWit({ caller: wallets[1].getCompleteAddress().address, action }, true) - .send() - .wait(); - - await action.send().wait(); - }); - - it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) .send() .wait(); const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(910)); - }); - it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { - await delay(5); - - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); - - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(masterNullifierPublicKey.toFields())); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(420)); + await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey, keyRegistry.address).send().wait(); }); }); }); diff --git a/yarn-project/key-store/src/test_key_store.ts b/yarn-project/key-store/src/test_key_store.ts index c2755aecf0e..288ffc9430d 100644 --- a/yarn-project/key-store/src/test_key_store.ts +++ b/yarn-project/key-store/src/test_key_store.ts @@ -292,4 +292,17 @@ export class TestKeyStore implements KeyStore { } return Promise.resolve(Fr.fromBuffer(publicKeysHashBuffer)); } + + 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/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 5f90b66be33..3e75a1fe655 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -42,7 +42,7 @@ import { import { computeCommitmentNonce, 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 } from '@aztec/foundation/fields'; +import { Fr, Point } from '@aztec/foundation/fields'; import { SerialQueue } from '@aztec/foundation/fifo'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; @@ -216,8 +216,13 @@ export class PXEService implements PXE { return this.keyStore.getPublicKeysHash(address); } - public async registerRecipient(recipient: CompleteAddress): Promise { + public async registerRecipient(recipient: CompleteAddress, publicKeys: Point[] = []): Promise { const wasAdded = await this.db.addCompleteAddress(recipient); + + 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 { diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 02f820666fd..26a4a677c59 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 { acvmFieldMessageToString, oracleDebugCallToFormattedStr } from '@aztec/circuits.js'; +import { type PartialAddress, 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'; @@ -174,12 +174,26 @@ export class Oracle { } async getPublicKeysAndPartialAddress([address]: ACVMField[]): Promise { - const { partialAddress } = await this.typedOracle.getCompleteAddress( - AztecAddress.fromField(fromACVMField(address)), - ); + let partialAddress: PartialAddress; + let publicKeys: Point[] | undefined; + try { + ({ partialAddress } = await this.typedOracle.getCompleteAddress( + AztecAddress.fromField(fromACVMField(address)), + )); + } catch (err) { + partialAddress = Fr.ZERO; + } + + try { + publicKeys = await this.typedOracle.getPublicKeysForAddress(AztecAddress.fromField(fromACVMField(address))); + } catch(err) { + publicKeys = Array(4).fill(Point.ZERO); + } + + console.log('partial address', partialAddress); + console.log('public keys', publicKeys); - const publicKeys = await this.typedOracle.getPublicKeysForAddress(AztecAddress.fromField(fromACVMField(address))); - const acvmKeys = publicKeys?.flatMap(key => key.toFields()) ?? Array(8).fill(toACVMField(0)); + const acvmKeys = publicKeys.flatMap(key => key.toFields()); return [partialAddress, ...acvmKeys].map(toACVMField); } diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 86b3d5d6439..103214d3c98 100644 --- a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts @@ -142,16 +142,10 @@ export abstract class TypedOracle { getPublicKeysForAddress( _address: AztecAddress, - ): Promise { + ): Promise { throw new OracleMethodNotAvailableError('getPublicKeysForAddress'); } - async getAddressMetadata( - _address: AztecAddress, - ): Promise { - throw new OracleMethodNotAvailableError('getAddressMetadata'); - } - 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 b8d56098703..3e193b56472 100644 --- a/yarn-project/simulator/src/client/db_oracle.ts +++ b/yarn-project/simulator/src/client/db_oracle.ts @@ -67,8 +67,6 @@ export interface DBOracle extends CommitmentsDB { getPublicKeysForAddress(address: AztecAddress): Promise; - getAddressMetadata(address: AztecAddress): Promise; - /** * Retrieve nullifier keys associated with a specific account and app/contract address. * From 1b13804151dc797e3b376900dc40eeb56b243907 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 15:22:54 +0000 Subject: [PATCH 06/23] cleanup --- .../src/keys/assert_public_key_freshness.nr | 55 +- .../key_registry_contract/src/main.nr | 8 +- .../contracts/test_contract/src/main.nr | 3 +- .../end-to-end/src/e2e_key_registry.test.ts | 549 ++++++++++-------- 4 files changed, 339 insertions(+), 276 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr index 5390a2b7848..d1961792feb 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr @@ -1,68 +1,65 @@ use dep::protocol_types::{ + address::{ + AztecAddress, + PartialAddress + }, constants::{ - GENERATOR_INDEX__PUBLIC_KEYS_HASH, GENERATOR_INDEX__CONTRACT_ADDRESS_V1}, - address::{AztecAddress, PartialAddress}, grumpkin_point::GrumpkinPoint}; + GENERATOR_INDEX__PUBLIC_KEYS_HASH, + GENERATOR_INDEX__CONTRACT_ADDRESS_V1, + CANONICAL_KEY_REGISTRY_ADDRESS + }, + grumpkin_point::GrumpkinPoint, +}; + use crate::context::PrivateContext; -use crate::note::{ - constants::{GET_NOTE_ORACLE_RETURN_LENGTH, MAX_NOTES_PER_PAGE, VIEW_NOTE_ORACLE_RETURN_LENGTH}, - note_getter_options::{NoteGetterOptions, Select, Sort, SortOrder, Comparator, NoteStatus, PropertySelector}, - note_interface::NoteInterface, note_viewer_options::NoteViewerOptions, - utils::compute_note_hash_for_consumption, +use crate::hash::{ + pedersen_hash, + poseidon2_hash, }; -use crate::state_vars::shared_mutable::shared_mutable_private_getter::SharedMutablePrivateGetter; -use crate::hash::{pedersen_hash, poseidon2_hash}; use crate::oracle; +use crate::state_vars::shared_mutable::shared_mutable_private_getter::SharedMutablePrivateGetter; struct PublicKeyTypeEnum { NULLIFIER: u8, - INCOMING: u8, } global PublicKeyType = PublicKeyTypeEnum { NULLIFIER: 0, - INCOMING: 1, }; pub fn assert_nullifier_public_key_fresh( context: &mut PrivateContext, address: AztecAddress, nullifier_public_key_to_test: GrumpkinPoint, - // remove after - registry_contract_address: AztecAddress, ) { - // Canonical Key Registry - let contract_address_to_read = registry_contract_address; + // This is the storage slot of the nullifier_public_key inside the key registry contract let storage_slot_of_nullifier_public_key = 1; // We have to derive this slot to get the location of the shared mutable inside the Map + // This should mimic how maps derive their slots let derived_slot = pedersen_hash( [storage_slot_of_nullifier_public_key, address.to_field()], 0 ); // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly - let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(*context, contract_address_to_read, derived_slot); + // We read from the canonical Key Registry + let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(*context, AztecAddress::from_field(CANONICAL_KEY_REGISTRY_ADDRESS), derived_slot); let hashed_nullifier_public_key = registry_private_getter.get_current_value_in_private(); + // In the case that the value is not found in the registry we need to manually pass in the address preimage if (hashed_nullifier_public_key == 0) { - check_key(address, PublicKeyType.NULLIFIER, nullifier_public_key_to_test); + check_public_key_validity(address, PublicKeyType.NULLIFIER, nullifier_public_key_to_test); } else { assert(hashed_nullifier_public_key == poseidon2_hash(nullifier_public_key_to_test.serialize())); } } -fn check_key(address: AztecAddress, key_type: u8, key: GrumpkinPoint) { - let mut (partial_address, keys) = check_key_internal(address); - - crate::oracle::debug_log::debug_log_array_with_prefix("partial", [partial_address]); - crate::oracle::debug_log::debug_log_array_with_prefix("ACTUAL NULLIFIER", key.serialize()); - crate::oracle::debug_log::debug_log_array_with_prefix("nullifier", keys[0].serialize()); - crate::oracle::debug_log::debug_log_array_with_prefix("incoming", keys[1].serialize()); - crate::oracle::debug_log::debug_log_array_with_prefix("outgoing", keys[2].serialize()); - crate::oracle::debug_log::debug_log_array_with_prefix("tagging", keys[3].serialize()); +fn check_public_key_validity(address: AztecAddress, key_type: u8, key: GrumpkinPoint) { + let (partial_address, keys) = get_public_keys_and_partial_address_internal(address); assert(keys[key_type].eq(key)); - _check_key_constrain_check_key_internal( + _check_public_key_validity_constrain_internal( address, partial_address, keys[0], @@ -72,13 +69,13 @@ fn check_key(address: AztecAddress, key_type: u8, key: GrumpkinPoint) { ) } -unconstrained fn check_key_internal(address: AztecAddress) -> (PartialAddress, [GrumpkinPoint; 4]) { +unconstrained fn get_public_keys_and_partial_address_internal(address: AztecAddress) -> (PartialAddress, [GrumpkinPoint; 4]) { let (partial_address, public_keys) = oracle::keys::get_public_keys_and_partial_address(address); (partial_address, public_keys) } -fn _check_key_constrain_check_key_internal( +fn _check_public_key_validity_constrain_internal( address: AztecAddress, partial_address: PartialAddress, nullifier_public_key: GrumpkinPoint, 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 ea5b1dd551a..6124253c417 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 @@ -34,12 +34,12 @@ contract KeyRegistry { } #[aztec(public)] - fn rotate_nullifier_public_key_hash( + fn rotate_nullifier_public_key( address: AztecAddress, - new_nullifier_public_key_hash: Field, + new_nullifier_public_key: GrumpkinPoint, ) { assert( - new_nullifier_public_key_hash != 0, + !new_nullifier_public_key.is_zero(), "New nullifier public key must be non-zero" ); @@ -49,7 +49,7 @@ contract KeyRegistry { let nullifier_key_registry = storage.nullifier_public_key_hash_registry.at(address); - nullifier_key_registry.schedule_value_change(new_nullifier_public_key_hash); + nullifier_key_registry.schedule_value_change(poseidon2_hash(new_nullifier_public_key.serialize())); } #[aztec(public)] 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 d5f5142fd03..68311b75f4f 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -414,9 +414,8 @@ contract Test { fn test_nullifier_key_freshness( address: AztecAddress, public_nullifying_key: GrumpkinPoint, - key_registry_contract: AztecAddress, ) { - assert_nullifier_public_key_fresh(&mut context, address, public_nullifying_key, key_registry_contract); + assert_nullifier_public_key_fresh(&mut context, address, public_nullifying_key); } #[aztec(public)] 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 967d9c1ee4a..a16f3e56ad9 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 @@ -10,11 +10,11 @@ import { publicDeployAccounts, setup } from './fixtures/utils.js'; const TIMEOUT = 100_000; -describe('SharedMutablePrivateGetter', () => { +describe('Key Registry', () => { let keyRegistry: KeyRegistryContract; + let pxe: PXE; let testContract: TestContract; - let pxe: PXE; jest.setTimeout(TIMEOUT); let wallets: AccountWallet[]; @@ -38,245 +38,102 @@ describe('SharedMutablePrivateGetter', () => { afterAll(() => teardown()); - // describe('failure cases', () => { - // let accountAddedToRegistry: AztecAddress; - - // describe('should fail registering with bad input', () => { - // const partialAddress = new Fr(69); - - // const masterNullifierPublicKey = new Fr(12); - // const masterIncomingViewingPublicKey = new Fr(34); - // const masterOutgoingViewingPublicKey = new Fr(56); - // const masterTaggingPublicKey = new Fr(78); - - // // TODO(#5726): use computePublicKeysHash function - // const publicKeysHash = poseidon2Hash([ - // masterNullifierPublicKey, - // masterIncomingViewingPublicKey, - // masterOutgoingViewingPublicKey, - // masterTaggingPublicKey, - // GeneratorIndex.PUBLIC_KEYS_HASH, - // ]); - - // // We hash the partial address and the public keys hash to get the account address - // // TODO(#5726): Move the following line to AztecAddress class? - // accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); - - // it('should fail registering with mismatched address', async () => { - // const mismatchedAddress = Fr.random(); - - // await expect( - // keyRegistry - // .withWallet(wallets[0]) - // .methods.register( - // AztecAddress.fromField(mismatchedAddress), - // partialAddress, - // masterNullifierPublicKey, - // masterIncomingViewingPublicKey, - // masterOutgoingViewingPublicKey, - // masterTaggingPublicKey, - // ) - // .send() - // .wait(), - // ).rejects.toThrow('Computed address does not match supplied address'); - // }); - - // it('should fail registering with mismatched nullifier public key', async () => { - // const mismatchedMasterNullifierPublicKey = Fr.random(); - - // await expect( - // keyRegistry - // .withWallet(wallets[0]) - // .methods.register( - // AztecAddress.fromField(accountAddedToRegistry), - // partialAddress, - // mismatchedMasterNullifierPublicKey, - // masterIncomingViewingPublicKey, - // masterOutgoingViewingPublicKey, - // masterTaggingPublicKey, - // ) - // .send() - // .wait(), - // ).rejects.toThrow('Computed address does not match supplied address'); - // }); - // }); - - // describe('should fail when rotating keys with bad input', () => { - // it('should fail when trying to rotate setting a 0 key', async () => { - // await expect( - // keyRegistry - // .withWallet(wallets[0]) - // .methods.rotate_nullifier_public_key(wallets[0].getAddress(), new Fr(0)) - // .send() - // .wait(), - // ).rejects.toThrow('New nullifier public key must be non-zero'); - // }); - - // it('should fail when trying to rotate for another address without authwit', async () => { - // await expect( - // keyRegistry - // .withWallet(wallets[0]) - // .methods.rotate_nullifier_public_key(wallets[1].getAddress(), new Fr(2)) - // .send() - // .wait(), - // ).rejects.toThrow('Assertion failed: Message not authorized by account'); - // }); - // }); - // }); - - // describe('key registration flow', () => { - // let accountAddedToRegistry: AztecAddress; - - // it('should generate and register with original keys', async () => { - // const partialAddress = new Fr(69); - - // const masterNullifierPublicKey = new Fr(12); - // const masterIncomingViewingPublicKey = new Fr(34); - // const masterOutgoingViewingPublicKey = new Fr(56); - // const masterTaggingPublicKey = new Fr(78); - - // const publicKeysHash = poseidon2Hash([ - // masterNullifierPublicKey, - // masterIncomingViewingPublicKey, - // masterOutgoingViewingPublicKey, - // masterTaggingPublicKey, - // GeneratorIndex.PUBLIC_KEYS_HASH, - // ]); - - // // We hash the partial address and the public keys hash to get the account address - // // TODO(#5726): Move the following line to AztecAddress class? - // accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); - - // await keyRegistry - // .withWallet(wallets[0]) - // .methods.register( - // AztecAddress.fromField(accountAddedToRegistry), - // partialAddress, - // masterNullifierPublicKey, - // masterIncomingViewingPublicKey, - // masterOutgoingViewingPublicKey, - // masterTaggingPublicKey, - // ) - // .send() - // .wait(); - // }); - - // it('checks our registry contract from test contract and fails because the address has not been registered yet', async () => { - // const { txHash } = await testContract.methods - // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) - // .send() - // .wait(); - - // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(Fr.ZERO); - // }); - - // it('checks our registry contract from test contract and finds the address and associated nullifier public key after a delay', async () => { - // await delay(5); - - // const { txHash } = await testContract.methods - // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) - // .send() - // .wait(); - - // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - - // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(12)); - // }); - // }); - - // describe('key rotation flow', () => { - // it('we rotate the nullifier key', async () => { - // // This changes - // const newMasterNullifierPublicKey = new Fr(910); - - // await keyRegistry - // .withWallet(wallets[0]) - // .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey) - // .send() - // .wait(); - // }); - - // it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { - // const { txHash } = await testContract.methods - // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - // .send() - // .wait(); - - // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(0)); - // }); - - // it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { - // await delay(5); - - // const { txHash } = await testContract.methods - // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - // .send() - // .wait(); - - // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - - // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(910)); - // }); - // }); - - // describe('key rotation flow with authwit', () => { - // it('wallet 0 lets wallet 1 call rotate_nullifier_public_key on his behalf with a pre-defined new public key', async () => { - // // This changes - // const newMasterNullifierPublicKey = new Fr(420); - - // const action = keyRegistry - // .withWallet(wallets[1]) - // .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey); - - // await wallets[0] - // .setPublicAuthWit({ caller: wallets[1].getCompleteAddress().address, action }, true) - // .send() - // .wait(); - - // await action.send().wait(); - // }); - - // it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { - // const { txHash } = await testContract.methods - // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - // .send() - // .wait(); - - // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(910)); - // }); - - // it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { - // await delay(5); - - // const { txHash } = await testContract.methods - // .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - // .send() - // .wait(); - - // const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - - // expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(420)); - // }); - // }); + describe('failure cases', () => { + let accountAddedToRegistry: AztecAddress; + + describe('should fail registering with bad input', () => { + const partialAddress = new Fr(69); + + const masterNullifierPublicKey = new Fr(12); + const masterIncomingViewingPublicKey = new Fr(34); + const masterOutgoingViewingPublicKey = new Fr(56); + const masterTaggingPublicKey = new Fr(78); + + // TODO(#5726): use computePublicKeysHash function + const publicKeysHash = poseidon2Hash([ + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + GeneratorIndex.PUBLIC_KEYS_HASH, + ]); + + // We hash the partial address and the public keys hash to get the account address + // TODO(#5726): Move the following line to AztecAddress class? + accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); + + it('should fail registering with mismatched address', async () => { + const mismatchedAddress = Fr.random(); + + await expect( + keyRegistry + .withWallet(wallets[0]) + .methods.register( + AztecAddress.fromField(mismatchedAddress), + partialAddress, + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + ) + .send() + .wait(), + ).rejects.toThrow('Computed address does not match supplied address'); + }); + + it('should fail registering with mismatched nullifier public key', async () => { + const mismatchedMasterNullifierPublicKey = Fr.random(); + + await expect( + keyRegistry + .withWallet(wallets[0]) + .methods.register( + AztecAddress.fromField(accountAddedToRegistry), + partialAddress, + mismatchedMasterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + ) + .send() + .wait(), + ).rejects.toThrow('Computed address does not match supplied address'); + }); + }); + + describe('should fail when rotating keys with bad input', () => { + it('should fail when trying to rotate setting a 0 key', async () => { + await expect( + keyRegistry + .withWallet(wallets[0]) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), new Fr(0)) + .send() + .wait(), + ).rejects.toThrow('New nullifier public key must be non-zero'); + }); + + it('should fail when trying to rotate for another address without authwit', async () => { + await expect( + keyRegistry + .withWallet(wallets[0]) + .methods.rotate_nullifier_public_key(wallets[1].getAddress(), new Fr(2)) + .send() + .wait(), + ).rejects.toThrow('Assertion failed: Message not authorized by account'); + }); + }); + }); describe('key registration flow', () => { let accountAddedToRegistry: AztecAddress; - let masterNullifierPublicKey: Point; - let masterIncomingViewingPublicKey: Point; - let masterOutgoingViewingPublicKey: Point; - let masterTaggingPublicKey: Point; - let partialAddress: PartialAddress; it('should generate and register with original keys', async () => { - partialAddress = new Fr(69); + const partialAddress = new Fr(69); - masterNullifierPublicKey = new Point(new Fr(1), new Fr(2)); - masterIncomingViewingPublicKey = new Point(new Fr(3), new Fr(4)); - masterOutgoingViewingPublicKey = new Point(new Fr(5), new Fr(6)); - masterTaggingPublicKey = new Point(new Fr(7), new Fr(8)); + const masterNullifierPublicKey = new Fr(12); + const masterIncomingViewingPublicKey = new Fr(34); + const masterOutgoingViewingPublicKey = new Fr(56); + const masterTaggingPublicKey = new Fr(78); const publicKeysHash = poseidon2Hash([ masterNullifierPublicKey, @@ -312,22 +169,210 @@ describe('SharedMutablePrivateGetter', () => { const rawLogs = await pxe.getUnencryptedLogs({ txHash }); expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(Fr.ZERO); + }); + + it('checks our registry contract from test contract and finds the address and associated nullifier public key after a delay', async () => { + await delay(5); + + const { txHash } = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) + .send() + .wait(); + + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(12)); + }); + }); + + describe('key rotation flow', () => { + it('we rotate the nullifier key', async () => { + // This changes + const newMasterNullifierPublicKey = new Fr(910); + + await keyRegistry + .withWallet(wallets[0]) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey) + .send() + .wait(); + }); + + it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { + const { txHash } = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .send() + .wait(); + + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(0)); + }); + + it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { + await delay(5); + + const { txHash } = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .send() + .wait(); + + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(910)); + }); + }); + + describe('key rotation flow with authwit', () => { + it('wallet 0 lets wallet 1 call rotate_nullifier_public_key on his behalf with a pre-defined new public key', async () => { + // This changes + const newMasterNullifierPublicKey = new Fr(420); + + const action = keyRegistry + .withWallet(wallets[1]) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey); + + await wallets[0] + .setPublicAuthWit({ caller: wallets[1].getCompleteAddress().address, action }, true) + .send() + .wait(); + + await action.send().wait(); + }); + + it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { + const { txHash } = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .send() + .wait(); + + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(910)); + }); - // Checks freshness of newly added keys, but the change hasn't been affected yet - await expect(testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey, keyRegistry.address).send().wait()).rejects.toThrow(); + it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { + await delay(5); + + const { txHash } = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .send() + .wait(); + + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(420)); }); + }); - it('', async () => { + describe('key registration flow no PXE', () => { + const masterNullifierPublicKey: Point = new Point(new Fr(9), new Fr(10)); + const masterIncomingViewingPublicKey: Point = new Point(new Fr(11), new Fr(12)); + const masterOutgoingViewingPublicKey: Point = new Point(new Fr(13), new Fr(14)); + const masterTaggingPublicKey: Point = new Point(new Fr(15), new Fr(16)); + const partialAddress: PartialAddress = new Fr(420); + + const publicKeysHash = poseidon2Hash([ + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + GeneratorIndex.PUBLIC_KEYS_HASH, + ]); + + // 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 accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); + + it('should fail as we have not registered anything to the registry nor have we registered a recipient', async () => { + await expect(testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait()).rejects.toThrow(); + }); + + it('Now we add it to registry', async () => { + await keyRegistry + .withWallet(wallets[0]) + .methods.register( + AztecAddress.fromField(accountAddedToRegistry), + partialAddress, + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + ) + .send() + .wait(); + }); + + it('checks key freshness and fails because the address change has not been applied yet due to lack of delay', async () => { + await expect(testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait()).rejects.toThrow(); + }); + + it('checks key freshness after a delay, and is successful', async () => { + await delay(5); + + await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait(); + }); + }); + + describe('key registration flow via PXE', () => { + const masterNullifierPublicKey: Point = new Point(new Fr(1), new Fr(2)); + const masterIncomingViewingPublicKey: Point = new Point(new Fr(3), new Fr(4)); + const masterOutgoingViewingPublicKey: Point = new Point(new Fr(5), new Fr(6)); + const masterTaggingPublicKey: Point = new Point(new Fr(7), new Fr(8)); + const partialAddress: PartialAddress = new Fr(69);; + + const publicKeysHash = poseidon2Hash([ + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + GeneratorIndex.PUBLIC_KEYS_HASH, + ]); + + // 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 accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); + + it('should fail as we have not registered anything to the registry nor have we registered a recipient', async () => { + await expect(testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait()).rejects.toThrow(); + }) + + it('should succeed because we register our recipient manually and the lib checks our pxe', async () => { // FIX THIS await pxe.registerRecipient(CompleteAddress.create(accountAddedToRegistry, Point.ZERO, partialAddress), [ masterNullifierPublicKey, masterIncomingViewingPublicKey, masterOutgoingViewingPublicKey, masterTaggingPublicKey]); - await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey, keyRegistry.address).send().wait(); + await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait(); }) - it('checks our registry contract from test contract and finds the address and associated nullifier public key after a delay', async () => { + it('Now we add it to registry', async () => { + await keyRegistry + .withWallet(wallets[0]) + .methods.register( + AztecAddress.fromField(accountAddedToRegistry), + partialAddress, + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + ) + .send() + .wait(); + }) + + it('we start the change in the registry, it has not been applied yet, but we still see we have a fresh key due to it being added in the pxe', async () => { + const { txHash } = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) + .send() + .wait(); + + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(Fr.ZERO); + + // Checks freshness of newly added keys, but the change hasn't been affected yet, but we have manually added it to our pxe so it should pass + await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait(); + }); + + it('in the case where the key exists both in the pxe and our registry, we know it works', async () => { await delay(5); const { txHash } = await testContract.methods @@ -339,7 +384,29 @@ describe('SharedMutablePrivateGetter', () => { expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(masterNullifierPublicKey.toFields())); - await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey, keyRegistry.address).send().wait(); + await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait(); + }); + }); + + describe('key rotation flow; assert keys are fresh', () => { + const newMasterNullifierPublicKey = new Point(new Fr(910), new Fr(1112)); + + it('we rotate the nullifier key', async () => { + await keyRegistry + .withWallet(wallets[0]) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey) + .send() + .wait(); + }); + + it("checks our registry contract from test contract and fails because the change hasn't been applied yet", async () => { + await expect(testContract.methods.test_nullifier_key_freshness(wallets[0].getAddress(), newMasterNullifierPublicKey).send().wait()).rejects.toThrow(); + }); + + it('checks our registry contract from test contract and succeeds because the change has been applied', async () => { + await delay(5); + + await testContract.methods.test_nullifier_key_freshness(wallets[0].getAddress(), newMasterNullifierPublicKey).send().wait(); }); }); }); From 211a060db0040faad1e34c0219a816021f4bd5db Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 15:26:02 +0000 Subject: [PATCH 07/23] yarn format --- .../circuit-types/src/interfaces/pxe.ts | 2 +- .../circuit-types/src/keys/key_store.ts | 4 +- .../end-to-end/jest.integration.config.json | 2 +- .../end-to-end/src/e2e_key_registry.test.ts | 68 ++++++++++++++----- yarn-project/package.common.json | 2 +- .../pxe/src/pxe_service/pxe_service.ts | 12 +++- .../pxe/src/simulator_oracle/index.ts | 7 +- .../simulator/src/acvm/oracle/oracle.ts | 9 +-- .../simulator/src/acvm/oracle/typed_oracle.ts | 6 +- .../simulator/src/client/db_oracle.ts | 3 +- .../simulator/src/client/view_data_oracle.ts | 4 +- 11 files changed, 75 insertions(+), 44 deletions(-) diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index 0fc42af9308..f36958df987 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -1,4 +1,4 @@ -import { Point, type AztecAddress, type CompleteAddress, type Fr, type PartialAddress } from '@aztec/circuits.js'; +import { type AztecAddress, type CompleteAddress, type Fr, type PartialAddress, type Point } 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'; diff --git a/yarn-project/circuit-types/src/keys/key_store.ts b/yarn-project/circuit-types/src/keys/key_store.ts index f670683d905..e5cefbd7bc4 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 { - Point, type AztecAddress, type Fr, type GrumpkinPrivateKey, type PartialAddress, + type Point, type PublicKey, } from '@aztec/circuits.js'; @@ -119,7 +119,7 @@ export interface KeyStore { getPublicKeysHash(account: AztecAddress): Promise; /** - * + * */ addPublicKeysForAccount( accountAddress: AztecAddress, diff --git a/yarn-project/end-to-end/jest.integration.config.json b/yarn-project/end-to-end/jest.integration.config.json index 84d61df320c..721267ff552 100644 --- a/yarn-project/end-to-end/jest.integration.config.json +++ b/yarn-project/end-to-end/jest.integration.config.json @@ -6,7 +6,7 @@ "moduleNameMapper": { "^(\\.{1,2}/.*)\\.js$": "$1" }, - "reporters": [["default", {"summaryThreshold": 9999}]], + "reporters": [["default", { "summaryThreshold": 9999 }]], "testRegex": "./src/.*\\.test\\.ts$", "rootDir": "./src" } 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 a16f3e56ad9..2b686e27288 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,5 +1,5 @@ import { type AccountWallet, AztecAddress, Fr, type PXE } from '@aztec/aztec.js'; -import { CompleteAddress, GeneratorIndex, PartialAddress, Point } from '@aztec/circuits.js'; +import { CompleteAddress, GeneratorIndex, type PartialAddress, Point } from '@aztec/circuits.js'; import { poseidon2Hash } from '@aztec/foundation/crypto'; import { KeyRegistryContract, TestContract } from '@aztec/noir-contracts.js'; import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry'; @@ -13,7 +13,7 @@ const TIMEOUT = 100_000; describe('Key Registry', () => { let keyRegistry: KeyRegistryContract; - let pxe: PXE; + let pxe: PXE; let testContract: TestContract; jest.setTimeout(TIMEOUT); @@ -282,7 +282,12 @@ describe('Key Registry', () => { const accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); it('should fail as we have not registered anything to the registry nor have we registered a recipient', async () => { - await expect(testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait()).rejects.toThrow(); + await expect( + testContract.methods + .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) + .send() + .wait(), + ).rejects.toThrow(); }); it('Now we add it to registry', async () => { @@ -301,13 +306,21 @@ describe('Key Registry', () => { }); it('checks key freshness and fails because the address change has not been applied yet due to lack of delay', async () => { - await expect(testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait()).rejects.toThrow(); + await expect( + testContract.methods + .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) + .send() + .wait(), + ).rejects.toThrow(); }); it('checks key freshness after a delay, and is successful', async () => { await delay(5); - await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait(); + await testContract.methods + .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) + .send() + .wait(); }); }); @@ -316,7 +329,7 @@ describe('Key Registry', () => { const masterIncomingViewingPublicKey: Point = new Point(new Fr(3), new Fr(4)); const masterOutgoingViewingPublicKey: Point = new Point(new Fr(5), new Fr(6)); const masterTaggingPublicKey: Point = new Point(new Fr(7), new Fr(8)); - const partialAddress: PartialAddress = new Fr(69);; + const partialAddress: PartialAddress = new Fr(69); const publicKeysHash = poseidon2Hash([ masterNullifierPublicKey, @@ -331,8 +344,13 @@ describe('Key Registry', () => { const accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); it('should fail as we have not registered anything to the registry nor have we registered a recipient', async () => { - await expect(testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait()).rejects.toThrow(); - }) + await expect( + testContract.methods + .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) + .send() + .wait(), + ).rejects.toThrow(); + }); it('should succeed because we register our recipient manually and the lib checks our pxe', async () => { // FIX THIS @@ -340,9 +358,13 @@ describe('Key Registry', () => { masterNullifierPublicKey, masterIncomingViewingPublicKey, masterOutgoingViewingPublicKey, - masterTaggingPublicKey]); - await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait(); - }) + masterTaggingPublicKey, + ]); + await testContract.methods + .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) + .send() + .wait(); + }); it('Now we add it to registry', async () => { await keyRegistry @@ -357,7 +379,7 @@ describe('Key Registry', () => { ) .send() .wait(); - }) + }); it('we start the change in the registry, it has not been applied yet, but we still see we have a fresh key due to it being added in the pxe', async () => { const { txHash } = await testContract.methods @@ -369,7 +391,10 @@ describe('Key Registry', () => { expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(Fr.ZERO); // Checks freshness of newly added keys, but the change hasn't been affected yet, but we have manually added it to our pxe so it should pass - await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait(); + await testContract.methods + .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) + .send() + .wait(); }); it('in the case where the key exists both in the pxe and our registry, we know it works', async () => { @@ -384,7 +409,10 @@ describe('Key Registry', () => { expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(masterNullifierPublicKey.toFields())); - await testContract.methods.test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey).send().wait(); + await testContract.methods + .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) + .send() + .wait(); }); }); @@ -400,13 +428,21 @@ describe('Key Registry', () => { }); it("checks our registry contract from test contract and fails because the change hasn't been applied yet", async () => { - await expect(testContract.methods.test_nullifier_key_freshness(wallets[0].getAddress(), newMasterNullifierPublicKey).send().wait()).rejects.toThrow(); + await expect( + testContract.methods + .test_nullifier_key_freshness(wallets[0].getAddress(), newMasterNullifierPublicKey) + .send() + .wait(), + ).rejects.toThrow(); }); it('checks our registry contract from test contract and succeeds because the change has been applied', async () => { await delay(5); - await testContract.methods.test_nullifier_key_freshness(wallets[0].getAddress(), newMasterNullifierPublicKey).send().wait(); + await testContract.methods + .test_nullifier_key_freshness(wallets[0].getAddress(), newMasterNullifierPublicKey) + .send() + .wait(); }); }); }); diff --git a/yarn-project/package.common.json b/yarn-project/package.common.json index 80b56a8d697..6fcf1a28315 100644 --- a/yarn-project/package.common.json +++ b/yarn-project/package.common.json @@ -24,7 +24,7 @@ "moduleNameMapper": { "^(\\.{1,2}/.*)\\.[cm]?js$": "$1" }, - "reporters": [["default", {"summaryThreshold": 9999}]], + "reporters": [["default", { "summaryThreshold": 9999 }]], "testRegex": "./src/.*\\.test\\.(js|mjs|ts)$", "rootDir": "./src" } diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index 607f4679940..b9ef265e408 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -42,7 +42,7 @@ import { import { computeCommitmentNonce, 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, Point } from '@aztec/foundation/fields'; +import { Fr, type Point } from '@aztec/foundation/fields'; import { SerialQueue } from '@aztec/foundation/fifo'; import { type DebugLogger, createDebugLogger } from '@aztec/foundation/log'; import { Timer } from '@aztec/foundation/timer'; @@ -218,9 +218,15 @@ export class PXEService implements PXE { public async registerRecipient(recipient: CompleteAddress, publicKeys: Point[] = []): Promise { const wasAdded = await this.db.addCompleteAddress(recipient); - + if (publicKeys.length !== 0) { - await this.keyStore.addPublicKeysForAccount(recipient.address, publicKeys[0], publicKeys[1], publicKeys[2], publicKeys[3]); + await this.keyStore.addPublicKeysForAccount( + recipient.address, + publicKeys[0], + publicKeys[1], + publicKeys[2], + publicKeys[3], + ); } if (wasAdded) { diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 80b51a611b8..867ca8d0824 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -9,14 +9,13 @@ import { type SiblingPath, } from '@aztec/circuit-types'; import { - Fr, - Point, type AztecAddress, type CompleteAddress, - type EthAddress, + type Fr, 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 FunctionArtifactWithDebugMetadata, getFunctionArtifactWithDebugMetadata } from '@aztec/foundation/abi'; @@ -85,7 +84,7 @@ export class SimulatorOracle implements DBOracle { const outgoingViewingPublicKey = await this.keyStore.getMasterOutgoingViewingPublicKey(address); const taggingPublicKey = await this.keyStore.getMasterTaggingPublicKey(address); - return [nullifierPublicKey, incomingViewingPublicKey, outgoingViewingPublicKey, taggingPublicKey] + return [nullifierPublicKey, incomingViewingPublicKey, outgoingViewingPublicKey, taggingPublicKey]; } async getNotes(contractAddress: AztecAddress, storageSlot: Fr, status: NoteStatus) { diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 4aca6d5f5e7..8226f58a1bc 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -176,22 +176,17 @@ export class Oracle { let partialAddress: PartialAddress; let publicKeys: Point[] | undefined; try { - ({ partialAddress } = await this.typedOracle.getCompleteAddress( - AztecAddress.fromField(fromACVMField(address)), - )); + ({ partialAddress } = await this.typedOracle.getCompleteAddress(AztecAddress.fromField(fromACVMField(address)))); } catch (err) { partialAddress = Fr.ZERO; } try { publicKeys = await this.typedOracle.getPublicKeysForAddress(AztecAddress.fromField(fromACVMField(address))); - } catch(err) { + } catch (err) { publicKeys = Array(4).fill(Point.ZERO); } - console.log('partial address', partialAddress); - console.log('public keys', publicKeys); - const acvmKeys = publicKeys.flatMap(key => key.toFields()); return [partialAddress, ...acvmKeys].map(toACVMField); diff --git a/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts b/yarn-project/simulator/src/acvm/oracle/typed_oracle.ts index 568b6c38f6d..de60e6e55e1 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, Point } from '@aztec/foundation/fields'; +import { Fr, type Point } from '@aztec/foundation/fields'; import { type ContractInstance } from '@aztec/types/contracts'; /** Nullifier keys which both correspond to the same master nullifier secret key. */ @@ -140,9 +140,7 @@ export abstract class TypedOracle { throw new OracleMethodNotAvailableError('popCapsule'); } - getPublicKeysForAddress( - _address: AztecAddress, - ): Promise { + getPublicKeysForAddress(_address: AztecAddress): Promise { throw new OracleMethodNotAvailableError('getPublicKeysForAddress'); } diff --git a/yarn-project/simulator/src/client/db_oracle.ts b/yarn-project/simulator/src/client/db_oracle.ts index 8433ca44d88..9287249f1cf 100644 --- a/yarn-project/simulator/src/client/db_oracle.ts +++ b/yarn-project/simulator/src/client/db_oracle.ts @@ -8,8 +8,7 @@ import { import { type CompleteAddress, type Header } from '@aztec/circuits.js'; import { type FunctionArtifactWithDebugMetadata, type FunctionSelector } from '@aztec/foundation/abi'; import { type AztecAddress } from '@aztec/foundation/aztec-address'; -import { type EthAddress } from '@aztec/foundation/eth-address'; -import { Point, type Fr } from '@aztec/foundation/fields'; +import { type Fr, type Point } from '@aztec/foundation/fields'; import { type ContractInstance } from '@aztec/types/contracts'; import { type NoteData, type NullifierKeys } from '../acvm/index.js'; diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index 00bb685e8c8..d2a85c4a242 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -166,9 +166,7 @@ export class ViewDataOracle extends TypedOracle { return this.db.popCapsule(); } - public override getPublicKeysForAddress( - address: AztecAddress, - ) { + public override getPublicKeysForAddress(address: AztecAddress) { return this.db.getPublicKeysForAddress(address); } From 29bfb809d0e84fdeaa90d6ea2da160a884585d10 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 15:28:47 +0000 Subject: [PATCH 08/23] fix --- noir-projects/aztec-nr/aztec/src/keys.nr | 2 +- .../aztec-nr/aztec/src/keys/assert_public_key_freshness.nr | 2 +- .../noir-contracts/contracts/test_contract/src/main.nr | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/keys.nr b/noir-projects/aztec-nr/aztec/src/keys.nr index 7e83884a099..427d30ba671 100644 --- a/noir-projects/aztec-nr/aztec/src/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/keys.nr @@ -1,3 +1,3 @@ mod assert_public_key_freshness; -use crate::keys::assert_public_key_freshness::assert_nullifier_public_key_fresh; +use crate::keys::assert_public_key_freshness::assert_nullifier_public_key_is_fresh; diff --git a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr index d1961792feb..a1fffce3ef4 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr @@ -27,7 +27,7 @@ global PublicKeyType = PublicKeyTypeEnum { NULLIFIER: 0, }; -pub fn assert_nullifier_public_key_fresh( +pub fn assert_nullifier_public_key_is_fresh( context: &mut PrivateContext, address: AztecAddress, nullifier_public_key_to_test: GrumpkinPoint, 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 68311b75f4f..5d8fecf96da 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -19,7 +19,7 @@ contract Test { use dep::aztec::state_vars::shared_mutable::SharedMutablePrivateGetter; use dep::aztec::{ - keys::assert_public_key_freshness::assert_nullifier_public_key_fresh, + keys::assert_public_key_freshness::assert_nullifier_public_key_is_fresh, context::{Context, inputs::private_context_inputs::PrivateContextInputs}, hash::{pedersen_hash, compute_secret_hash, ArgsHasher}, note::{ @@ -415,7 +415,7 @@ contract Test { address: AztecAddress, public_nullifying_key: GrumpkinPoint, ) { - assert_nullifier_public_key_fresh(&mut context, address, public_nullifying_key); + assert_nullifier_public_key_is_fresh(&mut context, address, public_nullifying_key); } #[aztec(public)] From 7d1620d6ca9b6c9bdc147b0fcc878edc5f14c8e1 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 16:47:18 +0000 Subject: [PATCH 09/23] change some stuff --- .../src/keys/assert_public_key_freshness.nr | 48 +---- .../aztec-nr/aztec/src/oracle/keys.nr | 97 +++++---- .../end-to-end/src/e2e_key_registry.test.ts | 192 +++++++++--------- .../pxe/src/simulator_oracle/index.ts | 2 + .../simulator/src/acvm/oracle/oracle.ts | 1 + .../simulator/src/client/db_oracle.ts | 6 + .../simulator/src/client/view_data_oracle.ts | 7 + 7 files changed, 180 insertions(+), 173 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr index a1fffce3ef4..46a9122dc19 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr @@ -55,53 +55,13 @@ pub fn assert_nullifier_public_key_is_fresh( } fn check_public_key_validity(address: AztecAddress, key_type: u8, key: GrumpkinPoint) { - let (partial_address, keys) = get_public_keys_and_partial_address_internal(address); + let keys = get_public_keys_internal(address); assert(keys[key_type].eq(key)); - - _check_public_key_validity_constrain_internal( - address, - partial_address, - keys[0], - keys[1], - keys[2], - keys[3], - ) -} - -unconstrained fn get_public_keys_and_partial_address_internal(address: AztecAddress) -> (PartialAddress, [GrumpkinPoint; 4]) { - let (partial_address, public_keys) = oracle::keys::get_public_keys_and_partial_address(address); - - (partial_address, public_keys) } -fn _check_public_key_validity_constrain_internal( - address: AztecAddress, - partial_address: PartialAddress, - nullifier_public_key: GrumpkinPoint, - incoming_public_key: GrumpkinPoint, - outgoing_public_key: GrumpkinPoint, - tagging_public_key: GrumpkinPoint - ) { - let public_keys_hash = poseidon2_hash([ - nullifier_public_key.serialize()[0], - nullifier_public_key.serialize()[1], - incoming_public_key.serialize()[0], - incoming_public_key.serialize()[1], - outgoing_public_key.serialize()[0], - outgoing_public_key.serialize()[1], - tagging_public_key.serialize()[0], - tagging_public_key.serialize()[1], - GENERATOR_INDEX__PUBLIC_KEYS_HASH, - ]); - - let computed_address = AztecAddress::from_field( - poseidon2_hash([ - partial_address.to_field(), - public_keys_hash.to_field(), - GENERATOR_INDEX__CONTRACT_ADDRESS_V1, - ]) - ); +fn get_public_keys_internal(address: AztecAddress) -> [GrumpkinPoint; 4] { + let (_, public_keys) = oracle::keys::get_public_keys_and_partial_address(address); - assert(computed_address.eq(address)); + public_keys } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr index 4ff757be4d4..ca67986d093 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr @@ -1,47 +1,76 @@ -use dep::protocol_types::{address::{AztecAddress, PartialAddress, PublicKeysHash}, grumpkin_point::GrumpkinPoint}; +use dep::protocol_types::{ + address::{ + AztecAddress, + PartialAddress, + PublicKeysHash, + }, + constants::{ + GENERATOR_INDEX__PUBLIC_KEYS_HASH, + GENERATOR_INDEX__CONTRACT_ADDRESS_V1, + }, + grumpkin_point::GrumpkinPoint, +}; -#[oracle(getPublicKeysForAddress)] -fn get_public_keys_for_address_oracle( - address: AztecAddress, -) -> [GrumpkinPoint; 4] {} +use crate::hash::poseidon2_hash; -unconstrained fn get_public_keys_for_address_oracle_wrapper( - address: AztecAddress -) -> [GrumpkinPoint; 4] { - get_public_keys_for_address_oracle( - address, - ) +#[oracle(getPublicKeysAndPartialAddress)] +fn get_public_keys_and_partial_address_oracle(_address: AztecAddress) -> [Field; 9] {} + +unconstrained fn get_public_keys_and_partial_address_oracle_wrapper(address: AztecAddress) -> [Field; 9] { + get_public_keys_and_partial_address_oracle(address) } -unconstrained pub fn get_public_keys_for_address( - address: AztecAddress, -) -> [GrumpkinPoint; 4] { - let public_keys = get_public_keys_for_address_oracle_wrapper( +pub fn get_public_keys_and_partial_address(address: AztecAddress) -> (PartialAddress, [GrumpkinPoint; 4]) { + let result = get_public_keys_and_partial_address_oracle_wrapper(address); + + let partial_address = PartialAddress::from_field(result[0]); + let nullifier_pub_key = GrumpkinPoint::new(result[1], result[2]); + let incoming_pub_key = GrumpkinPoint::new(result[3], result[4]); + let outgoing_pub_key = GrumpkinPoint::new(result[5], result[6]); + let tagging_pub_key = GrumpkinPoint::new(result[7], result[8]); + + _check_public_key_validity_constrain_oracle( address, + partial_address, + nullifier_pub_key, + incoming_pub_key, + outgoing_pub_key, + tagging_pub_key, ); - public_keys + (partial_address, [nullifier_pub_key, incoming_pub_key, outgoing_pub_key, tagging_pub_key]) } +fn _check_public_key_validity_constrain_oracle( + address: AztecAddress, + partial_address: PartialAddress, + nullifier_public_key: GrumpkinPoint, + incoming_public_key: GrumpkinPoint, + outgoing_public_key: GrumpkinPoint, + tagging_public_key: GrumpkinPoint + ) { + let public_keys_hash = poseidon2_hash([ + nullifier_public_key.serialize()[0], + nullifier_public_key.serialize()[1], + incoming_public_key.serialize()[0], + incoming_public_key.serialize()[1], + outgoing_public_key.serialize()[0], + outgoing_public_key.serialize()[1], + tagging_public_key.serialize()[0], + tagging_public_key.serialize()[1], + GENERATOR_INDEX__PUBLIC_KEYS_HASH, + ]); -#[oracle(getPublicKeysAndPartialAddress)] -fn get_public_keys_and_partial_address_oracle(_address: AztecAddress) -> [Field; 9] {} +// TODO: #5830: we can compute this like below once refactored +// let calculated_address = AztecAddress::compute(PublicKeysHash::compute(pub_key), partial_address); -unconstrained fn get_public_keys_and_partial_address_oracle_wrapper(address: AztecAddress) -> [Field; 9] { - get_public_keys_and_partial_address_oracle(address) -} + let computed_address = AztecAddress::from_field( + poseidon2_hash([ + partial_address.to_field(), + public_keys_hash.to_field(), + GENERATOR_INDEX__CONTRACT_ADDRESS_V1, + ]) + ); -pub fn get_public_keys_and_partial_address(address: AztecAddress) -> (PartialAddress, [GrumpkinPoint; 4]) { - let result = get_public_keys_and_partial_address_oracle_wrapper(address); - let partial_address = PartialAddress::from_field(result[0]); - let nullifier_pub_key = GrumpkinPoint::new(result[1], result[2]); - let incoming_pub_key = GrumpkinPoint::new(result[3], result[4]); - let outgoing_pub_key = GrumpkinPoint::new(result[5], result[6]); - let tagging_pub_key = GrumpkinPoint::new(result[7], result[8]); - - // 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)); - - (partial_address, [nullifier_pub_key, incoming_pub_key, outgoing_pub_key, tagging_pub_key]) + assert(computed_address.eq(address)); } 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 2b686e27288..e11585002cb 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 @@ -22,7 +22,7 @@ describe('Key Registry', () => { let teardown: () => Promise; beforeAll(async () => { - ({ teardown, pxe, wallets } = await setup(2)); + ({ teardown, pxe, wallets } = await setup(3)); keyRegistry = await KeyRegistryContract.at(getCanonicalKeyRegistryAddress(), wallets[0]); testContract = await TestContract.deploy(wallets[0]).send().deployed(); @@ -42,12 +42,11 @@ describe('Key Registry', () => { let accountAddedToRegistry: AztecAddress; describe('should fail registering with bad input', () => { - const partialAddress = new Fr(69); - - const masterNullifierPublicKey = new Fr(12); - const masterIncomingViewingPublicKey = new Fr(34); - const masterOutgoingViewingPublicKey = new Fr(56); - const masterTaggingPublicKey = new Fr(78); + const masterNullifierPublicKey: Point = new Point(new Fr(1), new Fr(2)); + const masterIncomingViewingPublicKey: Point = new Point(new Fr(3), new Fr(4)); + const masterOutgoingViewingPublicKey: Point = new Point(new Fr(5), new Fr(6)); + const masterTaggingPublicKey: Point = new Point(new Fr(7), new Fr(8)); + const partialAddress: PartialAddress = new Fr(69); // TODO(#5726): use computePublicKeysHash function const publicKeysHash = poseidon2Hash([ @@ -82,7 +81,7 @@ describe('Key Registry', () => { }); it('should fail registering with mismatched nullifier public key', async () => { - const mismatchedMasterNullifierPublicKey = Fr.random(); + const mismatchedMasterNullifierPublicKey = Point.random(); await expect( keyRegistry @@ -106,7 +105,7 @@ describe('Key Registry', () => { await expect( keyRegistry .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), new Fr(0)) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), Point.ZERO) .send() .wait(), ).rejects.toThrow('New nullifier public key must be non-zero'); @@ -116,7 +115,7 @@ describe('Key Registry', () => { await expect( keyRegistry .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[1].getAddress(), new Fr(2)) + .methods.rotate_nullifier_public_key(wallets[1].getAddress(), Point.random()) .send() .wait(), ).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -126,14 +125,13 @@ describe('Key Registry', () => { describe('key registration flow', () => { let accountAddedToRegistry: AztecAddress; + const masterNullifierPublicKey: Point = new Point(new Fr(1), new Fr(2)); it('should generate and register with original keys', async () => { - const partialAddress = new Fr(69); - - const masterNullifierPublicKey = new Fr(12); - const masterIncomingViewingPublicKey = new Fr(34); - const masterOutgoingViewingPublicKey = new Fr(56); - const masterTaggingPublicKey = new Fr(78); + const masterIncomingViewingPublicKey: Point = new Point(new Fr(3), new Fr(4)); + const masterOutgoingViewingPublicKey: Point = new Point(new Fr(5), new Fr(6)); + const masterTaggingPublicKey: Point = new Point(new Fr(7), new Fr(8)); + const partialAddress: PartialAddress = new Fr(69); const publicKeysHash = poseidon2Hash([ masterNullifierPublicKey, @@ -181,86 +179,89 @@ describe('Key Registry', () => { const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(12)); + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(masterNullifierPublicKey.toFields())); }); }); - describe('key rotation flow', () => { - it('we rotate the nullifier key', async () => { - // This changes - const newMasterNullifierPublicKey = new Fr(910); - - await keyRegistry - .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey) - .send() - .wait(); - }); - - it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); - - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(0)); - }); - - it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { - await delay(5); - - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); + describe('key rotation flows', () => { + const firstNewMasterNullifierPublicKey = Point.random(); - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(910)); - }); - }); - - describe('key rotation flow with authwit', () => { - it('wallet 0 lets wallet 1 call rotate_nullifier_public_key on his behalf with a pre-defined new public key', async () => { + describe('normal key rotation flow', () => { // This changes - const newMasterNullifierPublicKey = new Fr(420); - - const action = keyRegistry - .withWallet(wallets[1]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey); - - await wallets[0] - .setPublicAuthWit({ caller: wallets[1].getCompleteAddress().address, action }, true) - .send() - .wait(); - - await action.send().wait(); - }); - - it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); - - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(910)); + + it('we rotate the nullifier key', async () => { + await keyRegistry + .withWallet(wallets[0]) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), firstNewMasterNullifierPublicKey) + .send() + .wait(); + }); + + it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { + const { txHash } = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .send() + .wait(); + + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(0)); + }); + + it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { + await delay(5); + + const { txHash } = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .send() + .wait(); + + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(firstNewMasterNullifierPublicKey.toFields())); + }); }); - - it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { - await delay(5); - - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); - - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(420)); + + describe('key rotation flow with authwit', () => { + // This changes + const secondNewMasterNullifierPublicKey = Point.random(); + + it('wallet 0 lets wallet 1 call rotate_nullifier_public_key on his behalf with a pre-defined new public key', async () => { + const action = keyRegistry + .withWallet(wallets[1]) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), secondNewMasterNullifierPublicKey); + + await wallets[0] + .setPublicAuthWit({ caller: wallets[1].getCompleteAddress().address, action }, true) + .send() + .wait(); + + await action.send().wait(); + }); + + it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { + const { txHash } = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .send() + .wait(); + + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(firstNewMasterNullifierPublicKey.toFields())); + }); + + it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { + await delay(5); + + const { txHash } = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .send() + .wait(); + + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(secondNewMasterNullifierPublicKey.toFields())); + }); }); - }); + }) describe('key registration flow no PXE', () => { const masterNullifierPublicKey: Point = new Point(new Fr(9), new Fr(10)); @@ -325,11 +326,12 @@ describe('Key Registry', () => { }); describe('key registration flow via PXE', () => { - const masterNullifierPublicKey: Point = new Point(new Fr(1), new Fr(2)); - const masterIncomingViewingPublicKey: Point = new Point(new Fr(3), new Fr(4)); - const masterOutgoingViewingPublicKey: Point = new Point(new Fr(5), new Fr(6)); - const masterTaggingPublicKey: Point = new Point(new Fr(7), new Fr(8)); - const partialAddress: PartialAddress = new Fr(69); + const masterNullifierPublicKey: Point = new Point(new Fr(17), new Fr(18)); + const masterIncomingViewingPublicKey: Point = new Point(new Fr(19), new Fr(20)); + const masterOutgoingViewingPublicKey: Point = new Point(new Fr(21), new Fr(22)); + const masterTaggingPublicKey: Point = new Point(new Fr(23), new Fr(24)); + + const partialAddress: PartialAddress = new Fr(69420); const publicKeysHash = poseidon2Hash([ masterNullifierPublicKey, @@ -397,7 +399,7 @@ describe('Key Registry', () => { .wait(); }); - it('in the case where the key exists both in the pxe and our registry, we know it works', async () => { + it('in the case where the key exists both in the pxe and our registry, we know nothing weird will happen', async () => { await delay(5); const { txHash } = await testContract.methods diff --git a/yarn-project/pxe/src/simulator_oracle/index.ts b/yarn-project/pxe/src/simulator_oracle/index.ts index 867ca8d0824..0a81cc5b1d6 100644 --- a/yarn-project/pxe/src/simulator_oracle/index.ts +++ b/yarn-project/pxe/src/simulator_oracle/index.ts @@ -44,6 +44,7 @@ export class SimulatorOracle implements DBOracle { return { masterNullifierPublicKey, appNullifierSecretKey }; } + // TODO: #5834 async getCompleteAddress(address: AztecAddress): Promise { const completeAddress = await this.db.getCompleteAddress(address); if (!completeAddress) { @@ -78,6 +79,7 @@ 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); diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 8226f58a1bc..3eaf7f9411f 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -175,6 +175,7 @@ export class Oracle { async getPublicKeysAndPartialAddress([address]: ACVMField[]): Promise { let partialAddress: PartialAddress; let publicKeys: Point[] | undefined; + // 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) { diff --git a/yarn-project/simulator/src/client/db_oracle.ts b/yarn-project/simulator/src/client/db_oracle.ts index 9287249f1cf..2646898a612 100644 --- a/yarn-project/simulator/src/client/db_oracle.ts +++ b/yarn-project/simulator/src/client/db_oracle.ts @@ -64,6 +64,12 @@ export interface DBOracle extends CommitmentsDB { */ popCapsule(): Promise; + /** + * Gets public keys for an address, getCompleteAddress should be modified to include this + * @param The address to look up + * @returns The public keys for a specific address + * TODO: #5834 + */ getPublicKeysForAddress(address: AztecAddress): Promise; /** diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index d2a85c4a242..48c4adc873f 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -166,6 +166,13 @@ export class ViewDataOracle extends TypedOracle { return this.db.popCapsule(); } + + /** + * Gets public keys for an address, getCompleteAddress should be modified to include this + * @param The address to look up + * @returns The public keys for a specific address + * TODO: #5834 + */ public override getPublicKeysForAddress(address: AztecAddress) { return this.db.getPublicKeysForAddress(address); } From f0ece6935a48d79059db942134574bfb483d8345 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 16:49:51 +0000 Subject: [PATCH 10/23] fix --- yarn-project/simulator/src/acvm/oracle/oracle.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 3eaf7f9411f..900a99558f9 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -53,7 +53,7 @@ export class Oracle { ]; } - // TODO (ek): Nuke this + // TODO: #5830 Nuke this async getPublicKeyAndPartialAddress([address]: ACVMField[]) { const { publicKey, partialAddress } = await this.typedOracle.getCompleteAddress( AztecAddress.fromField(fromACVMField(address)), From 046100659ec34f09dd36ba7a180485c1ca75e339 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 16:50:55 +0000 Subject: [PATCH 11/23] fix --- yarn-project/simulator/src/acvm/oracle/oracle.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 900a99558f9..0aaca5464f9 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -53,7 +53,7 @@ export class Oracle { ]; } - // TODO: #5830 Nuke this + // TODO: #5834 Nuke this async getPublicKeyAndPartialAddress([address]: ACVMField[]) { const { publicKey, partialAddress } = await this.typedOracle.getCompleteAddress( AztecAddress.fromField(fromACVMField(address)), From e4f6d15b5c4d0ca3d209f2e77fbbc0aefc47d871 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 16:52:15 +0000 Subject: [PATCH 12/23] asdf --- yarn-project/pxe/src/pxe_service/pxe_service.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index b9ef265e408..b302acf598d 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -219,6 +219,7 @@ export class PXEService implements PXE { public async registerRecipient(recipient: CompleteAddress, publicKeys: Point[] = []): Promise { const wasAdded = await this.db.addCompleteAddress(recipient); + // #5834 if (publicKeys.length !== 0) { await this.keyStore.addPublicKeysForAccount( recipient.address, From f9a844b701c4fd7410343171728917fba335e535 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 16:58:13 +0000 Subject: [PATCH 13/23] fix --- yarn-project/circuit-types/src/interfaces/pxe.ts | 2 +- yarn-project/circuit-types/src/keys/key_store.ts | 7 ++++++- yarn-project/pxe/src/pxe_service/pxe_service.ts | 2 +- 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index f36958df987..eab85b46980 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -73,7 +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: FIX THIS AFTER THE COMPLETE ADDRESS REFACTOR + // TODO: #5834: FIX THIS AFTER THE COMPLETE ADDRESS REFACTOR registerRecipient(recipient: CompleteAddress, publicKeys?: Point[]): Promise; /** diff --git a/yarn-project/circuit-types/src/keys/key_store.ts b/yarn-project/circuit-types/src/keys/key_store.ts index e5cefbd7bc4..dd77bde64ed 100644 --- a/yarn-project/circuit-types/src/keys/key_store.ts +++ b/yarn-project/circuit-types/src/keys/key_store.ts @@ -119,7 +119,12 @@ export interface KeyStore { 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 */ addPublicKeysForAccount( accountAddress: AztecAddress, diff --git a/yarn-project/pxe/src/pxe_service/pxe_service.ts b/yarn-project/pxe/src/pxe_service/pxe_service.ts index b302acf598d..c1747a2d6c4 100644 --- a/yarn-project/pxe/src/pxe_service/pxe_service.ts +++ b/yarn-project/pxe/src/pxe_service/pxe_service.ts @@ -219,7 +219,7 @@ export class PXEService implements PXE { public async registerRecipient(recipient: CompleteAddress, publicKeys: Point[] = []): Promise { const wasAdded = await this.db.addCompleteAddress(recipient); - // #5834 + // TODO #5834: This should be refactored to be okay with only adding complete address if (publicKeys.length !== 0) { await this.keyStore.addPublicKeysForAccount( recipient.address, From 0e0b63e3fe7c8c4907c0bfa7c1fce615b818b4c4 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 18:51:05 +0000 Subject: [PATCH 14/23] fix --- .../src/keys/assert_public_key_freshness.nr | 6 +- .../aztec-nr/aztec/src/oracle/keys.nr | 6 +- .../end-to-end/src/e2e_key_registry.test.ts | 90 +++++++++++++------ 3 files changed, 69 insertions(+), 33 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr index 46a9122dc19..dc0915b92e4 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr @@ -44,13 +44,13 @@ pub fn assert_nullifier_public_key_is_fresh( // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly // We read from the canonical Key Registry let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(*context, AztecAddress::from_field(CANONICAL_KEY_REGISTRY_ADDRESS), derived_slot); - let hashed_nullifier_public_key = registry_private_getter.get_current_value_in_private(); + let hashed_nullifier_public_key_in_registry = registry_private_getter.get_current_value_in_private(); // In the case that the value is not found in the registry we need to manually pass in the address preimage - if (hashed_nullifier_public_key == 0) { + if (hashed_nullifier_public_key_in_registry == 0) { check_public_key_validity(address, PublicKeyType.NULLIFIER, nullifier_public_key_to_test); } else { - assert(hashed_nullifier_public_key == poseidon2_hash(nullifier_public_key_to_test.serialize())); + assert(hashed_nullifier_public_key_in_registry == poseidon2_hash(nullifier_public_key_to_test.serialize())); } } diff --git a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr index ca67986d093..2a7fd4a41ee 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr @@ -66,9 +66,9 @@ fn _check_public_key_validity_constrain_oracle( let computed_address = AztecAddress::from_field( poseidon2_hash([ - partial_address.to_field(), - public_keys_hash.to_field(), - GENERATOR_INDEX__CONTRACT_ADDRESS_V1, + partial_address.to_field(), + public_keys_hash.to_field(), + GENERATOR_INDEX__CONTRACT_ADDRESS_V1, ]) ); 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 e11585002cb..6ca01a15d1e 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 @@ -42,11 +42,11 @@ describe('Key Registry', () => { let accountAddedToRegistry: AztecAddress; describe('should fail registering with bad input', () => { - const masterNullifierPublicKey: Point = new Point(new Fr(1), new Fr(2)); - const masterIncomingViewingPublicKey: Point = new Point(new Fr(3), new Fr(4)); - const masterOutgoingViewingPublicKey: Point = new Point(new Fr(5), new Fr(6)); - const masterTaggingPublicKey: Point = new Point(new Fr(7), new Fr(8)); - const partialAddress: PartialAddress = new Fr(69); + const masterNullifierPublicKey = Point.random(); + const masterIncomingViewingPublicKey = Point.random(); + const masterOutgoingViewingPublicKey = Point.random(); + const masterTaggingPublicKey = Point.random(); + const partialAddress: PartialAddress = Fr.random(); // TODO(#5726): use computePublicKeysHash function const publicKeysHash = poseidon2Hash([ @@ -59,16 +59,16 @@ describe('Key Registry', () => { // We hash the partial address and the public keys hash to get the account address // TODO(#5726): Move the following line to AztecAddress class? - accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); + accountAddedToRegistry = AztecAddress.fromField(poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1])); it('should fail registering with mismatched address', async () => { - const mismatchedAddress = Fr.random(); + const mismatchedAddress = AztecAddress.random(); await expect( keyRegistry .withWallet(wallets[0]) .methods.register( - AztecAddress.fromField(mismatchedAddress), + mismatchedAddress, partialAddress, masterNullifierPublicKey, masterIncomingViewingPublicKey, @@ -143,7 +143,7 @@ describe('Key Registry', () => { // We hash the partial address and the public keys hash to get the account address // TODO(#5726): Move the following line to AztecAddress class? - accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); + accountAddedToRegistry = AztecAddress.fromField(poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1])); await keyRegistry .withWallet(wallets[0]) @@ -186,9 +186,7 @@ describe('Key Registry', () => { describe('key rotation flows', () => { const firstNewMasterNullifierPublicKey = Point.random(); - describe('normal key rotation flow', () => { - // This changes - + describe('normal key rotation flow', () => { it('we rotate the nullifier key', async () => { await keyRegistry .withWallet(wallets[0]) @@ -222,7 +220,7 @@ describe('Key Registry', () => { }); describe('key rotation flow with authwit', () => { - // This changes + // This is the new value const secondNewMasterNullifierPublicKey = Point.random(); it('wallet 0 lets wallet 1 call rotate_nullifier_public_key on his behalf with a pre-defined new public key', async () => { @@ -263,11 +261,11 @@ describe('Key Registry', () => { }); }) - describe('key registration flow no PXE', () => { - const masterNullifierPublicKey: Point = new Point(new Fr(9), new Fr(10)); - const masterIncomingViewingPublicKey: Point = new Point(new Fr(11), new Fr(12)); - const masterOutgoingViewingPublicKey: Point = new Point(new Fr(13), new Fr(14)); - const masterTaggingPublicKey: Point = new Point(new Fr(15), new Fr(16)); + describe('test keys are fresh: key registration flow, no PXE', () => { + const masterNullifierPublicKey = Point.random(); + const masterIncomingViewingPublicKey = Point.random(); + const masterOutgoingViewingPublicKey = Point.random(); + const masterTaggingPublicKey = Point.random(); const partialAddress: PartialAddress = new Fr(420); const publicKeysHash = poseidon2Hash([ @@ -280,7 +278,7 @@ describe('Key Registry', () => { // 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 accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); + const accountAddedToRegistry = AztecAddress.fromField(poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1])); it('should fail as we have not registered anything to the registry nor have we registered a recipient', async () => { await expect( @@ -288,7 +286,7 @@ describe('Key Registry', () => { .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) .send() .wait(), - ).rejects.toThrow(); + ).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); }); it('Now we add it to registry', async () => { @@ -312,7 +310,7 @@ describe('Key Registry', () => { .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) .send() .wait(), - ).rejects.toThrow(); + ).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); }); it('checks key freshness after a delay, and is successful', async () => { @@ -323,9 +321,24 @@ describe('Key Registry', () => { .send() .wait(); }); + + it('should succeed even if our pxe gives conflicting information', async () => { + // FIX THIS (#5834) + await pxe.registerRecipient(CompleteAddress.create(accountAddedToRegistry, Point.ZERO, partialAddress), [ + new Point(Fr.random(), Fr.random()), + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + ]); + + await testContract.methods + .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) + .send() + .wait(); + }); }); - describe('key registration flow via PXE', () => { + describe('test keys are fresh: key registration flow, with PXE', () => { const masterNullifierPublicKey: Point = new Point(new Fr(17), new Fr(18)); const masterIncomingViewingPublicKey: Point = new Point(new Fr(19), new Fr(20)); const masterOutgoingViewingPublicKey: Point = new Point(new Fr(21), new Fr(22)); @@ -343,7 +356,7 @@ describe('Key Registry', () => { // 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 accountAddedToRegistry = poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]); + const accountAddedToRegistry = AztecAddress.fromField(poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1])); it('should fail as we have not registered anything to the registry nor have we registered a recipient', async () => { await expect( @@ -351,11 +364,27 @@ describe('Key Registry', () => { .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) .send() .wait(), - ).rejects.toThrow(); + ).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); + }); + + it('should fail when we register bad keys and the lib checks our pxe', async () => { + const randAddress = AztecAddress.random(); + // FIX THIS (#5834) + await pxe.registerRecipient(CompleteAddress.create(randAddress, Point.ZERO, partialAddress), [ + masterNullifierPublicKey, + masterIncomingViewingPublicKey, + masterOutgoingViewingPublicKey, + masterTaggingPublicKey, + ]); + + await expect(testContract.methods + .test_nullifier_key_freshness(randAddress, masterNullifierPublicKey) + .send() + .wait()).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); }); it('should succeed because we register our recipient manually and the lib checks our pxe', async () => { - // FIX THIS + // FIX THIS (#5834) await pxe.registerRecipient(CompleteAddress.create(accountAddedToRegistry, Point.ZERO, partialAddress), [ masterNullifierPublicKey, masterIncomingViewingPublicKey, @@ -368,6 +397,13 @@ describe('Key Registry', () => { .wait(); }); + it('should fail when we put in a different key', async () => { + await expect(testContract.methods + .test_nullifier_key_freshness(accountAddedToRegistry, masterIncomingViewingPublicKey) + .send() + .wait()).rejects.toThrow(`Cannot satisfy constraint 'keys[key_type].eq(key)'`); + }); + it('Now we add it to registry', async () => { await keyRegistry .withWallet(wallets[0]) @@ -419,7 +455,7 @@ describe('Key Registry', () => { }); describe('key rotation flow; assert keys are fresh', () => { - const newMasterNullifierPublicKey = new Point(new Fr(910), new Fr(1112)); + const newMasterNullifierPublicKey = Point.random(); it('we rotate the nullifier key', async () => { await keyRegistry @@ -435,7 +471,7 @@ describe('Key Registry', () => { .test_nullifier_key_freshness(wallets[0].getAddress(), newMasterNullifierPublicKey) .send() .wait(), - ).rejects.toThrow(); + ).rejects.toThrow(`Cannot satisfy constraint 'hashed_nullifier_public_key == poseidon2_hash(nullifier_public_key_to_test.serialize())`); }); it('checks our registry contract from test contract and succeeds because the change has been applied', async () => { From 9051c8ebaa0410a8a3a07e7c03e0ac2727db617f Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 19:23:58 +0000 Subject: [PATCH 15/23] format --- .../end-to-end/src/e2e_key_registry.test.ts | 89 +++++++++++-------- .../simulator/src/client/view_data_oracle.ts | 1 - 2 files changed, 53 insertions(+), 37 deletions(-) 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 6ca01a15d1e..c719e0a0f5c 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 @@ -59,7 +59,9 @@ describe('Key Registry', () => { // We hash the partial address and the public keys hash to get the account address // TODO(#5726): Move the following line to AztecAddress class? - accountAddedToRegistry = AztecAddress.fromField(poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1])); + accountAddedToRegistry = AztecAddress.fromField( + poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]), + ); it('should fail registering with mismatched address', async () => { const mismatchedAddress = AztecAddress.random(); @@ -143,7 +145,9 @@ describe('Key Registry', () => { // We hash the partial address and the public keys hash to get the account address // TODO(#5726): Move the following line to AztecAddress class? - accountAddedToRegistry = AztecAddress.fromField(poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1])); + accountAddedToRegistry = AztecAddress.fromField( + poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]), + ); await keyRegistry .withWallet(wallets[0]) @@ -186,7 +190,7 @@ describe('Key Registry', () => { describe('key rotation flows', () => { const firstNewMasterNullifierPublicKey = Point.random(); - describe('normal key rotation flow', () => { + describe('normal key rotation flow', () => { it('we rotate the nullifier key', async () => { await keyRegistry .withWallet(wallets[0]) @@ -194,72 +198,78 @@ describe('Key Registry', () => { .send() .wait(); }); - + it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { const { txHash } = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) .send() .wait(); - + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(0)); }); - + it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { await delay(5); - + const { txHash } = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) .send() .wait(); - + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(firstNewMasterNullifierPublicKey.toFields())); + + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual( + poseidon2Hash(firstNewMasterNullifierPublicKey.toFields()), + ); }); }); - + describe('key rotation flow with authwit', () => { // This is the new value const secondNewMasterNullifierPublicKey = Point.random(); - + it('wallet 0 lets wallet 1 call rotate_nullifier_public_key on his behalf with a pre-defined new public key', async () => { const action = keyRegistry .withWallet(wallets[1]) .methods.rotate_nullifier_public_key(wallets[0].getAddress(), secondNewMasterNullifierPublicKey); - + await wallets[0] .setPublicAuthWit({ caller: wallets[1].getCompleteAddress().address, action }, true) .send() .wait(); - + await action.send().wait(); }); - + it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { const { txHash } = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) .send() .wait(); - + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(firstNewMasterNullifierPublicKey.toFields())); + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual( + poseidon2Hash(firstNewMasterNullifierPublicKey.toFields()), + ); }); - + it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { await delay(5); - + const { txHash } = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) .send() .wait(); - + const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(secondNewMasterNullifierPublicKey.toFields())); + + expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual( + poseidon2Hash(secondNewMasterNullifierPublicKey.toFields()), + ); }); }); - }) + }); describe('test keys are fresh: key registration flow, no PXE', () => { const masterNullifierPublicKey = Point.random(); @@ -278,7 +288,9 @@ describe('Key Registry', () => { // 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 accountAddedToRegistry = AztecAddress.fromField(poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1])); + const accountAddedToRegistry = AztecAddress.fromField( + poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]), + ); it('should fail as we have not registered anything to the registry nor have we registered a recipient', async () => { await expect( @@ -323,7 +335,7 @@ describe('Key Registry', () => { }); it('should succeed even if our pxe gives conflicting information', async () => { - // FIX THIS (#5834) + // FIX THIS (#5834) await pxe.registerRecipient(CompleteAddress.create(accountAddedToRegistry, Point.ZERO, partialAddress), [ new Point(Fr.random(), Fr.random()), masterIncomingViewingPublicKey, @@ -356,7 +368,9 @@ describe('Key Registry', () => { // 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 accountAddedToRegistry = AztecAddress.fromField(poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1])); + const accountAddedToRegistry = AztecAddress.fromField( + poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]), + ); it('should fail as we have not registered anything to the registry nor have we registered a recipient', async () => { await expect( @@ -369,7 +383,7 @@ describe('Key Registry', () => { it('should fail when we register bad keys and the lib checks our pxe', async () => { const randAddress = AztecAddress.random(); - // FIX THIS (#5834) + // FIX THIS (#5834) await pxe.registerRecipient(CompleteAddress.create(randAddress, Point.ZERO, partialAddress), [ masterNullifierPublicKey, masterIncomingViewingPublicKey, @@ -377,10 +391,9 @@ describe('Key Registry', () => { masterTaggingPublicKey, ]); - await expect(testContract.methods - .test_nullifier_key_freshness(randAddress, masterNullifierPublicKey) - .send() - .wait()).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); + await expect( + testContract.methods.test_nullifier_key_freshness(randAddress, masterNullifierPublicKey).send().wait(), + ).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); }); it('should succeed because we register our recipient manually and the lib checks our pxe', async () => { @@ -398,10 +411,12 @@ describe('Key Registry', () => { }); it('should fail when we put in a different key', async () => { - await expect(testContract.methods - .test_nullifier_key_freshness(accountAddedToRegistry, masterIncomingViewingPublicKey) - .send() - .wait()).rejects.toThrow(`Cannot satisfy constraint 'keys[key_type].eq(key)'`); + await expect( + testContract.methods + .test_nullifier_key_freshness(accountAddedToRegistry, masterIncomingViewingPublicKey) + .send() + .wait(), + ).rejects.toThrow(`Cannot satisfy constraint 'keys[key_type].eq(key)'`); }); it('Now we add it to registry', async () => { @@ -471,7 +486,9 @@ describe('Key Registry', () => { .test_nullifier_key_freshness(wallets[0].getAddress(), newMasterNullifierPublicKey) .send() .wait(), - ).rejects.toThrow(`Cannot satisfy constraint 'hashed_nullifier_public_key == poseidon2_hash(nullifier_public_key_to_test.serialize())`); + ).rejects.toThrow( + `Cannot satisfy constraint 'hashed_nullifier_public_key == poseidon2_hash(nullifier_public_key_to_test.serialize())`, + ); }); it('checks our registry contract from test contract and succeeds because the change has been applied', async () => { diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index 48c4adc873f..2bc1fbfc937 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -166,7 +166,6 @@ export class ViewDataOracle extends TypedOracle { return this.db.popCapsule(); } - /** * Gets public keys for an address, getCompleteAddress should be modified to include this * @param The address to look up From 6e3509acbb06f7644ef839df8ebb545a0b1f61e9 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Fri, 26 Apr 2024 19:48:50 +0000 Subject: [PATCH 16/23] test --- yarn-project/end-to-end/src/e2e_key_registry.test.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 c719e0a0f5c..ce62bc216ff 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 @@ -487,7 +487,7 @@ describe('Key Registry', () => { .send() .wait(), ).rejects.toThrow( - `Cannot satisfy constraint 'hashed_nullifier_public_key == poseidon2_hash(nullifier_public_key_to_test.serialize())`, + `Cannot satisfy constraint 'hashed_nullifier_public_key_in_registry == poseidon2_hash(nullifier_public_key_to_test.serialize())'`, ); }); From 0ca8578b0713e104555103eccb87cb9aa3276b91 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 1 May 2024 12:00:42 +0000 Subject: [PATCH 17/23] Addressing comments --- noir-projects/aztec-nr/aztec/src/keys.nr | 4 +- .../src/keys/assert_public_key_freshness.nr | 67 ------ .../aztec-nr/aztec/src/keys/getters.nr | 55 +++++ .../aztec-nr/aztec/src/oracle/keys.nr | 53 +---- .../aztec-nr/aztec/src/state_vars/map.nr | 6 +- .../key_registry_contract/src/main.nr | 34 +-- .../contracts/test_contract/src/main.nr | 28 ++- .../crates/types/src/address/aztec_address.nr | 19 ++ .../types/src/address/public_keys_hash.nr | 27 ++- .../circuit-types/src/keys/key_store.ts | 1 + .../end-to-end/jest.integration.config.json | 2 +- .../end-to-end/src/e2e_key_registry.test.ts | 221 +++++++----------- .../end-to-end/src/e2e_state_vars.test.ts | 18 +- yarn-project/key-store/src/test_key_store.ts | 1 + yarn-project/package.common.json | 2 +- .../simulator/src/acvm/oracle/oracle.ts | 7 +- 16 files changed, 237 insertions(+), 308 deletions(-) delete mode 100644 noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr create mode 100644 noir-projects/aztec-nr/aztec/src/keys/getters.nr diff --git a/noir-projects/aztec-nr/aztec/src/keys.nr b/noir-projects/aztec-nr/aztec/src/keys.nr index 427d30ba671..25249687e3c 100644 --- a/noir-projects/aztec-nr/aztec/src/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/keys.nr @@ -1,3 +1,3 @@ -mod assert_public_key_freshness; +mod getters; -use crate::keys::assert_public_key_freshness::assert_nullifier_public_key_is_fresh; +use crate::keys::getters::get_fresh_nullifier_public_key_hash; diff --git a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr b/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr deleted file mode 100644 index dc0915b92e4..00000000000 --- a/noir-projects/aztec-nr/aztec/src/keys/assert_public_key_freshness.nr +++ /dev/null @@ -1,67 +0,0 @@ -use dep::protocol_types::{ - address::{ - AztecAddress, - PartialAddress - }, - constants::{ - GENERATOR_INDEX__PUBLIC_KEYS_HASH, - GENERATOR_INDEX__CONTRACT_ADDRESS_V1, - CANONICAL_KEY_REGISTRY_ADDRESS - }, - grumpkin_point::GrumpkinPoint, -}; - -use crate::context::PrivateContext; -use crate::hash::{ - pedersen_hash, - poseidon2_hash, -}; -use crate::oracle; -use crate::state_vars::shared_mutable::shared_mutable_private_getter::SharedMutablePrivateGetter; - -struct PublicKeyTypeEnum { - NULLIFIER: u8, -} - -global PublicKeyType = PublicKeyTypeEnum { - NULLIFIER: 0, -}; - -pub fn assert_nullifier_public_key_is_fresh( - context: &mut PrivateContext, - address: AztecAddress, - nullifier_public_key_to_test: GrumpkinPoint, -) { - // This is the storage slot of the nullifier_public_key inside the key registry contract - let storage_slot_of_nullifier_public_key = 1; - // We have to derive this slot to get the location of the shared mutable inside the Map - // This should mimic how maps derive their slots - let derived_slot = pedersen_hash( - [storage_slot_of_nullifier_public_key, address.to_field()], - 0 - ); - - // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly - // We read from the canonical Key Registry - let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(*context, AztecAddress::from_field(CANONICAL_KEY_REGISTRY_ADDRESS), derived_slot); - let hashed_nullifier_public_key_in_registry = registry_private_getter.get_current_value_in_private(); - - // In the case that the value is not found in the registry we need to manually pass in the address preimage - if (hashed_nullifier_public_key_in_registry == 0) { - check_public_key_validity(address, PublicKeyType.NULLIFIER, nullifier_public_key_to_test); - } else { - assert(hashed_nullifier_public_key_in_registry == poseidon2_hash(nullifier_public_key_to_test.serialize())); - } -} - -fn check_public_key_validity(address: AztecAddress, key_type: u8, key: GrumpkinPoint) { - let keys = get_public_keys_internal(address); - - assert(keys[key_type].eq(key)); -} - -fn get_public_keys_internal(address: AztecAddress) -> [GrumpkinPoint; 4] { - let (_, public_keys) = oracle::keys::get_public_keys_and_partial_address(address); - - public_keys -} diff --git a/noir-projects/aztec-nr/aztec/src/keys/getters.nr b/noir-projects/aztec-nr/aztec/src/keys/getters.nr new file mode 100644 index 00000000000..321441e7a7e --- /dev/null +++ b/noir-projects/aztec-nr/aztec/src/keys/getters.nr @@ -0,0 +1,55 @@ +use dep::protocol_types::{ + address::{ + AztecAddress, + PartialAddress + }, + constants::{ + GENERATOR_INDEX__PUBLIC_KEYS_HASH, + GENERATOR_INDEX__CONTRACT_ADDRESS_V1, + CANONICAL_KEY_REGISTRY_ADDRESS + }, + grumpkin_point::GrumpkinPoint, +}; + +use crate::context::PrivateContext; +use crate::hash::{ + pedersen_hash, + poseidon2_hash, +}; +use crate::oracle; +use crate::state_vars::{ + map::derive_storage_slot_in_map, + shared_mutable::shared_mutable_private_getter::SharedMutablePrivateGetter, +}; + +struct PublicKeyTypeEnum { + NULLIFIER: u8, +} + +global PublicKeyType = PublicKeyTypeEnum { + NULLIFIER: 0, +}; + +pub fn get_fresh_nullifier_public_key_hash( + context: &mut PrivateContext, + address: AztecAddress, +) -> Field { + // This is the storage slot of the nullifier_public_key inside the key registry contract + let storage_slot_of_nullifier_public_key = 1; + + let derived_slot = derive_storage_slot_in_map(storage_slot_of_nullifier_public_key, address); + + // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly + // We read from the canonical Key Registry + let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(*context, AztecAddress::from_field(CANONICAL_KEY_REGISTRY_ADDRESS), derived_slot); + let nullifier_public_key_hash_in_registry = registry_private_getter.get_current_value_in_private(); + + let nullifier_public_key_hash = if nullifier_public_key_hash_in_registry == 0 { + let keys = oracle::keys::get_public_keys(address); + poseidon2_hash(keys[PublicKeyType.NULLIFIER].serialize()) + } else { + nullifier_public_key_hash_in_registry + }; + + nullifier_public_key_hash +} diff --git a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr index 2a7fd4a41ee..98ea76ed617 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr @@ -20,57 +20,24 @@ unconstrained fn get_public_keys_and_partial_address_oracle_wrapper(address: Azt get_public_keys_and_partial_address_oracle(address) } -pub fn get_public_keys_and_partial_address(address: AztecAddress) -> (PartialAddress, [GrumpkinPoint; 4]) { +pub fn get_public_keys(address: AztecAddress) -> [GrumpkinPoint; 4] { let result = get_public_keys_and_partial_address_oracle_wrapper(address); - let partial_address = PartialAddress::from_field(result[0]); - let nullifier_pub_key = GrumpkinPoint::new(result[1], result[2]); - let incoming_pub_key = GrumpkinPoint::new(result[3], result[4]); - let outgoing_pub_key = GrumpkinPoint::new(result[5], result[6]); - let tagging_pub_key = GrumpkinPoint::new(result[7], result[8]); + let nullifier_pub_key = GrumpkinPoint::new(result[0], result[1]); + let incoming_pub_key = GrumpkinPoint::new(result[2], result[3]); + let outgoing_pub_key = GrumpkinPoint::new(result[4], result[5]); + let tagging_pub_key = GrumpkinPoint::new(result[6], result[7]); + let partial_address = PartialAddress::from_field(result[8]); - _check_public_key_validity_constrain_oracle( - address, - partial_address, + 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, [nullifier_pub_key, incoming_pub_key, outgoing_pub_key, tagging_pub_key]) -} - -fn _check_public_key_validity_constrain_oracle( - address: AztecAddress, - partial_address: PartialAddress, - nullifier_public_key: GrumpkinPoint, - incoming_public_key: GrumpkinPoint, - outgoing_public_key: GrumpkinPoint, - tagging_public_key: GrumpkinPoint - ) { - let public_keys_hash = poseidon2_hash([ - nullifier_public_key.serialize()[0], - nullifier_public_key.serialize()[1], - incoming_public_key.serialize()[0], - incoming_public_key.serialize()[1], - outgoing_public_key.serialize()[0], - outgoing_public_key.serialize()[1], - tagging_public_key.serialize()[0], - tagging_public_key.serialize()[1], - GENERATOR_INDEX__PUBLIC_KEYS_HASH, - ]); - -// TODO: #5830: we can compute this like below once refactored -// let calculated_address = AztecAddress::compute(PublicKeysHash::compute(pub_key), partial_address); - - let computed_address = AztecAddress::from_field( - poseidon2_hash([ - partial_address.to_field(), - public_keys_hash.to_field(), - GENERATOR_INDEX__CONTRACT_ADDRESS_V1, - ]) + partial_address, ); assert(computed_address.eq(address)); + + [nullifier_pub_key, incoming_pub_key, outgoing_pub_key, tagging_pub_key] } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/map.nr b/noir-projects/aztec-nr/aztec/src/state_vars/map.nr index a138a8deb9c..c075578db3f 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/map.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/map.nr @@ -27,10 +27,14 @@ impl Map { // docs:start:at pub fn at(self, key: K) -> V where K: ToField { // TODO(#1204): use a generator index for the storage slot - let derived_storage_slot = pedersen_hash([self.storage_slot, key.to_field()], 0); + let derived_storage_slot = derive_storage_slot_in_map(self.storage_slot, key); let state_var_constructor = self.state_var_constructor; state_var_constructor(self.context, derived_storage_slot) } // docs:end:at } + +pub fn derive_storage_slot_in_map(storage_slot: Field, key: K) -> Field where K: ToField { + pedersen_hash([storage_slot, key.to_field()], 0) +} 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 6124253c417..9d25af0055e 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 @@ -25,9 +25,12 @@ contract KeyRegistry { #[aztec(storage)] struct Storage { + //! This should stay at storage slot 1. If you change this, make sure you change the hardcoded value in keys/assert_public_key_freshness. + //! We use this hardcoded storage slot with derive_storage_slot_in_map and the SharedMutablePrivateGetter to directly read the value at an address in this contract. + nullifier_public_key_hash_registry: Map>, + // We are not supporting rotating / changing keys other than the nullifier public in the registry at the moment, but will in the future. // Uncomment lines below to enable that functionality - nullifier_public_key_hash_registry: Map>, // incoming_public_key_registry: Map>, // outgoing_public_key_registry: Map>, // tagging_public_key_registry: Map>, @@ -70,30 +73,13 @@ contract KeyRegistry { "All public keys must be non-zero" ); - // TODO (ek): Do it below after refactoring all public_keys_hash_elemtns - // let public_keys_hash = PublicKeysHash::compute(nullifier_public_key, tagging_public_key, incoming_public_key, outgoing_public_key); - // let address = AztecAddress::compute(public_keys_hash, partial_address); // We could also pass in original_public_keys_hash instead of computing it here, if all we need the original one is for being able to prove ownership of address - let public_keys_hash = poseidon2_hash([ - nullifier_public_key.serialize()[0], - nullifier_public_key.serialize()[1], - incoming_public_key.serialize()[0], - incoming_public_key.serialize()[1], - outgoing_public_key.serialize()[0], - outgoing_public_key.serialize()[1], - tagging_public_key.serialize()[0], - tagging_public_key.serialize()[1], - GENERATOR_INDEX__PUBLIC_KEYS_HASH, - ] - ); - - let computed_address = AztecAddress::from_field( - poseidon2_hash([ - partial_address.to_field(), - public_keys_hash.to_field(), - GENERATOR_INDEX__CONTRACT_ADDRESS_V1 as Field, - ] - ) + let computed_address = AztecAddress::compute_from_public_keys_and_partial_address( + nullifier_public_key, + incoming_public_key, + outgoing_public_key, + tagging_public_key, + partial_address, ); assert(computed_address.eq(address), "Computed address does not match supplied 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 e84e4b4e596..7349bb9c2c5 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -10,18 +10,18 @@ contract Test { use dep::aztec::protocol_types::{ abis::private_circuit_public_inputs::PrivateCircuitPublicInputs, - constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, traits::Serialize, + constants::{MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, CANONICAL_KEY_REGISTRY_ADDRESS}, traits::Serialize, grumpkin_point::GrumpkinPoint }; use dep::aztec::note::constants::MAX_NOTES_PER_PAGE; - use dep::aztec::state_vars::shared_mutable::SharedMutablePrivateGetter; + use dep::aztec::state_vars::{shared_mutable::SharedMutablePrivateGetter, map::derive_storage_slot_in_map}; use dep::aztec::{ - keys::assert_public_key_freshness::assert_nullifier_public_key_is_fresh, + keys::getters::get_fresh_nullifier_public_key_hash, context::{Context, inputs::private_context_inputs::PrivateContextInputs}, - hash::{pedersen_hash, compute_secret_hash, ArgsHasher}, + hash::{pedersen_hash, poseidon2_hash, compute_secret_hash, ArgsHasher}, note::{ lifecycle::{create_note, destroy_note}, note_getter::{get_notes, view_notes}, note_getter_options::NoteStatus @@ -379,36 +379,34 @@ contract Test { #[aztec(private)] fn test_shared_mutable_private_getter_for_registry_contract( - contract_address_to_read: AztecAddress, storage_slot_of_shared_mutable: Field, address_to_get_in_registry: AztecAddress - ) { + ) -> Field { // We have to derive this slot to get the location of the shared mutable inside the Map - let derived_slot = dep::aztec::hash::pedersen_hash( - [storage_slot_of_shared_mutable, address_to_get_in_registry.to_field()], - 0 - ); + let derived_slot = derive_storage_slot_in_map(storage_slot_of_shared_mutable, address_to_get_in_registry); + // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly - let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(context, contract_address_to_read, derived_slot); + let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(context, AztecAddress::from_field(CANONICAL_KEY_REGISTRY_ADDRESS), derived_slot); let nullifier_public_key = registry_private_getter.get_current_value_in_private(); - context.emit_unencrypted_log(nullifier_public_key); + nullifier_public_key } #[aztec(private)] fn test_shared_mutable_private_getter( contract_address_to_read: AztecAddress, storage_slot_of_shared_mutable: Field - ) { + ) -> AztecAddress { // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly let test: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new( context, contract_address_to_read, storage_slot_of_shared_mutable ); + let authorized = test.get_current_value_in_private(); - context.emit_unencrypted_log(authorized); + authorized } #[aztec(private)] @@ -416,7 +414,7 @@ contract Test { address: AztecAddress, public_nullifying_key: GrumpkinPoint, ) { - assert_nullifier_public_key_is_fresh(&mut context, address, public_nullifying_key); + assert_eq(get_fresh_nullifier_public_key_hash(&mut context, address), poseidon2_hash(public_nullifying_key.serialize())); } #[aztec(public)] 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 fcbae4871d9..06463ce268c 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 @@ -61,6 +61,25 @@ 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 } 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 dfe3023abb2..9ea508fc140 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 @@ -1,6 +1,7 @@ use crate::{ - constants::GENERATOR_INDEX__PARTIAL_ADDRESS, hash::pedersen_hash, grumpkin_point::GrumpkinPoint, - traits::{ToField, Serialize, Deserialize} + constants::{GENERATOR_INDEX__PARTIAL_ADDRESS, GENERATOR_INDEX__PUBLIC_KEYS_HASH}, hash::pedersen_hash, grumpkin_point::GrumpkinPoint, + traits::{ToField, Serialize, Deserialize}, + hash::poseidon2_hash, }; // Public keys hash. Used in the computation of an address. @@ -50,6 +51,28 @@ impl PublicKeysHash { ) } + // TODO(#5830): Use this as the new one + pub fn compute_new( + nullifier_public_key: GrumpkinPoint, + incoming_public_key: GrumpkinPoint, + outgoing_public_key: GrumpkinPoint, + tagging_public_key: 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, + GENERATOR_INDEX__PUBLIC_KEYS_HASH, + ]) + ) + } + pub fn to_field(self) -> Field { self.inner } diff --git a/yarn-project/circuit-types/src/keys/key_store.ts b/yarn-project/circuit-types/src/keys/key_store.ts index dd77bde64ed..168ec8d5f04 100644 --- a/yarn-project/circuit-types/src/keys/key_store.ts +++ b/yarn-project/circuit-types/src/keys/key_store.ts @@ -126,6 +126,7 @@ export interface KeyStore { * @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, diff --git a/yarn-project/end-to-end/jest.integration.config.json b/yarn-project/end-to-end/jest.integration.config.json index 721267ff552..84d61df320c 100644 --- a/yarn-project/end-to-end/jest.integration.config.json +++ b/yarn-project/end-to-end/jest.integration.config.json @@ -6,7 +6,7 @@ "moduleNameMapper": { "^(\\.{1,2}/.*)\\.js$": "$1" }, - "reporters": [["default", { "summaryThreshold": 9999 }]], + "reporters": [["default", {"summaryThreshold": 9999}]], "testRegex": "./src/.*\\.test\\.ts$", "rootDir": "./src" } 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 ce62bc216ff..a02e952fecc 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 @@ -41,7 +41,7 @@ describe('Key Registry', () => { describe('failure cases', () => { let accountAddedToRegistry: AztecAddress; - describe('should fail registering with bad input', () => { + describe('should fail when registering with different types of invalid input', () => { const masterNullifierPublicKey = Point.random(); const masterIncomingViewingPublicKey = Point.random(); const masterOutgoingViewingPublicKey = Point.random(); @@ -57,13 +57,13 @@ describe('Key Registry', () => { GeneratorIndex.PUBLIC_KEYS_HASH, ]); - // We hash the partial address and the public keys hash to get the account address + // TODO(#5726): Move the following line to AztecAddress class? accountAddedToRegistry = AztecAddress.fromField( - poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]), + poseidon2Hash([publicKeysHash, partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]), ); - it('should fail registering with mismatched address', async () => { + it('should fail when we register with a mismatched address', async () => { const mismatchedAddress = AztecAddress.random(); await expect( @@ -82,7 +82,7 @@ describe('Key Registry', () => { ).rejects.toThrow('Computed address does not match supplied address'); }); - it('should fail registering with mismatched nullifier public key', async () => { + it('should fail when we register with mismatched nullifier public key', async () => { const mismatchedMasterNullifierPublicKey = Point.random(); await expect( @@ -102,8 +102,8 @@ describe('Key Registry', () => { }); }); - describe('should fail when rotating keys with bad input', () => { - it('should fail when trying to rotate setting a 0 key', async () => { + describe('should fail when rotating keys with different types of bad input', () => { + it('should fail when we try to rotate keys, while setting a 0 key', async () => { await expect( keyRegistry .withWallet(wallets[0]) @@ -113,7 +113,7 @@ describe('Key Registry', () => { ).rejects.toThrow('New nullifier public key must be non-zero'); }); - it('should fail when trying to rotate for another address without authwit', async () => { + it('should fail when we try to rotate keys for another address without authwit', async () => { await expect( keyRegistry .withWallet(wallets[0]) @@ -127,13 +127,13 @@ describe('Key Registry', () => { describe('key registration flow', () => { let accountAddedToRegistry: AztecAddress; - const masterNullifierPublicKey: Point = new Point(new Fr(1), new Fr(2)); + const masterNullifierPublicKey = Point.random(); - it('should generate and register with original keys', async () => { - const masterIncomingViewingPublicKey: Point = new Point(new Fr(3), new Fr(4)); - const masterOutgoingViewingPublicKey: Point = new Point(new Fr(5), new Fr(6)); - const masterTaggingPublicKey: Point = new Point(new Fr(7), new Fr(8)); - const partialAddress: PartialAddress = new Fr(69); + it('should generate master public keys, a partial address, and register with the key registry', async () => { + const masterIncomingViewingPublicKey = Point.random(); + const masterOutgoingViewingPublicKey = Point.random(); + const masterTaggingPublicKey = Point.random(); + const partialAddress: PartialAddress = new Fr(420); const publicKeysHash = poseidon2Hash([ masterNullifierPublicKey, @@ -143,10 +143,9 @@ describe('Key Registry', () => { GeneratorIndex.PUBLIC_KEYS_HASH, ]); - // We hash the partial address and the public keys hash to get the account address // TODO(#5726): Move the following line to AztecAddress class? accountAddedToRegistry = AztecAddress.fromField( - poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]), + poseidon2Hash([publicKeysHash, partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]), ); await keyRegistry @@ -161,75 +160,60 @@ describe('Key Registry', () => { ) .send() .wait(); - }); - it('checks our registry contract from test contract and fails because the address has not been registered yet', async () => { - const { txHash } = await testContract.methods + // We check if our registered nullifier key is equal to the key obtained from the getter by + // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet + const emptyNullifierPublicKey = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) - .send() - .wait(); + .simulate(); - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(Fr.ZERO); - }); + expect(new Fr(emptyNullifierPublicKey)).toEqual(Fr.ZERO); - it('checks our registry contract from test contract and finds the address and associated nullifier public key after a delay', async () => { + // We check it again after a delay and expect that the change has been applied and consequently the assert is true await delay(5); - const { txHash } = await testContract.methods + const nullifierPublicKey = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) - .send() - .wait(); + .simulate(); - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(masterNullifierPublicKey.toFields())); + expect(new Fr(nullifierPublicKey)).toEqual(poseidon2Hash(masterNullifierPublicKey.toFields())); }); }); describe('key rotation flows', () => { const firstNewMasterNullifierPublicKey = Point.random(); - describe('normal key rotation flow', () => { - it('we rotate the nullifier key', async () => { + describe('key rotation flow without authwit', () => { + it('we call the key registry to rotate our nullifier key', async () => { await keyRegistry .withWallet(wallets[0]) .methods.rotate_nullifier_public_key(wallets[0].getAddress(), firstNewMasterNullifierPublicKey) .send() .wait(); - }); - - it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(0)); - }); + // We check if our rotated nullifier key is equal to the key obtained from the getter by + // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet + const emptyNullifierPublicKey = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .simulate(); - it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { - await delay(5); + expect(new Fr(emptyNullifierPublicKey)).toEqual(Fr.ZERO); - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); + // We check it again after a delay and expect that the change has been applied and consequently the assert is true + await delay(5); - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + const nullifierPublicKey = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .simulate(); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual( - poseidon2Hash(firstNewMasterNullifierPublicKey.toFields()), - ); + expect(new Fr(nullifierPublicKey)).toEqual(poseidon2Hash(firstNewMasterNullifierPublicKey.toFields())); }); }); describe('key rotation flow with authwit', () => { - // This is the new value const secondNewMasterNullifierPublicKey = Point.random(); - it('wallet 0 lets wallet 1 call rotate_nullifier_public_key on his behalf with a pre-defined new public key', async () => { + it(`wallet 1 rotates wallet 0's nullifying public key with an authwit`, async () => { const action = keyRegistry .withWallet(wallets[1]) .methods.rotate_nullifier_public_key(wallets[0].getAddress(), secondNewMasterNullifierPublicKey); @@ -240,38 +224,28 @@ describe('Key Registry', () => { .wait(); await action.send().wait(); - }); - it("checks our registry contract from test contract and finds our old public key because the key rotation hasn't been applied yet", async () => { - const { txHash } = await testContract.methods + // We check if our rotated nullifier key is equal to the key obtained from the getter by + // reading our registry contract from the test contract. We expect this value to be the old one, because the new one hasn't been applied + const oldNullifierPublicKey = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); + .simulate(); - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual( - poseidon2Hash(firstNewMasterNullifierPublicKey.toFields()), - ); - }); + expect(new Fr(oldNullifierPublicKey)).toEqual(poseidon2Hash(firstNewMasterNullifierPublicKey.toFields())); - it('checks our registry contract from test contract and finds the new nullifier public key that has been rotated', async () => { + // We check it again after a delay and expect that the change has been applied and consequently the assert is true await delay(5); - const { txHash } = await testContract.methods + const newNullifierPublicKey = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) - .send() - .wait(); - - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); + .simulate(); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual( - poseidon2Hash(secondNewMasterNullifierPublicKey.toFields()), - ); + expect(new Fr(newNullifierPublicKey)).toEqual(poseidon2Hash(secondNewMasterNullifierPublicKey.toFields())); }); }); }); - describe('test keys are fresh: key registration flow, no PXE', () => { + describe('testing get_fresh_nullifier_public_key_hash: key registration flow, no PXE', () => { const masterNullifierPublicKey = Point.random(); const masterIncomingViewingPublicKey = Point.random(); const masterOutgoingViewingPublicKey = Point.random(); @@ -286,10 +260,9 @@ describe('Key Registry', () => { GeneratorIndex.PUBLIC_KEYS_HASH, ]); - // 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 accountAddedToRegistry = AztecAddress.fromField( - poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]), + poseidon2Hash([publicKeysHash, partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]), ); it('should fail as we have not registered anything to the registry nor have we registered a recipient', async () => { @@ -301,7 +274,7 @@ describe('Key Registry', () => { ).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); }); - it('Now we add it to registry', async () => { + it('adds an entry to the key registry, and checks the key freshness without and with conflicting information from our pxe', async () => { await keyRegistry .withWallet(wallets[0]) .methods.register( @@ -314,28 +287,25 @@ describe('Key Registry', () => { ) .send() .wait(); - }); - it('checks key freshness and fails because the address change has not been applied yet due to lack of delay', async () => { + // We check if our registered nullifier key is equal to the key obtained from the getter by + // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet await expect( testContract.methods .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) .send() .wait(), ).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); - }); - it('checks key freshness after a delay, and is successful', async () => { + // We check it again after a delay and expect that the change has been applied and consequently the assert is true await delay(5); await testContract.methods .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) .send() .wait(); - }); - it('should succeed even if our pxe gives conflicting information', async () => { - // FIX THIS (#5834) + // TODO: (#5834) Refactor complete address to move the public keys await pxe.registerRecipient(CompleteAddress.create(accountAddedToRegistry, Point.ZERO, partialAddress), [ new Point(Fr.random(), Fr.random()), masterIncomingViewingPublicKey, @@ -343,6 +313,7 @@ describe('Key Registry', () => { masterTaggingPublicKey, ]); + // Our check should still succeed even if our pxe gives conflicting information, taking the registry as the source of truth. await testContract.methods .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) .send() @@ -350,12 +321,11 @@ describe('Key Registry', () => { }); }); - describe('test keys are fresh: key registration flow, with PXE', () => { - const masterNullifierPublicKey: Point = new Point(new Fr(17), new Fr(18)); - const masterIncomingViewingPublicKey: Point = new Point(new Fr(19), new Fr(20)); - const masterOutgoingViewingPublicKey: Point = new Point(new Fr(21), new Fr(22)); - const masterTaggingPublicKey: Point = new Point(new Fr(23), new Fr(24)); - + describe('testing assert_nullifier_key_is_fresh: key registration flow, with PXE', () => { + const masterNullifierPublicKey = Point.random(); + const masterIncomingViewingPublicKey = Point.random(); + const masterOutgoingViewingPublicKey = Point.random(); + const masterTaggingPublicKey = Point.random(); const partialAddress: PartialAddress = new Fr(69420); const publicKeysHash = poseidon2Hash([ @@ -366,10 +336,9 @@ describe('Key Registry', () => { GeneratorIndex.PUBLIC_KEYS_HASH, ]); - // 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 accountAddedToRegistry = AztecAddress.fromField( - poseidon2Hash([partialAddress, publicKeysHash, GeneratorIndex.CONTRACT_ADDRESS_V1]), + poseidon2Hash([publicKeysHash, partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]), ); it('should fail as we have not registered anything to the registry nor have we registered a recipient', async () => { @@ -381,9 +350,9 @@ describe('Key Registry', () => { ).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); }); - it('should fail when we register bad keys and the lib checks our pxe', async () => { + it('should fail when we try to check the public keys for a invalid address', async () => { const randAddress = AztecAddress.random(); - // FIX THIS (#5834) + // TODO: (#5834) Refactor complete address to move the public keys await pxe.registerRecipient(CompleteAddress.create(randAddress, Point.ZERO, partialAddress), [ masterNullifierPublicKey, masterIncomingViewingPublicKey, @@ -394,32 +363,24 @@ describe('Key Registry', () => { await expect( testContract.methods.test_nullifier_key_freshness(randAddress, masterNullifierPublicKey).send().wait(), ).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); - }); + }) - it('should succeed because we register our recipient manually and the lib checks our pxe', async () => { - // FIX THIS (#5834) + it('adds a recipient to our pxe, and checks the key freshness with and without adding an entry to our key registry', async () => { + // TODO: (#5834) Refactor complete address to move the public keys await pxe.registerRecipient(CompleteAddress.create(accountAddedToRegistry, Point.ZERO, partialAddress), [ masterNullifierPublicKey, masterIncomingViewingPublicKey, masterOutgoingViewingPublicKey, masterTaggingPublicKey, ]); + + // The check should succeed because we register our recipient manually and the lib checks our pxe await testContract.methods .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) .send() .wait(); - }); - - it('should fail when we put in a different key', async () => { - await expect( - testContract.methods - .test_nullifier_key_freshness(accountAddedToRegistry, masterIncomingViewingPublicKey) - .send() - .wait(), - ).rejects.toThrow(`Cannot satisfy constraint 'keys[key_type].eq(key)'`); - }); - it('Now we add it to registry', async () => { + // Now we add the keys to registry await keyRegistry .withWallet(wallets[0]) .methods.register( @@ -432,36 +393,23 @@ describe('Key Registry', () => { ) .send() .wait(); - }); - it('we start the change in the registry, it has not been applied yet, but we still see we have a fresh key due to it being added in the pxe', async () => { - const { txHash } = await testContract.methods + // We check if our rotated nullifier key is equal to the key obtained from the getter by + // reading our registry contract from the test contract. We expect this to be 0 because the change has not been applied yet + const emptyNullifierPublicKey = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) - .send() - .wait(); + .simulate(); - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(Fr.ZERO); + expect(new Fr(emptyNullifierPublicKey)).toEqual(Fr.ZERO); - // Checks freshness of newly added keys, but the change hasn't been affected yet, but we have manually added it to our pxe so it should pass + // We check if our rotated nullifier key is equal to the key obtained from the getter. We expect this to succeed because even though the change + // has not been applied yet to the registry, we have manually the keys to our pxe await testContract.methods .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) .send() .wait(); - }); - - it('in the case where the key exists both in the pxe and our registry, we know nothing weird will happen', async () => { - await delay(5); - - const { txHash } = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) - .send() - .wait(); - - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(poseidon2Hash(masterNullifierPublicKey.toFields())); + // In the case where the key exists both in the pxe and our registry, we know that our assert will still remain true await testContract.methods .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) .send() @@ -469,29 +417,28 @@ describe('Key Registry', () => { }); }); - describe('key rotation flow; assert keys are fresh', () => { + describe('testing assert_nullifier_key_is_fresh: key rotation flow', () => { const newMasterNullifierPublicKey = Point.random(); - it('we rotate the nullifier key', async () => { + it('we rotate the nullifier key and check that the key is fresh', async () => { await keyRegistry .withWallet(wallets[0]) .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey) .send() .wait(); - }); - it("checks our registry contract from test contract and fails because the change hasn't been applied yet", async () => { + // We check if our rotated nullifier key is equal to the key obtained from the getter by + // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet await expect( testContract.methods .test_nullifier_key_freshness(wallets[0].getAddress(), newMasterNullifierPublicKey) .send() .wait(), ).rejects.toThrow( - `Cannot satisfy constraint 'hashed_nullifier_public_key_in_registry == poseidon2_hash(nullifier_public_key_to_test.serialize())'`, + `Cannot satisfy constraint 'assert_eq(get_fresh_nullifier_public_key_hash(&mut context, address), poseidon2_hash(public_nullifying_key.serialize()))'`, ); - }); - it('checks our registry contract from test contract and succeeds because the change has been applied', async () => { + // We check it again after a delay and expect that the change has been applied and consequently the assert is true await delay(5); await testContract.methods diff --git a/yarn-project/end-to-end/src/e2e_state_vars.test.ts b/yarn-project/end-to-end/src/e2e_state_vars.test.ts index 8a6ed6dc23e..c9e8609a9c1 100644 --- a/yarn-project/end-to-end/src/e2e_state_vars.test.ts +++ b/yarn-project/end-to-end/src/e2e_state_vars.test.ts @@ -249,27 +249,21 @@ describe('e2e_state_vars', () => { }, 30_000); it("checks authorized in auth contract from test contract and finds the old value because the change hasn't been applied yet", async () => { - const { txHash } = await testContract.methods + const authorized = await testContract.methods .test_shared_mutable_private_getter(authContract.address, 2) - .send() - .wait(); + .simulate(); - // The function above emits an unencrypted log as a means of returning the data - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(0)); + expect(AztecAddress.fromBigInt(authorized)).toEqual(AztecAddress.ZERO); }); it('checks authorized in auth contract from test contract and finds the correctly set value', async () => { await delay(5); - const { txHash } = await testContract.methods + const authorized = await testContract.methods .test_shared_mutable_private_getter(authContract.address, 2) - .send() - .wait(); + .simulate(); - // The function above emits an unencrypted log as a means of returning the data - const rawLogs = await pxe.getUnencryptedLogs({ txHash }); - expect(Fr.fromBuffer(rawLogs.logs[0].log.data)).toEqual(new Fr(6969696969)); + expect(AztecAddress.fromBigInt(authorized)).toEqual(AztecAddress.fromBigInt(6969696969n)); }); }); }); diff --git a/yarn-project/key-store/src/test_key_store.ts b/yarn-project/key-store/src/test_key_store.ts index 288ffc9430d..a3c0d4b239b 100644 --- a/yarn-project/key-store/src/test_key_store.ts +++ b/yarn-project/key-store/src/test_key_store.ts @@ -293,6 +293,7 @@ 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, diff --git a/yarn-project/package.common.json b/yarn-project/package.common.json index 6fcf1a28315..80b56a8d697 100644 --- a/yarn-project/package.common.json +++ b/yarn-project/package.common.json @@ -24,7 +24,7 @@ "moduleNameMapper": { "^(\\.{1,2}/.*)\\.[cm]?js$": "$1" }, - "reporters": [["default", { "summaryThreshold": 9999 }]], + "reporters": [["default", {"summaryThreshold": 9999}]], "testRegex": "./src/.*\\.test\\.(js|mjs|ts)$", "rootDir": "./src" } diff --git a/yarn-project/simulator/src/acvm/oracle/oracle.ts b/yarn-project/simulator/src/acvm/oracle/oracle.ts index 625830ba973..f46990d5ca9 100644 --- a/yarn-project/simulator/src/acvm/oracle/oracle.ts +++ b/yarn-project/simulator/src/acvm/oracle/oracle.ts @@ -173,8 +173,9 @@ export class Oracle { } async getPublicKeysAndPartialAddress([address]: ACVMField[]): Promise { - let partialAddress: PartialAddress; 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)))); @@ -188,9 +189,9 @@ export class Oracle { publicKeys = Array(4).fill(Point.ZERO); } - const acvmKeys = publicKeys.flatMap(key => key.toFields()); + const acvmPublicKeys = publicKeys.flatMap(key => key.toFields()); - return [partialAddress, ...acvmKeys].map(toACVMField); + return [...acvmPublicKeys, partialAddress].map(toACVMField); } async getNotes( From c852740f1700ff71979479e795d7c4c89b877438 Mon Sep 17 00:00:00 2001 From: esau <152162806+sklppy88@users.noreply.github.com> Date: Wed, 1 May 2024 07:09:34 -0500 Subject: [PATCH 18/23] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Jan Beneš --- yarn-project/circuit-types/src/interfaces/pxe.ts | 2 +- yarn-project/simulator/src/client/db_oracle.ts | 4 ++-- yarn-project/simulator/src/client/view_data_oracle.ts | 4 ++-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/yarn-project/circuit-types/src/interfaces/pxe.ts b/yarn-project/circuit-types/src/interfaces/pxe.ts index eab85b46980..0e95d024727 100644 --- a/yarn-project/circuit-types/src/interfaces/pxe.ts +++ b/yarn-project/circuit-types/src/interfaces/pxe.ts @@ -73,7 +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: FIX THIS AFTER THE COMPLETE ADDRESS REFACTOR + // TODO: #5834: Nuke publicKeys optional parameter after `CompleteAddress` refactor. registerRecipient(recipient: CompleteAddress, publicKeys?: Point[]): Promise; /** diff --git a/yarn-project/simulator/src/client/db_oracle.ts b/yarn-project/simulator/src/client/db_oracle.ts index 2646898a612..eb545df6e11 100644 --- a/yarn-project/simulator/src/client/db_oracle.ts +++ b/yarn-project/simulator/src/client/db_oracle.ts @@ -65,10 +65,10 @@ export interface DBOracle extends CommitmentsDB { popCapsule(): Promise; /** - * Gets public keys for an address, getCompleteAddress should be modified to include this + * Gets public keys for an address. * @param The address to look up * @returns The public keys for a specific address - * TODO: #5834 + * TODO(#5834): Replace with `getCompleteAddress`. */ getPublicKeysForAddress(address: AztecAddress): Promise; diff --git a/yarn-project/simulator/src/client/view_data_oracle.ts b/yarn-project/simulator/src/client/view_data_oracle.ts index 2bc1fbfc937..50dc2552c25 100644 --- a/yarn-project/simulator/src/client/view_data_oracle.ts +++ b/yarn-project/simulator/src/client/view_data_oracle.ts @@ -167,10 +167,10 @@ export class ViewDataOracle extends TypedOracle { } /** - * Gets public keys for an address, getCompleteAddress should be modified to include this + * Gets public keys for an address. * @param The address to look up * @returns The public keys for a specific address - * TODO: #5834 + * TODO(#5834): Replace with `getCompleteAddress`. */ public override getPublicKeysForAddress(address: AztecAddress) { return this.db.getPublicKeysForAddress(address); From b76ab1a613164f4d8c73133e102f854594380c92 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 1 May 2024 12:56:20 +0000 Subject: [PATCH 19/23] fix --- .../end-to-end/src/e2e_key_registry.test.ts | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) 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 501e2734cc3..4fb21eb4a99 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 @@ -164,7 +164,7 @@ describe('Key Registry', () => { // We check if our registered nullifier key is equal to the key obtained from the getter by // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet const emptyNullifierPublicKey = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) + .test_shared_mutable_private_getter_for_registry_contract(1, accountAddedToRegistry) .simulate(); expect(new Fr(emptyNullifierPublicKey)).toEqual(Fr.ZERO); @@ -173,7 +173,7 @@ describe('Key Registry', () => { await delay(5); const nullifierPublicKey = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) + .test_shared_mutable_private_getter_for_registry_contract(1, accountAddedToRegistry) .simulate(); expect(new Fr(nullifierPublicKey)).toEqual(poseidon2Hash(masterNullifierPublicKey.toFields())); @@ -194,7 +194,7 @@ describe('Key Registry', () => { // We check if our rotated nullifier key is equal to the key obtained from the getter by // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet const emptyNullifierPublicKey = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .test_shared_mutable_private_getter_for_registry_contract(1, wallets[0].getAddress()) .simulate(); expect(new Fr(emptyNullifierPublicKey)).toEqual(Fr.ZERO); @@ -203,7 +203,7 @@ describe('Key Registry', () => { await delay(5); const nullifierPublicKey = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .test_shared_mutable_private_getter_for_registry_contract(1, wallets[0].getAddress()) .simulate(); expect(new Fr(nullifierPublicKey)).toEqual(poseidon2Hash(firstNewMasterNullifierPublicKey.toFields())); @@ -228,7 +228,7 @@ describe('Key Registry', () => { // We check if our rotated nullifier key is equal to the key obtained from the getter by // reading our registry contract from the test contract. We expect this value to be the old one, because the new one hasn't been applied const oldNullifierPublicKey = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .test_shared_mutable_private_getter_for_registry_contract(1, wallets[0].getAddress()) .simulate(); expect(new Fr(oldNullifierPublicKey)).toEqual(poseidon2Hash(firstNewMasterNullifierPublicKey.toFields())); @@ -237,7 +237,7 @@ describe('Key Registry', () => { await delay(5); const newNullifierPublicKey = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, wallets[0].getAddress()) + .test_shared_mutable_private_getter_for_registry_contract(1, wallets[0].getAddress()) .simulate(); expect(new Fr(newNullifierPublicKey)).toEqual(poseidon2Hash(secondNewMasterNullifierPublicKey.toFields())); @@ -397,7 +397,7 @@ describe('Key Registry', () => { // We check if our rotated nullifier key is equal to the key obtained from the getter by // reading our registry contract from the test contract. We expect this to be 0 because the change has not been applied yet const emptyNullifierPublicKey = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(keyRegistry.address, 1, accountAddedToRegistry) + .test_shared_mutable_private_getter_for_registry_contract(1, accountAddedToRegistry) .simulate(); expect(new Fr(emptyNullifierPublicKey)).toEqual(Fr.ZERO); From 59a4c1894063620d2810b91c3f42cf82bf940477 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 1 May 2024 16:22:05 +0000 Subject: [PATCH 20/23] format --- .../end-to-end/src/e2e_key_registry.test.ts | 43 +++++++++---------- .../end-to-end/src/e2e_state_vars.test.ts | 5 +-- 2 files changed, 23 insertions(+), 25 deletions(-) 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 4fb21eb4a99..092ee32682d 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 @@ -57,7 +57,6 @@ describe('Key Registry', () => { GeneratorIndex.PUBLIC_KEYS_HASH, ]); - // TODO(#5726): Move the following line to AztecAddress class? accountAddedToRegistry = AztecAddress.fromField( poseidon2Hash([publicKeysHash, partialAddress, GeneratorIndex.CONTRACT_ADDRESS_V1]), @@ -161,7 +160,7 @@ describe('Key Registry', () => { .send() .wait(); - // We check if our registered nullifier key is equal to the key obtained from the getter by + // We check if our registered nullifier key is equal to the key obtained from the getter by // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet const emptyNullifierPublicKey = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(1, accountAddedToRegistry) @@ -191,22 +190,22 @@ describe('Key Registry', () => { .send() .wait(); - // We check if our rotated nullifier key is equal to the key obtained from the getter by - // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet - const emptyNullifierPublicKey = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(1, wallets[0].getAddress()) - .simulate(); + // We check if our rotated nullifier key is equal to the key obtained from the getter by + // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet + const emptyNullifierPublicKey = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(1, wallets[0].getAddress()) + .simulate(); - expect(new Fr(emptyNullifierPublicKey)).toEqual(Fr.ZERO); + expect(new Fr(emptyNullifierPublicKey)).toEqual(Fr.ZERO); - // We check it again after a delay and expect that the change has been applied and consequently the assert is true - await delay(5); + // We check it again after a delay and expect that the change has been applied and consequently the assert is true + await delay(5); - const nullifierPublicKey = await testContract.methods - .test_shared_mutable_private_getter_for_registry_contract(1, wallets[0].getAddress()) - .simulate(); + const nullifierPublicKey = await testContract.methods + .test_shared_mutable_private_getter_for_registry_contract(1, wallets[0].getAddress()) + .simulate(); - expect(new Fr(nullifierPublicKey)).toEqual(poseidon2Hash(firstNewMasterNullifierPublicKey.toFields())); + expect(new Fr(nullifierPublicKey)).toEqual(poseidon2Hash(firstNewMasterNullifierPublicKey.toFields())); }); }); @@ -225,9 +224,9 @@ describe('Key Registry', () => { await action.send().wait(); - // We check if our rotated nullifier key is equal to the key obtained from the getter by - // reading our registry contract from the test contract. We expect this value to be the old one, because the new one hasn't been applied - const oldNullifierPublicKey = await testContract.methods + // We check if our rotated nullifier key is equal to the key obtained from the getter by + // reading our registry contract from the test contract. We expect this value to be the old one, because the new one hasn't been applied + const oldNullifierPublicKey = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(1, wallets[0].getAddress()) .simulate(); @@ -288,7 +287,7 @@ describe('Key Registry', () => { .send() .wait(); - // We check if our registered nullifier key is equal to the key obtained from the getter by + // We check if our registered nullifier key is equal to the key obtained from the getter by // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet await expect( testContract.methods @@ -363,7 +362,7 @@ describe('Key Registry', () => { await expect( testContract.methods.test_nullifier_key_freshness(randAddress, masterNullifierPublicKey).send().wait(), ).rejects.toThrow(`Cannot satisfy constraint 'computed_address.eq(address)'`); - }) + }); it('adds a recipient to our pxe, and checks the key freshness with and without adding an entry to our key registry', async () => { // TODO: (#5834) Refactor complete address to move the public keys @@ -394,7 +393,7 @@ describe('Key Registry', () => { .send() .wait(); - // We check if our rotated nullifier key is equal to the key obtained from the getter by + // We check if our rotated nullifier key is equal to the key obtained from the getter by // reading our registry contract from the test contract. We expect this to be 0 because the change has not been applied yet const emptyNullifierPublicKey = await testContract.methods .test_shared_mutable_private_getter_for_registry_contract(1, accountAddedToRegistry) @@ -402,7 +401,7 @@ describe('Key Registry', () => { expect(new Fr(emptyNullifierPublicKey)).toEqual(Fr.ZERO); - // We check if our rotated nullifier key is equal to the key obtained from the getter. We expect this to succeed because even though the change + // We check if our rotated nullifier key is equal to the key obtained from the getter. We expect this to succeed because even though the change // has not been applied yet to the registry, we have manually the keys to our pxe await testContract.methods .test_nullifier_key_freshness(accountAddedToRegistry, masterNullifierPublicKey) @@ -427,7 +426,7 @@ describe('Key Registry', () => { .send() .wait(); - // We check if our rotated nullifier key is equal to the key obtained from the getter by + // We check if our rotated nullifier key is equal to the key obtained from the getter by // reading our registry contract from the test contract. We expect this to fail because the change has not been applied yet await expect( testContract.methods diff --git a/yarn-project/end-to-end/src/e2e_state_vars.test.ts b/yarn-project/end-to-end/src/e2e_state_vars.test.ts index 426072cf8fc..dcdbdfd9454 100644 --- a/yarn-project/end-to-end/src/e2e_state_vars.test.ts +++ b/yarn-project/end-to-end/src/e2e_state_vars.test.ts @@ -1,4 +1,4 @@ -import { AztecAddress, Fr, type PXE, type Wallet } from '@aztec/aztec.js'; +import { AztecAddress, Fr, type Wallet } from '@aztec/aztec.js'; import { AuthContract, DocsExampleContract, TestContract } from '@aztec/noir-contracts.js'; import { jest } from '@jest/globals'; @@ -8,7 +8,6 @@ import { setup } from './fixtures/utils.js'; const TIMEOUT = 100_000; describe('e2e_state_vars', () => { - let pxe: PXE; jest.setTimeout(TIMEOUT); let wallet: Wallet; @@ -20,7 +19,7 @@ describe('e2e_state_vars', () => { const RANDOMNESS = 2n; beforeAll(async () => { - ({ teardown, wallet, pxe } = await setup(2)); + ({ teardown, wallet } = await setup(2)); contract = await DocsExampleContract.deploy(wallet).send().deployed(); }); From 194df19b36aef093b785d5113a4a5e33891540c5 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 1 May 2024 18:20:42 +0000 Subject: [PATCH 21/23] Address comments --- .../aztec-nr/aztec/src/keys/getters.nr | 30 ++++++++++++-- .../aztec-nr/aztec/src/oracle/keys.nr | 21 ++-------- .../key_registry_contract/src/main.nr | 4 ++ .../contracts/test_contract/src/main.nr | 39 ++++++++++--------- .../types/src/address/public_keys_hash.nr | 4 +- .../end-to-end/src/e2e_key_registry.test.ts | 10 ++--- 6 files changed, 62 insertions(+), 46 deletions(-) diff --git a/noir-projects/aztec-nr/aztec/src/keys/getters.nr b/noir-projects/aztec-nr/aztec/src/keys/getters.nr index 321441e7a7e..bbc0eb2dda8 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/getters.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/getters.nr @@ -16,7 +16,7 @@ use crate::hash::{ pedersen_hash, poseidon2_hash, }; -use crate::oracle; +use crate::oracle::keys::get_public_keys_and_partial_address; use crate::state_vars::{ map::derive_storage_slot_in_map, shared_mutable::shared_mutable_private_getter::SharedMutablePrivateGetter, @@ -35,17 +35,19 @@ pub fn get_fresh_nullifier_public_key_hash( address: AztecAddress, ) -> Field { // This is the storage slot of the nullifier_public_key inside the key registry contract + // TODO: (#6133) We should have this be directly imported from the other contract if possible, or at least this should not be this brittle let storage_slot_of_nullifier_public_key = 1; let derived_slot = derive_storage_slot_in_map(storage_slot_of_nullifier_public_key, address); - // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly // We read from the canonical Key Registry + // TODO: (#6134) It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly. + // We should allow for this usecase without needing to hard code it here. let registry_private_getter: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new(*context, AztecAddress::from_field(CANONICAL_KEY_REGISTRY_ADDRESS), derived_slot); let nullifier_public_key_hash_in_registry = registry_private_getter.get_current_value_in_private(); let nullifier_public_key_hash = if nullifier_public_key_hash_in_registry == 0 { - let keys = oracle::keys::get_public_keys(address); + let keys = get_original_public_keys_internal(address); poseidon2_hash(keys[PublicKeyType.NULLIFIER].serialize()) } else { nullifier_public_key_hash_in_registry @@ -53,3 +55,25 @@ pub fn get_fresh_nullifier_public_key_hash( nullifier_public_key_hash } + +// This constraint only works on keys that have not been rotated, otherwise this call will fail as the public keys are not constrained +fn get_original_public_keys_internal(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 computed_address = AztecAddress::compute_from_public_keys_and_partial_address( + nullifier_pub_key, + incoming_pub_key, + outgoing_pub_key, + tagging_pub_key, + partial_address, + ); + + assert(computed_address.eq(address)); + + [nullifier_pub_key, incoming_pub_key, outgoing_pub_key, tagging_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 98ea76ed617..d8737a0dd06 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/keys.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/keys.nr @@ -2,12 +2,7 @@ use dep::protocol_types::{ address::{ AztecAddress, PartialAddress, - PublicKeysHash, }, - constants::{ - GENERATOR_INDEX__PUBLIC_KEYS_HASH, - GENERATOR_INDEX__CONTRACT_ADDRESS_V1, - }, grumpkin_point::GrumpkinPoint, }; @@ -20,7 +15,7 @@ unconstrained fn get_public_keys_and_partial_address_oracle_wrapper(address: Azt get_public_keys_and_partial_address_oracle(address) } -pub fn get_public_keys(address: AztecAddress) -> [GrumpkinPoint; 4] { +fn get_public_keys_and_partial_address(address: AztecAddress) -> ([GrumpkinPoint; 4], PartialAddress) { let result = get_public_keys_and_partial_address_oracle_wrapper(address); let nullifier_pub_key = GrumpkinPoint::new(result[0], result[1]); @@ -29,15 +24,5 @@ pub fn get_public_keys(address: AztecAddress) -> [GrumpkinPoint; 4] { let tagging_pub_key = GrumpkinPoint::new(result[6], result[7]); let partial_address = PartialAddress::from_field(result[8]); - 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, - ); - - assert(computed_address.eq(address)); - - [nullifier_pub_key, incoming_pub_key, outgoing_pub_key, tagging_pub_key] -} + ([nullifier_pub_key, incoming_pub_key, outgoing_pub_key, tagging_pub_key], partial_address) +} \ No newline at end of file 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 9d25af0055e..2d2111d07dd 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 @@ -40,14 +40,18 @@ contract KeyRegistry { fn rotate_nullifier_public_key( address: AztecAddress, new_nullifier_public_key: GrumpkinPoint, + nonce: Field, ) { assert( !new_nullifier_public_key.is_zero(), "New nullifier public key must be non-zero" ); + // TODO: (#6137) if (!address.eq(context.msg_sender())) { assert_current_call_valid_authwit_public(&mut context, address); + } else { + assert(nonce == 0, "invalid nonce"); } let nullifier_key_registry = storage.nullifier_public_key_hash_registry.at(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 7349bb9c2c5..29c71837291 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -10,7 +10,7 @@ contract Test { use dep::aztec::protocol_types::{ abis::private_circuit_public_inputs::PrivateCircuitPublicInputs, - constants::{MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, CANONICAL_KEY_REGISTRY_ADDRESS}, traits::Serialize, + constants::{MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, CANONICAL_KEY_REGISTRY_ADDRESS}, traits::{Serialize, ToField, FromField}, grumpkin_point::GrumpkinPoint }; @@ -377,6 +377,26 @@ contract Test { constant.value } + // This function is used in the e2e_state_vars to test the SharedMutablePrivateGetter in isolation + #[aztec(private)] + fn test_shared_mutable_private_getter( + contract_address_to_read: AztecAddress, + storage_slot_of_shared_mutable: Field + ) where T: FromField, T: ToField { + // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly + let test: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new( + context, + contract_address_to_read, + storage_slot_of_shared_mutable + ); + + let ret = test.get_current_value_in_private(); + + ret.to_field() + } + + // This function is used for testing the registry contract and fresh public key getters. If nothing exists in the registry, but we have added public + // keys to the pxe, this function will return nothing, but the public key getters will return the correct value #[aztec(private)] fn test_shared_mutable_private_getter_for_registry_contract( storage_slot_of_shared_mutable: Field, @@ -392,23 +412,6 @@ contract Test { nullifier_public_key } - #[aztec(private)] - fn test_shared_mutable_private_getter( - contract_address_to_read: AztecAddress, - storage_slot_of_shared_mutable: Field - ) -> AztecAddress { - // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly - let test: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new( - context, - contract_address_to_read, - storage_slot_of_shared_mutable - ); - - let authorized = test.get_current_value_in_private(); - - authorized - } - #[aztec(private)] fn test_nullifier_key_freshness( address: AztecAddress, 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 9ea508fc140..bff82cc1644 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,7 +38,7 @@ impl PublicKeysHash { Self { inner: field } } - // TODO(#5830): update this + // TODO(#5830): When we do this refactor, rename compute_new -> compute pub fn compute(public_key: GrumpkinPoint) -> Self { PublicKeysHash::from_field( pedersen_hash( @@ -51,7 +51,7 @@ impl PublicKeysHash { ) } - // TODO(#5830): Use this as the new one + // TODO(#5830): When we do this refactor, rename compute_new -> compute pub fn compute_new( nullifier_public_key: GrumpkinPoint, incoming_public_key: GrumpkinPoint, 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 092ee32682d..ebfc6a07fa1 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 @@ -106,7 +106,7 @@ describe('Key Registry', () => { await expect( keyRegistry .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), Point.ZERO) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), Point.ZERO, new Fr(1)) .send() .wait(), ).rejects.toThrow('New nullifier public key must be non-zero'); @@ -116,7 +116,7 @@ describe('Key Registry', () => { await expect( keyRegistry .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[1].getAddress(), Point.random()) + .methods.rotate_nullifier_public_key(wallets[1].getAddress(), Point.random(), new Fr(1)) .send() .wait(), ).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -186,7 +186,7 @@ describe('Key Registry', () => { it('we call the key registry to rotate our nullifier key', async () => { await keyRegistry .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), firstNewMasterNullifierPublicKey) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), firstNewMasterNullifierPublicKey, new Fr(1)) .send() .wait(); @@ -215,7 +215,7 @@ describe('Key Registry', () => { it(`wallet 1 rotates wallet 0's nullifying public key with an authwit`, async () => { const action = keyRegistry .withWallet(wallets[1]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), secondNewMasterNullifierPublicKey); + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), secondNewMasterNullifierPublicKey, new Fr(1)); await wallets[0] .setPublicAuthWit({ caller: wallets[1].getCompleteAddress().address, action }, true) @@ -422,7 +422,7 @@ describe('Key Registry', () => { it('we rotate the nullifier key and check that the key is fresh', async () => { await keyRegistry .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey, new Fr(1)) .send() .wait(); From a85f5131a497450ce04838369381a613e167f833 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 1 May 2024 19:45:14 +0000 Subject: [PATCH 22/23] fix --- yarn-project/end-to-end/src/e2e_key_registry.test.ts | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) 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 ebfc6a07fa1..b801beed9e4 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 @@ -106,7 +106,7 @@ describe('Key Registry', () => { await expect( keyRegistry .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), Point.ZERO, new Fr(1)) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), Point.ZERO, Fr.ZERO) .send() .wait(), ).rejects.toThrow('New nullifier public key must be non-zero'); @@ -116,7 +116,7 @@ describe('Key Registry', () => { await expect( keyRegistry .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[1].getAddress(), Point.random(), new Fr(1)) + .methods.rotate_nullifier_public_key(wallets[1].getAddress(), Point.random(), Fr.ZERO) .send() .wait(), ).rejects.toThrow('Assertion failed: Message not authorized by account'); @@ -186,7 +186,7 @@ describe('Key Registry', () => { it('we call the key registry to rotate our nullifier key', async () => { await keyRegistry .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), firstNewMasterNullifierPublicKey, new Fr(1)) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), firstNewMasterNullifierPublicKey, Fr.ZERO) .send() .wait(); @@ -215,7 +215,7 @@ describe('Key Registry', () => { it(`wallet 1 rotates wallet 0's nullifying public key with an authwit`, async () => { const action = keyRegistry .withWallet(wallets[1]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), secondNewMasterNullifierPublicKey, new Fr(1)); + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), secondNewMasterNullifierPublicKey, Fr.ZERO); await wallets[0] .setPublicAuthWit({ caller: wallets[1].getCompleteAddress().address, action }, true) @@ -422,7 +422,7 @@ describe('Key Registry', () => { it('we rotate the nullifier key and check that the key is fresh', async () => { await keyRegistry .withWallet(wallets[0]) - .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey, new Fr(1)) + .methods.rotate_nullifier_public_key(wallets[0].getAddress(), newMasterNullifierPublicKey, Fr.ZERO) .send() .wait(); From 94db9f592074157afc8c7af2bed61f25f58bc603 Mon Sep 17 00:00:00 2001 From: sklppy88 Date: Wed, 1 May 2024 20:01:05 +0000 Subject: [PATCH 23/23] Okay --- .../noir-contracts/contracts/test_contract/src/main.nr | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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 29c71837291..74f0e049512 100644 --- a/noir-projects/noir-contracts/contracts/test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/test_contract/src/main.nr @@ -382,7 +382,7 @@ contract Test { fn test_shared_mutable_private_getter( contract_address_to_read: AztecAddress, storage_slot_of_shared_mutable: Field - ) where T: FromField, T: ToField { + ) -> Field where T: FromField, T: ToField { // It's a bit wonky because we need to know the delay for get_current_value_in_private to work correctly let test: SharedMutablePrivateGetter = SharedMutablePrivateGetter::new( context,