Skip to content

Commit

Permalink
feat(avm): make authwit work with avm
Browse files Browse the repository at this point in the history
  • Loading branch information
fcarreiro committed Apr 5, 2024
1 parent 0d29922 commit 425f059
Show file tree
Hide file tree
Showing 8 changed files with 79 additions and 20 deletions.
16 changes: 12 additions & 4 deletions noir-projects/aztec-nr/authwit/src/auth.nr
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,10 @@ 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}, hash::hash_args_array};
use dep::aztec::{
context::{PrivateContext, PublicContext, Context, interface::{ContextInterface, PublicContextInterface}},
hash::hash_args_array
};

global IS_VALID_SELECTOR = 0xabf64ad4; // 4 first bytes of keccak256("IS_VALID()")

Expand All @@ -18,10 +21,15 @@ 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<TPublicContext>(
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(on_behalf_of, function_selector, [inner_hash])[0];
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])[0];
assert(result == IS_VALID_SELECTOR, "Message not authorized by account");
}
// docs:end:assert_current_call_valid_authwit_public
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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()
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,4 +6,5 @@ type = "contract"

[dependencies]
aztec = { path = "../../../aztec-nr/aztec" }
compressed_string = { path = "../../../aztec-nr/compressed-string" }
compressed_string = { path = "../../../aztec-nr/compressed-string" }
authwit = { path = "../../../aztec-nr/authwit" }
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -252,6 +253,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
************************************************************************/
Expand Down
1 change: 1 addition & 0 deletions yarn-project/end-to-end/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"clean": "rm -rf ./dest .tsbuildinfo",
"formatting": "run -T prettier --check ./src \"!src/web/main.js\" && run -T eslint ./src",
"formatting:fix": "run -T eslint --fix ./src && run -T prettier -w ./src",
"test:lean": "DEBUG='aztec:*,-*avm_simulator:memory,-*avm_simulator:core*' NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --runInBand --testTimeout=60000 --forceExit",
"test": "DEBUG='aztec:*' NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --runInBand --testTimeout=60000 --forceExit",
"test:integration": "concurrently -k -s first -c reset,dim -n test,anvil \"yarn test:integration:run\" \"anvil\"",
"test:integration:run": "NODE_NO_WARNINGS=1 node --experimental-vm-modules ../node_modules/.bin/jest --no-cache --runInBand --config jest.integration.config.json"
Expand Down
63 changes: 49 additions & 14 deletions yarn-project/end-to-end/src/e2e_avm_simulator.test.ts
Original file line number Diff line number Diff line change
@@ -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<void>;

beforeAll(async () => {
({ teardown, wallet } = await setup());
await publicDeployAccounts(wallet, [wallet]);
}, 100_000);

afterAll(() => teardown());
Expand Down Expand Up @@ -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();
// });
Expand All @@ -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]);
});
});
});
});
});
Expand Down
3 changes: 3 additions & 0 deletions yarn-project/simulator/src/avm/opcodes/external_calls.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,11 +78,14 @@ abstract class ExternalCall extends Instruction {
const pxContext = createPublicExecutionContext(nestedContext, calldata);
const pxResults = await executePublicFunction(pxContext, /*nested=*/ true);
const nestedCallResults: AvmContractCallResults = convertPublicExecutionResult(pxResults);

adjustAvmContextFromPublicExecutionResult(nestedContext, pxResults);
const nestedPersistableState = nestedContext.persistableState;
// const nestedContext = context.createNestedContractCallContext(
// callAddress.toFr(),
// calldata,
// allocatedGas,
// this.type,
// FunctionSelector.fromField(functionSelector),
// );
// const nestedCallResults: AvmContractCallResults = await new AvmSimulator(nestedContext).execute();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -245,6 +245,7 @@ export class PublicExecutionContext extends TypedOracle {
if (!this.header.globalVariables.blockNumber.equals(new Fr(blockNumber))) {
throw new Error(`Public execution oracle can only access nullifier membership witnesses for the current block`);
}
this.log(`Getting nullifier membership witness for nullifier=${nullifier.toString()}`);
return await this.commitmentsDb.getNullifierMembershipWitnessAtLatestBlock(nullifier);
}

Expand Down

0 comments on commit 425f059

Please sign in to comment.