Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
benesjan committed May 3, 2024
1 parent fbd78fd commit 18c66c0
Show file tree
Hide file tree
Showing 4 changed files with 140 additions and 152 deletions.
2 changes: 1 addition & 1 deletion noir-projects/aztec-nr/aztec/src/keys.nr
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod getters;
mod point_to_symmetric_key;

use crate::keys::getters::get_fresh_nullifier_public_key_hash;
use crate::keys::getters::{get_npk_m, get_ivpk_m, get_ovpk_m, get_tpk_m};
135 changes: 73 additions & 62 deletions noir-projects/aztec-nr/aztec/src/keys/getters.nr
Original file line number Diff line number Diff line change
@@ -1,79 +1,90 @@
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 dep::protocol_types::{address::AztecAddress, constants::CANONICAL_KEY_REGISTRY_ADDRESS, grumpkin_point::GrumpkinPoint};
use crate::{
context::PrivateContext, hash::poseidon2_hash, oracle::keys::get_public_keys_and_partial_address,
state_vars::{
map::derive_storage_slot_in_map,
shared_mutable::shared_mutable_private_getter::SharedMutablePrivateGetter
}
};

use crate::context::PrivateContext;
use crate::hash::{
pedersen_hash,
poseidon2_hash,
};
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,
};
// Note: In fetch_hash_from_registry we expect that shared mutable slow is index + 1 (e.g. NULLIFIER_INDEX + 1),
// this changes the function will need to be refactored
global NULLIFIER_INDEX = 0;
global INCOMING_INDEX = 1;
global OUTGOING_INDEX = 2;
global TAGGING_INDEX = 3;

struct PublicKeyTypeEnum {
NULLIFIER: u8,
global DELAY = 5;

pub fn get_npk_m(context: &mut PrivateContext, address: AztecAddress) -> GrumpkinPoint {
get_master_key(context, address, NULLIFIER_INDEX)
}

global PublicKeyType = PublicKeyTypeEnum {
NULLIFIER: 0,
};
pub fn get_ivpk_m(context: &mut PrivateContext, address: AztecAddress) -> GrumpkinPoint {
get_master_key(context, address, INCOMING_INDEX)
}

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
// 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;
pub fn get_ovpk_m(context: &mut PrivateContext, address: AztecAddress) -> GrumpkinPoint {
get_master_key(context, address, OUTGOING_INDEX)
}

let derived_slot = derive_storage_slot_in_map(storage_slot_of_nullifier_public_key, address);
pub fn get_tpk_m(context: &mut PrivateContext, address: AztecAddress) -> GrumpkinPoint {
get_master_key(context, address, TAGGING_INDEX)
}

// 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<Field, 5> = 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();
fn get_master_key(
context: &mut PrivateContext,
address: AztecAddress,
key_index: Field
) -> GrumpkinPoint {
// 1. Get key hash from registry
let key_hash = fetch_hash_from_registry(context, key_index, address);
if key_hash == 0 {
// i. Keys were not registered yet --> fetch address preimage and check that the hash matches
fetch_and_constrain_keys(address)[key_index]
} else {
// ii. Keys were registered --> we fetch the key from oracle, hash it and check that it matches the hash in the registry
let (keys, _) = get_public_keys_and_partial_address(address);
let key = keys[key_index];
let key_hash_from_oracle = poseidon2_hash(key.serialize());
assert(key_hash_from_oracle == key_hash);
key
}
}

let nullifier_public_key_hash = if nullifier_public_key_hash_in_registry == 0 {
let keys = get_original_public_keys_internal(address);
poseidon2_hash(keys[PublicKeyType.NULLIFIER].serialize())
} else {
nullifier_public_key_hash_in_registry
};
fn fetch_hash_from_registry(
context: &mut PrivateContext,
key_index: Field,
address: AztecAddress
) -> Field {
let derived_slot = derive_storage_slot_in_map(key_index + 1, address);

nullifier_public_key_hash
let registry_private_getter: SharedMutablePrivateGetter<Field, DELAY> = SharedMutablePrivateGetter::new(
*context,
AztecAddress::from_field(CANONICAL_KEY_REGISTRY_ADDRESS),
derived_slot
);
registry_private_getter.get_current_value_in_private()
}

// 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);
// Passes only when keys were not rotated - is expected to be called only when keys were not registered yet
fn fetch_and_constrain_keys(address: AztecAddress) -> [GrumpkinPoint; 4] {
let (public_keys, partial_address) = get_public_keys_and_partial_address(address);

let nullifier_pub_key = public_keys[0];
let incoming_pub_key = public_keys[1];
let outgoing_pub_key = public_keys[2];
let tagging_pub_key = public_keys[3];
let 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,
);
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));
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]
}
Original file line number Diff line number Diff line change
@@ -1,104 +1,81 @@
contract KeyRegistry {
use dep::authwit::auth::assert_current_call_valid_authwit_public;
use dep::authwit::auth::assert_current_call_valid_authwit_public;

use dep::aztec::{
state_vars::{
SharedMutable,
Map
},
protocol_types::{
grumpkin_point::GrumpkinPoint,
address::{
AztecAddress,
PublicKeysHash,
PartialAddress,
},
constants::{
GENERATOR_INDEX__CONTRACT_ADDRESS_V1,
GENERATOR_INDEX__PUBLIC_KEYS_HASH
},
hash::poseidon2_hash,
},
};
use dep::aztec::{
state_vars::{SharedMutable, Map},
protocol_types::{
grumpkin_point::GrumpkinPoint, address::{AztecAddress, PartialAddress},
hash::poseidon2_hash
}
};

global KEY_ROTATION_DELAY = 5;
global KEY_ROTATION_DELAY = 5;

#[aztec(storage)]
#[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<AztecAddress, SharedMutable<Field, KEY_ROTATION_DELAY>>,

// 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_public_key_registry: Map<AztecAddress, SharedMutable<Field, KEY_ROTATION_DELAY>>,
// outgoing_public_key_registry: Map<AztecAddress, SharedMutable<Field, KEY_ROTATION_DELAY>>,
// tagging_public_key_registry: Map<AztecAddress, SharedMutable<Field, KEY_ROTATION_DELAY>>,
// The following stores a hash of individual master public keys
// If you change slots of vars bellow, you must update the slot in `SharedMutablePrivateGetter` in aztec-nr keys.
nullifier_registry: Map<AztecAddress, SharedMutable<Field, KEY_ROTATION_DELAY>>,
incoming_registry: Map<AztecAddress, SharedMutable<Field, KEY_ROTATION_DELAY>>,
outgoing_registry: Map<AztecAddress, SharedMutable<Field, KEY_ROTATION_DELAY>>,
tagging_registry: Map<AztecAddress, SharedMutable<Field, KEY_ROTATION_DELAY>>,
}

