diff --git a/noir-projects/aztec-nr/authwit/src/auth.nr b/noir-projects/aztec-nr/authwit/src/auth.nr index 4e97aebe2b35..d38ff2bbf78a 100644 --- a/noir-projects/aztec-nr/authwit/src/auth.nr +++ b/noir-projects/aztec-nr/authwit/src/auth.nr @@ -2,7 +2,13 @@ use dep::aztec::protocol_types::{ abis::function_selector::FunctionSelector, address::AztecAddress, constants::{GENERATOR_INDEX__AUTHWIT_INNER, GENERATOR_INDEX__AUTHWIT_OUTER}, hash::pedersen_hash }; -use dep::aztec::{context::{PrivateContext, PublicContext, Context, gas::GasOpts}, hash::hash_args_array}; +use dep::aztec::{ + context::{ + PrivateContext, PublicContext, Context, gas::GasOpts, + interface::{ContextInterface, PublicContextInterface} +}, + hash::hash_args_array +}; global IS_VALID_SELECTOR = 0xabf64ad4; // 4 first bytes of keccak256("IS_VALID()") @@ -18,10 +24,16 @@ pub fn assert_current_call_valid_authwit(context: &mut PrivateContext, on_behalf // docs:start:assert_current_call_valid_authwit_public // Assert that `on_behalf_of` have authorized the current call in a public context -pub fn assert_current_call_valid_authwit_public(context: &mut PublicContext, on_behalf_of: AztecAddress) { +pub fn assert_current_call_valid_authwit_public( + context: &mut TPublicContext, + on_behalf_of: AztecAddress +) where TPublicContext: ContextInterface + PublicContextInterface { let function_selector = FunctionSelector::from_signature("spend_public_authwit(Field)"); - let inner_hash = compute_inner_authwit_hash([context.msg_sender().to_field(), context.selector().to_field(), context.args_hash]); - let result = context.call_public_function( + let inner_hash = compute_inner_authwit_hash( + [(*context).msg_sender().to_field(), (*context).selector().to_field(), (*context).get_args_hash()] + ); + let result = PublicContextInterface::call_public_function( + context, on_behalf_of, function_selector, [inner_hash], diff --git a/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr index d2557a38a8d3..a71cf2a1de44 100644 --- a/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_initializer_test_contract/src/main.nr @@ -17,7 +17,8 @@ contract AvmInitializerTest { storage.immutable.initialize(42); } - unconstrained fn view_storage_immutable() -> pub Field { + #[aztec(public-vm)] + fn read_storage_immutable() -> pub Field { storage.immutable.read() } } diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml index dd0d58eea3b6..dff79424f9e5 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/Nargo.toml @@ -6,4 +6,5 @@ type = "contract" [dependencies] aztec = { path = "../../../aztec-nr/aztec" } -compressed_string = { path = "../../../aztec-nr/compressed-string" } \ No newline at end of file +compressed_string = { path = "../../../aztec-nr/compressed-string" } +authwit = { path = "../../../aztec-nr/authwit" } diff --git a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr index 3161a7ff39bb..33a7d095cb73 100644 --- a/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -37,6 +37,7 @@ contract AvmTest { use dep::aztec::protocol_types::traits::ToField; use dep::aztec::protocol_types::constants::RETURN_VALUES_LENGTH; use dep::compressed_string::CompressedString; + use dep::authwit::{auth::{assert_current_call_valid_authwit, assert_current_call_valid_authwit_public}}; // avm lib use dep::aztec::avm::hash::{keccak256, poseidon, sha256}; @@ -250,6 +251,14 @@ contract AvmTest { assert(ci.is_some()); } + /************************************************************************ + * Authwit functions + ************************************************************************/ + #[aztec(public-vm)] + fn test_authwit_send_money(from: AztecAddress, _to: AztecAddress, _amount: Field) { + assert_current_call_valid_authwit_public(&mut context, from); + } + /************************************************************************ * AvmContext functions ************************************************************************/ diff --git a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts index a40731b019ac..f7c7dadef8da 100644 --- a/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts +++ b/yarn-project/end-to-end/src/e2e_avm_simulator.test.ts @@ -1,20 +1,21 @@ -import { AztecAddress, Fr, FunctionSelector, TxStatus, type Wallet } from '@aztec/aztec.js'; +import { type AccountWallet, AztecAddress, Fr, FunctionSelector, TxStatus } from '@aztec/aztec.js'; import { AvmInitializerTestContract, AvmTestContract } from '@aztec/noir-contracts.js'; import { jest } from '@jest/globals'; -import { setup } from './fixtures/utils.js'; +import { publicDeployAccounts, setup } from './fixtures/utils.js'; const TIMEOUT = 100_000; describe('e2e_avm_simulator', () => { jest.setTimeout(TIMEOUT); - let wallet: Wallet; + let wallet: AccountWallet; let teardown: () => Promise; beforeAll(async () => { ({ teardown, wallet } = await setup()); + await publicDeployAccounts(wallet, [wallet]); }, 100_000); afterAll(() => teardown()); @@ -78,7 +79,8 @@ describe('e2e_avm_simulator', () => { expect(await avmContract.methods.call_acvm_from_avm().simulate()).toEqual([123456n, 0n, 0n, 0n]); }); - // Cannot work because ACVM does not support pending nullifiers. + // This will not work because the ACVM does not see pending nullifiers. + // // Cannot work because ACVM does not support pending nullifiers. // it('AVM->ACVM nullifiers work (pending)', async () => { // await avmContract.methods.avm_to_acvm_nullifier().send().wait(); // }); @@ -96,20 +98,53 @@ describe('e2e_avm_simulator', () => { .avm_to_acvm_call(FunctionSelector.fromSignature('assert_unsiloed_nullifier_acvm(Field)'), nullifier) .send() .wait(); + // }); }); - }); - }); - describe('AvmInitializerTestContract', () => { - let avmContract: AvmInitializerTestContract; + describe('Authwit', () => { + it('Works if authwit provided', async () => { + const recipient = AztecAddress.random(); + const action = avmContract.methods.test_authwit_send_money( + /*from=*/ wallet.getCompleteAddress(), + recipient, + 100, + ); + let tx = await wallet + .setPublicAuthWit({ caller: wallet.getCompleteAddress().address, action }, /*authorized=*/ true) + .send() + .wait(); + expect(tx.status).toEqual(TxStatus.MINED); + + tx = await avmContract.methods + .test_authwit_send_money(/*from=*/ wallet.getCompleteAddress(), recipient, 100) + .send() + .wait(); + expect(tx.status).toEqual(TxStatus.MINED); + }); + + it('Fails if authwit not provided', async () => { + await expect( + async () => + await avmContract.methods + .test_authwit_send_money(/*from=*/ wallet.getCompleteAddress(), /*to=*/ AztecAddress.random(), 100) + .send() + .wait(), + ).rejects.toThrow(/Message not authorized by account/); + }); + }); - beforeEach(async () => { - avmContract = await AvmInitializerTestContract.deploy(wallet).send().deployed(); - }, 50_000); + describe('AvmInitializerTestContract', () => { + let avmContract: AvmInitializerTestContract; - describe('Storage', () => { - it('Read immutable (initialized) storage (Field)', async () => { - expect(await avmContract.methods.view_storage_immutable().simulate()).toEqual(42n); + beforeEach(async () => { + avmContract = await AvmInitializerTestContract.deploy(wallet).send().deployed(); + }, 50_000); + + describe('Storage', () => { + it('Read immutable (initialized) storage (Field)', async () => { + expect(await avmContract.methods.read_storage_immutable().simulate()).toEqual([42n, 0n, 0n, 0n]); + }); + }); }); }); }); diff --git a/yarn-project/simulator/src/avm/opcodes/external_calls.ts b/yarn-project/simulator/src/avm/opcodes/external_calls.ts index 87aa3197d520..2d25634055ab 100644 --- a/yarn-project/simulator/src/avm/opcodes/external_calls.ts +++ b/yarn-project/simulator/src/avm/opcodes/external_calls.ts @@ -83,6 +83,8 @@ abstract class ExternalCall extends Instruction { // const nestedContext = context.createNestedContractCallContext( // callAddress.toFr(), // calldata, + // allocatedGas, + // this.type, // FunctionSelector.fromField(functionSelector), // ); // const nestedCallResults: AvmContractCallResults = await new AvmSimulator(nestedContext).execute();