diff --git a/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.test.ts b/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.test.ts index 4ed6f4b374d2..788ed71166a4 100644 --- a/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.test.ts +++ b/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.test.ts @@ -1,6 +1,5 @@ import { PUBLIC_LOG_DATA_SIZE_IN_FIELDS } from '@aztec/constants'; import { timesParallel } from '@aztec/foundation/collection'; -import { poseidon2Hash } from '@aztec/foundation/crypto'; import { Fq, Fr } from '@aztec/foundation/fields'; import type { Tuple } from '@aztec/foundation/serialize'; import { KeyStore } from '@aztec/key-store'; @@ -11,7 +10,7 @@ import { AztecAddress } from '@aztec/stdlib/aztec-address'; import { randomInBlock } from '@aztec/stdlib/block'; import { CompleteAddress } from '@aztec/stdlib/contract'; import type { AztecNode } from '@aztec/stdlib/interfaces/client'; -import { computeAddress, computeTaggingSecretPoint, deriveKeys } from '@aztec/stdlib/keys'; +import { computeAddress, computeAppTaggingSecret, deriveKeys } from '@aztec/stdlib/keys'; import { IndexedTaggingSecret, PrivateLog, PublicLog, TxScopedL2Log } from '@aztec/stdlib/logs'; import { randomContractArtifact, randomContractInstanceWithAddress } from '@aztec/stdlib/testing'; import { TxEffect, TxHash } from '@aztec/stdlib/tx'; @@ -37,10 +36,9 @@ async function computeSiloedTagForIndex( contractAddress: AztecAddress, index: number, ) { - const secretPoint = await computeTaggingSecretPoint(sender.completeAddress, sender.ivsk, recipient); - const appSecret = await poseidon2Hash([secretPoint.x, secretPoint.y, contractAddress]); - const tag = await poseidon2Hash([appSecret, recipient, index]); - return poseidon2Hash([contractAddress, tag]); + const appSecret = await computeAppTaggingSecret(sender.completeAddress, sender.ivsk, recipient, contractAddress); + const indexedTaggingSecret = new IndexedTaggingSecret(appSecret, index); + return indexedTaggingSecret.computeSiloedTag(recipient, contractAddress); } describe('PXEOracleInterface', () => { @@ -175,14 +173,9 @@ describe('PXEOracleInterface', () => { const ivsk = await keyStore.getMasterIncomingViewingSecretKey(recipient.address); const secrets = await Promise.all( - senders.map(async sender => { - const firstSenderSecretPoint = await computeTaggingSecretPoint( - recipient, - ivsk, - sender.completeAddress.address, - ); - return poseidon2Hash([firstSenderSecretPoint.x, firstSenderSecretPoint.y, contractAddress]); - }), + senders.map(sender => + computeAppTaggingSecret(recipient, ivsk, sender.completeAddress.address, contractAddress), + ), ); // First sender should have 2 logs, but keep index 1 since they were built using the same tag @@ -210,14 +203,9 @@ describe('PXEOracleInterface', () => { // Recompute the secrets (as recipient) to ensure indexes are updated const ivsk = await keyStore.getMasterIncomingViewingSecretKey(recipient.address); const secrets = await Promise.all( - senders.map(async sender => { - const firstSenderSecretPoint = await computeTaggingSecretPoint( - recipient, - ivsk, - sender.completeAddress.address, - ); - return poseidon2Hash([firstSenderSecretPoint.x, firstSenderSecretPoint.y, contractAddress]); - }), + senders.map(sender => + computeAppTaggingSecret(recipient, ivsk, sender.completeAddress.address, contractAddress), + ), ); const indexesAsSender = await taggingDataProvider.getTaggingSecretsIndexesAsSender(secrets); @@ -268,14 +256,9 @@ describe('PXEOracleInterface', () => { // Recompute the secrets (as recipient) to ensure indexes are updated const ivsk = await keyStore.getMasterIncomingViewingSecretKey(recipient.address); const secrets = await Promise.all( - senders.map(async sender => { - const firstSenderSecretPoint = await computeTaggingSecretPoint( - recipient, - ivsk, - sender.completeAddress.address, - ); - return poseidon2Hash([firstSenderSecretPoint.x, firstSenderSecretPoint.y, contractAddress]); - }), + senders.map(sender => + computeAppTaggingSecret(recipient, ivsk, sender.completeAddress.address, contractAddress), + ), ); // First sender should have 2 logs, but keep index 1 since they were built using the same tag @@ -298,14 +281,9 @@ describe('PXEOracleInterface', () => { // Recompute the secrets (as recipient) to update indexes const ivsk = await keyStore.getMasterIncomingViewingSecretKey(recipient.address); const secrets = await Promise.all( - senders.map(async sender => { - const firstSenderSecretPoint = await computeTaggingSecretPoint( - recipient, - ivsk, - sender.completeAddress.address, - ); - return poseidon2Hash([firstSenderSecretPoint.x, firstSenderSecretPoint.y, contractAddress]); - }), + senders.map(sender => + computeAppTaggingSecret(recipient, ivsk, sender.completeAddress.address, contractAddress), + ), ); // Increase our indexes to 2 @@ -339,14 +317,9 @@ describe('PXEOracleInterface', () => { // Recompute the secrets (as recipient) to update indexes const ivsk = await keyStore.getMasterIncomingViewingSecretKey(recipient.address); const secrets = await Promise.all( - senders.map(async sender => { - const firstSenderSecretPoint = await computeTaggingSecretPoint( - recipient, - ivsk, - sender.completeAddress.address, - ); - return poseidon2Hash([firstSenderSecretPoint.x, firstSenderSecretPoint.y, contractAddress]); - }), + senders.map(sender => + computeAppTaggingSecret(recipient, ivsk, sender.completeAddress.address, contractAddress), + ), ); // We set the indexes to WINDOW_HALF_SIZE + 1 so that it's outside the window and for this reason no updates @@ -377,14 +350,9 @@ describe('PXEOracleInterface', () => { // Recompute the secrets (as recipient) to update indexes const ivsk = await keyStore.getMasterIncomingViewingSecretKey(recipient.address); const secrets = await Promise.all( - senders.map(async sender => { - const firstSenderSecretPoint = await computeTaggingSecretPoint( - recipient, - ivsk, - sender.completeAddress.address, - ); - return poseidon2Hash([firstSenderSecretPoint.x, firstSenderSecretPoint.y, contractAddress]); - }), + senders.map(sender => + computeAppTaggingSecret(recipient, ivsk, sender.completeAddress.address, contractAddress), + ), ); await taggingDataProvider.setTaggingSecretsIndexesAsRecipient( diff --git a/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts b/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts index fbc0c394f98f..42fc4624f855 100644 --- a/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts +++ b/yarn-project/pxe/src/pxe_oracle_interface/pxe_oracle_interface.ts @@ -1,6 +1,6 @@ import { type L1_TO_L2_MSG_TREE_HEIGHT, MAX_NOTE_HASHES_PER_TX, PRIVATE_LOG_SIZE_IN_FIELDS } from '@aztec/constants'; import { timesParallel } from '@aztec/foundation/collection'; -import { poseidon2Hash, randomInt } from '@aztec/foundation/crypto'; +import { randomInt } from '@aztec/foundation/crypto'; import { Fr, Point } from '@aztec/foundation/fields'; import { createLogger } from '@aztec/foundation/log'; import type { KeyStore } from '@aztec/key-store'; @@ -26,7 +26,7 @@ import type { CompleteAddress, ContractInstance } from '@aztec/stdlib/contract'; import { computeUniqueNoteHash, siloNoteHash, siloNullifier } from '@aztec/stdlib/hash'; import type { AztecNode } from '@aztec/stdlib/interfaces/client'; import type { KeyValidationRequest } from '@aztec/stdlib/kernel'; -import { computeAddressSecret, computeTaggingSecretPoint } from '@aztec/stdlib/keys'; +import { computeAddressSecret, computeAppTaggingSecret } from '@aztec/stdlib/keys'; import { IndexedTaggingSecret, LogWithTxData, @@ -333,10 +333,7 @@ export class PXEOracleInterface implements ExecutionDataProvider { async #calculateAppTaggingSecret(contractAddress: AztecAddress, sender: AztecAddress, recipient: AztecAddress) { const senderCompleteAddress = await this.getCompleteAddress(sender); const senderIvsk = await this.keyStore.getMasterIncomingViewingSecretKey(sender); - const secretPoint = await computeTaggingSecretPoint(senderCompleteAddress, senderIvsk, recipient); - // Silo the secret so it can't be used to track other app's notes - const appSecret = poseidon2Hash([secretPoint.x, secretPoint.y, contractAddress]); - return appSecret; + return computeAppTaggingSecret(senderCompleteAddress, senderIvsk, recipient, contractAddress); } /** @@ -362,10 +359,9 @@ export class PXEOracleInterface implements ExecutionDataProvider { ...(await this.keyStore.getAccounts()), ].filter((address, index, self) => index === self.findIndex(otherAddress => otherAddress.equals(address))); const appTaggingSecrets = await Promise.all( - senders.map(async contact => { - const sharedSecret = await computeTaggingSecretPoint(recipientCompleteAddress, recipientIvsk, contact); - return poseidon2Hash([sharedSecret.x, sharedSecret.y, contractAddress]); - }), + senders.map(contact => + computeAppTaggingSecret(recipientCompleteAddress, recipientIvsk, contact, contractAddress), + ), ); const indexes = await this.taggingDataProvider.getTaggingSecretsIndexesAsRecipient(appTaggingSecrets); return appTaggingSecrets.map((secret, i) => new IndexedTaggingSecret(secret, indexes[i])); diff --git a/yarn-project/stdlib/src/keys/derivation.ts b/yarn-project/stdlib/src/keys/derivation.ts index 0d481848b71b..da9bd0f02e6c 100644 --- a/yarn-project/stdlib/src/keys/derivation.ts +++ b/yarn-project/stdlib/src/keys/derivation.ts @@ -1,5 +1,5 @@ import { GeneratorIndex } from '@aztec/constants'; -import { Grumpkin, poseidon2HashWithSeparator, sha512ToGrumpkinScalar } from '@aztec/foundation/crypto'; +import { Grumpkin, poseidon2Hash, poseidon2HashWithSeparator, sha512ToGrumpkinScalar } from '@aztec/foundation/crypto'; import { Fq, Fr, GrumpkinScalar } from '@aztec/foundation/fields'; import { AztecAddress } from '../aztec-address/index.js'; @@ -123,11 +123,7 @@ export async function deriveKeys(secretKey: Fr) { } // Returns shared tagging secret computed with Diffie-Hellman key exchange. -export async function computeTaggingSecretPoint( - knownAddress: CompleteAddress, - ivsk: Fq, - externalAddress: AztecAddress, -) { +async function computeTaggingSecretPoint(knownAddress: CompleteAddress, ivsk: Fq, externalAddress: AztecAddress) { const knownPreaddress = await computePreaddress(await knownAddress.publicKeys.hash(), knownAddress.partialAddress); // TODO: #8970 - Computation of address point from x coordinate might fail const externalAddressPoint = await externalAddress.toAddressPoint(); @@ -139,3 +135,13 @@ export async function computeTaggingSecretPoint( // computeAddressSecret takes care of selecting the one that leads to a positive y-coordinate, which is the only valid address point return curve.mul(externalAddressPoint, await computeAddressSecret(knownPreaddress, ivsk)); } + +export async function computeAppTaggingSecret( + knownAddress: CompleteAddress, + ivsk: Fq, + externalAddress: AztecAddress, + app: AztecAddress, +) { + const taggingSecretPoint = await computeTaggingSecretPoint(knownAddress, ivsk, externalAddress); + return poseidon2Hash([taggingSecretPoint.x, taggingSecretPoint.y, app]); +}