diff --git a/noir-projects/aztec-nr/authwit/src/account.nr b/noir-projects/aztec-nr/authwit/src/account.nr index e1e3b5de50b9..0a42a2fdf957 100644 --- a/noir-projects/aztec-nr/authwit/src/account.nr +++ b/noir-projects/aztec-nr/authwit/src/account.nr @@ -1,4 +1,7 @@ -use dep::aztec::context::PrivateContext; +use dep::aztec::{ + context::PrivateContext, protocol_types::constants::GENERATOR_INDEX__COMBINED_PAYLOAD, + hash::poseidon2_hash_with_separator +}; use crate::entrypoint::{app::AppPayload, fee::FeePayload}; use crate::auth::{IS_VALID_SELECTOR, compute_authwit_message_hash}; @@ -16,17 +19,17 @@ impl AccountActions { /** * An implementation of the Account Action struct for the private context. - * + * * Implements logic to verify authorization and execute payloads. */ impl AccountActions<&mut PrivateContext> { - /** + /** * Verifies that the `app_hash` and `fee_hash` are authorized and then executes them. - * + * * Executes the `fee_payload` and `app_payload` in sequence. * Will execute the `fee_payload` as part of the setup, and then enter the app phase. - * + * * @param app_payload The payload that contains the calls to be executed in the app phase. * @param fee_payload The payload that contains the calls to be executed in the setup phase. */ @@ -34,30 +37,31 @@ impl AccountActions<&mut PrivateContext> { pub fn entrypoint(self, app_payload: AppPayload, fee_payload: FeePayload) { let valid_fn = self.is_valid_impl; - let fee_hash = fee_payload.hash(); - assert(valid_fn(self.context, fee_hash)); + let combined_payload_hash = poseidon2_hash_with_separator( + [app_payload.hash(), fee_payload.hash()], + GENERATOR_INDEX__COMBINED_PAYLOAD + ); + assert(valid_fn(self.context, combined_payload_hash)); + fee_payload.execute_calls(self.context); self.context.end_setup(); - - let app_hash = app_payload.hash(); - assert(valid_fn(self.context, app_hash)); app_payload.execute_calls(self.context); } // docs:end:entrypoint /** * Verifies that the `msg_sender` is authorized to consume `inner_hash` by the account. - * + * * Computes the `message_hash` using the `msg_sender`, `chain_id`, `version` and `inner_hash`. * Then executes the `is_valid_impl` function to verify that the message is authorized. - * - * Will revert if the message is not authorized. - * + * + * Will revert if the message is not authorized. + * * @param inner_hash The hash of the message that the `msg_sender` is trying to consume. */ // docs:start:verify_private_authwit pub fn verify_private_authwit(self, inner_hash: Field) -> Field { - // The `inner_hash` is "siloed" with the `msg_sender` to ensure that only it can + // The `inner_hash` is "siloed" with the `msg_sender` to ensure that only it can // consume the message. // This ensures that contracts cannot consume messages that are not intended for them. let message_hash = compute_authwit_message_hash( diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index cf082ee91ff7..5b9b3204d3b6 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -133,7 +133,7 @@ global INITIAL_L2_BLOCK_NUM: Field = 1; global BLOB_SIZE_IN_BYTES: Field = 31 * 4096; global ETHEREUM_SLOT_DURATION: u32 = 12; global IS_DEV_NET: bool = true; -// The following and the value in `deploy_l1_contracts´ must match. We should not have the code both places, but +// The following and the value in `deploy_l1_contracts´ must match. We should not have the code both places, but // we are running into circular dependency issues. #3342 global FEE_JUICE_INITIAL_MINT: Field = 20000000000; @@ -325,6 +325,7 @@ global GENERATOR_INDEX__PARTIAL_ADDRESS: u32 = 27; global GENERATOR_INDEX__BLOCK_HASH: u32 = 28; global GENERATOR_INDEX__SIDE_EFFECT: u32 = 29; global GENERATOR_INDEX__FEE_PAYLOAD: u32 = 30; +global GENERATOR_INDEX__COMBINED_PAYLOAD: u32 = 31; // Indices with size ≤ 16 global GENERATOR_INDEX__TX_REQUEST: u32 = 33; global GENERATOR_INDEX__SIGNATURE_PAYLOAD: u32 = 34; diff --git a/yarn-project/aztec.js/src/account_manager/deploy_account_method.ts b/yarn-project/aztec.js/src/account_manager/deploy_account_method.ts index f87dd1e2e4ac..80643c7eb1f5 100644 --- a/yarn-project/aztec.js/src/account_manager/deploy_account_method.ts +++ b/yarn-project/aztec.js/src/account_manager/deploy_account_method.ts @@ -12,7 +12,7 @@ import { type Wallet } from '../account/wallet.js'; import { type ExecutionRequestInit } from '../api/entrypoint.js'; import { Contract } from '../contract/contract.js'; import { DeployMethod, type DeployOptions } from '../contract/deploy_method.js'; -import { EntrypointPayload } from '../entrypoint/payload.js'; +import { EntrypointPayload, computeCombinedPayloadHash } from '../entrypoint/payload.js'; /** * Contract interaction for deploying an account contract. Handles fee preparation and contract initialization. @@ -70,8 +70,10 @@ export class DeployAccountMethod extends DeployMethod { exec.authWitnesses ??= []; exec.packedArguments ??= []; - exec.authWitnesses.push(await this.#authWitnessProvider.createAuthWit(emptyAppPayload.hash())); - exec.authWitnesses.push(await this.#authWitnessProvider.createAuthWit(feePayload.hash())); + exec.authWitnesses.push( + await this.#authWitnessProvider.createAuthWit(computeCombinedPayloadHash(emptyAppPayload, feePayload)), + ); + exec.packedArguments.push(...emptyAppPayload.packedArguments); exec.packedArguments.push(...feePayload.packedArguments); } diff --git a/yarn-project/aztec.js/src/entrypoint/entrypoint.ts b/yarn-project/aztec.js/src/entrypoint/entrypoint.ts index bb5bb3849a78..fb60762860e1 100644 --- a/yarn-project/aztec.js/src/entrypoint/entrypoint.ts +++ b/yarn-project/aztec.js/src/entrypoint/entrypoint.ts @@ -1,8 +1,8 @@ import { type AuthWitness, type FunctionCall, type PackedValues, type TxExecutionRequest } from '@aztec/circuit-types'; -import { EntrypointPayload, type FeeOptions } from './payload.js'; +import { EntrypointPayload, type FeeOptions, computeCombinedPayloadHash } from './payload.js'; -export { EntrypointPayload, FeeOptions }; +export { EntrypointPayload, FeeOptions, computeCombinedPayloadHash }; export { DefaultEntrypoint } from './default_entrypoint.js'; export { DefaultMultiCallEntrypoint } from './default_multi_call_entrypoint.js'; diff --git a/yarn-project/aztec.js/src/entrypoint/payload.ts b/yarn-project/aztec.js/src/entrypoint/payload.ts index bb849489f3d4..e0e110e61536 100644 --- a/yarn-project/aztec.js/src/entrypoint/payload.ts +++ b/yarn-project/aztec.js/src/entrypoint/payload.ts @@ -178,3 +178,13 @@ class FeeEntrypointPayload extends EntrypointPayload { } /* eslint-enable camelcase */ } + +/** + * Computes a hash of a combined payload. + * @param appPayload - An app payload. + * @param feePayload - A fee payload. + * @returns A hash of a combined payload. + */ +export function computeCombinedPayloadHash(appPayload: AppEntrypointPayload, feePayload: FeeEntrypointPayload): Fr { + return poseidon2HashWithSeparator([appPayload.hash(), feePayload.hash()], GeneratorIndex.COMBINED_PAYLOAD); +} diff --git a/yarn-project/circuits.js/src/constants.gen.ts b/yarn-project/circuits.js/src/constants.gen.ts index 4943d1fd7643..17852a805675 100644 --- a/yarn-project/circuits.js/src/constants.gen.ts +++ b/yarn-project/circuits.js/src/constants.gen.ts @@ -388,6 +388,7 @@ export enum GeneratorIndex { BLOCK_HASH = 28, SIDE_EFFECT = 29, FEE_PAYLOAD = 30, + COMBINED_PAYLOAD = 31, TX_REQUEST = 33, SIGNATURE_PAYLOAD = 34, VK = 41, diff --git a/yarn-project/entrypoints/src/account_entrypoint.ts b/yarn-project/entrypoints/src/account_entrypoint.ts index 0cb5040507e4..65c97571e087 100644 --- a/yarn-project/entrypoints/src/account_entrypoint.ts +++ b/yarn-project/entrypoints/src/account_entrypoint.ts @@ -1,5 +1,10 @@ import { type AuthWitnessProvider } from '@aztec/aztec.js/account'; -import { type EntrypointInterface, EntrypointPayload, type ExecutionRequestInit } from '@aztec/aztec.js/entrypoint'; +import { + type EntrypointInterface, + EntrypointPayload, + type ExecutionRequestInit, + computeCombinedPayloadHash, +} from '@aztec/aztec.js/entrypoint'; import { PackedValues, TxExecutionRequest } from '@aztec/circuit-types'; import { type AztecAddress, GasSettings, TxContext } from '@aztec/circuits.js'; import { type FunctionAbi, FunctionSelector, encodeArguments } from '@aztec/foundation/abi'; @@ -27,8 +32,9 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { const entrypointPackedArgs = PackedValues.fromValues(encodeArguments(abi, [appPayload, feePayload])); const gasSettings = exec.fee?.gasSettings ?? GasSettings.default(); - const appAuthWitness = await this.auth.createAuthWit(appPayload.hash()); - const feeAuthWitness = await this.auth.createAuthWit(feePayload.hash()); + const combinedPayloadAuthWitness = await this.auth.createAuthWit( + computeCombinedPayloadHash(appPayload, feePayload), + ); const txRequest = TxExecutionRequest.from({ firstCallArgsHash: entrypointPackedArgs.hash, @@ -36,7 +42,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { functionSelector: FunctionSelector.fromNameAndParameters(abi.name, abi.parameters), txContext: new TxContext(this.chainId, this.version, gasSettings), argsOfCalls: [...appPayload.packedArguments, ...feePayload.packedArguments, entrypointPackedArgs], - authWitnesses: [appAuthWitness, feeAuthWitness], + authWitnesses: [combinedPayloadAuthWitness], }); return txRequest;