-
Notifications
You must be signed in to change notification settings - Fork 236
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
Changes from 10 commits
7d4ace4
a49681c
9b1eb35
034948d
f6902d0
3d10f31
0e738f7
5ac568e
49652b5
50a3909
29b70fd
06fb183
7853a03
c9e0a05
b206b7c
c602171
d33e54f
a3a503d
eaaf567
11b9e89
f595765
41b99f4
6e9a0d3
7309988
6777c35
0d2bdd3
42a0551
e26e04b
924b901
6044733
3378ac0
62ccede
cb500ec
7bbed9e
0225544
0fecfc2
3e9e018
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,5 +1,6 @@ | ||
import { createAccounts } from '@aztec/accounts/testing'; | ||
import { | ||
type AccountWallet, | ||
type AztecAddress, | ||
type AztecNode, | ||
type DebugLogger, | ||
|
@@ -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'; | ||
|
||
|
@@ -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; | ||
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. Being forced to replace interface with an instance seems incorrect. Why not update the Wallet interface? 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. I saw how it was being used in 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. Ok ok, yes sounds good doing that in another PR. 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. 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; | ||
|
@@ -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(); | ||
|
@@ -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(); | ||
} | ||
|
||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -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} | ||
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. 🫡 |
||
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()); | ||
|
@@ -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()}.`, | ||
|
@@ -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), | ||
|
@@ -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( | ||
|
@@ -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( | ||
|
@@ -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()}`); | ||
} | ||
|
@@ -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( | ||
|
@@ -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()}`); | ||
} | ||
|
@@ -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; | ||
} | ||
} |
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.
I don't like this but don't see another way as BaseWallet impls PXE
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.
Why not just
rotateNskM
instead ofrotateNskMPxe
?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.
The
AccountWallet
would think we're overridingrotateNskM
onBaseWallet
/PXE
if we have the same names (rotateNskM
), but they have different signatures, theAccountWallet
impl takes only the new key, but thePXE
needs the address as well. I went for the cleaner approach on theAccountWallet
trading off cleanliness at thePXE
level.Other options include renaming the
AccountWallet
fns torotateNskMPxe
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.
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.
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.