Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
34 changes: 19 additions & 15 deletions noir-projects/aztec-nr/authwit/src/account.nr
Original file line number Diff line number Diff line change
@@ -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};
Expand All @@ -16,48 +19,49 @@ impl<Context> AccountActions<Context> {

/**
* 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.
*/
// docs:start:entrypoint
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(
Copy link
Contributor Author

@benesjan benesjan Aug 22, 2024

Choose a reason for hiding this comment

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

i decided to go with the combined payload hash because it seems good enough and it required much less time than somehow merging AppPayload and FeePayload into 1 struct. Given that this is not enshrined in protocol I think we don't need to chase perfection here (that would require monster refactor).

On an unrelated note. I think we could optimize this a bit more and just add the app payload and fee payload hashes instead of hashing them because as far as I know we don't really need the robust crypto properties on the outer hash here. But seems to make sense to do that later if it turns out we need to hyper optimize this.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we could optimize this a bit more and just add the app payload and fee payload hashes

Thinking about this more this could theoretically make it possible to swap the order in which fee payload and app payload are executed so it doesn't seem like a good idea.

[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(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions yarn-project/aztec.js/src/entrypoint/entrypoint.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down
10 changes: 10 additions & 0 deletions yarn-project/aztec.js/src/entrypoint/payload.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
1 change: 1 addition & 0 deletions yarn-project/circuits.js/src/constants.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
14 changes: 10 additions & 4 deletions yarn-project/entrypoints/src/account_entrypoint.ts
Original file line number Diff line number Diff line change
@@ -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';
Expand Down Expand Up @@ -27,16 +32,17 @@ 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,
origin: this.address,
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;
Expand Down