Skip to content
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

refactor: refactor key rotate and address comments from 6405 #6450

Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
7d4ace4
Initial
sklppy88 May 16, 2024
a49681c
Addressing comments
sklppy88 May 16, 2024
9b1eb35
Addressing comments
sklppy88 May 16, 2024
034948d
Comment
sklppy88 May 16, 2024
f6902d0
test
sklppy88 May 16, 2024
3d10f31
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 17, 2024
0e738f7
One way
sklppy88 May 17, 2024
5ac568e
Comments
sklppy88 May 17, 2024
49652b5
Add
sklppy88 May 17, 2024
50a3909
Fmt
sklppy88 May 17, 2024
29b70fd
comment
sklppy88 May 17, 2024
06fb183
Missing
sklppy88 May 17, 2024
7853a03
Apply Jan's suggestions
sklppy88 May 17, 2024
c9e0a05
Add to interface
sklppy88 May 17, 2024
b206b7c
Comment
sklppy88 May 17, 2024
c602171
Revert "Add to interface"
sklppy88 May 17, 2024
d33e54f
Revert "Revert "Add to interface""
sklppy88 May 17, 2024
a3a503d
Fix
sklppy88 May 17, 2024
eaaf567
Fix
sklppy88 May 17, 2024
11b9e89
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 17, 2024
f595765
Format
sklppy88 May 17, 2024
41b99f4
Comment
sklppy88 May 17, 2024
6e9a0d3
Fix
sklppy88 May 17, 2024
7309988
Comment
sklppy88 May 17, 2024
6777c35
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 17, 2024
0d2bdd3
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 17, 2024
42a0551
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 18, 2024
e26e04b
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 20, 2024
924b901
Fix issues from merge
sklppy88 May 20, 2024
6044733
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 20, 2024
3378ac0
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 21, 2024
62ccede
Comments
sklppy88 May 21, 2024
cb500ec
Format
sklppy88 May 21, 2024
7bbed9e
Merge fixes
sklppy88 May 21, 2024
0225544
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 21, 2024
0fecfc2
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 21, 2024
3e9e018
Merge branch 'master' into ek/refactor/refactor-key-rotate-call-and-a…
sklppy88 May 21, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -64,6 +64,7 @@ contract Child {
fn private_get_value(amount: Field, owner: AztecAddress) -> Field {
let owner_npk_m_hash = get_npk_m_hash(&mut context, owner);

// TODO (#6312): This will break with key rotation. Fix this. Will not be able to find any notes after rotating key.
let mut options = NoteGetterOptions::new();
options = options.select(ValueNote::properties().value, amount, Option::none()).select(
ValueNote::properties().npk_m_hash,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ pub fn create_account_card_getter_options(
account_npk_m_hash: Field,
offset: u32
) -> NoteGetterOptions<CardNote, CARD_NOTE_LEN, Field> {
// TODO (#6312): This will break with key rotation. Fix this. Will not be able to find any notes after rotating key.
let mut options = NoteGetterOptions::new();
options.select(
CardNote::properties().npk_m_hash,
Expand All @@ -26,6 +27,7 @@ pub fn create_exact_card_getter_options(
secret: Field,
account_npk_m_hash: Field
) -> NoteGetterOptions<CardNote, CARD_NOTE_LEN, Field> {
// TODO (#6312): This will break with key rotation. Fix this. Will not be able to find any notes after rotating key.
let mut options = NoteGetterOptions::new();
options.select(CardNote::properties().points, points as Field, Option::none()).select(CardNote::properties().randomness, secret, Option::none()).select(
CardNote::properties().npk_m_hash,
Expand Down Expand Up @@ -54,6 +56,7 @@ pub fn filter_min_points(

// docs:start:state_vars-NoteGetterOptionsFilter
pub fn create_account_cards_with_min_points_getter_options(account_npk_m_hash: Field, min_points: u8) -> NoteGetterOptions<CardNote, CARD_NOTE_LEN, u8> {
// TODO (#6312): This will break with key rotation. Fix this. Will not be able to find any notes after rotating key.
NoteGetterOptions::with_filter(filter_min_points, min_points).select(
CardNote::properties().npk_m_hash,
account_npk_m_hash,
Expand All @@ -64,6 +67,7 @@ pub fn create_account_cards_with_min_points_getter_options(account_npk_m_hash: F

// docs:start:state_vars-NoteGetterOptionsPickOne
pub fn create_largest_account_card_getter_options(account_npk_m_hash: Field) -> NoteGetterOptions<CardNote, CARD_NOTE_LEN, Field> {
// TODO (#6312): This will break with key rotation. Fix this. Will not be able to find any notes after rotating key.
let mut options = NoteGetterOptions::new();
options.select(
CardNote::properties().npk_m_hash,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ impl NoteInterface<ECDSA_PUBLIC_KEY_NOTE_LEN> for EcdsaPublicKeyNote {
// [1] = x[31]
// [2] = y[0..31]
// [3] = y[31]
// [4] = owner
// [4] = npk_m_hash
fn serialize_content(self) -> [Field; ECDSA_PUBLIC_KEY_NOTE_LEN] {
let mut x: Field = 0;
let mut y: Field = 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,6 @@ contract StatefulTest {
fn create_note_no_init_check(owner: AztecAddress, value: Field) {
if (value != 0) {
let loc = storage.notes.at(owner);
// TODO (#6312): This will break with key rotation. Fix this. Will not be able to spend / increment any notes after rotating key.
increment(context, loc, value, owner);
}
}
Expand Down
60 changes: 59 additions & 1 deletion yarn-project/aztec.js/src/wallet/account_wallet.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { type AuthWitness, type FunctionCall, type PXE, type TxExecutionRequest } from '@aztec/circuit-types';
import { type AztecAddress, Fr } from '@aztec/circuits.js';
import { AztecAddress, CANONICAL_KEY_REGISTRY_ADDRESS, type Fq, Fr, type Point } from '@aztec/circuits.js';
import { type ABIParameterVisibility, type FunctionAbi, FunctionType } from '@aztec/foundation/abi';

import { type AccountInterface } from '../account/interface.js';
Expand Down Expand Up @@ -165,6 +165,30 @@ export class AccountWallet extends BaseWallet {
return { isValidInPrivate, isValidInPublic };
}

/**
* Returns a function interaction to rotate our master nullifer public key in the canonical key registry.
* @param newNpkM - The new master nullifier public key we want to use.
* @remarks - This does not hinder our ability to spend notes tied to a previous master nullifier public key.
* @returns - A function interaction.
*/
public rotateNpkM(newNpkM: Point): ContractFunctionInteraction {
return new ContractFunctionInteraction(
this,
AztecAddress.fromBigInt(CANONICAL_KEY_REGISTRY_ADDRESS),
this.getRotateNpkMAbi(),
[this.getAddress(), newNpkM],
);
}

/**
* Rotates the account master nullifier secret key in our pxe / keystore
* @param newNskM - The new master nullifier secret key we want to use.
* @remarks - This does not hinder our ability to spend notes tied to a previous master nullifier public key.
*/
public async rotateNskM(newNskM: Fq): Promise<void> {
await this.pxe.rotateNskMPxe(this.getAddress(), newNskM);
}

/**
* Returns a function interaction to cancel a message hash as authorized in this account.
* @param messageHashOrIntent - The message or the caller and action to authorize/revoke
Expand Down Expand Up @@ -265,4 +289,38 @@ export class AccountWallet extends BaseWallet {
returnTypes: [{ kind: 'array', length: 2, type: { kind: 'boolean' } }],
};
}

private getRotateNpkMAbi(): FunctionAbi {
return {
name: 'rotate_npk_m',
isInitializer: false,
functionType: FunctionType.OPEN,
isInternal: false,
parameters: [
{
name: 'address',
type: {
fields: [{ name: 'inner', type: { kind: 'field' } }],
kind: 'struct',
path: 'authwit::aztec::protocol_types::address::aztec_address::AztecAddress',
},
visibility: 'private' as ABIParameterVisibility,
},
{
name: 'new_npk_m',
type: {
fields: [
{ name: 'x', type: { kind: 'field' } },
{ name: 'y', type: { kind: 'field' } },
],
kind: 'struct',
path: 'authwit::aztec::protocol_types::grumpkin_point::GrumpkinPoint',
},
visibility: 'private' as ABIParameterVisibility,
},
{ name: 'nonce', type: { kind: 'field' }, visibility: 'private' as ABIParameterVisibility },
],
returnTypes: [],
};
}
}
4 changes: 2 additions & 2 deletions yarn-project/aztec.js/src/wallet/base_wallet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -69,8 +69,8 @@ export abstract class BaseWallet implements Wallet {
registerAccount(secretKey: Fr, partialAddress: PartialAddress): Promise<CompleteAddress> {
return this.pxe.registerAccount(secretKey, partialAddress);
}
rotateMasterNullifierKey(account: AztecAddress, secretKey: Fq): Promise<void> {
return this.pxe.rotateMasterNullifierKey(account, secretKey);
rotateNskMPxe(address: AztecAddress, secretKey: Fq) {
Copy link
Contributor Author

@sklppy88 sklppy88 May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like this but don't see another way as BaseWallet impls PXE

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why not just rotateNskM instead of rotateNskMPxe?

Copy link
Contributor Author

@sklppy88 sklppy88 May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The AccountWallet would think we're overriding rotateNskM on BaseWallet / PXE if we have the same names (rotateNskM), but they have different signatures, the AccountWallet impl takes only the new key, but the PXE needs the address as well. I went for the cleaner approach on the AccountWallet trading off cleanliness at the PXE level.

Other options include renaming the AccountWallet fns to rotateNskMPxe or something along those lines, or doing shenanigans with the params—both not ideal to me, but they could work.

For the record, I don't like this interaction at all. Do you have any ideas ? Maybe I've forgotten something.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, the inheritance here is just weird and not sure if we should continue having BaseWallet inherit from PXE given that it makes sense that it modifies the signature of many methods of PXE (given that they are account-scoped in that context).

But anyway we could improve it now by having PXE.rotateNskMForAccount and refactor all the inheritance later if we decide to do so.

return this.pxe.rotateNskMPxe(address, secretKey);
}
registerRecipient(account: CompleteAddress): Promise<void> {
return this.pxe.registerRecipient(account);
Expand Down
12 changes: 10 additions & 2 deletions yarn-project/circuit-types/src/interfaces/pxe.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,6 @@ export interface PXE {
*/
registerAccount(secretKey: Fr, partialAddress: PartialAddress): Promise<CompleteAddress>;

rotateMasterNullifierKey(account: AztecAddress, secretKey: Fq): Promise<void>;

/**
* Registers a recipient in PXE. This is required when sending encrypted notes to
* a user who hasn't deployed their account contract yet. Since their account is not deployed, their
Expand Down Expand Up @@ -107,6 +105,16 @@ export interface PXE {
*/
getRecipient(address: AztecAddress): Promise<CompleteAddress | undefined>;

/**
* Rotates our master nullifier secret key by adding it to our keystore
sklppy88 marked this conversation as resolved.
Show resolved Hide resolved
* @param address - The address of the account we want to rotate our key for.
* @param newNskM - The new master nullifier secret key we want to use.
* @remarks - This does not hinder our ability to spend notes tied to a previous master nullifier public key.
* Also, one should not use this function directly without also calling the canonical key registry, and it is preferred to use the function
* under the AccountWallet interface, as that implementation also returns a contract interaction one could use to call the key registry with.
*/
rotateNskMPxe(address: AztecAddress, newNskM: Fq): Promise<void>;

/**
* Registers a contract class in the PXE without registering any associated contract instance with it.
*
Expand Down
17 changes: 9 additions & 8 deletions yarn-project/end-to-end/src/e2e_key_rotation.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { createAccounts } from '@aztec/accounts/testing';
import {
type AccountWallet,
type AztecAddress,
type AztecNode,
type DebugLogger,
Expand All @@ -14,8 +15,7 @@ import {
retryUntil,
} from '@aztec/aztec.js';
import { type PublicKey, derivePublicKeyFromSecretKey } from '@aztec/circuits.js';
import { KeyRegistryContract, TestContract, TokenContract } from '@aztec/noir-contracts.js';
import { getCanonicalKeyRegistryAddress } from '@aztec/protocol-contracts/key-registry';
import { TestContract, TokenContract } from '@aztec/noir-contracts.js';

import { jest } from '@jest/globals';

Expand All @@ -31,13 +31,12 @@ describe('e2e_key_rotation', () => {
let aztecNode: AztecNode;
let pxeA: PXE;
let pxeB: PXE;
let walletA: Wallet;
let walletB: Wallet;
let walletA: AccountWallet;
let walletB: AccountWallet;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Being forced to replace interface with an instance seems incorrect. Why not update the Wallet interface?

Copy link
Contributor Author

@sklppy88 sklppy88 May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw how it was being used in e2e_authwit, transfer_private.test, and transfer_public.test, because what is returned from createAccounts and setup is an AccountWallet and not a Wallet. You bring a good point though. I have changes and can address in a downstream PR if you need this PR in now, or right after scrum and I'll commit changes now.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ok ok, yes sounds good doing that in another PR.

Copy link
Contributor Author

@sklppy88 sklppy88 May 17, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Whoops false alarm, talked to @LHerskind and we came to an agreement that we probably want to have one encapsulated call. At this point I had already finished the interface changes, so snuck it in and it should be all good to go.

let logger: DebugLogger;
let teardownA: () => Promise<void>;
let teardownB: () => Promise<void>;

let keyRegistryWithB: KeyRegistryContract;
let testContract: TestContract;
let contractWithWalletA: TokenContract;
let contractWithWalletB: TokenContract;
Expand All @@ -58,7 +57,6 @@ describe('e2e_key_rotation', () => {
({ pxe: pxeB, teardown: teardownB } = await setupPXEService(aztecNode, {}, undefined, true));

[walletB] = await createAccounts(pxeB, 1);
keyRegistryWithB = await KeyRegistryContract.at(getCanonicalKeyRegistryAddress(), walletB);

// We deploy test and token contracts
testContract = await TestContract.deploy(walletA).send().deployed();
Expand Down Expand Up @@ -176,9 +174,12 @@ describe('e2e_key_rotation', () => {
{
const newNskM = Fq.random();
newNpkM = derivePublicKeyFromSecretKey(newNskM);
await pxeB.rotateMasterNullifierKey(walletB.getAddress(), newNskM);

await keyRegistryWithB.methods.rotate_npk_m(walletB.getAddress(), newNpkM, 0).send().wait();
// We call the registry to rotate our key here
await walletB.rotateNpkM(newNpkM).send().wait();
// We add it to our Pxe here
sklppy88 marked this conversation as resolved.
Show resolved Hide resolved
await walletB.rotateNskM(newNskM);

await crossDelay();
}

Expand Down
32 changes: 18 additions & 14 deletions yarn-project/key-store/src/test_key_store.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,14 +59,14 @@ export class TestKeyStore implements KeyStore {
// We save the keys to db associated with the account address
await this.#keys.set(`${accountAddress.toString()}-public_keys_hash`, publicKeysHash.toBuffer());

// Naming of keys is as follows ${from}-${to}_m
// Naming of keys is as follows ${from}-${to}_m${_s if multiple}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🫡

await this.#keys.set(`${accountAddress.toString()}-ivsk_m`, masterIncomingViewingSecretKey.toBuffer());
await this.#keys.set(`${accountAddress.toString()}-ovsk_m`, masterOutgoingViewingSecretKey.toBuffer());
await this.#keys.set(`${accountAddress.toString()}-tsk_m`, masterTaggingSecretKey.toBuffer());
// The key of the following is different from the others because the buffer can store multiple keys
await this.#keys.set(`${accountAddress.toString()}-ns_keys_m`, masterNullifierSecretKey.toBuffer());
await this.#keys.set(`${accountAddress.toString()}-nsk_m_s`, masterNullifierSecretKey.toBuffer());

await this.#keys.set(`${accountAddress.toString()}-np_keys_m`, publicKeys.masterNullifierPublicKey.toBuffer());
await this.#keys.set(`${accountAddress.toString()}-npk_m_s`, publicKeys.masterNullifierPublicKey.toBuffer());
await this.#keys.set(`${accountAddress.toString()}-ivpk_m`, publicKeys.masterIncomingViewingPublicKey.toBuffer());
await this.#keys.set(`${accountAddress.toString()}-ovpk_m`, publicKeys.masterOutgoingViewingPublicKey.toBuffer());
await this.#keys.set(`${accountAddress.toString()}-tpk_m`, publicKeys.masterTaggingPublicKey.toBuffer());
Expand Down Expand Up @@ -107,7 +107,7 @@ export class TestKeyStore implements KeyStore {
const accountAddress = AztecAddress.fromBuffer(accountAddressBuffer);

// Get the master nullifier public keys buffer for the account
const masterNullifierPublicKeysBuffer = this.#keys.get(`${accountAddress.toString()}-np_keys_m`);
const masterNullifierPublicKeysBuffer = this.#keys.get(`${accountAddress.toString()}-npk_m_s`);
if (!masterNullifierPublicKeysBuffer) {
throw new Error(
`Could not find master nullifier public key for account ${accountAddress.toString()} whose address was successfully obtained with npk_m_hash ${npkMHash.toString()}.`,
Expand All @@ -120,7 +120,7 @@ export class TestKeyStore implements KeyStore {
}

// Now we iterate over the public keys in the buffer to find the one that matches the hash
const numKeys = masterNullifierPublicKeysBuffer.byteLength / Point.SIZE_IN_BYTES;
const numKeys = this.#calculateNumKeys(masterNullifierPublicKeysBuffer, Point);
for (let i = 0; i < numKeys; i++) {
const masterNullifierPublicKey = Point.fromBuffer(
masterNullifierPublicKeysBuffer.subarray(i * Point.SIZE_IN_BYTES, (i + 1) * Point.SIZE_IN_BYTES),
Expand Down Expand Up @@ -196,7 +196,7 @@ export class TestKeyStore implements KeyStore {

// Now we get the master nullifier secret keys for the account
const masterNullifierSecretKeysBuffer = this.#keys.get(
`${AztecAddress.fromBuffer(accountAddressBuffer).toString()}-ns_keys_m`,
`${AztecAddress.fromBuffer(accountAddressBuffer).toString()}-nsk_m_s`,
);
if (!masterNullifierSecretKeysBuffer) {
throw new Error(
Expand All @@ -207,7 +207,7 @@ export class TestKeyStore implements KeyStore {
}

// Now we iterate over all the secret keys to find the one that matches the hash
const numKeys = masterNullifierSecretKeysBuffer.byteLength / GrumpkinScalar.SIZE_IN_BYTES;
const numKeys = this.#calculateNumKeys(masterNullifierSecretKeysBuffer, GrumpkinScalar);
for (let i = 0; i < numKeys; i++) {
const secretKey = GrumpkinScalar.fromBuffer(
masterNullifierSecretKeysBuffer.subarray(
Expand Down Expand Up @@ -295,7 +295,7 @@ export class TestKeyStore implements KeyStore {
const accountAddress = AztecAddress.fromBuffer(accountAddressBuffer);

// We fetch the public keys and find this specific public key's position in the buffer
const masterNullifierPublicKeysBuffer = this.#keys.get(`${accountAddress.toString()}-np_keys_m`);
const masterNullifierPublicKeysBuffer = this.#keys.get(`${accountAddress.toString()}-npk_m_s`);
if (!masterNullifierPublicKeysBuffer) {
throw new Error(`Could not find master nullifier public keys for account ${accountAddress.toString()}`);
}
Expand All @@ -306,7 +306,7 @@ export class TestKeyStore implements KeyStore {
}

// Now we iterate over the public keys in the buffer to find the one that matches the hash
const numKeys = masterNullifierPublicKeysBuffer.byteLength / Point.SIZE_IN_BYTES;
const numKeys = this.#calculateNumKeys(masterNullifierPublicKeysBuffer, Point);
let keyIndex = -1;
for (let i = 0; i < numKeys; i++) {
const publicKey = Point.fromBuffer(
Expand All @@ -319,7 +319,7 @@ export class TestKeyStore implements KeyStore {
}

// Now we fetch the secret keys buffer and extract the secret key at the same index
const masterNullifierSecretKeysBuffer = this.#keys.get(`${accountAddress.toString()}-ns_keys_m`);
const masterNullifierSecretKeysBuffer = this.#keys.get(`${accountAddress.toString()}-nsk_m_s`);
if (!masterNullifierSecretKeysBuffer) {
throw new Error(`Could not find master nullifier secret keys for account ${accountAddress.toString()}`);
}
Expand Down Expand Up @@ -401,27 +401,31 @@ export class TestKeyStore implements KeyStore {
*/
public async rotateMasterNullifierKey(account: AztecAddress, newSecretKey: Fq = Fq.random()) {
// We append the secret key to the original secret key
const secretKeysBuffer = this.#keys.get(`${account.toString()}-ns_keys_m`);
const secretKeysBuffer = this.#keys.get(`${account.toString()}-nsk_m_s`);
if (!secretKeysBuffer) {
throw new Error(`Could not find nullifier secret keys for account ${account.toString()}`);
}

// We append the new secret key to the buffer of secret keys
const newSecretKeysBuffer = Buffer.concat([secretKeysBuffer, newSecretKey.toBuffer()]);
await this.#keys.set(`${account.toString()}-ns_keys_m`, newSecretKeysBuffer);
await this.#keys.set(`${account.toString()}-nsk_m_s`, newSecretKeysBuffer);

// Now we derive the public key from the new secret key and append it to the buffer of original public keys
const newPublicKey = derivePublicKeyFromSecretKey(newSecretKey);
const publicKeysBuffer = this.#keys.get(`${account.toString()}-np_keys_m`);
const publicKeysBuffer = this.#keys.get(`${account.toString()}-npk_m_s`);
if (!publicKeysBuffer) {
throw new Error(`Could not find nullifier public keys for account ${account.toString()}`);
}

// We append the new public key to the buffer of public keys
const newPublicKeysBuffer = Buffer.concat([publicKeysBuffer, newPublicKey.toBuffer()]);
await this.#keys.set(`${account.toString()}-np_keys_m`, newPublicKeysBuffer);
await this.#keys.set(`${account.toString()}-npk_m_s`, newPublicKeysBuffer);

// We store a npk_m_hash-account_address map to make address easy to obtain with the hash later on
await this.#keys.set(`${newPublicKey.hash().toString()}-npk_m_hash`, account.toBuffer());
}

#calculateNumKeys(buf: Buffer, T: typeof Point | typeof Fq) {
return buf.byteLength / T.SIZE_IN_BYTES;
}
}
8 changes: 4 additions & 4 deletions yarn-project/pxe/src/pxe_service/pxe_service.ts
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,10 @@ export class PXEService implements PXE {
return this.db.getAuthWitness(messageHash);
}

async rotateNskMPxe(account: AztecAddress, secretKey: Fq = Fq.random()): Promise<void> {
await this.keyStore.rotateMasterNullifierKey(account, secretKey);
}

public addCapsule(capsule: Fr[]) {
return this.db.addCapsule(capsule);
}
Expand Down Expand Up @@ -192,10 +196,6 @@ export class PXEService implements PXE {
return accountCompleteAddress;
}

public async rotateMasterNullifierKey(account: AztecAddress, secretKey: Fq = Fq.random()): Promise<void> {
await this.keyStore.rotateMasterNullifierKey(account, secretKey);
}

public async getRegisteredAccounts(): Promise<CompleteAddress[]> {
// Get complete addresses of both the recipients and the accounts
const completeAddresses = await this.db.getCompleteAddresses();
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/simulator/src/acvm/oracle/oracle.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,9 +40,9 @@ export class Oracle {
return unpacked.map(toACVMField);
}

async getNullifierKeys([masterNullifierPublicKeyHash]: ACVMField[]): Promise<ACVMField[]> {
async getNullifierKeys([npkMHash]: ACVMField[]): Promise<ACVMField[]> {
const { masterNullifierPublicKey, appNullifierSecretKey } = await this.typedOracle.getNullifierKeys(
fromACVMField(masterNullifierPublicKeyHash),
fromACVMField(npkMHash),
);

return [
Expand Down
Loading
Loading