From 8a71fd5a1a8d7a59302ac5671536d5b505b8cf23 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Jan=20Bene=C5=A1?= Date: Thu, 16 May 2024 19:10:21 +0200 Subject: [PATCH] refactor: get_nullifier_keys cleanup (#6451) --- .../aztec/aztec/concepts/accounts/keys.md | 5 +-- .../aztec-nr/address-note/src/address_note.nr | 2 +- .../aztec/src/context/private_context.nr | 38 +++++++++---------- .../aztec-nr/aztec/src/keys/getters.nr | 24 +++--------- .../aztec/src/oracle/nullifier_keys.nr | 36 ++++++------------ .../aztec-nr/value-note/src/value_note.nr | 2 +- .../src/subscription_note.nr | 2 +- .../src/types/card_note.nr | 2 +- .../src/ecdsa_public_key_note.nr | 2 +- .../src/public_key_note.nr | 2 +- .../src/types/token_note.nr | 2 +- .../token_contract/src/types/token_note.nr | 2 +- 12 files changed, 44 insertions(+), 75 deletions(-) diff --git a/docs/docs/aztec/aztec/concepts/accounts/keys.md b/docs/docs/aztec/aztec/concepts/accounts/keys.md index 9f23398164b..a0cc247d1b4 100644 --- a/docs/docs/aztec/aztec/concepts/accounts/keys.md +++ b/docs/docs/aztec/aztec/concepts/accounts/keys.md @@ -119,10 +119,9 @@ This is a snippet of our Schnorr Account contract implementation, which uses Sch Still, different accounts may use different signing schemes, may require multi-factor authentication, or _may not even use signing keys_ and instead rely on other authentication mechanisms. Read [how to write an account contract](/tutorials/tutorials/write_accounts_contract.md) for a full example of how to manage authentication. Furthermore, and since signatures are fully abstracted, how the key is stored in the contract is abstracted as well and left to the developer of the account contract. -Below are a few ideas on how to store them, each with their pros and cons. +In the following section we describe a few ways how an account contract could be architected to store signing keys. -### Ways to store signing keys -Below we described a few ways how an account contract could be architected to obtain signing keys. +### Storing signing keys #### Using a private note diff --git a/noir-projects/aztec-nr/address-note/src/address_note.nr b/noir-projects/aztec-nr/address-note/src/address_note.nr index 8ee0ecce031..3d33ecb4a52 100644 --- a/noir-projects/aztec-nr/address-note/src/address_note.nr +++ b/noir-projects/aztec-nr/address-note/src/address_note.nr @@ -4,7 +4,7 @@ use dep::aztec::{ grumpkin_point::GrumpkinPoint, hash::poseidon2_hash }, note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext + oracle::unsafe_rand::unsafe_rand, oracle::nullifier_keys::get_nsk_app, context::PrivateContext }; global ADDRESS_NOTE_LEN: Field = 3; diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 43dd101a97c..abc74607c84 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -1,10 +1,10 @@ use crate::{ context::{inputs::PrivateContextInputs, interface::ContextInterface}, - keys::getters::get_nullifier_keys, messaging::process_l1_to_l2_message, + messaging::process_l1_to_l2_message, hash::{hash_args_array, ArgsHasher, compute_encrypted_log_hash, compute_unencrypted_log_hash}, note::{note_interface::NoteInterface, utils::compute_note_hash_for_insertion}, oracle::{ - nullifier_keys::NullifierKeys, arguments, returns, + nullifier_keys::get_nullifier_key_validation_request, arguments, returns, call_private_function::call_private_function_internal, header::get_header_at, logs::emit_encrypted_log, logs_traits::{LensForEncryptedLog, ToBytesForUnencryptedLog}, enqueue_public_function_call::{ @@ -71,7 +71,7 @@ struct PrivateContext { encrypted_log_preimages_length: Field, unencrypted_log_preimages_length: Field, - nullifier_key: Option, + last_nullifier_key_validation_request: Option, } impl ContextInterface for PrivateContext { @@ -133,7 +133,7 @@ impl PrivateContext { unencrypted_logs_hashes: BoundedVec::new(), encrypted_log_preimages_length: 0, unencrypted_log_preimages_length: 0, - nullifier_key: Option::none() + last_nullifier_key_validation_request: Option::none() } } @@ -208,24 +208,22 @@ impl PrivateContext { } pub fn request_nsk_app(&mut self, npk_m_hash: Field) -> Field { - // A value of empty nullifier keys will fail the key validation request. - let cached_nullifier_keys = self.nullifier_key.unwrap_or(NullifierKeys::empty()); + let cached_request = self.last_nullifier_key_validation_request.unwrap_or(NullifierKeyValidationRequest::empty()); - let nullifier_keys = if cached_nullifier_keys.master_nullifier_public_key.hash() == npk_m_hash { - cached_nullifier_keys + if cached_request.master_nullifier_public_key.hash() == npk_m_hash { + // We get a match so the cached request is the latest one + cached_request.app_nullifier_secret_key } else { - let fetched_nullifier_keys = get_nullifier_keys(npk_m_hash); - let request = NullifierKeyValidationRequest { - master_nullifier_public_key: fetched_nullifier_keys.master_nullifier_public_key, - app_nullifier_secret_key: fetched_nullifier_keys.app_nullifier_secret_key - }; + // We didn't get a match meaning the cached result is stale. We fetch new values from oracle and instruct + // protocol circuits to validate them by storing the validation request in context. + let request = get_nullifier_key_validation_request(npk_m_hash); + // We constrain that the npk_m_hash matches the one in the request (otherwise we could get an arbitrary + // valid key request and not the one corresponding to npk_m_hash). + assert(request.master_nullifier_public_key.hash() == npk_m_hash); self.nullifier_key_validation_requests.push(request); - self.nullifier_key = Option::some(fetched_nullifier_keys); - fetched_nullifier_keys - }; - - assert_eq(nullifier_keys.master_nullifier_public_key.hash(), npk_m_hash); - nullifier_keys.app_nullifier_secret_key + self.last_nullifier_key_validation_request = Option::some(request); + request.app_nullifier_secret_key + } } // docs:start:context_message_portal @@ -675,7 +673,7 @@ impl Empty for PrivateContext { unencrypted_logs_hashes: BoundedVec::new(), encrypted_log_preimages_length: 0, unencrypted_log_preimages_length: 0, - nullifier_key: Option::none(), + last_nullifier_key_validation_request: Option::none(), } } } diff --git a/noir-projects/aztec-nr/aztec/src/keys/getters.nr b/noir-projects/aztec-nr/aztec/src/keys/getters.nr index 1759d3a9e57..c0b2feffc12 100644 --- a/noir-projects/aztec-nr/aztec/src/keys/getters.nr +++ b/noir-projects/aztec-nr/aztec/src/keys/getters.nr @@ -1,10 +1,9 @@ -use dep::protocol_types::{address::AztecAddress, constants::CANONICAL_KEY_REGISTRY_ADDRESS, grumpkin_point::GrumpkinPoint}; +use dep::protocol_types::{ + abis::nullifier_key_validation_request::NullifierKeyValidationRequest, address::AztecAddress, + constants::CANONICAL_KEY_REGISTRY_ADDRESS, grumpkin_point::GrumpkinPoint +}; use crate::{ - context::PrivateContext, - oracle::{ - keys::get_public_keys_and_partial_address, - nullifier_keys::{NullifierKeys, get_nullifier_keys as get_nullifier_keys_oracle} -}, + context::PrivateContext, oracle::{keys::get_public_keys_and_partial_address}, keys::public_keys::{PublicKeys, NULLIFIER_INDEX, INCOMING_INDEX}, state_vars::{ map::derive_storage_slot_in_map, @@ -90,16 +89,3 @@ fn fetch_and_constrain_keys(address: AztecAddress) -> PublicKeys { public_keys } - -// We get the full struct Nullifier Keys here -pub fn get_nullifier_keys(npk_m_hash: Field) -> NullifierKeys { - let nullifier_keys = get_nullifier_keys_oracle(npk_m_hash); - assert_eq(nullifier_keys.master_nullifier_public_key.hash(), npk_m_hash); - - nullifier_keys -} - -// We are only getting the app_nullifier_secret_key here -pub fn get_nsk_app(npk_m_hash: Field) -> Field { - get_nullifier_keys(npk_m_hash).app_nullifier_secret_key -} diff --git a/noir-projects/aztec-nr/aztec/src/oracle/nullifier_keys.nr b/noir-projects/aztec-nr/aztec/src/oracle/nullifier_keys.nr index 1d8fd94052f..0eb33d7cb15 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/nullifier_keys.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/nullifier_keys.nr @@ -1,35 +1,21 @@ -use dep::protocol_types::{ - address::AztecAddress, traits::Empty, grumpkin_point::GrumpkinPoint, - grumpkin_private_key::GrumpkinPrivateKey -}; - -// Nullifier keys pertaining to a specific account -struct NullifierKeys { - master_nullifier_public_key: GrumpkinPoint, - app_nullifier_secret_key: Field, -} - -impl Empty for NullifierKeys { - fn empty() -> Self { - NullifierKeys { - master_nullifier_public_key: GrumpkinPoint::zero(), - app_nullifier_secret_key: 0 - } - } -} +use dep::protocol_types::{grumpkin_point::GrumpkinPoint, abis::nullifier_key_validation_request::NullifierKeyValidationRequest}; #[oracle(getNullifierKeys)] -fn get_nullifier_keys_oracle(_npk_m_hash: Field) -> [Field; 3] {} +fn get_nullifier_key_validation_request_oracle(_npk_m_hash: Field) -> [Field; 3] {} -unconstrained fn get_nullifier_keys_internal(npk_m_hash: Field) -> NullifierKeys { - let result = get_nullifier_keys_oracle(npk_m_hash); - NullifierKeys { +unconstrained fn get_nullifier_key_validation_request_internal(npk_m_hash: Field) -> NullifierKeyValidationRequest { + let result = get_nullifier_key_validation_request_oracle(npk_m_hash); + NullifierKeyValidationRequest { master_nullifier_public_key: GrumpkinPoint { x: result[0], y: result[1] }, app_nullifier_secret_key: result[2] } } // We get the full struct Nullifier Keys here -pub fn get_nullifier_keys(npk_m_hash: Field) -> NullifierKeys { - get_nullifier_keys_internal(npk_m_hash) +pub fn get_nullifier_key_validation_request(npk_m_hash: Field) -> NullifierKeyValidationRequest { + get_nullifier_key_validation_request_internal(npk_m_hash) +} + +pub fn get_nsk_app(npk_m_hash: Field) -> Field { + get_nullifier_key_validation_request_internal(npk_m_hash).app_nullifier_secret_key } diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index 13d9943efd3..06c01fcbaa4 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -5,7 +5,7 @@ use dep::aztec::{ constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash }, note::{note_header::NoteHeader, note_interface::NoteInterface, utils::compute_note_hash_for_consumption}, - oracle::unsafe_rand::unsafe_rand, keys::getters::get_nsk_app, context::PrivateContext + oracle::unsafe_rand::unsafe_rand, oracle::nullifier_keys::get_nsk_app, context::PrivateContext }; global VALUE_NOTE_LEN: Field = 3; // 3 plus a header. diff --git a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr index f0029823418..e8e2dd2f2e5 100644 --- a/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr +++ b/noir-projects/noir-contracts/contracts/app_subscription_contract/src/subscription_note.nr @@ -2,7 +2,7 @@ use dep::aztec::prelude::{AztecAddress, PrivateContext, NoteHeader, NoteInterfac use dep::aztec::{ keys::getters::get_ivpk_m, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash}, - note::utils::compute_note_hash_for_consumption, keys::getters::get_nsk_app + note::utils::compute_note_hash_for_consumption, oracle::nullifier_keys::get_nsk_app }; global SUBSCRIPTION_NOTE_LEN: Field = 3; diff --git a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr index 9767ed03b92..2c3100cbc60 100644 --- a/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr +++ b/noir-projects/noir-contracts/contracts/docs_example_contract/src/types/card_note.nr @@ -1,7 +1,7 @@ use dep::aztec::prelude::{AztecAddress, NoteInterface, NoteHeader, PrivateContext}; use dep::aztec::{ keys::getters::get_ivpk_m, note::{utils::compute_note_hash_for_consumption}, - keys::getters::get_nsk_app, + oracle::nullifier_keys::get_nsk_app, protocol_types::{ traits::Empty, grumpkin_point::GrumpkinPoint, constants::GENERATOR_INDEX__NOTE_NULLIFIER, hash::poseidon2_hash diff --git a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr index 359c6fceae1..fa1b79f879d 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_account_contract/src/ecdsa_public_key_note.nr @@ -2,7 +2,7 @@ use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, NoteInterf use dep::aztec::{ keys::getters::get_ivpk_m, note::utils::compute_note_hash_for_consumption, - keys::getters::get_nsk_app, + oracle::nullifier_keys::get_nsk_app, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash} }; diff --git a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr index aa79ae7755c..3b675374f11 100644 --- a/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr +++ b/noir-projects/noir-contracts/contracts/schnorr_account_contract/src/public_key_note.nr @@ -1,6 +1,6 @@ use dep::aztec::prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}; use dep::aztec::{ - note::utils::compute_note_hash_for_consumption, keys::getters::get_nsk_app, + note::utils::compute_note_hash_for_consumption, oracle::nullifier_keys::get_nsk_app, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash} }; diff --git a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr index 17a75d2a4e1..721dc23ad24 100644 --- a/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_blacklist_contract/src/types/token_note.nr @@ -2,7 +2,7 @@ use dep::aztec::{ prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash}, note::utils::compute_note_hash_for_consumption, oracle::unsafe_rand::unsafe_rand, - keys::getters::get_nsk_app + oracle::nullifier_keys::get_nsk_app }; trait OwnedNote { diff --git a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr index 17a75d2a4e1..721dc23ad24 100644 --- a/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr +++ b/noir-projects/noir-contracts/contracts/token_contract/src/types/token_note.nr @@ -2,7 +2,7 @@ use dep::aztec::{ prelude::{AztecAddress, NoteHeader, NoteInterface, PrivateContext}, protocol_types::{constants::GENERATOR_INDEX__NOTE_NULLIFIER, grumpkin_point::GrumpkinPoint, hash::poseidon2_hash}, note::utils::compute_note_hash_for_consumption, oracle::unsafe_rand::unsafe_rand, - keys::getters::get_nsk_app + oracle::nullifier_keys::get_nsk_app }; trait OwnedNote {