Skip to content

Commit

Permalink
feat: initial auth registry
Browse files Browse the repository at this point in the history
  • Loading branch information
LHerskind committed Jun 12, 2024
1 parent f6fca41 commit fc6fa68
Show file tree
Hide file tree
Showing 25 changed files with 394 additions and 217 deletions.
2 changes: 2 additions & 0 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,8 @@ library Constants {
uint256 internal constant FIXED_DA_GAS = 512;
uint256 internal constant CANONICAL_KEY_REGISTRY_ADDRESS =
2153455745675440165069577621832684870696142028027528497509357256345838682961;
uint256 internal constant CANONICAL_AUTH_REGISTRY_ADDRESS =
5898258266404571728375734270441090444556852501104099015553649938782324233968;
uint256 internal constant DEPLOYER_CONTRACT_ADDRESS =
19511485909966796736993840362353440247573331327062358513665772226446629198132;
uint256 internal constant REGISTERER_CONTRACT_ADDRESS =
Expand Down
3 changes: 3 additions & 0 deletions noir-projects/aztec-nr/authwit/src/account.nr
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use dep::aztec::protocol_types::{address::AztecAddress, abis::function_selector:
use crate::entrypoint::{app::AppPayload, fee::FeePayload};
use crate::auth::{IS_VALID_SELECTOR, compute_outer_authwit_hash};

// @todo Remove the `approved_action`
struct AccountActions<Context> {
context: Context,
is_valid_impl: fn(&mut PrivateContext, Field) -> bool,
Expand Down Expand Up @@ -66,6 +67,8 @@ impl AccountActions<&mut PrivateContext> {
// docs:end:spend_private_authwit
}


// @todo We can entirely remove this one when the other is working.
impl AccountActions<&mut PublicContext> {
// docs:start:spend_public_authwit
pub fn spend_public_authwit(self, inner_hash: Field) -> Field {
Expand Down
11 changes: 6 additions & 5 deletions noir-projects/aztec-nr/authwit/src/auth.nr
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use dep::aztec::protocol_types::{
abis::function_selector::FunctionSelector, address::AztecAddress,
constants::{GENERATOR_INDEX__AUTHWIT_INNER, GENERATOR_INDEX__AUTHWIT_OUTER}, hash::pedersen_hash
constants::{GENERATOR_INDEX__AUTHWIT_INNER, GENERATOR_INDEX__AUTHWIT_OUTER, CANONICAL_AUTH_REGISTRY_ADDRESS},
hash::pedersen_hash
};
use dep::aztec::{prelude::Deserialize, context::{PrivateContext, PublicContext, gas::GasOpts}, hash::hash_args_array};

Expand All @@ -19,14 +20,14 @@ pub fn assert_current_call_valid_authwit(context: &mut PrivateContext, on_behalf
// docs:start:assert_current_call_valid_authwit_public
// Assert that `on_behalf_of` have authorized the current call in a public context
pub fn assert_current_call_valid_authwit_public(context: &mut PublicContext, on_behalf_of: AztecAddress) {
let function_selector = FunctionSelector::from_signature("spend_public_authwit(Field)");
let inner_hash = compute_inner_authwit_hash(
[(*context).msg_sender().to_field(), (*context).selector().to_field(), (*context).get_args_hash()]
);

let result: Field = context.call_public_function(
on_behalf_of,
function_selector,
[inner_hash].as_slice(),
AztecAddress::from_field(CANONICAL_AUTH_REGISTRY_ADDRESS),
FunctionSelector::from_signature("consume((Field),Field)"),
[on_behalf_of.to_field(), inner_hash].as_slice(),
GasOpts::default()
).deserialize_into();
assert(result == IS_VALID_SELECTOR, "Message not authorized by account");
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ impl UnconstrainedContext {
self.block_number
}

fn contract_address(self) -> AztecAddress {
fn this_address(self) -> AztecAddress {
self.contract_address
}
}
Expand Down
1 change: 1 addition & 0 deletions noir-projects/noir-contracts/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
members = [
"contracts/app_subscription_contract",
"contracts/auth_contract",
"contracts/auth_registry_contract",
"contracts/avm_initializer_test_contract",
"contracts/avm_test_contract",
"contracts/fpc_contract",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[package]
name = "auth_registry_contract"
authors = [""]
compiler_version = ">=0.25.0"
type = "contract"

[dependencies]
aztec = { path = "../../../aztec-nr/aztec" }
authwit = { path = "../../../aztec-nr/authwit" }
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
contract AuthRegistry {
use dep::aztec::{state_vars::{PublicMutable, Map}, protocol_types::address::AztecAddress};
use dep::authwit::auth::{IS_VALID_SELECTOR, compute_outer_authwit_hash};

#[aztec(storage)]
struct Storage {
reject_all: Map<AztecAddress, PublicMutable<bool>>,
// on_behalf_of => authwit hash => authorized
approved_actions: Map<AztecAddress, Map<Field, PublicMutable<bool>>>,
}

/**
* Updates the `reject_all` value for `msg_sender`.
*
* When `reject_all` is `true` any `consume` on `msg_sender` will revert.
*
* @param reject True if all actions should be rejected, false otherwise
*/
#[aztec(public)]
fn set_reject_all(reject: bool) {
storage.reject_all.at(context.msg_sender()).write(reject);
}

/**
* Updates the `authorized` value for `msg_sender` for `messageHash`.
*
* @param message_hash The message hash being authorized
* @param authorize True if the caller is authorized to perform the message hash, false otherwise
*/
#[aztec(public)]
fn set_authorized(message_hash: Field, authorize: bool) {
storage.approved_actions.at(context.msg_sender()).at(message_hash).write(authorize);
}

/**
* Consumes an `inner_hash` on behalf of `on_behalf_of` if the caller is authorized to do so.
*
* Will revert even if the caller is authorized if `reject_all` is set to true for `on_behalf_of`.
* This is to support "mass-revoke".
*
* @param on_behalf_of The address on whose behalf the action is being consumed
* @param inner_hash The inner_hash of the authwit
* @return `IS_VALID_SELECTOR` if the action was consumed, revert otherwise
*/
#[aztec(public)]
fn consume(on_behalf_of: AztecAddress, inner_hash: Field) -> Field {
assert_eq(false, storage.reject_all.at(on_behalf_of).read(), "rejecting all");

let message_hash = compute_outer_authwit_hash(
context.msg_sender(),
context.chain_id(),
context.version(),
inner_hash
);

let authorized = storage.approved_actions.at(on_behalf_of).at(message_hash).read();

assert_eq(true, authorized, "unauthorized");
storage.approved_actions.at(on_behalf_of).at(message_hash).write(false);

IS_VALID_SELECTOR
}

/**
* Fetches the `reject_all` value for `on_behalf_of`.
*
* @param on_behalf_of The address to check
* @return True if all actions are rejected, false otherwise
*/
#[aztec(public)]
#[aztec(view)]
fn is_reject_all(on_behalf_of: AztecAddress) -> bool {
storage.reject_all.at(on_behalf_of).read()
}

/*
* Fetches the `authorized` value for `on_behalf_of` for `message_hash`.
*
* @param on_behalf_of The address on whose behalf the action is being consumed
* @param message_hash The message hash to check
* @return True if the caller is authorized to perform the action, false otherwise
*/
#[aztec(public)]
#[aztec(view)]
fn is_consumable(on_behalf_of: AztecAddress, message_hash: Field) -> bool {
storage.approved_actions.at(on_behalf_of).at(message_hash).read()
}

unconstrained fn unconstrained_is_consumable(on_behalf_of: AztecAddress, message_hash: Field) -> pub bool {
storage.approved_actions.at(on_behalf_of).at(message_hash).read()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -52,25 +52,12 @@ contract EcdsaAccount {
actions.spend_private_authwit(inner_hash)
}

#[aztec(public)]
fn spend_public_authwit(inner_hash: Field) -> Field {
let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
actions.spend_public_authwit(inner_hash)
}

#[aztec(private)]
#[aztec(internal)]
fn cancel_authwit(outer_hash: Field) {
context.push_new_nullifier(outer_hash, 0);
}

#[aztec(public)]
#[aztec(internal)]
fn approve_public_authwit(outer_hash: Field) {
let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
actions.approve_public_authwit(outer_hash)
}

#[contract_library_method]
fn is_valid_impl(context: &mut PrivateContext, outer_hash: Field) -> bool {
// Load public key from storage
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,35 +65,12 @@ contract SchnorrAccount {
actions.spend_private_authwit(inner_hash)
}

#[aztec(public)]
#[aztec(noinitcheck)]
fn spend_public_authwit(inner_hash: Field) -> Field {
let actions = AccountActions::init(
&mut context,
storage.approved_actions.storage_slot,
is_valid_impl
);
actions.spend_public_authwit(inner_hash)
}

#[aztec(private)]
#[aztec(internal)]
fn cancel_authwit(outer_hash: Field) {
context.push_new_nullifier(outer_hash, 0);
}

#[aztec(public)]
#[aztec(internal)]
#[aztec(noinitcheck)]
fn approve_public_authwit(outer_hash: Field) {
let actions = AccountActions::init(
&mut context,
storage.approved_actions.storage_slot,
is_valid_impl
);
actions.approve_public_authwit(outer_hash)
}

#[contract_library_method]
fn is_valid_impl(context: &mut PrivateContext, outer_hash: Field) -> bool {
// docs:start:entrypoint
Expand Down Expand Up @@ -123,39 +100,25 @@ contract SchnorrAccount {

/**
* @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
* @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
* @return True if the message_hash can be consumed, false otherwise
*/
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_slice(
public_key.x,
public_key.y,
signature,
message_hash.to_be_bytes(32)
)
} else {
false
};
unconstrained fn lookup_validity(message_hash: Field) -> pub bool {
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;
}
let valid_in_private = std::schnorr::verify_signature_slice(
public_key.x,
public_key.y,
signature,
message_hash.to_be_bytes(32)
);

let valid_in_public = storage.approved_actions.at(message_hash).read();
let block_number = context.block_number();
let myself = context.this_address();

// Compute the nullifier and check if it is spent
// This will BLINDLY TRUST the oracle, but the oracle is us, and
Expand All @@ -164,10 +127,6 @@ contract SchnorrAccount {
let lower_wit = get_low_nullifier_membership_witness(block_number, siloed_nullifier);
let is_spent = lower_wit.leaf_preimage.nullifier == siloed_nullifier;

if is_spent {
[false, false]
} else {
[valid_in_private, valid_in_public]
}
!is_spent & valid_in_private
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -27,25 +27,12 @@ contract SchnorrHardcodedAccount {
actions.spend_private_authwit(inner_hash)
}

#[aztec(public)]
fn spend_public_authwit(inner_hash: Field) -> Field {
let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
actions.spend_public_authwit(inner_hash)
}

#[aztec(private)]
#[aztec(internal)]
fn cancel_authwit(outer_hash: Field) {
context.push_new_nullifier(outer_hash, 0);
}

#[aztec(public)]
#[aztec(internal)]
fn approve_public_authwit(outer_hash: Field) {
let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
actions.approve_public_authwit(outer_hash)
}

// docs:start:is-valid
#[contract_library_method]
fn is_valid_impl(_context: &mut PrivateContext, outer_hash: Field) -> bool {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,25 +23,12 @@ contract SchnorrSingleKeyAccount {
actions.spend_private_authwit(inner_hash)
}

#[aztec(public)]
fn spend_public_authwit(inner_hash: Field) -> Field {
let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
actions.spend_public_authwit(inner_hash)
}

#[aztec(private)]
#[aztec(internal)]
fn cancel_authwit(outer_hash: Field) {
context.push_new_nullifier(outer_hash, 0);
}

#[aztec(public)]
#[aztec(internal)]
fn approve_public_authwit(outer_hash: Field) {
let actions = AccountActions::init(&mut context, ACCOUNT_ACTIONS_STORAGE_SLOT, is_valid_impl);
actions.approve_public_authwit(outer_hash)
}

#[contract_library_method]
fn is_valid_impl(context: &mut PrivateContext, outer_hash: Field) -> bool {
let witness = get_auth_witness(outer_hash);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,7 @@ global FIXED_DA_GAS: u32 = 512;

// CANONICAL CONTRACT ADDRESSES
global CANONICAL_KEY_REGISTRY_ADDRESS = 0x04c2d010f88e8c238882fbbcbce5c81fdc1dc8ece85e8dbf3f602b4d81ec0351;
global CANONICAL_AUTH_REGISTRY_ADDRESS = 0x0d0a4bbe66a1e2312dae122534699f2594c9b699695b02c4a5041aa86b9396f0;
global DEPLOYER_CONTRACT_ADDRESS = 0x2b231c13768709b1ba51c1f86275b47e38dfac16e3d7f242cb578d92a4e2d934;
global REGISTERER_CONTRACT_ADDRESS = 0x302da9b6000a76691341b250565ca5c67723261fa99af1435ffe5178ccb21417;
global GAS_TOKEN_ADDRESS = 0x06fc7badd50bb8ee32439b52e8874b5a16ddd2aa1d5647ec46b2a0f51356f889;
Expand Down
Loading

0 comments on commit fc6fa68

Please sign in to comment.