#[aztec(public)]
#[aztec(public)]
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");
}
address: AztecAddress,
new_nullifier_public_key: GrumpkinPoint,
nonce: Field
) {
assert(!new_nullifier_public_key.is_zero(), "New nullifier public key must be non-zero");

let nullifier_key_registry = storage.nullifier_public_key_hash_registry.at(address);
// TODO: (#6137)
if (!address.eq(context.msg_sender())) {
assert_current_call_valid_authwit_public(&mut context, address);
} else {
assert(nonce == 0, "invalid nonce");
}

nullifier_key_registry.schedule_value_change(poseidon2_hash(new_nullifier_public_key.serialize()));
}
let nullifier_registry = storage.nullifier_registry.at(address);
nullifier_registry.schedule_value_change(poseidon2_hash(new_nullifier_public_key.serialize()));
}

#[aztec(public)]
#[aztec(public)]
fn register(
address: AztecAddress,
partial_address: PartialAddress,
nullifier_public_key: GrumpkinPoint,
incoming_public_key: GrumpkinPoint,
outgoing_public_key: GrumpkinPoint,
tagging_public_key: GrumpkinPoint,
) {
assert(
!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"
);
address: AztecAddress,
partial_address: PartialAddress,
nullifier_public_key: GrumpkinPoint,
incoming_public_key: GrumpkinPoint,
outgoing_public_key: GrumpkinPoint,
tagging_public_key: GrumpkinPoint
) {
assert(
!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"
);

// 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 computed_address = AztecAddress::compute_from_public_keys_and_partial_address(
nullifier_public_key,
incoming_public_key,
outgoing_public_key,
tagging_public_key,
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 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");
assert(computed_address.eq(address), "Computed address does not match supplied 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);
let nullifier_registry = storage.nullifier_registry.at(address);
let incoming_registry = storage.incoming_registry.at(address);
let outgoing_registry = storage.outgoing_registry.at(address);
let tagging_registry = storage.tagging_registry.at(address);

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);
// tagging_key_registry.schedule_value_change(new_tagging_public_key);
}
nullifier_registry.schedule_value_change(poseidon2_hash(nullifier_public_key.serialize()));
incoming_registry.schedule_value_change(poseidon2_hash(incoming_public_key.serialize()));
outgoing_registry.schedule_value_change(poseidon2_hash(outgoing_public_key.serialize()));
tagging_registry.schedule_value_change(poseidon2_hash(tagging_public_key.serialize()));
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ contract Test {
use dep::aztec::state_vars::{shared_mutable::SharedMutablePrivateGetter, map::derive_storage_slot_in_map};

use dep::aztec::{
keys::getters::get_fresh_nullifier_public_key_hash,
keys::getters::get_npk_m,
context::{Context, inputs::private_context_inputs::PrivateContextInputs},
hash::{pedersen_hash, poseidon2_hash, compute_secret_hash, ArgsHasher},
note::{
Expand Down Expand Up @@ -435,7 +435,7 @@ contract Test {
address: AztecAddress,
public_nullifying_key: GrumpkinPoint,
) {
assert_eq(get_fresh_nullifier_public_key_hash(&mut context, address), poseidon2_hash(public_nullifying_key.serialize()));
assert_eq(get_npk_m(&mut context, address), poseidon2_hash(public_nullifying_key.serialize()));
}

#[aztec(public)]
Expand Down

0 comments on commit 18c66c0

Please sign in to comment.