From fdbe2b2c6a3fc9918921bde5dadbe4d37a64ce11 Mon Sep 17 00:00:00 2001 From: Lasse Herskind <16536249+LHerskind@users.noreply.github.com> Date: Wed, 4 Oct 2023 14:48:48 +0100 Subject: [PATCH] refactor: Update authwit computation (#2651) Fixes #2448 --- .../wallets/writing_an_account_contract.md | 4 +- yarn-project/aztec-nr/authwit/Nargo.toml | 8 + .../{aztec => authwit}/src/account.nr | 12 +- yarn-project/aztec-nr/authwit/src/auth.nr | 47 +++ .../oracle => authwit/src}/auth_witness.nr | 0 .../{aztec => authwit}/src/entrypoint.nr | 12 +- yarn-project/aztec-nr/authwit/src/lib.nr | 4 + yarn-project/aztec-nr/aztec/src/auth.nr | 18 - yarn-project/aztec-nr/aztec/src/hash.nr | 6 - yarn-project/aztec-nr/aztec/src/lib.nr | 3 - yarn-project/aztec-nr/aztec/src/oracle.nr | 3 +- .../src/abis/ecdsa_account_contract.json | 4 +- .../src/abis/schnorr_account_contract.json | 4 +- .../schnorr_single_key_account_contract.json | 4 +- .../account/defaults/default_entrypoint.ts | 4 +- yarn-project/aztec.js/src/utils/authwit.ts | 24 ++ yarn-project/aztec.js/src/utils/index.ts | 1 + .../src/uniswap_trade_on_l1_from_l2.test.ts | 19 +- yarn-project/canary/src/utils.ts | 15 - .../src/e2e_cross_chain_messaging.test.ts | 30 +- .../src/e2e_lending_contract.test.ts | 102 ++--- .../e2e_public_cross_chain_messaging.test.ts | 18 +- .../end-to-end/src/e2e_token_contract.test.ts | 364 ++++++------------ yarn-project/end-to-end/src/fixtures/utils.ts | 15 - .../src/uniswap_trade_on_l1_from_l2.test.ts | 70 ++-- .../ecdsa_account_contract/Nargo.toml | 1 + .../ecdsa_account_contract/src/main.nr | 6 +- .../schnorr_account_contract/Nargo.toml | 3 +- .../schnorr_account_contract/src/main.nr | 7 +- .../Nargo.toml | 3 +- .../src/main.nr | 7 +- .../Nargo.toml | 1 + .../src/auth_oracle.nr | 2 +- .../src/main.nr | 4 +- .../src/contracts/token_contract/Nargo.toml | 3 +- .../src/contracts/token_contract/src/main.nr | 28 +- .../src/contracts/uniswap_contract/Nargo.toml | 1 + .../contracts/uniswap_contract/src/main.nr | 34 +- 38 files changed, 354 insertions(+), 537 deletions(-) create mode 100644 yarn-project/aztec-nr/authwit/Nargo.toml rename yarn-project/aztec-nr/{aztec => authwit}/src/account.nr (86%) create mode 100644 yarn-project/aztec-nr/authwit/src/auth.nr rename yarn-project/aztec-nr/{aztec/src/oracle => authwit/src}/auth_witness.nr (100%) rename yarn-project/aztec-nr/{aztec => authwit}/src/entrypoint.nr (91%) create mode 100644 yarn-project/aztec-nr/authwit/src/lib.nr delete mode 100644 yarn-project/aztec-nr/aztec/src/auth.nr create mode 100644 yarn-project/aztec.js/src/utils/authwit.ts diff --git a/docs/docs/dev_docs/wallets/writing_an_account_contract.md b/docs/docs/dev_docs/wallets/writing_an_account_contract.md index 8f14c62f1cc..96639cff70d 100644 --- a/docs/docs/dev_docs/wallets/writing_an_account_contract.md +++ b/docs/docs/dev_docs/wallets/writing_an_account_contract.md @@ -34,9 +34,9 @@ Public Key: 0x0ede151adaef1cfcc1b3e152ea39f00c5cda3f3857cef00decb049d283672dc71 The important part of this contract is the `entrypoint` function, which will be the first function executed in any transaction originated from this account. This function has two main responsibilities: authenticating the transaction and executing calls. It receives a `payload` with the list of function calls to execute, and requests a corresponding auth witness from an oracle to validate it. You will find this logic implemented in the `AccountActions` module, which uses the `EntrypointPayload` struct: -#include_code entrypoint yarn-project/aztec-nr/aztec/src/account.nr rust +#include_code entrypoint yarn-project/aztec-nr/authwit/src/account.nr rust -#include_code entrypoint-struct yarn-project/aztec-nr/aztec/src/entrypoint.nr rust +#include_code entrypoint-struct yarn-project/aztec-nr/authwit/src/entrypoint.nr rust :::info Using the `AccountActions` module and the `EntrypointPayload` struct is not mandatory. You can package the instructions to be carried out by your account contract however you want. However, using these modules can save you a lot of time when writing a new account contract, both in Noir and in Typescript. diff --git a/yarn-project/aztec-nr/authwit/Nargo.toml b/yarn-project/aztec-nr/authwit/Nargo.toml new file mode 100644 index 00000000000..eaebdf5b323 --- /dev/null +++ b/yarn-project/aztec-nr/authwit/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "auth_wit" +authors = ["aztec-labs"] +compiler_version = "0.1" +type = "lib" + +[dependencies] +aztec = { path = "../aztec" } \ No newline at end of file diff --git a/yarn-project/aztec-nr/aztec/src/account.nr b/yarn-project/aztec-nr/authwit/src/account.nr similarity index 86% rename from yarn-project/aztec-nr/aztec/src/account.nr rename to yarn-project/aztec-nr/authwit/src/account.nr index 3437dbd8519..7e93e89eba4 100644 --- a/yarn-project/aztec-nr/aztec/src/account.nr +++ b/yarn-project/aztec-nr/authwit/src/account.nr @@ -1,8 +1,12 @@ +mod entrypoint; +mod auth; + +use dep::aztec::context::{PrivateContext, PublicContext, Context}; +use dep::aztec::oracle::compute_selector::compute_selector; +use dep::aztec::state_vars::{map::Map, public_state::PublicState}; +use dep::aztec::types::type_serialization::bool_serialization::{BoolSerializationMethods,BOOL_SERIALIZED_LEN}; + use crate::entrypoint::EntrypointPayload; -use crate::context::{PrivateContext, PublicContext, Context}; -use crate::oracle::compute_selector::compute_selector; -use crate::state_vars::{map::Map, public_state::PublicState}; -use crate::types::type_serialization::bool_serialization::{BoolSerializationMethods,BOOL_SERIALIZED_LEN}; use crate::auth::IS_VALID_SELECTOR; struct AccountActions { diff --git a/yarn-project/aztec-nr/authwit/src/auth.nr b/yarn-project/aztec-nr/authwit/src/auth.nr new file mode 100644 index 00000000000..45adb83a6a0 --- /dev/null +++ b/yarn-project/aztec-nr/authwit/src/auth.nr @@ -0,0 +1,47 @@ +use dep::std::hash::pedersen_with_separator; + +use dep::aztec::{ + context::{PrivateContext, PublicContext, Context}, + constants_gen::{EMPTY_NULLIFIED_COMMITMENT, GENERATOR_INDEX__SIGNATURE_PAYLOAD}, + types::address::AztecAddress, + abi::hash_args, +}; + +global IS_VALID_SELECTOR = 0xe86ab4ff; +global IS_VALID_PUBLIC_SELECTOR = 0xf3661153; + +// @todo #2676 Should use different generator than the payload to limit probability of collisions. + +// Assert that `whom` have authorized `message_hash` with a valid authentication witness +fn assert_valid_authwit(context: &mut PrivateContext, whom: AztecAddress, message_hash: Field) { + let result = context.call_private_function(whom.address, IS_VALID_SELECTOR, [message_hash])[0]; + context.push_new_nullifier(message_hash, EMPTY_NULLIFIED_COMMITMENT); + assert(result == IS_VALID_SELECTOR, "Message not authorized by account"); +} + +// Assert that `whom` have authorized the current call with a valid authentication witness +fn assert_current_call_valid_authwit(context: &mut PrivateContext, whom: AztecAddress) { + let args = [context.msg_sender(), context.this_address(), context.selector(), context.args_hash]; + let message_hash = pedersen_with_separator(args, GENERATOR_INDEX__SIGNATURE_PAYLOAD)[0]; + assert_valid_authwit(context, whom, message_hash); +} + +// Assert that `whom` have authorized `message_hash` in a public context +fn assert_valid_authwit_public(context: &mut PublicContext, whom: AztecAddress, message_hash: Field) { + let result = context.call_public_function(whom.address, IS_VALID_PUBLIC_SELECTOR, [message_hash])[0]; + context.push_new_nullifier(message_hash, EMPTY_NULLIFIED_COMMITMENT); + assert(result == IS_VALID_SELECTOR, "Message not authorized by account"); +} + +// Assert that `whom` have authorized the current call in a public context +fn assert_current_call_valid_authwit_public(context: &mut PublicContext, whom: AztecAddress) { + let args = [context.msg_sender(), context.this_address(), context.selector(), context.args_hash]; + let message_hash = pedersen_with_separator(args, GENERATOR_INDEX__SIGNATURE_PAYLOAD)[0]; + assert_valid_authwit_public(context, whom, message_hash); +} + +// Compute the message hash to be used by an authentication witness +fn compute_authwit_message_hash(caller: AztecAddress, target: AztecAddress, selector: Field, args: [Field; N]) -> Field { + let args_hash = hash_args(args); + pedersen_with_separator([caller.address, target.address, selector, args_hash], GENERATOR_INDEX__SIGNATURE_PAYLOAD)[0] +} \ No newline at end of file diff --git a/yarn-project/aztec-nr/aztec/src/oracle/auth_witness.nr b/yarn-project/aztec-nr/authwit/src/auth_witness.nr similarity index 100% rename from yarn-project/aztec-nr/aztec/src/oracle/auth_witness.nr rename to yarn-project/aztec-nr/authwit/src/auth_witness.nr diff --git a/yarn-project/aztec-nr/aztec/src/entrypoint.nr b/yarn-project/aztec-nr/authwit/src/entrypoint.nr similarity index 91% rename from yarn-project/aztec-nr/aztec/src/entrypoint.nr rename to yarn-project/aztec-nr/authwit/src/entrypoint.nr index eb1a170b277..8dd233ac1c3 100644 --- a/yarn-project/aztec-nr/aztec/src/entrypoint.nr +++ b/yarn-project/aztec-nr/authwit/src/entrypoint.nr @@ -1,9 +1,9 @@ -use crate::abi; -use crate::types::vec::BoundedVec; -use crate::context::PrivateContext; -use crate::private_call_stack_item::PrivateCallStackItem; -use crate::public_call_stack_item::PublicCallStackItem; -use crate::constants_gen::GENERATOR_INDEX__SIGNATURE_PAYLOAD; +use dep::aztec::abi; +use dep::aztec::types::vec::BoundedVec; +use dep::aztec::context::PrivateContext; +use dep::aztec::private_call_stack_item::PrivateCallStackItem; +use dep::aztec::public_call_stack_item::PublicCallStackItem; +use dep::aztec::constants_gen::GENERATOR_INDEX__SIGNATURE_PAYLOAD; use dep::std::hash; diff --git a/yarn-project/aztec-nr/authwit/src/lib.nr b/yarn-project/aztec-nr/authwit/src/lib.nr new file mode 100644 index 00000000000..ec0b9239404 --- /dev/null +++ b/yarn-project/aztec-nr/authwit/src/lib.nr @@ -0,0 +1,4 @@ +mod account; +mod auth_witness; +mod auth; +mod entrypoint; \ No newline at end of file diff --git a/yarn-project/aztec-nr/aztec/src/auth.nr b/yarn-project/aztec-nr/aztec/src/auth.nr deleted file mode 100644 index 3d7b68d9241..00000000000 --- a/yarn-project/aztec-nr/aztec/src/auth.nr +++ /dev/null @@ -1,18 +0,0 @@ -use crate::context::{PrivateContext, PublicContext}; -use crate::oracle::compute_selector::compute_selector; -use crate::constants_gen::EMPTY_NULLIFIED_COMMITMENT; - -global IS_VALID_SELECTOR = 0xe86ab4ff; -global IS_VALID_PUBLIC_SELECTOR = 0xf3661153; - -fn assert_valid_message_for(context: &mut PrivateContext, whom: Field, message_hash: Field) { - let result = context.call_private_function(whom, IS_VALID_SELECTOR, [message_hash])[0]; - context.push_new_nullifier(message_hash, EMPTY_NULLIFIED_COMMITMENT); - assert(result == IS_VALID_SELECTOR, "Message not authorized by account"); -} - -fn assert_valid_public_message_for(context: &mut PublicContext, whom: Field, message_hash: Field) { - let result = context.call_public_function(whom, IS_VALID_PUBLIC_SELECTOR, [message_hash])[0]; - context.push_new_nullifier(message_hash, EMPTY_NULLIFIED_COMMITMENT); - assert(result == IS_VALID_SELECTOR, "Message not authorized by account"); -} \ No newline at end of file diff --git a/yarn-project/aztec-nr/aztec/src/hash.nr b/yarn-project/aztec-nr/aztec/src/hash.nr index 09bdd46f0d3..9ddcb02c533 100644 --- a/yarn-project/aztec-nr/aztec/src/hash.nr +++ b/yarn-project/aztec-nr/aztec/src/hash.nr @@ -24,12 +24,6 @@ fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field { hash_in_a_field } -fn compute_message_hash(args: [Field; N]) -> Field { - // @todo @lherskind We should probably use a separate generator for this, - // to avoid any potential collisions with payloads. - pedersen_with_separator(args, GENERATOR_INDEX__SIGNATURE_PAYLOAD)[0] -} - fn compute_secret_hash(secret: Field) -> Field { // TODO(#1205) This is probably not the right index to use pedersen_with_separator([secret], GENERATOR_INDEX__L1_TO_L2_MESSAGE_SECRET)[0] diff --git a/yarn-project/aztec-nr/aztec/src/lib.nr b/yarn-project/aztec-nr/aztec/src/lib.nr index 98c8e638bb0..18d634ee213 100644 --- a/yarn-project/aztec-nr/aztec/src/lib.nr +++ b/yarn-project/aztec-nr/aztec/src/lib.nr @@ -1,10 +1,7 @@ mod abi; -mod account; mod address; -mod auth; mod constants_gen; mod context; -mod entrypoint; mod hash; mod log; mod messaging; diff --git a/yarn-project/aztec-nr/aztec/src/oracle.nr b/yarn-project/aztec-nr/aztec/src/oracle.nr index 375a1931f1f..da760abf487 100644 --- a/yarn-project/aztec-nr/aztec/src/oracle.nr +++ b/yarn-project/aztec-nr/aztec/src/oracle.nr @@ -15,5 +15,4 @@ mod public_call; mod notes; mod storage; mod logs; -mod compute_selector; -mod auth_witness; \ No newline at end of file +mod compute_selector; \ No newline at end of file diff --git a/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json b/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json index 38b5b956876..d234c8d31ef 100644 --- a/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json +++ b/yarn-project/aztec.js/src/abis/ecdsa_account_contract.json @@ -96,7 +96,7 @@ "name": "payload", "type": { "kind": "struct", - "path": "aztec::entrypoint::EntrypointPayload", + "path": "authwit::entrypoint::EntrypointPayload", "fields": [ { "name": "function_calls", @@ -105,7 +105,7 @@ "length": 4, "type": { "kind": "struct", - "path": "aztec::entrypoint::FunctionCall", + "path": "authwit::entrypoint::FunctionCall", "fields": [ { "name": "args_hash", diff --git a/yarn-project/aztec.js/src/abis/schnorr_account_contract.json b/yarn-project/aztec.js/src/abis/schnorr_account_contract.json index e9acbfdf607..fbabf82ba74 100644 --- a/yarn-project/aztec.js/src/abis/schnorr_account_contract.json +++ b/yarn-project/aztec.js/src/abis/schnorr_account_contract.json @@ -84,7 +84,7 @@ "name": "payload", "type": { "kind": "struct", - "path": "aztec::entrypoint::EntrypointPayload", + "path": "authwit::entrypoint::EntrypointPayload", "fields": [ { "name": "function_calls", @@ -93,7 +93,7 @@ "length": 4, "type": { "kind": "struct", - "path": "aztec::entrypoint::FunctionCall", + "path": "authwit::entrypoint::FunctionCall", "fields": [ { "name": "args_hash", diff --git a/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json b/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json index 64e0095a7ee..df05692221b 100644 --- a/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json +++ b/yarn-project/aztec.js/src/abis/schnorr_single_key_account_contract.json @@ -19,7 +19,7 @@ "name": "payload", "type": { "kind": "struct", - "path": "aztec::entrypoint::EntrypointPayload", + "path": "authwit::entrypoint::EntrypointPayload", "fields": [ { "name": "function_calls", @@ -28,7 +28,7 @@ "length": 4, "type": { "kind": "struct", - "path": "aztec::entrypoint::FunctionCall", + "path": "authwit::entrypoint::FunctionCall", "fields": [ { "name": "args_hash", diff --git a/yarn-project/aztec.js/src/account/defaults/default_entrypoint.ts b/yarn-project/aztec.js/src/account/defaults/default_entrypoint.ts index 263714f1144..d036f1fbade 100644 --- a/yarn-project/aztec.js/src/account/defaults/default_entrypoint.ts +++ b/yarn-project/aztec.js/src/account/defaults/default_entrypoint.ts @@ -46,7 +46,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { name: 'payload', type: { kind: 'struct', - path: 'aztec::entrypoint::EntrypointPayload', + path: 'authwit::entrypoint::EntrypointPayload', fields: [ { name: 'function_calls', @@ -55,7 +55,7 @@ export class DefaultAccountEntrypoint implements EntrypointInterface { length: 4, type: { kind: 'struct', - path: 'aztec::entrypoint::FunctionCall', + path: 'authwit::entrypoint::FunctionCall', fields: [ { name: 'args_hash', diff --git a/yarn-project/aztec.js/src/utils/authwit.ts b/yarn-project/aztec.js/src/utils/authwit.ts new file mode 100644 index 00000000000..cbad0a84c94 --- /dev/null +++ b/yarn-project/aztec.js/src/utils/authwit.ts @@ -0,0 +1,24 @@ +import { AztecAddress, CircuitsWasm, GeneratorIndex } from '@aztec/circuits.js'; +import { pedersenPlookupCompressWithHashIndex } from '@aztec/circuits.js/barretenberg'; +import { FunctionCall, PackedArguments } from '@aztec/types'; + +/** + * Compute an authentication witness message hash from a caller and a request + * H(caller: AztecAddress, target: AztecAddress, selector: Field, args_hash: Field) + * @param caller - The caller approved to make the call + * @param request - The request to be made (function call) + * @returns The message hash for the witness + */ +export const computeAuthWitMessageHash = async (caller: AztecAddress, request: FunctionCall) => { + const wasm = await CircuitsWasm.get(); + return pedersenPlookupCompressWithHashIndex( + wasm, + [ + caller.toField(), + request.to.toField(), + request.functionData.selector.toField(), + (await PackedArguments.fromArgs(request.args, wasm)).hash, + ].map(fr => fr.toBuffer()), + GeneratorIndex.SIGNATURE_PAYLOAD, + ); +}; diff --git a/yarn-project/aztec.js/src/utils/index.ts b/yarn-project/aztec.js/src/utils/index.ts index a2df1771c57..08d014635ff 100644 --- a/yarn-project/aztec.js/src/utils/index.ts +++ b/yarn-project/aztec.js/src/utils/index.ts @@ -4,3 +4,4 @@ export * from './l1_contracts.js'; export * from './l2_contracts.js'; export * from './abi_types.js'; export * from './cheat_codes.js'; +export * from './authwit.js'; diff --git a/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts b/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts index b028577511c..2224f446025 100644 --- a/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts +++ b/yarn-project/canary/src/uniswap_trade_on_l1_from_l2.test.ts @@ -6,6 +6,7 @@ import { NotePreimage, TxHash, TxStatus, + computeAuthWitMessageHash, computeMessageSecretHash, createDebugLogger, createPXEClient, @@ -14,7 +15,6 @@ import { sleep, waitForSandbox, } from '@aztec/aztec.js'; -import { FunctionSelector } from '@aztec/circuits.js'; import { UniswapPortalAbi, UniswapPortalBytecode } from '@aztec/l1-artifacts'; import { TokenBridgeContract, TokenContract, UniswapContract } from '@aztec/noir-contracts/types'; @@ -32,7 +32,7 @@ import { import { mnemonicToAccount } from 'viem/accounts'; import { Chain, foundry } from 'viem/chains'; -import { deployAndInitializeTokenAndBridgeContracts, deployL1Contract, hashPayload } from './utils.js'; +import { deployAndInitializeTokenAndBridgeContracts, deployL1Contract } from './utils.js'; const logger = createDebugLogger('aztec:canary'); @@ -335,15 +335,12 @@ describe('uniswap_trade_on_l1_from_l2', () => { // 4. Owner gives uniswap approval to unshield funds to self on its behalf logger('Approving uniswap to unshield funds to self on my behalf'); const nonceForWETHUnshieldApproval = new Fr(2n); - const unshieldToUniswapMessageHash = await hashPayload([ - uniswapL2Contract.address.toField(), - wethL2Contract.address.toField(), - FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)').toField(), - ownerAddress.toField(), - uniswapL2Contract.address.toField(), - new Fr(wethAmountToBridge), - nonceForWETHUnshieldApproval, - ]); + const unshieldToUniswapMessageHash = await computeAuthWitMessageHash( + uniswapL2Contract.address, + wethL2Contract.methods + .unshield(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHUnshieldApproval) + .request(), + ); await ownerWallet.createAuthWitness(Fr.fromBuffer(unshieldToUniswapMessageHash)); // 5. Swap on L1 - sends L2 to L1 message to withdraw WETH to L1 and another message to swap assets. diff --git a/yarn-project/canary/src/utils.ts b/yarn-project/canary/src/utils.ts index efb29ebb328..0bcc6926632 100644 --- a/yarn-project/canary/src/utils.ts +++ b/yarn-project/canary/src/utils.ts @@ -1,6 +1,4 @@ import { AztecAddress, EthAddress, Fr, TxStatus, Wallet } from '@aztec/aztec.js'; -import { CircuitsWasm, GeneratorIndex } from '@aztec/circuits.js'; -import { pedersenPlookupCompressWithHashIndex } from '@aztec/circuits.js/barretenberg'; import { PortalERC20Abi, PortalERC20Bytecode, TokenPortalAbi, TokenPortalBytecode } from '@aztec/l1-artifacts'; import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts/types'; @@ -136,16 +134,3 @@ export async function deployL1Contract( return EthAddress.fromString(receipt.contractAddress!); } - -/** - * Hash a payload to generate a signature on an account contract - * @param payload - payload to hash - * @returns the hashed message - */ -export const hashPayload = async (payload: Fr[]) => { - return pedersenPlookupCompressWithHashIndex( - await CircuitsWasm.get(), - payload.map(fr => fr.toBuffer()), - GeneratorIndex.SIGNATURE_PAYLOAD, - ); -}; diff --git a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts index 7b3531c1695..463d1ac6c34 100644 --- a/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_cross_chain_messaging.test.ts @@ -1,12 +1,12 @@ -import { AccountWallet, AztecAddress } from '@aztec/aztec.js'; -import { Fr, FunctionSelector } from '@aztec/circuits.js'; +import { AccountWallet, AztecAddress, computeAuthWitMessageHash } from '@aztec/aztec.js'; +import { Fr } from '@aztec/circuits.js'; import { EthAddress } from '@aztec/foundation/eth-address'; import { DebugLogger } from '@aztec/foundation/log'; import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts/types'; import { TxStatus } from '@aztec/types'; import { CrossChainTestHarness } from './fixtures/cross_chain_test_harness.js'; -import { delay, hashPayload, setup } from './fixtures/utils.js'; +import { delay, setup } from './fixtures/utils.js'; describe('e2e_cross_chain_messaging', () => { let logger: DebugLogger; @@ -107,14 +107,10 @@ describe('e2e_cross_chain_messaging', () => { // 4. Give approval to bridge to burn owner's funds: const withdrawAmount = 9n; const nonce = Fr.random(); - const burnMessageHash = await hashPayload([ - l2Bridge.address.toField(), - l2Token.address.toField(), - FunctionSelector.fromSignature('burn((Field),Field,Field)').toField(), - ownerAddress.toField(), - new Fr(withdrawAmount), - nonce, - ]); + const burnMessageHash = await computeAuthWitMessageHash( + l2Bridge.address, + l2Token.methods.burn(ownerAddress, withdrawAmount, nonce).request(), + ); await user1Wallet.createAuthWitness(burnMessageHash); // 5. Withdraw owner's funds from L2 to L1 @@ -201,14 +197,10 @@ describe('e2e_cross_chain_messaging', () => { const withdrawAmount = 9n; const nonce = Fr.random(); - const expectedBurnMessageHash = await hashPayload([ - l2Bridge.address.toField(), - l2Token.address.toField(), - FunctionSelector.fromSignature('burn((Field),Field,Field)').toField(), - user1Wallet.getAddress().toField(), - new Fr(withdrawAmount), - nonce, - ]); + const expectedBurnMessageHash = await computeAuthWitMessageHash( + l2Bridge.address, + l2Token.methods.burn(user1Wallet.getAddress(), withdrawAmount, nonce).request(), + ); // Should fail as owner has not given approval to bridge burn their funds. await expect( l2Bridge diff --git a/yarn-project/end-to-end/src/e2e_lending_contract.test.ts b/yarn-project/end-to-end/src/e2e_lending_contract.test.ts index 2b9469b922b..07a09a14558 100644 --- a/yarn-project/end-to-end/src/e2e_lending_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_lending_contract.test.ts @@ -1,6 +1,12 @@ -import { AccountWallet, CheatCodes, Fr, SentTx, computeMessageSecretHash } from '@aztec/aztec.js'; -import { CircuitsWasm, CompleteAddress, FunctionSelector, GeneratorIndex } from '@aztec/circuits.js'; -import { pedersenPlookupCompressWithHashIndex } from '@aztec/circuits.js/barretenberg'; +import { + AccountWallet, + CheatCodes, + Fr, + SentTx, + computeAuthWitMessageHash, + computeMessageSecretHash, +} from '@aztec/aztec.js'; +import { CompleteAddress } from '@aztec/circuits.js'; import { DebugLogger } from '@aztec/foundation/log'; import { LendingContract, PriceFeedContract, TokenContract } from '@aztec/noir-contracts/types'; import { NotePreimage, TxStatus } from '@aztec/types'; @@ -99,14 +105,6 @@ describe('e2e_lending_contract', () => { await lendingSim.check(); }); - const hashPayload = async (payload: Fr[]) => { - return pedersenPlookupCompressWithHashIndex( - await CircuitsWasm.get(), - payload.map(fr => fr.toBuffer()), - GeneratorIndex.SIGNATURE_PAYLOAD, - ); - }; - it('Mint assets for later usage', async () => { await waitForSuccess(priceFeedContract.methods.set_price(0n, 2n * 10n ** 9n).send()); @@ -151,15 +149,13 @@ describe('e2e_lending_contract', () => { it('Depositing 🥸 : 💰 -> 🏦', async () => { const depositAmount = 420n; const nonce = Fr.random(); - const messageHash = await hashPayload([ - lendingContract.address.toField(), - collateralAsset.address.toField(), - FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)').toField(), - lendingAccount.address.toField(), - lendingContract.address.toField(), - new Fr(depositAmount), - nonce, - ]); + const messageHash = await computeAuthWitMessageHash( + lendingContract.address, + collateralAsset.methods + .unshield(lendingAccount.address, lendingContract.address, depositAmount, nonce) + .request(), + ); + await wallet.createAuthWitness(Fr.fromBuffer(messageHash)); await lendingSim.progressTime(TIME_JUMP); lendingSim.depositPrivate(lendingAccount.address, await lendingAccount.key(), depositAmount); @@ -187,15 +183,12 @@ describe('e2e_lending_contract', () => { it('Depositing 🥸 on behalf of recipient: 💰 -> 🏦', async () => { const depositAmount = 421n; const nonce = Fr.random(); - const messageHash = await hashPayload([ - lendingContract.address.toField(), - collateralAsset.address.toField(), - FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)').toField(), - lendingAccount.address.toField(), - lendingContract.address.toField(), - new Fr(depositAmount), - nonce, - ]); + const messageHash = await computeAuthWitMessageHash( + lendingContract.address, + collateralAsset.methods + .unshield(lendingAccount.address, lendingContract.address, depositAmount, nonce) + .request(), + ); await wallet.createAuthWitness(Fr.fromBuffer(messageHash)); await lendingSim.progressTime(TIME_JUMP); @@ -224,15 +217,12 @@ describe('e2e_lending_contract', () => { const depositAmount = 211n; const nonce = Fr.random(); - const messageHash = await hashPayload([ - lendingContract.address.toField(), - collateralAsset.address.toField(), - FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)').toField(), - lendingAccount.address.toField(), - lendingContract.address.toField(), - new Fr(depositAmount), - nonce, - ]); + const messageHash = await computeAuthWitMessageHash( + lendingContract.address, + collateralAsset.methods + .transfer_public(lendingAccount.address, lendingContract.address, depositAmount, nonce) + .request(), + ); // Add it to the wallet as approved await wallet.setPublicAuth(messageHash, true).send().wait(); @@ -305,14 +295,10 @@ describe('e2e_lending_contract', () => { it('Repay 🥸 : 🍌 -> 🏦', async () => { const repayAmount = 20n; const nonce = Fr.random(); - const messageHash = await hashPayload([ - lendingContract.address.toField(), - stableCoin.address.toField(), - FunctionSelector.fromSignature('burn((Field),Field,Field)').toField(), - lendingAccount.address.toField(), - new Fr(repayAmount), - nonce, - ]); + const messageHash = await computeAuthWitMessageHash( + lendingContract.address, + stableCoin.methods.burn(lendingAccount.address, repayAmount, nonce).request(), + ); await wallet.createAuthWitness(Fr.fromBuffer(messageHash)); await lendingSim.progressTime(TIME_JUMP); @@ -335,14 +321,10 @@ describe('e2e_lending_contract', () => { it('Repay 🥸 on behalf of public: 🍌 -> 🏦', async () => { const repayAmount = 21n; const nonce = Fr.random(); - const messageHash = await hashPayload([ - lendingContract.address.toField(), - stableCoin.address.toField(), - FunctionSelector.fromSignature('burn((Field),Field,Field)').toField(), - lendingAccount.address.toField(), - new Fr(repayAmount), - nonce, - ]); + const messageHash = await computeAuthWitMessageHash( + lendingContract.address, + stableCoin.methods.burn(lendingAccount.address, repayAmount, nonce).request(), + ); await wallet.createAuthWitness(Fr.fromBuffer(messageHash)); await lendingSim.progressTime(TIME_JUMP); @@ -366,14 +348,10 @@ describe('e2e_lending_contract', () => { const repayAmount = 20n; const nonce = Fr.random(); - const messageHash = await hashPayload([ - lendingContract.address.toField(), - stableCoin.address.toField(), - FunctionSelector.fromSignature('burn_public((Field),Field,Field)').toField(), - lendingAccount.address.toField(), - new Fr(repayAmount), - nonce, - ]); + const messageHash = await computeAuthWitMessageHash( + lendingContract.address, + stableCoin.methods.burn_public(lendingAccount.address, repayAmount, nonce).request(), + ); // Add it to the wallet as approved await wallet.setPublicAuth(messageHash, true).send().wait(); diff --git a/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts b/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts index 88980573b2c..67dd9725de0 100644 --- a/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts +++ b/yarn-project/end-to-end/src/e2e_public_cross_chain_messaging.test.ts @@ -1,12 +1,12 @@ -import { AccountWallet, AztecAddress } from '@aztec/aztec.js'; -import { Fr, FunctionSelector } from '@aztec/circuits.js'; +import { AccountWallet, AztecAddress, computeAuthWitMessageHash } from '@aztec/aztec.js'; +import { Fr } from '@aztec/circuits.js'; import { EthAddress } from '@aztec/foundation/eth-address'; import { DebugLogger } from '@aztec/foundation/log'; import { TokenBridgeContract, TokenContract } from '@aztec/noir-contracts/types'; import { TxStatus } from '@aztec/types'; import { CrossChainTestHarness } from './fixtures/cross_chain_test_harness.js'; -import { delay, hashPayload, setup } from './fixtures/utils.js'; +import { delay, setup } from './fixtures/utils.js'; describe('e2e_public_cross_chain_messaging', () => { let logger: DebugLogger; @@ -94,14 +94,10 @@ describe('e2e_public_cross_chain_messaging', () => { // 4. Give approval to bridge to burn owner's funds: const withdrawAmount = 9n; const nonce = Fr.random(); - const burnMessageHash = await hashPayload([ - l2Bridge.address.toField(), - l2Token.address.toField(), - FunctionSelector.fromSignature('burn_public((Field),Field,Field)').toField(), - ownerAddress.toField(), - new Fr(withdrawAmount), - nonce, - ]); + const burnMessageHash = await computeAuthWitMessageHash( + l2Bridge.address, + l2Token.methods.burn_public(ownerAddress, withdrawAmount, nonce).request(), + ); await ownerWallet.setPublicAuth(burnMessageHash, true).send().wait(); // 5. Withdraw owner's funds from L2 to L1 diff --git a/yarn-project/end-to-end/src/e2e_token_contract.test.ts b/yarn-project/end-to-end/src/e2e_token_contract.test.ts index ad35a01bc68..eed45f17ff4 100644 --- a/yarn-project/end-to-end/src/e2e_token_contract.test.ts +++ b/yarn-project/end-to-end/src/e2e_token_contract.test.ts @@ -1,6 +1,12 @@ -import { AccountWallet, NotePreimage, TxHash, TxStatus, computeMessageSecretHash } from '@aztec/aztec.js'; -import { CircuitsWasm, CompleteAddress, Fr, FunctionSelector, GeneratorIndex } from '@aztec/circuits.js'; -import { pedersenPlookupCompressWithHashIndex } from '@aztec/circuits.js/barretenberg'; +import { + AccountWallet, + NotePreimage, + TxHash, + TxStatus, + computeAuthWitMessageHash, + computeMessageSecretHash, +} from '@aztec/aztec.js'; +import { CompleteAddress, Fr, FunctionSelector } from '@aztec/circuits.js'; import { DebugLogger } from '@aztec/foundation/log'; import { TokenContract } from '@aztec/noir-contracts/types'; @@ -9,14 +15,6 @@ import { jest } from '@jest/globals'; import { setup } from './fixtures/utils.js'; import { TokenSimulator } from './simulators/token_simulator.js'; -const hashPayload = async (payload: Fr[]) => { - return pedersenPlookupCompressWithHashIndex( - await CircuitsWasm.get(), - payload.map(fr => fr.toBuffer()), - GeneratorIndex.SIGNATURE_PAYLOAD, - ); -}; - const TIMEOUT = 90_000; describe('e2e_token_contract', () => { @@ -219,24 +217,6 @@ describe('e2e_token_contract', () => { describe('Transfer', () => { describe('public', () => { - const transferMessageHash = async ( - caller: CompleteAddress, - from: CompleteAddress, - to: CompleteAddress, - amount: bigint, - nonce: Fr, - ) => { - return await hashPayload([ - caller.address.toField(), - asset.address.toField(), - FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)').toField(), - from.address.toField(), - to.address.toField(), - new Fr(amount), - nonce, - ]); - }; - it('transfer less than balance', async () => { const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balance0 / 2n; @@ -265,15 +245,17 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); const nonce = Fr.random(); + const action = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); + // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await transferMessageHash(accounts[1], accounts[0], accounts[1], amount, nonce); + //const messageHash = await transferMessageHash(accounts[1], accounts[0], accounts[1], amount, nonce); await wallets[0].setPublicAuth(messageHash, true).send().wait(); // Perform the transfer - const tx = asset - .withWallet(wallets[1]) - .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) - .send(); + const tx = action.send(); const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); @@ -327,17 +309,16 @@ describe('e2e_token_contract', () => { const nonce = Fr.random(); expect(amount).toBeGreaterThan(0n); + const action = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); + // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await transferMessageHash(accounts[1], accounts[0], accounts[1], amount, nonce); await wallets[0].setPublicAuth(messageHash, true).send().wait(); // Perform the transfer - await expect( - asset - .withWallet(wallets[1]) - .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) - .simulate(), - ).rejects.toThrowError('Assertion failed: Underflow'); + await expect(action.simulate()).rejects.toThrowError('Assertion failed: Underflow'); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_public(accounts[1].address).view()).toEqual(balance1); @@ -351,16 +332,15 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await transferMessageHash(accounts[0], accounts[0], accounts[1], amount, nonce); + const action = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[0].address, action.request()); + await wallets[0].setPublicAuth(messageHash, true).send().wait(); // Perform the transfer - await expect( - asset - .withWallet(wallets[1]) - .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) - .simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); + await expect(action.simulate()).rejects.toThrowError('Assertion failed: Message not authorized by account'); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_public(accounts[1].address).view()).toEqual(balance1); @@ -374,16 +354,14 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await transferMessageHash(accounts[0], accounts[0], accounts[1], amount, nonce); + const action = asset + .withWallet(wallets[1]) + .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[0].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); // Perform the transfer - await expect( - asset - .withWallet(wallets[1]) - .methods.transfer_public(accounts[0].address, accounts[1].address, amount, nonce) - .simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); + await expect(action.simulate()).rejects.toThrowError('Assertion failed: Message not authorized by account'); expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_public(accounts[1].address).view()).toEqual(balance1); @@ -399,24 +377,6 @@ describe('e2e_token_contract', () => { }); describe('private', () => { - const transferMessageHash = async ( - caller: CompleteAddress, - from: CompleteAddress, - to: CompleteAddress, - amount: bigint, - nonce: Fr, - ) => { - return await hashPayload([ - caller.address.toField(), - asset.address.toField(), - FunctionSelector.fromSignature('transfer((Field),(Field),Field,Field)').toField(), - from.address.toField(), - to.address.toField(), - new Fr(amount), - nonce, - ]); - }; - it('transfer less than balance', async () => { const balance0 = await asset.methods.balance_of_private(accounts[0].address).view(); const amount = balance0 / 2n; @@ -444,7 +404,10 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await transferMessageHash(accounts[1], accounts[0], accounts[1], amount, nonce); + const action = asset + .withWallet(wallets[1]) + .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); // Both wallets are connected to same node and PXE so we could just insert directly using // await wallet.signAndAddAuthWitness(messageHash, ); @@ -453,10 +416,7 @@ describe('e2e_token_contract', () => { await wallets[1].addAuthWitness(witness); // Perform the transfer - const tx = asset - .withWallet(wallets[1]) - .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce) - .send(); + const tx = action.send(); const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); tokenSim.transferPrivate(accounts[0].address, accounts[1].address, amount); @@ -498,7 +458,10 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await transferMessageHash(accounts[1], accounts[0], accounts[1], amount, nonce); + const action = asset + .withWallet(wallets[1]) + .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); // Both wallets are connected to same node and PXE so we could just insert directly using // await wallet.signAndAddAuthWitness(messageHash, ); @@ -507,12 +470,7 @@ describe('e2e_token_contract', () => { await wallets[1].addAuthWitness(witness); // Perform the transfer - await expect( - asset - .withWallet(wallets[1]) - .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce) - .simulate(), - ).rejects.toThrowError('Assertion failed: Balance too low'); + await expect(action.simulate()).rejects.toThrowError('Assertion failed: Balance too low'); expect(await asset.methods.balance_of_private(accounts[0].address).view()).toEqual(balance0); expect(await asset.methods.balance_of_private(accounts[1].address).view()).toEqual(balance1); }); @@ -531,14 +489,14 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await transferMessageHash(accounts[1], accounts[0], accounts[1], amount, nonce); + const action = asset + .withWallet(wallets[1]) + .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); - await expect( - asset - .withWallet(wallets[1]) - .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce) - .simulate(), - ).rejects.toThrowError(`Unknown auth witness for message hash 0x${messageHash.toString('hex')}`); + await expect(action.simulate()).rejects.toThrowError( + `Unknown auth witness for message hash 0x${messageHash.toString('hex')}`, + ); }); it('transfer on behalf of other, wrong designated caller', async () => { @@ -548,18 +506,18 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await transferMessageHash(accounts[1], accounts[0], accounts[1], amount, nonce); - const expectedMessageHash = await transferMessageHash(accounts[2], accounts[0], accounts[1], amount, nonce); + const action = asset + .withWallet(wallets[2]) + .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); + const expectedMessageHash = await computeAuthWitMessageHash(accounts[2].address, action.request()); const witness = await wallets[0].createAuthWitness(messageHash); await wallets[2].addAuthWitness(witness); - await expect( - asset - .withWallet(wallets[2]) - .methods.transfer(accounts[0].address, accounts[1].address, amount, nonce) - .simulate(), - ).rejects.toThrowError(`Unknown auth witness for message hash 0x${expectedMessageHash.toString('hex')}`); + await expect(action.simulate()).rejects.toThrowError( + `Unknown auth witness for message hash 0x${expectedMessageHash.toString('hex')}`, + ); expect(await asset.methods.balance_of_private(accounts[0].address).view()).toEqual(balance0); }); }); @@ -574,24 +532,6 @@ describe('e2e_token_contract', () => { secretHash = await computeMessageSecretHash(secret); }); - const shieldMessageHash = async ( - caller: CompleteAddress, - from: CompleteAddress, - amount: bigint, - secretHash: Fr, - nonce: Fr, - ) => { - return await hashPayload([ - caller.address.toField(), - asset.address.toField(), - FunctionSelector.fromSignature('shield((Field),Field,Field,Field)').toField(), - from.address.toField(), - new Fr(amount), - secretHash, - nonce, - ]); - }; - it('on behalf of self', async () => { const balancePub = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balancePub / 2n; @@ -620,10 +560,11 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await shieldMessageHash(accounts[1], accounts[0], amount, secretHash, nonce); + const action = asset.withWallet(wallets[1]).methods.shield(accounts[0].address, amount, secretHash, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - const tx = asset.withWallet(wallets[1]).methods.shield(accounts[0].address, amount, secretHash, nonce).send(); + const tx = action.send(); const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); @@ -676,46 +617,25 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await shieldMessageHash(accounts[1], accounts[0], amount, secretHash, nonce); - await wallets[0].setPublicAuth(messageHash, true).send().wait(); - - await expect( - asset.withWallet(wallets[1]).methods.shield(accounts[0].address, amount, secretHash, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: Underflow'); - }); - - it('on behalf of other (wrong designated caller)', async () => { - const balancePub = await asset.methods.balance_of_public(accounts[0].address).view(); - const amount = balancePub + 1n; - const nonce = Fr.random(); - expect(amount).toBeGreaterThan(0n); - - // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await shieldMessageHash(accounts[1], accounts[0], amount, secretHash, nonce); + const action = asset.withWallet(wallets[1]).methods.shield(accounts[0].address, amount, secretHash, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - await expect( - asset.withWallet(wallets[2]).methods.shield(accounts[0].address, amount, secretHash, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); + await expect(action.simulate()).rejects.toThrowError('Assertion failed: Underflow'); }); it('on behalf of other (wrong designated caller)', async () => { const balancePub = await asset.methods.balance_of_public(accounts[0].address).view(); - const balancePriv = await asset.methods.balance_of_private(accounts[0].address).view(); const amount = balancePub + 1n; const nonce = Fr.random(); expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await shieldMessageHash(accounts[1], accounts[0], amount, secretHash, nonce); + const action = asset.withWallet(wallets[2]).methods.shield(accounts[0].address, amount, secretHash, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - await expect( - asset.withWallet(wallets[2]).methods.shield(accounts[0].address, amount, secretHash, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: Message not authorized by account'); - - expect(await asset.methods.balance_of_public(accounts[0].address).view()).toEqual(balancePub); - expect(await asset.methods.balance_of_private(accounts[0].address).view()).toEqual(balancePriv); + await expect(action.simulate()).rejects.toThrowError('Assertion failed: Message not authorized by account'); }); it('on behalf of other (without approval)', async () => { @@ -732,24 +652,6 @@ describe('e2e_token_contract', () => { }); describe('Unshielding', () => { - const unshieldMessageHash = async ( - caller: CompleteAddress, - from: CompleteAddress, - to: CompleteAddress, - amount: bigint, - nonce: Fr, - ) => { - return await hashPayload([ - caller.address.toField(), - asset.address.toField(), - FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)').toField(), - from.address.toField(), - to.address.toField(), - new Fr(amount), - nonce, - ]); - }; - it('on behalf of self', async () => { const balancePriv = await asset.methods.balance_of_private(accounts[0].address).view(); const amount = balancePriv / 2n; @@ -769,7 +671,10 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await unshieldMessageHash(accounts[1], accounts[0], accounts[1], amount, nonce); + const action = asset + .withWallet(wallets[1]) + .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); // Both wallets are connected to same node and PXE so we could just insert directly using // await wallet.signAndAddAuthWitness(messageHash, ); @@ -777,10 +682,7 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[1].addAuthWitness(witness); - const tx = asset - .withWallet(wallets[1]) - .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce) - .send(); + const tx = action.send(); const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); tokenSim.unshield(accounts[0].address, accounts[1].address, amount); @@ -823,7 +725,10 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await unshieldMessageHash(accounts[1], accounts[0], accounts[1], amount, nonce); + const action = asset + .withWallet(wallets[1]) + .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); // Both wallets are connected to same node and PXE so we could just insert directly using // await wallet.signAndAddAuthWitness(messageHash, ); @@ -831,12 +736,7 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[1].addAuthWitness(witness); - await expect( - asset - .withWallet(wallets[1]) - .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce) - .simulate(), - ).rejects.toThrowError('Assertion failed: Balance too low'); + await expect(action.simulate()).rejects.toThrowError('Assertion failed: Balance too low'); }); it('on behalf of other (invalid designated caller)', async () => { @@ -846,8 +746,11 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await unshieldMessageHash(accounts[1], accounts[0], accounts[1], amount, nonce); - const expectedMessageHash = await unshieldMessageHash(accounts[2], accounts[0], accounts[1], amount, nonce); + const action = asset + .withWallet(wallets[2]) + .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); + const expectedMessageHash = await computeAuthWitMessageHash(accounts[2].address, action.request()); // Both wallets are connected to same node and PXE so we could just insert directly using // await wallet.signAndAddAuthWitness(messageHash, ); @@ -855,29 +758,15 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[2].addAuthWitness(witness); - await expect( - asset - .withWallet(wallets[2]) - .methods.unshield(accounts[0].address, accounts[1].address, amount, nonce) - .simulate(), - ).rejects.toThrowError(`Unknown auth witness for message hash 0x${expectedMessageHash.toString('hex')}`); + await expect(action.simulate()).rejects.toThrowError( + `Unknown auth witness for message hash 0x${expectedMessageHash.toString('hex')}`, + ); }); }); }); describe('Burn', () => { describe('public', () => { - const burnMessageHash = async (caller: CompleteAddress, from: CompleteAddress, amount: bigint, nonce: Fr) => { - return await hashPayload([ - caller.address.toField(), - asset.address.toField(), - FunctionSelector.fromSignature('burn_public((Field),Field,Field)').toField(), - from.address.toField(), - new Fr(amount), - nonce, - ]); - }; - it('burn less than balance', async () => { const balance0 = await asset.methods.balance_of_public(accounts[0].address).view(); const amount = balance0 / 2n; @@ -896,10 +785,11 @@ describe('e2e_token_contract', () => { const nonce = Fr.random(); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await burnMessageHash(accounts[1], accounts[0], amount, nonce); + const action = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - const tx = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).send(); + const tx = action.send(); const receipt = await tx.wait(); expect(receipt.status).toBe(TxStatus.MINED); @@ -948,12 +838,11 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await burnMessageHash(accounts[1], accounts[0], amount, nonce); + const action = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); - await expect( - asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: Underflow'); + await expect(action.simulate()).rejects.toThrowError('Assertion failed: Underflow'); }); it('burn on behalf of other, wrong designated caller', async () => { @@ -963,7 +852,8 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await burnMessageHash(accounts[0], accounts[0], amount, nonce); + const action = asset.withWallet(wallets[1]).methods.burn_public(accounts[0].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[0].address, action.request()); await wallets[0].setPublicAuth(messageHash, true).send().wait(); await expect( @@ -974,17 +864,6 @@ describe('e2e_token_contract', () => { }); describe('private', () => { - const burnMessageHash = async (caller: CompleteAddress, from: CompleteAddress, amount: bigint, nonce: Fr) => { - return await hashPayload([ - caller.address.toField(), - asset.address.toField(), - FunctionSelector.fromSignature('burn((Field),Field,Field)').toField(), - from.address.toField(), - new Fr(amount), - nonce, - ]); - }; - it('burn less than balance', async () => { const balance0 = await asset.methods.balance_of_private(accounts[0].address).view(); const amount = balance0 / 2n; @@ -1002,7 +881,8 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await burnMessageHash(accounts[1], accounts[0], amount, nonce); + const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); // Both wallets are connected to same node and PXE so we could just insert directly using // await wallet.signAndAddAuthWitness(messageHash, ); @@ -1048,7 +928,8 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await burnMessageHash(accounts[1], accounts[0], amount, nonce); + const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); // Both wallets are connected to same node and PXE so we could just insert directly using // await wallet.signAndAddAuthWitness(messageHash, ); @@ -1056,9 +937,7 @@ describe('e2e_token_contract', () => { const witness = await wallets[0].createAuthWitness(messageHash); await wallets[1].addAuthWitness(witness); - await expect( - asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce).simulate(), - ).rejects.toThrowError('Assertion failed: Balance too low'); + await expect(action.simulate()).rejects.toThrowError('Assertion failed: Balance too low'); }); it('burn on behalf of other without approval', async () => { @@ -1068,52 +947,33 @@ describe('e2e_token_contract', () => { expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await burnMessageHash(accounts[1], accounts[0], amount, nonce); + const action = asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); - await expect( - asset.withWallet(wallets[1]).methods.burn(accounts[0].address, amount, nonce).simulate(), - ).rejects.toThrowError(`Unknown auth witness for message hash 0x${messageHash.toString('hex')}`); + await expect(action.simulate()).rejects.toThrowError( + `Unknown auth witness for message hash 0x${messageHash.toString('hex')}`, + ); }); - it('burn on behalf of other, wrong designated caller', async () => { - const balance0 = await asset.methods.balance_of_private(accounts[0].address).view(); - const amount = balance0 / 2n; + it('on behalf of other (invalid designated caller)', async () => { + const balancePriv0 = await asset.methods.balance_of_private(accounts[0].address).view(); + const amount = balancePriv0 + 2n; const nonce = Fr.random(); expect(amount).toBeGreaterThan(0n); // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await burnMessageHash(accounts[1], accounts[0], amount, nonce); - const expectedMessageHash = await burnMessageHash(accounts[2], accounts[0], amount, nonce); + const action = asset.withWallet(wallets[2]).methods.burn(accounts[0].address, amount, nonce); + const messageHash = await computeAuthWitMessageHash(accounts[1].address, action.request()); + const expectedMessageHash = await computeAuthWitMessageHash(accounts[2].address, action.request()); const witness = await wallets[0].createAuthWitness(messageHash); await wallets[2].addAuthWitness(witness); - await expect( - asset.withWallet(wallets[2]).methods.burn(accounts[0].address, amount, nonce).simulate(), - ).rejects.toThrowError(`Unknown auth witness for message hash 0x${expectedMessageHash.toString('hex')}`); + await expect(action.simulate()).rejects.toThrowError( + `Unknown auth witness for message hash 0x${expectedMessageHash.toString('hex')}`, + ); }); }); - - it('on behalf of other (invalid designated caller)', async () => { - const balancePriv0 = await asset.methods.balance_of_private(accounts[0].address).view(); - const amount = balancePriv0 + 2n; - const nonce = Fr.random(); - expect(amount).toBeGreaterThan(0n); - - // We need to compute the message we want to sign and add it to the wallet as approved - const messageHash = await burnMessageHash(accounts[1], accounts[0], amount, nonce); - const expectedMessageHash = await burnMessageHash(accounts[2], accounts[0], amount, nonce); - - // Both wallets are connected to same node and PXE so we could just insert directly using - // await wallet.signAndAddAuthWitness(messageHash, { origin: accounts[0].address }); - // But doing it in two actions to show the flow. - const witness = await wallets[0].createAuthWitness(messageHash); - await wallets[2].addAuthWitness(witness); - - await expect( - asset.withWallet(wallets[2]).methods.burn(accounts[0].address, amount, nonce).simulate(), - ).rejects.toThrowError(`Unknown auth witness for message hash 0x${expectedMessageHash.toString('hex')}`); - }); }); }); }); diff --git a/yarn-project/end-to-end/src/fixtures/utils.ts b/yarn-project/end-to-end/src/fixtures/utils.ts index 9dcdcecb427..18cf976c69b 100644 --- a/yarn-project/end-to-end/src/fixtures/utils.ts +++ b/yarn-project/end-to-end/src/fixtures/utils.ts @@ -11,8 +11,6 @@ import { createPXEClient, getSandboxAccountsWallets, } from '@aztec/aztec.js'; -import { CircuitsWasm, GeneratorIndex } from '@aztec/circuits.js'; -import { pedersenPlookupCompressWithHashIndex } from '@aztec/circuits.js/barretenberg'; import { DeployL1Contracts, L1ContractArtifactsForDeployment, @@ -551,16 +549,3 @@ export const expectUnencryptedLogsFromLastBlockToBe = async (pxe: PXE, logMessag expect(asciiLogs).toStrictEqual(logMessages); }; - -/** - * Hash a payload to generate a signature on an account contract - * @param payload - payload to hash - * @returns the hashed message - */ -export const hashPayload = async (payload: Fr[]) => { - return pedersenPlookupCompressWithHashIndex( - await CircuitsWasm.get(), - payload.map(fr => fr.toBuffer()), - GeneratorIndex.SIGNATURE_PAYLOAD, - ); -}; diff --git a/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts b/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts index 4e090f1a0d3..b1d70709416 100644 --- a/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts +++ b/yarn-project/end-to-end/src/uniswap_trade_on_l1_from_l2.test.ts @@ -1,5 +1,5 @@ -import { AccountWallet, AztecAddress } from '@aztec/aztec.js'; -import { Fr, FunctionSelector } from '@aztec/circuits.js'; +import { AccountWallet, AztecAddress, computeAuthWitMessageHash } from '@aztec/aztec.js'; +import { Fr } from '@aztec/circuits.js'; import { deployL1Contract } from '@aztec/ethereum'; import { EthAddress } from '@aztec/foundation/eth-address'; import { DebugLogger } from '@aztec/foundation/log'; @@ -10,7 +10,7 @@ import { AztecNode, PXE, TxStatus } from '@aztec/types'; import { getContract, parseEther } from 'viem'; import { CrossChainTestHarness } from './fixtures/cross_chain_test_harness.js'; -import { delay, hashPayload, setup } from './fixtures/utils.js'; +import { delay, setup } from './fixtures/utils.js'; // PSA: This tests works on forked mainnet. There is a dump of the data in `dumpedState` such that we // don't need to burn through RPC requests. @@ -179,15 +179,12 @@ describe('uniswap_trade_on_l1_from_l2', () => { // 3. Owner gives uniswap approval to unshield funds to self on its behalf logger('Approving uniswap to unshield funds to self on my behalf'); const nonceForWETHUnshieldApproval = new Fr(2n); - const unshieldToUniswapMessageHash = await hashPayload([ - uniswapL2Contract.address.toField(), - wethCrossChainHarness.l2Token.address.toField(), - FunctionSelector.fromSignature('unshield((Field),(Field),Field,Field)').toField(), - ownerAddress.toField(), - uniswapL2Contract.address.toField(), - new Fr(wethAmountToBridge), - nonceForWETHUnshieldApproval, - ]); + const unshieldToUniswapMessageHash = await computeAuthWitMessageHash( + uniswapL2Contract.address, + wethCrossChainHarness.l2Token.methods + .unshield(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHUnshieldApproval) + .request(), + ); await ownerWallet.createAuthWitness(Fr.fromBuffer(unshieldToUniswapMessageHash)); // 4. Swap on L1 - sends L2 to L1 message to withdraw WETH to L1 and another message to swap assets. @@ -315,15 +312,12 @@ describe('uniswap_trade_on_l1_from_l2', () => { // 3. Owner gives uniswap approval to transfer funds on its behalf const nonceForWETHTransferApproval = new Fr(2n); - const transferMessageHash = await hashPayload([ - uniswapL2Contract.address.toField(), - wethCrossChainHarness.l2Token.address.toField(), - FunctionSelector.fromSignature('transfer_public((Field),(Field),Field,Field)').toField(), - ownerAddress.toField(), - uniswapL2Contract.address.toField(), - new Fr(wethAmountToBridge), - nonceForWETHTransferApproval, - ]); + const transferMessageHash = await computeAuthWitMessageHash( + uniswapL2Contract.address, + wethCrossChainHarness.l2Token.methods + .transfer_public(ownerAddress, uniswapL2Contract.address, wethAmountToBridge, nonceForWETHTransferApproval) + .request(), + ); await ownerWallet.setPublicAuth(transferMessageHash, true).send().wait(); // 4. Swap on L1 - sends L2 to L1 message to withdraw WETH to L1 and another message to swap assets. @@ -333,30 +327,7 @@ describe('uniswap_trade_on_l1_from_l2', () => { // 4.1 Owner approves user to swap on their behalf: const nonceForSwap = new Fr(3n); - const swapMessageHash = await hashPayload([ - sponsorAddress.toField(), - uniswapL2Contract.address.toField(), - FunctionSelector.fromSignature( - 'swap_public((Field),(Field),Field,(Field),Field,Field,Field,(Field),Field,Field,(Field),(Field),Field)', - ).toField(), - ownerAddress.toField(), - wethCrossChainHarness.l2Bridge.address.toField(), - new Fr(wethAmountToBridge), - daiCrossChainHarness.l2Bridge.address.toField(), - nonceForWETHTransferApproval, - new Fr(uniswapFeeTier), - new Fr(minimumOutputAmount), - ownerAddress.toField(), - secretHashForDepositingSwappedDai, - new Fr(deadlineForDepositingSwappedDai), - ownerEthAddress.toField(), - ownerEthAddress.toField(), - nonceForSwap, - ]); - await ownerWallet.setPublicAuth(swapMessageHash, true).send().wait(); - - // 4.2 Call swap_public from user2 on behalf of owner - const withdrawReceipt = await uniswapL2Contract + const action = uniswapL2Contract .withWallet(sponsorWallet) .methods.swap_public( ownerAddress, @@ -372,9 +343,12 @@ describe('uniswap_trade_on_l1_from_l2', () => { ownerEthAddress, ownerEthAddress, nonceForSwap, - ) - .send() - .wait(); + ); + const swapMessageHash = await computeAuthWitMessageHash(sponsorAddress, action.request()); + await ownerWallet.setPublicAuth(swapMessageHash, true).send().wait(); + + // 4.2 Call swap_public from user2 on behalf of owner + const withdrawReceipt = await action.send().wait(); expect(withdrawReceipt.status).toBe(TxStatus.MINED); // check weth balance of owner on L2 (we first bridged `wethAmountToBridge` into L2 and now withdrew it!) diff --git a/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/Nargo.toml b/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/Nargo.toml index b0e030b7808..e8c766ac634 100644 --- a/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/Nargo.toml +++ b/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/Nargo.toml @@ -6,3 +6,4 @@ type = "contract" [dependencies] aztec = { path = "../../../../aztec-nr/aztec" } +authwit = { path = "../../../../aztec-nr/authwit" } \ No newline at end of file diff --git a/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr index b03e055c956..be8a8dd2f12 100644 --- a/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/ecdsa_account_contract/src/main.nr @@ -8,16 +8,18 @@ contract EcdsaAccount { use dep::aztec::{ abi::CallContext, context::{PrivateContext, PublicContext, Context}, - entrypoint::{EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE}, log::emit_encrypted_log, note::{ note_header::NoteHeader, utils as note_utils, }, oracle::get_public_key::get_public_key, - oracle::auth_witness::get_auth_witness, state_vars::immutable_singleton::ImmutableSingleton, + }; + use dep::authwit:: { + entrypoint::{ EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE }, account::AccountActions, + auth_witness::get_auth_witness, }; use crate::ecdsa_public_key_note::{ diff --git a/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/Nargo.toml b/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/Nargo.toml index 4ac82f6b7e6..eb36ef983f1 100644 --- a/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/Nargo.toml +++ b/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/Nargo.toml @@ -5,4 +5,5 @@ compiler_version = "0.1" type = "contract" [dependencies] -aztec = { path = "../../../../aztec-nr/aztec" } \ No newline at end of file +aztec = { path = "../../../../aztec-nr/aztec" } +authwit = { path = "../../../../aztec-nr/authwit" } \ No newline at end of file diff --git a/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/src/main.nr index 851b9e8b528..24b25e9cdb6 100644 --- a/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/schnorr_account_contract/src/main.nr @@ -8,12 +8,15 @@ contract SchnorrAccount { use dep::aztec::{ context::{PrivateContext, PublicContext, Context}, - entrypoint::{ENTRYPOINT_PAYLOAD_SIZE, EntrypointPayload}, log::emit_encrypted_log, note::{ note_header::NoteHeader, utils as note_utils }, - oracle::{ get_public_key::get_public_key, auth_witness::get_auth_witness }, + oracle::get_public_key::get_public_key, state_vars::immutable_singleton::ImmutableSingleton, + }; + use dep::authwit:: { + entrypoint::{ EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE }, account::AccountActions, + auth_witness::get_auth_witness, }; use crate::public_key_note::{PublicKeyNote, PublicKeyNoteMethods, PUBLIC_KEY_NOTE_LEN}; diff --git a/yarn-project/noir-contracts/src/contracts/schnorr_hardcoded_account_contract/Nargo.toml b/yarn-project/noir-contracts/src/contracts/schnorr_hardcoded_account_contract/Nargo.toml index 586e246467d..a248fd0c1d3 100644 --- a/yarn-project/noir-contracts/src/contracts/schnorr_hardcoded_account_contract/Nargo.toml +++ b/yarn-project/noir-contracts/src/contracts/schnorr_hardcoded_account_contract/Nargo.toml @@ -5,4 +5,5 @@ compiler_version = "0.1" type = "contract" [dependencies] -aztec = { path = "../../../../aztec-nr/aztec" } \ No newline at end of file +aztec = { path = "../../../../aztec-nr/aztec" } +authwit = { path = "../../../../aztec-nr/authwit" } \ No newline at end of file diff --git a/yarn-project/noir-contracts/src/contracts/schnorr_hardcoded_account_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/schnorr_hardcoded_account_contract/src/main.nr index 562e403d1f7..bfaa0b285e4 100644 --- a/yarn-project/noir-contracts/src/contracts/schnorr_hardcoded_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/schnorr_hardcoded_account_contract/src/main.nr @@ -3,12 +3,15 @@ contract SchnorrHardcodedAccount { use dep::std; use dep::aztec::{ - entrypoint::{ EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE }, abi::{ PrivateCircuitPublicInputs, PrivateContextInputs, Hasher }, types::{ vec::BoundedVec, point::Point }, context::PrivateContext, + }; + + use dep::authwit:: { + entrypoint::{ EntrypointPayload, ENTRYPOINT_PAYLOAD_SIZE }, account::AccountActions, - oracle::auth_witness::get_auth_witness, + auth_witness::get_auth_witness, }; global public_key_x: Field = 0x0ede3d33c920df8fdf43f3e39ed38b0882c25b056620ef52fd016fe811aa2443; diff --git a/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/Nargo.toml b/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/Nargo.toml index d02343f7772..58fb759e513 100644 --- a/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/Nargo.toml +++ b/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/Nargo.toml @@ -6,3 +6,4 @@ type = "contract" [dependencies] aztec = { path = "../../../../aztec-nr/aztec" } +authwit = { path = "../../../../aztec-nr/authwit" } \ No newline at end of file diff --git a/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr b/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr index 0fddb5aa238..878da45b183 100644 --- a/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr +++ b/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/src/auth_oracle.nr @@ -1,5 +1,5 @@ use dep::aztec::types::point::Point; -use dep::aztec::oracle::auth_witness; +use dep::authwit::auth_witness; struct AuthWitness { owner: Point, diff --git a/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/src/main.nr index 9380c99187e..83a9efb4e85 100644 --- a/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/schnorr_single_key_account_contract/src/main.nr @@ -6,11 +6,11 @@ contract SchnorrSingleKeyAccount { hash::pedersen_with_separator, option::Option, }; + use dep::aztec::context::{ PrivateContext, PublicContext, Context }; - use dep::aztec::{ + use dep::authwit::{ entrypoint::EntrypointPayload, account::AccountActions, - context::{ PrivateContext, PublicContext, Context }, }; use crate::{ util::recover_address, auth_oracle::get_auth_witness }; diff --git a/yarn-project/noir-contracts/src/contracts/token_contract/Nargo.toml b/yarn-project/noir-contracts/src/contracts/token_contract/Nargo.toml index 6bc97909172..1da51baf184 100644 --- a/yarn-project/noir-contracts/src/contracts/token_contract/Nargo.toml +++ b/yarn-project/noir-contracts/src/contracts/token_contract/Nargo.toml @@ -7,4 +7,5 @@ type = "contract" [dependencies] aztec = { path = "../../../../aztec-nr/aztec" } value_note = { path = "../../../../aztec-nr/value-note"} -safe_math = { path = "../../../../aztec-nr/safe-math" } \ No newline at end of file +safe_math = { path = "../../../../aztec-nr/safe-math" } +authwit = { path = "../../../../aztec-nr/authwit" } \ No newline at end of file diff --git a/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr index 8ca0b4eb0a6..0a0f8fd5e2e 100644 --- a/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/token_contract/src/main.nr @@ -22,7 +22,7 @@ contract Token { utils as note_utils, }, context::{PrivateContext, PublicContext, Context}, - hash::{compute_message_hash, compute_secret_hash}, + hash::{compute_secret_hash}, state_vars::{map::Map, public_state::PublicState, set::Set}, types::type_serialization::{ field_serialization::{FieldSerializationMethods, FIELD_SERIALIZED_LEN}, @@ -31,7 +31,13 @@ contract Token { }, types::address::{AztecAddress}, oracle::compute_selector::compute_selector, - auth::{assert_valid_message_for, assert_valid_public_message_for} + }; + + use dep::authwit::{ + auth::{ + assert_current_call_valid_authwit, + assert_current_call_valid_authwit_public, + }, }; use crate::types::{ @@ -193,8 +199,7 @@ contract Token { ) -> Field { if (from.address != context.msg_sender()) { // The redeem is only spendable once, so we need to ensure that you cannot insert multiple shields from the same message. - let message_field = compute_message_hash([context.msg_sender(), context.this_address(), context.selector(), from.address, amount, secret_hash, nonce]); - assert_valid_public_message_for(&mut context, from.address, message_field); + assert_current_call_valid_authwit_public(&mut context, from); } else { assert(nonce == 0, "invalid nonce"); } @@ -220,8 +225,7 @@ contract Token { nonce: Field, ) -> Field { if (from.address != context.msg_sender()) { - let message_field = compute_message_hash([context.msg_sender(), context.this_address(), context.selector(), from.address, to.address, amount, nonce]); - assert_valid_public_message_for(&mut context, from.address, message_field); + assert_current_call_valid_authwit_public(&mut context, from); } else { assert(nonce == 0, "invalid nonce"); } @@ -245,8 +249,7 @@ contract Token { nonce: Field, ) -> Field { if (from.address != context.msg_sender()) { - let message_field = compute_message_hash([context.msg_sender(), context.this_address(), context.selector(), from.address, amount, nonce]); - assert_valid_public_message_for(&mut context, from.address, message_field); + assert_current_call_valid_authwit_public(&mut context, from); } else { assert(nonce == 0, "invalid nonce"); } @@ -291,8 +294,7 @@ contract Token { nonce: Field, ) -> Field { if (from.address != context.msg_sender()) { - let message_field = compute_message_hash([context.msg_sender(), context.this_address(), context.selector(), from.address, to.address, amount, nonce]); - assert_valid_message_for(&mut context, from.address, message_field); + assert_current_call_valid_authwit(&mut context, from); } else { assert(nonce == 0, "invalid nonce"); } @@ -315,8 +317,7 @@ contract Token { nonce: Field, ) -> Field { if (from.address != context.msg_sender()) { - let message_field = compute_message_hash([context.msg_sender(), context.this_address(), context.selector(), from.address, to.address, amount, nonce]); - assert_valid_message_for(&mut context, from.address, message_field); + assert_current_call_valid_authwit(&mut context, from); } else { assert(nonce == 0, "invalid nonce"); } @@ -337,8 +338,7 @@ contract Token { nonce: Field, ) -> Field { if (from.address != context.msg_sender()) { - let message_field = compute_message_hash([context.msg_sender(), context.this_address(), context.selector(), from.address, amount, nonce]); - assert_valid_message_for(&mut context, from.address, message_field); + assert_current_call_valid_authwit(&mut context, from); } else { assert(nonce == 0, "invalid nonce"); } diff --git a/yarn-project/noir-contracts/src/contracts/uniswap_contract/Nargo.toml b/yarn-project/noir-contracts/src/contracts/uniswap_contract/Nargo.toml index 110b8eb98fe..d0ffea4ccf7 100644 --- a/yarn-project/noir-contracts/src/contracts/uniswap_contract/Nargo.toml +++ b/yarn-project/noir-contracts/src/contracts/uniswap_contract/Nargo.toml @@ -6,3 +6,4 @@ type = "contract" [dependencies] aztec = { path = "../../../../aztec-nr/aztec" } +authwit = { path = "../../../../aztec-nr/authwit" } \ No newline at end of file diff --git a/yarn-project/noir-contracts/src/contracts/uniswap_contract/src/main.nr b/yarn-project/noir-contracts/src/contracts/uniswap_contract/src/main.nr index e92dd734d17..c71fdd4b662 100644 --- a/yarn-project/noir-contracts/src/contracts/uniswap_contract/src/main.nr +++ b/yarn-project/noir-contracts/src/contracts/uniswap_contract/src/main.nr @@ -6,11 +6,8 @@ mod util; // Uses the token bridge contract, which tells which input token we need to talk to and handles the exit funds to L1 contract Uniswap { use dep::aztec::{ - auth::{IS_VALID_SELECTOR, assert_valid_public_message_for}, context::{PrivateContext, PublicContext, Context}, - hash::compute_message_hash, - oracle::compute_selector::compute_selector, - oracle::context::get_portal_address, + oracle::{compute_selector::compute_selector, context::get_portal_address}, state_vars::{map::Map, public_state::PublicState}, types::address::{AztecAddress, EthereumAddress}, types::type_serialization::bool_serialization::{ @@ -20,6 +17,8 @@ contract Uniswap { FieldSerializationMethods, FIELD_SERIALIZED_LEN, }, }; + + use dep::authwit::auth::{IS_VALID_SELECTOR, assert_current_call_valid_authwit_public, compute_authwit_message_hash}; use crate::interfaces::{Token, TokenBridge}; use crate::util::{compute_swap_private_content_hash, compute_swap_public_content_hash}; @@ -72,30 +71,7 @@ contract Uniswap { ) -> Field { if (sender.address != context.msg_sender()) { - // if someone else is calling on swap on sender's behalf, they need to have authorisation to do so: - let selector = compute_selector( - "swap_public((Field),(Field),Field,(Field),Field,Field,Field,(Field),Field,Field,(Field),(Field),Field)" - ); - let message_field = compute_message_hash([ - context.msg_sender(), - context.this_address(), - selector, - sender.address, - input_asset_bridge.address, - input_amount, - output_asset_bridge.address, - nonce_for_transfer_approval, - uniswap_fee_tier, - minimum_output_amount, - recipient.address, - secret_hash_for_L1_to_l2_message, - deadline_for_L1_to_l2_message, - canceller_for_L1_to_L2_message.address, - caller_on_L1.address, - nonce_for_swap_approval, - ]); - // this also emits a nullifier for the message - assert_valid_public_message_for(&mut context,sender.address,message_field); + assert_current_call_valid_authwit_public(&mut context, sender); } let input_asset = AztecAddress::new(TokenBridge::at(input_asset_bridge.address).token(context)); @@ -230,7 +206,7 @@ contract Uniswap { // approve bridge to burn this contract's funds (required when exiting on L1, as it burns funds on L2): let nonce_for_burn_approval = storage.nonce_for_burn_approval.read(); let selector = compute_selector("burn_public((Field),Field,Field)"); - let message_hash = compute_message_hash([token_bridge.address, token.address, selector, context.this_address(), amount, nonce_for_burn_approval]); + let message_hash = compute_authwit_message_hash(token_bridge, token, selector, [context.this_address(), amount, nonce_for_burn_approval]); storage.approved_action.at(message_hash).write(true); // increment nonce_for_burn_approval so it won't be used again