-
Notifications
You must be signed in to change notification settings - Fork 310
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat(Authwit): lookup the validity of authwits #5316
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,13 @@ | ||
use dep::protocol_types::{constants::GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET, hash::pedersen_hash}; | ||
use dep::protocol_types::{ | ||
address::AztecAddress, | ||
constants::GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET, | ||
hash::{pedersen_hash, silo_nullifier}}; | ||
|
||
pub fn compute_secret_hash(secret: Field) -> Field { | ||
// TODO(#1205) This is probably not the right index to use | ||
pedersen_hash([secret], GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET) | ||
} | ||
|
||
pub fn compute_siloed_nullifier(address: AztecAddress, nullifier: Field) -> Field { | ||
silo_nullifier(address, nullifier) | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -6,23 +6,24 @@ contract SchnorrAccount { | |
use dep::std; | ||
|
||
use dep::aztec::prelude::{AztecAddress, FunctionSelector, NoteHeader, PrivateContext, PrivateImmutable}; | ||
|
||
use dep::aztec::state_vars::{Map, PublicMutable}; | ||
use dep::aztec::{context::Context, oracle::get_public_key::get_public_key}; | ||
use dep::authwit::{ | ||
entrypoint::{app::AppPayload, fee::FeePayload}, account::AccountActions, | ||
auth_witness::get_auth_witness | ||
}; | ||
use dep::aztec::hash::compute_siloed_nullifier; | ||
use dep::aztec::oracle::get_nullifier_membership_witness::get_low_nullifier_membership_witness; | ||
|
||
use crate::public_key_note::{PublicKeyNote, PUBLIC_KEY_NOTE_LEN}; | ||
|
||
struct Storage { | ||
// docs:start:storage | ||
signing_public_key: PrivateImmutable<PublicKeyNote>, | ||
// docs:end:storage | ||
approved_actions: Map<Field, PublicMutable<bool>>, | ||
} | ||
|
||
global ACCOUNT_ACTIONS_STORAGE_SLOT = 2; | ||
|
||
// Constructs the contract | ||
#[aztec(private)] | ||
#[aztec(initializer)] | ||
|
@@ -37,19 +38,31 @@ contract SchnorrAccount { | |
// Note: If you globally change the entrypoint signature don't forget to update default_entrypoint.ts file | ||
#[aztec(private)] | ||
fn entrypoint(app_payload: pub AppPayload, fee_payload: pub FeePayload) { | ||
let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); | ||
let actions = AccountActions::private( | ||
&mut context, | ||
storage.approved_actions.storage_slot, | ||
is_valid_impl | ||
); | ||
actions.entrypoint(app_payload, fee_payload); | ||
} | ||
|
||
#[aztec(private)] | ||
fn spend_private_authwit(inner_hash: Field) -> Field { | ||
let actions = AccountActions::private(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); | ||
let actions = AccountActions::private( | ||
&mut context, | ||
storage.approved_actions.storage_slot, | ||
is_valid_impl | ||
); | ||
actions.spend_private_authwit(inner_hash) | ||
} | ||
|
||
#[aztec(public)] | ||
fn spend_public_authwit(inner_hash: Field) -> Field { | ||
let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); | ||
let actions = AccountActions::public( | ||
&mut context, | ||
storage.approved_actions.storage_slot, | ||
is_valid_impl | ||
); | ||
actions.spend_public_authwit(inner_hash) | ||
} | ||
|
||
|
@@ -62,7 +75,11 @@ contract SchnorrAccount { | |
#[aztec(public)] | ||
#[aztec(internal)] | ||
fn approve_public_authwit(outer_hash: Field) { | ||
let actions = AccountActions::public(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl); | ||
let actions = AccountActions::public( | ||
&mut context, | ||
storage.approved_actions.storage_slot, | ||
is_valid_impl | ||
); | ||
actions.approve_public_authwit(outer_hash) | ||
} | ||
|
||
|
@@ -92,4 +109,54 @@ contract SchnorrAccount { | |
// docs:end:entrypoint | ||
true | ||
} | ||
|
||
/** | ||
* @notice Helper function to check the existing and validity of authwitnesses | ||
* @dev TODO: myself and block_number should be removed and passed from a context | ||
* @param myself The address of the contract | ||
* @param block_number The block number to check the nullifier against | ||
* @param check_private Whether to check the validity of the authwitness in private state or not | ||
* @param message_hash The message hash of the message to check the validity | ||
nventuro marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* @return An array of two booleans, the first is the validity of the authwitness in the private state, | ||
* the second is the validity of the authwitness in the public state | ||
* Both values will be `false` if the nullifier is spent | ||
*/ | ||
unconstrained fn lookup_validity( | ||
myself: AztecAddress, | ||
block_number: u32, | ||
check_private: bool, | ||
message_hash: Field | ||
) -> pub [bool; 2] { | ||
let valid_in_private = if check_private { | ||
let public_key = storage.signing_public_key.view_note(); | ||
let witness: [Field; 64] = get_auth_witness(message_hash); | ||
let mut signature: [u8; 64] = [0; 64]; | ||
for i in 0..64 { | ||
signature[i] = witness[i] as u8; | ||
} | ||
std::schnorr::verify_signature( | ||
public_key.x, | ||
public_key.y, | ||
signature, | ||
message_hash.to_be_bytes(32) | ||
) | ||
} else { | ||
false | ||
}; | ||
|
||
let valid_in_public = storage.approved_actions.at(message_hash).read(); | ||
|
||
// Compute the nullifier and check if it is spent | ||
// This will BLINDLY TRUST the oracle, but the oracle is us, and | ||
// it is not as part of execution of the contract, so we are good. | ||
let siloed_nullifier = compute_siloed_nullifier(myself, message_hash); | ||
let lower_wit = get_low_nullifier_membership_witness(block_number, siloed_nullifier); | ||
let is_spent = lower_wit.leaf_preimage.nullifier == siloed_nullifier; | ||
Comment on lines
+153
to
+154
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Why do we need a full membership witness if we're blinding trusting the oracle? We could just return a flag "spent". Or is this just to avoid introducing a new oracle call? There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Was to not introduce a new oracle 👍 |
||
|
||
if is_spent { | ||
[false, false] | ||
} else { | ||
[valid_in_private, valid_in_public] | ||
} | ||
} | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This would be solved by #2665 right?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not directly as this one is doing both public and private, likely better addressed by having a unconstrained context as we briefly discussed the other day in the scrum. Should likely have a larger issue as it can also align functions so they are not totally different.