From 93ff6a42c5bc52a2b58bb6e78d0d2c35e05c7349 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Fri, 2 Feb 2024 23:21:39 +0000 Subject: [PATCH 1/6] feat(avm): access execution environment within noir contracts --- avm-transpiler/src/transpile.rs | 28 ++++++++++++++++++- .../src/avm/avm_simulator.test.ts | 27 ++++++++++++++++++ yarn-project/aztec-nr/aztec/src/avm.nr | 2 ++ .../aztec-nr/aztec/src/avm/context.nr | 22 +++++++++++++++ .../aztec-nr/aztec/src/avm/env_getters.nr | 5 ++++ yarn-project/aztec-nr/aztec/src/lib.nr | 1 + .../contracts/avm_test_contract/src/main.nr | 8 ++++++ 7 files changed, 92 insertions(+), 1 deletion(-) create mode 100644 yarn-project/aztec-nr/aztec/src/avm.nr create mode 100644 yarn-project/aztec-nr/aztec/src/avm/context.nr create mode 100644 yarn-project/aztec-nr/aztec/src/avm/env_getters.nr diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 04af018da1d6..d9abb8775d47 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -1,7 +1,7 @@ use acvm::acir::brillig::Opcode as BrilligOpcode; use acvm::acir::circuit::brillig::Brillig; -use acvm::brillig_vm::brillig::{BinaryFieldOp, BinaryIntOp}; +use acvm::brillig_vm::brillig::{BinaryFieldOp, BinaryIntOp, ValueOrArray}; use crate::instructions::{ AvmInstruction, AvmOperand, AvmTypeTag, FIRST_OPERAND_INDIRECT, ZEROTH_OPERAND_INDIRECT, @@ -252,6 +252,32 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { ], ..Default::default() }); + }, + BrilligOpcode::ForeignCall { function, destinations, inputs } => { + println!("{}", function); + match function.as_str() { + "address" => { + assert!(inputs.len() == 0); + assert!(destinations.len() == 1); + let dest_offset_maybe = destinations[0]; + let dest_offset = match dest_offset_maybe { + ValueOrArray::MemoryAddress(dest_offset) => dest_offset.0, + _ => panic!("ForeignCall address destination should be a single value"), + }; + + avm_instrs.push(AvmInstruction { + opcode: AvmOpcode::ADDRESS, + indirect: Some(0), + operands: vec![ + AvmOperand::U32 { value: dest_offset as u32}, + ], + ..Default::default() + }); + } + _ => panic!("Transpiler doesn't know how to process ForeignCall function {:?}", function), + } + println!("{:?}", destinations); + println!("{:?}", inputs); } _ => panic!( "Transpiler doesn't know how to process {:?} brillig instruction", diff --git a/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts b/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts index 62a2c1ab56d0..59758c5aad2b 100644 --- a/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts @@ -1,3 +1,4 @@ +import { AztecAddress } from '@aztec/foundation/aztec-address'; import { Fr } from '@aztec/foundation/fields'; import { AvmTestContractArtifact } from '@aztec/noir-contracts'; @@ -8,8 +9,16 @@ import { AvmSimulator } from './avm_simulator.js'; import { initContext, initExecutionEnvironment } from './fixtures/index.js'; import { Add, CalldataCopy, Return } from './opcodes/index.js'; import { encodeToBytecode } from './serialization/bytecode_serialization.js'; +import { MockProxy, mock } from 'jest-mock-extended'; +import { AvmWorldStateJournal } from './journal/journal.js'; describe('avm', () => { + let journal: MockProxy; + + beforeEach(() => { + journal = mock(); + }); + it('Should execute bytecode that performs basic addition', async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; @@ -54,5 +63,23 @@ describe('avm', () => { expect(returnData.length).toBe(1); expect(returnData).toEqual([new Fr(3)]); }); + + it('Should execute contract function that returns data from the environment', async () => { + const getterArtifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_accessEnv'); + + // Decode + const instructions = decodeFromBytecode(Buffer.from(getterArtifact!.bytecode, 'base64')); + + // Execute + const address = AztecAddress.fromField(new Fr(1234n)); + const context = new AvmMachineState(initExecutionEnvironment({ address })); + const avmReturnData = await executeAvm(context, journal, instructions); + + expect(avmReturnData.reverted).toBe(false); + + const returnData = avmReturnData.output; + expect(returnData.length).toBe(1); + expect(returnData).toEqual([address]); + }); }); }); diff --git a/yarn-project/aztec-nr/aztec/src/avm.nr b/yarn-project/aztec-nr/aztec/src/avm.nr new file mode 100644 index 000000000000..42deea963351 --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/avm.nr @@ -0,0 +1,2 @@ +mod context; +mod env_getters; diff --git a/yarn-project/aztec-nr/aztec/src/avm/context.nr b/yarn-project/aztec-nr/aztec/src/avm/context.nr new file mode 100644 index 000000000000..5307bd6a5ce7 --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/avm/context.nr @@ -0,0 +1,22 @@ +use crate::avm::env_getters::{ + get_address, + get_storage_address +}; + +// Getters that will be converted by the transpiler into their +// own opcodes +struct AvmContext {} + +impl AvmContext { + pub fn new() -> Self { + Self {} + } + + pub fn address() -> Field { + get_address() + } + + pub fn storage_address() -> Field { + get_storage_address() + } +} diff --git a/yarn-project/aztec-nr/aztec/src/avm/env_getters.nr b/yarn-project/aztec-nr/aztec/src/avm/env_getters.nr new file mode 100644 index 000000000000..1600e38d3885 --- /dev/null +++ b/yarn-project/aztec-nr/aztec/src/avm/env_getters.nr @@ -0,0 +1,5 @@ +#[oracle(address)] +unconstrained pub fn get_address() -> Field {} + +#[oracle(storage_address)] +unconstrained pub fn get_storage_address() -> Field {} diff --git a/yarn-project/aztec-nr/aztec/src/lib.nr b/yarn-project/aztec-nr/aztec/src/lib.nr index 7a8531601c4f..88866fb2fbcf 100644 --- a/yarn-project/aztec-nr/aztec/src/lib.nr +++ b/yarn-project/aztec-nr/aztec/src/lib.nr @@ -1,4 +1,5 @@ mod abi; +mod avm; mod context; mod hash; mod history; diff --git a/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr index 28dbf5576d07..963f176aa847 100644 --- a/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -6,6 +6,9 @@ contract AvmTest { address::AztecAddress, }; + // avm lib + use dep::aztec::avm::context::AvmContext; + #[aztec(private)] fn constructor() {} @@ -15,6 +18,11 @@ contract AvmTest { argA + argB } + #[aztec(public-vm)] + fn accessEnv() -> pub Field { + AvmContext::address() + } + // Function required for all contracts unconstrained fn compute_note_hash_and_nullifier( _contract_address: AztecAddress, From e9c077afb8fc2dec47a1a023502659bd0c15096f Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Sat, 3 Feb 2024 00:17:25 +0000 Subject: [PATCH 2/6] feat: add tests for all env types --- avm-transpiler/src/transpile.rs | 69 +++++++++----- .../src/avm/avm_simulator.test.ts | 94 ++++++++++++++++--- .../aztec-nr/aztec/src/avm/context.nr | 80 ++++++++++++++-- .../aztec-nr/aztec/src/avm/env_getters.nr | 50 +++++++++- .../contracts/avm_test_contract/src/main.nr | 80 +++++++++++++++- 5 files changed, 323 insertions(+), 50 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index d9abb8775d47..1465c5ce9c51 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -254,32 +254,9 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { }); }, BrilligOpcode::ForeignCall { function, destinations, inputs } => { - println!("{}", function); - match function.as_str() { - "address" => { - assert!(inputs.len() == 0); - assert!(destinations.len() == 1); - let dest_offset_maybe = destinations[0]; - let dest_offset = match dest_offset_maybe { - ValueOrArray::MemoryAddress(dest_offset) => dest_offset.0, - _ => panic!("ForeignCall address destination should be a single value"), - }; - - avm_instrs.push(AvmInstruction { - opcode: AvmOpcode::ADDRESS, - indirect: Some(0), - operands: vec![ - AvmOperand::U32 { value: dest_offset as u32}, - ], - ..Default::default() - }); - } - _ => panic!("Transpiler doesn't know how to process ForeignCall function {:?}", function), - } - println!("{:?}", destinations); - println!("{:?}", inputs); + handle_foreign_call(&mut avm_instrs, function, destinations, inputs); } - _ => panic!( + _ => panic!( "Transpiler doesn't know how to process {:?} brillig instruction", brillig_instr ), @@ -296,6 +273,48 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { bytecode } +fn handle_foreign_call(avm_instrs: &mut Vec, function: &String, destinations: &Vec, inputs: &Vec) { + // For the foreign calls we want to handle, we do not want inputs, as they are getters + assert!(inputs.len() == 0); + assert!(destinations.len() == 1); + let dest_offset_maybe = destinations[0]; + let dest_offset = match dest_offset_maybe { + ValueOrArray::MemoryAddress(dest_offset) => dest_offset.0, + _ => panic!("ForeignCall address destination should be a single value"), + }; + + let opcode = match function.as_str() { + "address" => AvmOpcode::ADDRESS, + "storageAddress" => AvmOpcode::STORAGEADDRESS, + "origin" => AvmOpcode::ORIGIN, + "sender" => AvmOpcode::SENDER, + "portal" => AvmOpcode::PORTAL, + "feePerL1Gas" => AvmOpcode::FEEPERL1GAS, + "feePerL2Gas" => AvmOpcode::FEEPERL2GAS, + "feePerDaGas" => AvmOpcode::FEEPERDAGAS, + "chainId" => AvmOpcode::CHAINID, + "version" => AvmOpcode::VERSION, + "blockNumber" => AvmOpcode::BLOCKNUMBER, + "timestamp" => AvmOpcode::TIMESTAMP, + // "isStaticCall" => AvmOpcode::ISSTATICCALL, + // "isDelegateCall" => AvmOpcode::ISDELEGATECALL, + _ => panic!("Transpiler doesn't know how to process ForeignCall function {:?}", function), + + }; + + avm_instrs.push(AvmInstruction { + opcode, + indirect: Some(0), + operands: vec![ + AvmOperand::U32 { value: dest_offset as u32}, + ], + ..Default::default() + }); + + +} + + /// Compute an array that maps each Brillig pc to an AVM pc. /// This must be done before transpiling to properly transpile jump destinations. /// This is necessary for two reasons: diff --git a/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts b/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts index 59758c5aad2b..1ff99a379d79 100644 --- a/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts @@ -8,9 +8,11 @@ import { TypeTag } from './avm_memory_types.js'; import { AvmSimulator } from './avm_simulator.js'; import { initContext, initExecutionEnvironment } from './fixtures/index.js'; import { Add, CalldataCopy, Return } from './opcodes/index.js'; -import { encodeToBytecode } from './serialization/bytecode_serialization.js'; import { MockProxy, mock } from 'jest-mock-extended'; import { AvmWorldStateJournal } from './journal/journal.js'; +import { decodeFromBytecode, encodeToBytecode } from './serialization/bytecode_serialization.js'; +import { AvmMachineState } from './avm_machine_state.js'; +import { EthAddress } from '@aztec/foundation/eth-address'; describe('avm', () => { let journal: MockProxy; @@ -42,6 +44,7 @@ describe('avm', () => { }); describe('testing transpiled Noir contracts', () => { + // TODO(https://github.com/AztecProtocol/aztec-packages/issues/4361): sync wire format w/transpiler. it('Should execute contract function that performs addition', async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; @@ -64,22 +67,89 @@ describe('avm', () => { expect(returnData).toEqual([new Fr(3)]); }); - it('Should execute contract function that returns data from the environment', async () => { - const getterArtifact = AvmTestContractArtifact.functions.find(f => f.name === 'avm_accessEnv'); + describe("Test env getters from noir contract", () => { + + const testEnvGetter = async (valueName: string, value: any, functionName: string) => { + const getterArtifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!; - // Decode - const instructions = decodeFromBytecode(Buffer.from(getterArtifact!.bytecode, 'base64')); + // Execute + const overrides = {[valueName]: value}; + const context = initContext({ env: initExecutionEnvironment(overrides) }); - // Execute - const address = AztecAddress.fromField(new Fr(1234n)); - const context = new AvmMachineState(initExecutionEnvironment({ address })); - const avmReturnData = await executeAvm(context, journal, instructions); + // Decode bytecode into instructions + const bytecode = Buffer.from(getterArtifact.bytecode, 'base64'); + jest.spyOn(context.worldState.hostStorage.contractsDb, 'getBytecode').mockReturnValue(Promise.resolve(bytecode)); - expect(avmReturnData.reverted).toBe(false); + const results = await new AvmSimulator(context).execute(); - const returnData = avmReturnData.output; + expect(results.reverted).toBe(false); + + const returnData = results.output; expect(returnData.length).toBe(1); - expect(returnData).toEqual([address]); + expect(returnData).toEqual([value.toField()]); + + } + + it('address', async () => { + const address = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('address', address, 'avm_getAddress'); + }); + + it('storageAddress', async () => { + const storageAddress = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('storageAddress', storageAddress, 'avm_getStorageAddress'); + }); + + it('sender', async () => { + const sender = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('sender', sender, 'avm_getSender'); }); + + it('origin', async () => { + const origin = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('origin', origin, 'avm_getOrigin'); + }); + + it('portal', async () => { + const portal = EthAddress.fromField(new Fr(1)); + await testEnvGetter('portal', portal, 'avm_getPortal'); + }); + + it('getFeePerL1Gas', async () => { + const fee = new Fr(1); + await testEnvGetter('feePerL1Gas', fee, 'avm_getFeePerL1Gas'); + }); + + it('getFeePerL2Gas', async () => { + const fee = new Fr(1); + await testEnvGetter('feePerL2Gas', fee, 'avm_getFeePerL2Gas'); + }); + + it('getFeePerDaGas', async () => { + const fee = new Fr(1); + await testEnvGetter('feePerDaGas', fee, 'avm_getFeePerDaGas'); + }); + + // it('chainId', async () => { + // const chainId = new Fr(1); + // await testEnvGetter('chainId', chainId, 'avm_getChainId'); + // }); + + // it('version', async () => { + // const version = new Fr(1); + // await testEnvGetter('version', version, 'avm_getVersion'); + // }); + + // it('blockNumber', async () => { + // const blockNumber = new Fr(1); + // await testEnvGetter('blockNumber', blockNumber, 'avm_getBlockNumber'); + // }); + + // it('timestamp', async () => { + // const timestamp = new Fr(1); + // await testEnvGetter('timestamp', timestamp, 'avm_getTimestamp'); + // }); + }); + }); }); diff --git a/yarn-project/aztec-nr/aztec/src/avm/context.nr b/yarn-project/aztec-nr/aztec/src/avm/context.nr index 5307bd6a5ce7..29011a909865 100644 --- a/yarn-project/aztec-nr/aztec/src/avm/context.nr +++ b/yarn-project/aztec-nr/aztec/src/avm/context.nr @@ -1,22 +1,88 @@ use crate::avm::env_getters::{ get_address, - get_storage_address + get_storage_address, + get_origin, + get_sender, + get_portal, + get_fee_per_l1_gas, + get_fee_per_l2_gas, + get_fee_per_da_gas, + get_chain_id, + get_version, + get_block_number, + get_timestamp, + get_is_static_call, + get_is_delegate_call, +}; + +use dep::protocol_types::address::{ + AztecAddress, + EthAddress, }; // Getters that will be converted by the transpiler into their // own opcodes struct AvmContext {} +// No new function as this struct is entirely static getters impl AvmContext { - pub fn new() -> Self { - Self {} - } - - pub fn address() -> Field { + pub fn address() -> AztecAddress { get_address() } - pub fn storage_address() -> Field { + pub fn storage_address() -> AztecAddress { get_storage_address() } + + pub fn origin() -> AztecAddress { + get_origin() + } + + pub fn sender() -> AztecAddress { + get_sender() + } + + pub fn portal() -> EthAddress { + get_portal() + } + + pub fn fee_per_l1_gas() -> Field { + get_fee_per_l1_gas() + } + + pub fn fee_per_l2_gas() -> Field { + get_fee_per_l2_gas() + } + + pub fn fee_per_da_gas() -> Field { + get_fee_per_da_gas() + } + + pub fn chain_id() -> Field { + get_chain_id() + } + + pub fn version() -> Field { + get_version() + } + + pub fn block_number() -> Field { + get_block_number() + } + + pub fn timestamp() -> Field { + get_timestamp() + } + + // pub fn is_static_call() -> Field { + // get_is_static_call() + // } + + // pub fn is_delegate_call() -> Field { + // get_is_delegate_call() + // } + + // pub fn contract_call_depth() -> Field { + // get_contract_call_depth() + // } } diff --git a/yarn-project/aztec-nr/aztec/src/avm/env_getters.nr b/yarn-project/aztec-nr/aztec/src/avm/env_getters.nr index 1600e38d3885..8d491e567238 100644 --- a/yarn-project/aztec-nr/aztec/src/avm/env_getters.nr +++ b/yarn-project/aztec-nr/aztec/src/avm/env_getters.nr @@ -1,5 +1,49 @@ +use dep::protocol_types::address::{ + AztecAddress, + EthAddress, +}; + #[oracle(address)] -unconstrained pub fn get_address() -> Field {} +unconstrained pub fn get_address() -> AztecAddress {} + +#[oracle(storageAddress)] +unconstrained pub fn get_storage_address() -> AztecAddress {} + +#[oracle(origin)] +unconstrained pub fn get_origin() -> AztecAddress {} + +#[oracle(sender)] +unconstrained pub fn get_sender() -> AztecAddress {} + +#[oracle(portal)] +unconstrained pub fn get_portal() -> EthAddress {} + +#[oracle(feePerL1Gas)] +unconstrained pub fn get_fee_per_l1_gas() -> Field {} + +#[oracle(feePerL2Gas)] +unconstrained pub fn get_fee_per_l2_gas() -> Field {} + +#[oracle(feePerDaGas)] +unconstrained pub fn get_fee_per_da_gas() -> Field {} + +#[oracle(chainId)] +unconstrained pub fn get_chain_id() -> Field {} + +#[oracle(version)] +unconstrained pub fn get_version() -> Field {} + +#[oracle(blockNumber)] +unconstrained pub fn get_block_number() -> Field {} + +#[oracle(timestamp)] +unconstrained pub fn get_timestamp() -> Field {} + +#[oracle(isStaticCall)] +unconstrained pub fn get_is_static_call() -> Field {} + +#[oracle(isDelegateCall)] +unconstrained pub fn get_is_delegate_call() -> Field {} -#[oracle(storage_address)] -unconstrained pub fn get_storage_address() -> Field {} +// #[oracle(contractCallDepth)] +// unconstrained pub fn get_contract_call_depth() -> Field {} \ No newline at end of file diff --git a/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr index 963f176aa847..3b3400f173ef 100644 --- a/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -2,8 +2,9 @@ contract AvmTest { // Libs - use dep::aztec::protocol_types::{ - address::AztecAddress, + use dep::aztec::protocol_types::address::{ + AztecAddress, + EthAddress, }; // avm lib @@ -18,11 +19,84 @@ contract AvmTest { argA + argB } + /************************************************************************ + * AvmContext functions + ************************************************************************/ #[aztec(public-vm)] - fn accessEnv() -> pub Field { + fn getAddress() -> pub AztecAddress { AvmContext::address() } + #[aztec(public-vm)] + fn getStorageAddress() -> pub AztecAddress { + AvmContext::storage_address() + } + + #[aztec(public-vm)] + fn getSender() -> pub AztecAddress { + AvmContext::sender() + } + + #[aztec(public-vm)] + fn getOrigin() -> pub AztecAddress { + AvmContext::origin() + } + + #[aztec(public-vm)] + fn getPortal() -> pub EthAddress { + AvmContext::portal() + } + + #[aztec(public-vm)] + fn getFeePerL1Gas() -> pub Field { + AvmContext::fee_per_l1_gas() + } + + #[aztec(public-vm)] + fn getFeePerL2Gas() -> pub Field { + AvmContext::fee_per_l2_gas() + } + + #[aztec(public-vm)] + fn getFeePerDaGas() -> pub Field { + AvmContext::fee_per_da_gas() + } + + #[aztec(public-vm)] + fn getChainId() -> pub Field { + AvmContext::chain_id() + } + + #[aztec(public-vm)] + fn getVersion() -> pub Field { + AvmContext::version() + } + + #[aztec(public-vm)] + fn getBlockNumber() -> pub Field { + AvmContext::block_number() + } + + #[aztec(public-vm)] + fn getTimestamp() -> pub Field { + AvmContext::timestamp() + } + + // #[aztec(public-vm)] + // fn getIsStaticCall() -> pub Field { + // AvmContext::is_static_call() + // } + + // #[aztec(public-vm)] + // fn getIsDelegateCall() -> pub Field { + // AvmContext::is_delegate_call() + // } + + // #[aztec(public-vm)] + // fn getContractCallDepth() -> pub Field { + // AvmContext::contract_call_depth() + // } + // Function required for all contracts unconstrained fn compute_note_hash_and_nullifier( _contract_address: AztecAddress, From f619cf48ef15ed9ed2490acac413ee28c4406870 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Sat, 3 Feb 2024 00:17:51 +0000 Subject: [PATCH 3/6] fmt --- avm-transpiler/src/transpile.rs | 22 +-- .../src/avm/avm_simulator.test.ts | 129 ++++++++---------- 2 files changed, 72 insertions(+), 79 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 1465c5ce9c51..e61858861775 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -273,7 +273,12 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { bytecode } -fn handle_foreign_call(avm_instrs: &mut Vec, function: &String, destinations: &Vec, inputs: &Vec) { +fn handle_foreign_call( + avm_instrs: &mut Vec, + function: &String, + destinations: &Vec, + inputs: &Vec, +) { // For the foreign calls we want to handle, we do not want inputs, as they are getters assert!(inputs.len() == 0); assert!(destinations.len() == 1); @@ -298,23 +303,22 @@ fn handle_foreign_call(avm_instrs: &mut Vec, function: &String, "timestamp" => AvmOpcode::TIMESTAMP, // "isStaticCall" => AvmOpcode::ISSTATICCALL, // "isDelegateCall" => AvmOpcode::ISDELEGATECALL, - _ => panic!("Transpiler doesn't know how to process ForeignCall function {:?}", function), - + _ => panic!( + "Transpiler doesn't know how to process ForeignCall function {:?}", + function + ), }; avm_instrs.push(AvmInstruction { opcode, indirect: Some(0), - operands: vec![ - AvmOperand::U32 { value: dest_offset as u32}, - ], + operands: vec![AvmOperand::U32 { + value: dest_offset as u32, + }], ..Default::default() }); - - } - /// Compute an array that maps each Brillig pc to an AVM pc. /// This must be done before transpiling to properly transpile jump destinations. /// This is necessary for two reasons: diff --git a/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts b/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts index 1ff99a379d79..b72534a8ccc3 100644 --- a/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts @@ -3,23 +3,15 @@ import { Fr } from '@aztec/foundation/fields'; import { AvmTestContractArtifact } from '@aztec/noir-contracts'; import { jest } from '@jest/globals'; +import { EthAddress } from '@aztec/foundation/eth-address'; import { TypeTag } from './avm_memory_types.js'; import { AvmSimulator } from './avm_simulator.js'; import { initContext, initExecutionEnvironment } from './fixtures/index.js'; import { Add, CalldataCopy, Return } from './opcodes/index.js'; -import { MockProxy, mock } from 'jest-mock-extended'; -import { AvmWorldStateJournal } from './journal/journal.js'; -import { decodeFromBytecode, encodeToBytecode } from './serialization/bytecode_serialization.js'; -import { AvmMachineState } from './avm_machine_state.js'; -import { EthAddress } from '@aztec/foundation/eth-address'; +import {encodeToBytecode } from './serialization/bytecode_serialization.js'; describe('avm', () => { - let journal: MockProxy; - - beforeEach(() => { - journal = mock(); - }); it('Should execute bytecode that performs basic addition', async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; @@ -44,7 +36,6 @@ describe('avm', () => { }); describe('testing transpiled Noir contracts', () => { - // TODO(https://github.com/AztecProtocol/aztec-packages/issues/4361): sync wire format w/transpiler. it('Should execute contract function that performs addition', async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; @@ -67,8 +58,7 @@ describe('avm', () => { expect(returnData).toEqual([new Fr(3)]); }); - describe("Test env getters from noir contract", () => { - + describe('Test env getters from noir contract', () => { const testEnvGetter = async (valueName: string, value: any, functionName: string) => { const getterArtifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!; @@ -93,63 +83,62 @@ describe('avm', () => { it('address', async () => { const address = AztecAddress.fromField(new Fr(1)); await testEnvGetter('address', address, 'avm_getAddress'); + }); + + it('storageAddress', async () => { + const storageAddress = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('storageAddress', storageAddress, 'avm_getStorageAddress'); + }); + + it('sender', async () => { + const sender = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('sender', sender, 'avm_getSender'); + }); + + it('origin', async () => { + const origin = AztecAddress.fromField(new Fr(1)); + await testEnvGetter('origin', origin, 'avm_getOrigin'); + }); + + it('portal', async () => { + const portal = EthAddress.fromField(new Fr(1)); + await testEnvGetter('portal', portal, 'avm_getPortal'); + }); + + it('getFeePerL1Gas', async () => { + const fee = new Fr(1); + await testEnvGetter('feePerL1Gas', fee, 'avm_getFeePerL1Gas'); + }); + + it('getFeePerL2Gas', async () => { + const fee = new Fr(1); + await testEnvGetter('feePerL2Gas', fee, 'avm_getFeePerL2Gas'); + }); + + it('getFeePerDaGas', async () => { + const fee = new Fr(1); + await testEnvGetter('feePerDaGas', fee, 'avm_getFeePerDaGas'); + }); + + // it('chainId', async () => { + // const chainId = new Fr(1); + // await testEnvGetter('chainId', chainId, 'avm_getChainId'); + // }); + + // it('version', async () => { + // const version = new Fr(1); + // await testEnvGetter('version', version, 'avm_getVersion'); + // }); + + // it('blockNumber', async () => { + // const blockNumber = new Fr(1); + // await testEnvGetter('blockNumber', blockNumber, 'avm_getBlockNumber'); + // }); + + // it('timestamp', async () => { + // const timestamp = new Fr(1); + // await testEnvGetter('timestamp', timestamp, 'avm_getTimestamp'); + // }); }); - - it('storageAddress', async () => { - const storageAddress = AztecAddress.fromField(new Fr(1)); - await testEnvGetter('storageAddress', storageAddress, 'avm_getStorageAddress'); - }); - - it('sender', async () => { - const sender = AztecAddress.fromField(new Fr(1)); - await testEnvGetter('sender', sender, 'avm_getSender'); - }); - - it('origin', async () => { - const origin = AztecAddress.fromField(new Fr(1)); - await testEnvGetter('origin', origin, 'avm_getOrigin'); - }); - - it('portal', async () => { - const portal = EthAddress.fromField(new Fr(1)); - await testEnvGetter('portal', portal, 'avm_getPortal'); - }); - - it('getFeePerL1Gas', async () => { - const fee = new Fr(1); - await testEnvGetter('feePerL1Gas', fee, 'avm_getFeePerL1Gas'); - }); - - it('getFeePerL2Gas', async () => { - const fee = new Fr(1); - await testEnvGetter('feePerL2Gas', fee, 'avm_getFeePerL2Gas'); - }); - - it('getFeePerDaGas', async () => { - const fee = new Fr(1); - await testEnvGetter('feePerDaGas', fee, 'avm_getFeePerDaGas'); - }); - - // it('chainId', async () => { - // const chainId = new Fr(1); - // await testEnvGetter('chainId', chainId, 'avm_getChainId'); - // }); - - // it('version', async () => { - // const version = new Fr(1); - // await testEnvGetter('version', version, 'avm_getVersion'); - // }); - - // it('blockNumber', async () => { - // const blockNumber = new Fr(1); - // await testEnvGetter('blockNumber', blockNumber, 'avm_getBlockNumber'); - // }); - - // it('timestamp', async () => { - // const timestamp = new Fr(1); - // await testEnvGetter('timestamp', timestamp, 'avm_getTimestamp'); - // }); - }); - }); }); From 8c69cf1062e5727a1708cc4e21cbcdaae70f5b7c Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 5 Feb 2024 22:18:01 +0000 Subject: [PATCH 4/6] fix: test globals, run write oracles inline --- avm-transpiler/src/transpile.rs | 6 +- barretenberg/cpp/pil/avm/avm.pil | 191 ++++++++++++++++++ .../src/avm/avm_simulator.test.ts | 93 +++++---- yarn-project/aztec-nr/aztec/src/avm.nr | 1 - .../aztec-nr/aztec/src/avm/context.nr | 90 +++------ .../aztec-nr/aztec/src/avm/env_getters.nr | 49 ----- .../contracts/avm_test_contract/src/main.nr | 16 +- 7 files changed, 274 insertions(+), 172 deletions(-) create mode 100644 barretenberg/cpp/pil/avm/avm.pil delete mode 100644 yarn-project/aztec-nr/aztec/src/avm/env_getters.nr diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index e61858861775..13364a9b2ce7 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -273,6 +273,9 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { bytecode } +/// Handle foreign function calls +/// - Environment getting opcodes will be represented as foreign calls +/// - TODO: support for avm external calls through this function fn handle_foreign_call( avm_instrs: &mut Vec, function: &String, @@ -301,8 +304,7 @@ fn handle_foreign_call( "version" => AvmOpcode::VERSION, "blockNumber" => AvmOpcode::BLOCKNUMBER, "timestamp" => AvmOpcode::TIMESTAMP, - // "isStaticCall" => AvmOpcode::ISSTATICCALL, - // "isDelegateCall" => AvmOpcode::ISDELEGATECALL, + // "callStackDepth" => AvmOpcode::CallStackDepth, _ => panic!( "Transpiler doesn't know how to process ForeignCall function {:?}", function diff --git a/barretenberg/cpp/pil/avm/avm.pil b/barretenberg/cpp/pil/avm/avm.pil new file mode 100644 index 000000000000..26268fe25cd9 --- /dev/null +++ b/barretenberg/cpp/pil/avm/avm.pil @@ -0,0 +1,191 @@ + +include "mem_trace.pil"; +include "alu_chip.pil"; + +namespace avmMini(256); + + //===== CONSTANT POLYNOMIALS ================================================== + pol constant clk(i) { i }; + pol constant first = [1] + [0]*; // Used mostly to toggle off the first row consisting + // only in first element of shifted polynomials. + + //===== CONTROL FLOW ========================================================== + // Program counter + pol commit pc; + // Return Pointer + pol commit internal_return_ptr; + + pol commit sel_internal_call; + pol commit sel_internal_return; + pol commit sel_jump; + + // Halt program execution + pol commit sel_halt; + + //===== TABLE SUBOP-TR ======================================================== + // Boolean selectors for (sub-)operations. Only one operation is activated at + // a time. + + // ADD + pol commit sel_op_add; + // SUB + pol commit sel_op_sub; + // MUL + pol commit sel_op_mul; + // DIV + pol commit sel_op_div; + + // Instruction memory tag (0: uninitialized, 1: u8, 2: u16, 3: u32, 4: u64, 5: u128, 6:field) + pol commit in_tag; + + // Errors + pol commit op_err; // Boolean flag pertaining to an operation error + pol commit tag_err; // Boolean flag (foreign key to memTrace.m_tag_err) + + // A helper witness being the inverse of some value + // to show a non-zero equality + pol commit inv; + + // Intermediate register values + pol commit ia; + pol commit ib; + pol commit ic; + + // Memory operation per intermediate register + pol commit mem_op_a; + pol commit mem_op_b; + pol commit mem_op_c; + + // Read-write flag per intermediate register: Read = 0, Write = 1 + pol commit rwa; + pol commit rwb; + pol commit rwc; + + // Memory index involved into a memory operation per pertaining intermediate register + // We should range constrain it to 32 bits ultimately. For first mini-AVM, + // we will assume that these columns are of the right type. + pol commit mem_idx_a; + pol commit mem_idx_b; + pol commit mem_idx_c; + + + // Track the last line of the execution trace. It does NOT correspond to the last row of the whole table + // of size N. As this depends on the supplied bytecode, this polynomial cannot be constant. + pol commit last; + + // Relations on type constraints + + sel_op_add * (1 - sel_op_add) = 0; + sel_op_sub * (1 - sel_op_sub) = 0; + sel_op_mul * (1 - sel_op_mul) = 0; + sel_op_div * (1 - sel_op_div) = 0; + + sel_internal_call * (1 - sel_internal_call) = 0; + sel_internal_return * (1 - sel_internal_return) = 0; + sel_jump * (1 - sel_jump) = 0; + sel_halt * (1 - sel_halt) = 0; + + op_err * (1 - op_err) = 0; + tag_err * (1 - tag_err) = 0; // Potential optimization (boolean constraint derivation from equivalence check to memTrace)? + + mem_op_a * (1 - mem_op_a) = 0; + mem_op_b * (1 - mem_op_b) = 0; + mem_op_c * (1 - mem_op_c) = 0; + + rwa * (1 - rwa) = 0; + rwb * (1 - rwb) = 0; + rwc * (1 - rwc) = 0; + + // TODO: Constrain rwa, rwb, rwc to u32 type and 0 <= in_tag <= 6 + + // Set intermediate registers to 0 whenever tag_err occurs + tag_err * ia = 0; + tag_err * ib = 0; + tag_err * ic = 0; + + // Relation for division over the finite field + // If tag_err == 1 in a division, then ib == 0 and op_err == 1. + #[SUBOP_DIVISION_FF] + sel_op_div * (1 - op_err) * (ic * ib - ia) = 0; + + // When sel_op_div == 1, we want ib == 0 <==> op_err == 1 + // This can be achieved with the 2 following relations. + // inv is an extra witness to show that we can invert ib, i.e., inv = ib^(-1) + // If ib == 0, we have to set inv = 1 to satisfy the second relation, + // because op_err == 1 from the first relation. + #[SUBOP_DIVISION_ZERO_ERR1] + sel_op_div * (ib * inv - 1 + op_err) = 0; + #[SUBOP_DIVISION_ZERO_ERR2] + sel_op_div * op_err * (1 - inv) = 0; + + // op_err cannot be maliciously activated for a non-relevant + // operation selector, i.e., op_err == 1 ==> sel_op_div || sel_op_XXX || ... + // op_err * (sel_op_div + sel_op_XXX + ... - 1) == 0 + // Note that the above is even a stronger constraint, as it shows + // that exactly one sel_op_XXX must be true. + // At this time, we have only division producing an error. + #[SUBOP_ERROR_RELEVANT_OP] + op_err * (sel_op_div - 1) = 0; + + // TODO: constraint that we stop execution at the first error (tag_err or op_err) + // An error can only happen at the last sub-operation row. + + // OPEN/POTENTIAL OPTIMIZATION: Dedicated error per relevant operation? + // For the division, we could lower the degree from 4 to 3 + // (sel_op_div - op_div_err) * (ic * ib - ia) = 0; + // Same for the relations related to the error activation: + // (ib * inv - 1 + op_div_err) = 0 && op_err * (1 - inv) = 0 + // This works in combination with op_div_err * (sel_op_div - 1) = 0; + // Drawback is the need to paralllelize the latter. + + //===== CONTROL FLOW ======================================================= + //===== JUMP =============================================================== + sel_jump * (pc' - ia) = 0; + + //===== INTERNAL_CALL ====================================================== + // - The program counter in the next row should be equal to the value loaded from the ia register + // - We then write the return location (pc + 1) into the call stack (in memory) + + #[RETURN_POINTER_INCREMENT] + sel_internal_call * (internal_return_ptr' - (internal_return_ptr + 1)) = 0; + sel_internal_call * (internal_return_ptr - mem_idx_b) = 0; + sel_internal_call * (pc' - ia) = 0; + sel_internal_call * ((pc + 1) - ib) = 0; + + // TODO(md): Below relations may be removed through sub-op table lookup + sel_internal_call * (rwb - 1) = 0; + sel_internal_call * (mem_op_b - 1) = 0; + + //===== INTERNAL_RETURN =================================================== + // - We load the memory pointer to be the internal_return_ptr + // - Constrain then next program counter to be the loaded value + // - decrement the internal_return_ptr + + #[RETURN_POINTER_DECREMENT] + sel_internal_return * (internal_return_ptr' - (internal_return_ptr - 1)) = 0; + sel_internal_return * ((internal_return_ptr - 1) - mem_idx_a) = 0; + sel_internal_return * (pc' - ia) = 0; + + // TODO(md): Below relations may be removed through sub-op table lookup + sel_internal_return * rwa = 0; + sel_internal_return * (mem_op_a - 1) = 0; + + //===== CONTROL_FLOW_CONSISTENCY ============================================ + pol INTERNAL_CALL_STACK_SELECTORS = (first + sel_internal_call + sel_internal_return + sel_halt); + pol OPCODE_SELECTORS = (sel_op_add + sel_op_sub + sel_op_div + sel_op_mul); + + // Program counter must increment if not jumping or returning + #[PC_INCREMENT] + (1 - first) * (1 - sel_halt) * OPCODE_SELECTORS * (pc' - (pc + 1)) = 0; + + // first == 0 && sel_internal_call == 0 && sel_internal_return == 0 && sel_halt == 0 ==> internal_return_ptr == internal_return_ptr' + #[INTERNAL_RETURN_POINTER_CONSISTENCY] + (1 - INTERNAL_CALL_STACK_SELECTORS) * (internal_return_ptr' - internal_return_ptr) = 0; + + // TODO: we want to set an initial number for the reserved memory of the jump pointer + + // Inter-table Constraints + + // TODO: tag_err {clk} IS memTrace.m_tag_err {memTrace.m_clk} + // TODO: Map memory trace with intermediate register values whenever there is no tag error, sthg like: + // mem_op_a * (1 - tag_err) {mem_idx_a, clk, ia, rwa} IS m_sub_clk == 0 && 1 - m_tag_err {m_addr, m_clk, m_val, m_rw} diff --git a/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts b/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts index b72534a8ccc3..e2231ede872c 100644 --- a/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/acir-simulator/src/avm/avm_simulator.test.ts @@ -1,18 +1,17 @@ import { AztecAddress } from '@aztec/foundation/aztec-address'; +import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; import { AvmTestContractArtifact } from '@aztec/noir-contracts'; import { jest } from '@jest/globals'; -import { EthAddress } from '@aztec/foundation/eth-address'; import { TypeTag } from './avm_memory_types.js'; import { AvmSimulator } from './avm_simulator.js'; -import { initContext, initExecutionEnvironment } from './fixtures/index.js'; +import { initContext, initExecutionEnvironment, initGlobalVariables } from './fixtures/index.js'; import { Add, CalldataCopy, Return } from './opcodes/index.js'; -import {encodeToBytecode } from './serialization/bytecode_serialization.js'; +import { encodeToBytecode } from './serialization/bytecode_serialization.js'; describe('avm', () => { - it('Should execute bytecode that performs basic addition', async () => { const calldata: Fr[] = [new Fr(1), new Fr(2)]; @@ -59,26 +58,34 @@ describe('avm', () => { }); describe('Test env getters from noir contract', () => { - const testEnvGetter = async (valueName: string, value: any, functionName: string) => { - const getterArtifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!; - - // Execute - const overrides = {[valueName]: value}; - const context = initContext({ env: initExecutionEnvironment(overrides) }); - - // Decode bytecode into instructions - const bytecode = Buffer.from(getterArtifact.bytecode, 'base64'); - jest.spyOn(context.worldState.hostStorage.contractsDb, 'getBytecode').mockReturnValue(Promise.resolve(bytecode)); - - const results = await new AvmSimulator(context).execute(); - - expect(results.reverted).toBe(false); - - const returnData = results.output; - expect(returnData.length).toBe(1); - expect(returnData).toEqual([value.toField()]); - - } + const testEnvGetter = async (valueName: string, value: any, functionName: string, globalVar: boolean = false) => { + const getterArtifact = AvmTestContractArtifact.functions.find(f => f.name === functionName)!; + + // Execute + let overrides = {}; + if (globalVar === true) { + const globals = initGlobalVariables({ [valueName]: value }); + overrides = { globals }; + } else { + overrides = { [valueName]: value }; + } + const context = initContext({ env: initExecutionEnvironment(overrides) }); + + // Decode bytecode into instructions + const bytecode = Buffer.from(getterArtifact.bytecode, 'base64'); + jest + .spyOn(context.worldState.hostStorage.contractsDb, 'getBytecode') + .mockReturnValue(Promise.resolve(bytecode)); + // Execute + + const results = await new AvmSimulator(context).execute(); + + expect(results.reverted).toBe(false); + + const returnData = results.output; + expect(returnData.length).toBe(1); + expect(returnData).toEqual([value.toField()]); + }; it('address', async () => { const address = AztecAddress.fromField(new Fr(1)); @@ -120,25 +127,25 @@ describe('avm', () => { await testEnvGetter('feePerDaGas', fee, 'avm_getFeePerDaGas'); }); - // it('chainId', async () => { - // const chainId = new Fr(1); - // await testEnvGetter('chainId', chainId, 'avm_getChainId'); - // }); - - // it('version', async () => { - // const version = new Fr(1); - // await testEnvGetter('version', version, 'avm_getVersion'); - // }); - - // it('blockNumber', async () => { - // const blockNumber = new Fr(1); - // await testEnvGetter('blockNumber', blockNumber, 'avm_getBlockNumber'); - // }); - - // it('timestamp', async () => { - // const timestamp = new Fr(1); - // await testEnvGetter('timestamp', timestamp, 'avm_getTimestamp'); - // }); + it('chainId', async () => { + const chainId = new Fr(1); + await testEnvGetter('chainId', chainId, 'avm_getChainId', /*globalVar=*/ true); + }); + + it('version', async () => { + const version = new Fr(1); + await testEnvGetter('version', version, 'avm_getVersion', /*globalVar=*/ true); + }); + + it('blockNumber', async () => { + const blockNumber = new Fr(1); + await testEnvGetter('blockNumber', blockNumber, 'avm_getBlockNumber', /*globalVar=*/ true); + }); + + it('timestamp', async () => { + const timestamp = new Fr(1); + await testEnvGetter('timestamp', timestamp, 'avm_getTimestamp', /*globalVar=*/ true); + }); }); }); }); diff --git a/yarn-project/aztec-nr/aztec/src/avm.nr b/yarn-project/aztec-nr/aztec/src/avm.nr index 42deea963351..3d9885db80d8 100644 --- a/yarn-project/aztec-nr/aztec/src/avm.nr +++ b/yarn-project/aztec-nr/aztec/src/avm.nr @@ -1,2 +1 @@ mod context; -mod env_getters; diff --git a/yarn-project/aztec-nr/aztec/src/avm/context.nr b/yarn-project/aztec-nr/aztec/src/avm/context.nr index 29011a909865..4e6d3f56f214 100644 --- a/yarn-project/aztec-nr/aztec/src/avm/context.nr +++ b/yarn-project/aztec-nr/aztec/src/avm/context.nr @@ -1,20 +1,3 @@ -use crate::avm::env_getters::{ - get_address, - get_storage_address, - get_origin, - get_sender, - get_portal, - get_fee_per_l1_gas, - get_fee_per_l2_gas, - get_fee_per_da_gas, - get_chain_id, - get_version, - get_block_number, - get_timestamp, - get_is_static_call, - get_is_delegate_call, -}; - use dep::protocol_types::address::{ AztecAddress, EthAddress, @@ -26,63 +9,42 @@ struct AvmContext {} // No new function as this struct is entirely static getters impl AvmContext { - pub fn address() -> AztecAddress { - get_address() - } - - pub fn storage_address() -> AztecAddress { - get_storage_address() - } - - pub fn origin() -> AztecAddress { - get_origin() - } + #[oracle(address)] + pub fn address() -> AztecAddress {} - pub fn sender() -> AztecAddress { - get_sender() - } + #[oracle(storageAddress)] + pub fn storage_address() -> AztecAddress {} - pub fn portal() -> EthAddress { - get_portal() - } + #[oracle(origin)] + pub fn origin() -> AztecAddress {} - pub fn fee_per_l1_gas() -> Field { - get_fee_per_l1_gas() - } + #[oracle(sender)] + pub fn sender() -> AztecAddress {} - pub fn fee_per_l2_gas() -> Field { - get_fee_per_l2_gas() - } + #[oracle(portal)] + pub fn portal() -> EthAddress {} - pub fn fee_per_da_gas() -> Field { - get_fee_per_da_gas() - } + #[oracle(feePerL1Gas)] + pub fn fee_per_l1_gas() -> Field {} - pub fn chain_id() -> Field { - get_chain_id() - } + #[oracle(feePerL2Gas)] + pub fn fee_per_l2_gas() -> Field {} - pub fn version() -> Field { - get_version() - } + #[oracle(feePerDaGas)] + pub fn fee_per_da_gas() -> Field {} - pub fn block_number() -> Field { - get_block_number() - } + #[oracle(chainId)] + pub fn chain_id() -> Field {} - pub fn timestamp() -> Field { - get_timestamp() - } + #[oracle(version)] + pub fn version() -> Field {} - // pub fn is_static_call() -> Field { - // get_is_static_call() - // } + #[oracle(blockNumber)] + pub fn block_number() -> Field {} - // pub fn is_delegate_call() -> Field { - // get_is_delegate_call() - // } + #[oracle(timestamp)] + pub fn timestamp() -> Field {} - // pub fn contract_call_depth() -> Field { - // get_contract_call_depth() - // } + // #[oracle(contractCallDepth)] + // pub fn contract_call_depth() -> Field {} } diff --git a/yarn-project/aztec-nr/aztec/src/avm/env_getters.nr b/yarn-project/aztec-nr/aztec/src/avm/env_getters.nr deleted file mode 100644 index 8d491e567238..000000000000 --- a/yarn-project/aztec-nr/aztec/src/avm/env_getters.nr +++ /dev/null @@ -1,49 +0,0 @@ -use dep::protocol_types::address::{ - AztecAddress, - EthAddress, -}; - -#[oracle(address)] -unconstrained pub fn get_address() -> AztecAddress {} - -#[oracle(storageAddress)] -unconstrained pub fn get_storage_address() -> AztecAddress {} - -#[oracle(origin)] -unconstrained pub fn get_origin() -> AztecAddress {} - -#[oracle(sender)] -unconstrained pub fn get_sender() -> AztecAddress {} - -#[oracle(portal)] -unconstrained pub fn get_portal() -> EthAddress {} - -#[oracle(feePerL1Gas)] -unconstrained pub fn get_fee_per_l1_gas() -> Field {} - -#[oracle(feePerL2Gas)] -unconstrained pub fn get_fee_per_l2_gas() -> Field {} - -#[oracle(feePerDaGas)] -unconstrained pub fn get_fee_per_da_gas() -> Field {} - -#[oracle(chainId)] -unconstrained pub fn get_chain_id() -> Field {} - -#[oracle(version)] -unconstrained pub fn get_version() -> Field {} - -#[oracle(blockNumber)] -unconstrained pub fn get_block_number() -> Field {} - -#[oracle(timestamp)] -unconstrained pub fn get_timestamp() -> Field {} - -#[oracle(isStaticCall)] -unconstrained pub fn get_is_static_call() -> Field {} - -#[oracle(isDelegateCall)] -unconstrained pub fn get_is_delegate_call() -> Field {} - -// #[oracle(contractCallDepth)] -// unconstrained pub fn get_contract_call_depth() -> Field {} \ No newline at end of file diff --git a/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr b/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr index 3b3400f173ef..107b94940465 100644 --- a/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr +++ b/yarn-project/noir-contracts/contracts/avm_test_contract/src/main.nr @@ -28,17 +28,17 @@ contract AvmTest { } #[aztec(public-vm)] - fn getStorageAddress() -> pub AztecAddress { + fn getStorageAddress() -> pub AztecAddress { AvmContext::storage_address() } #[aztec(public-vm)] - fn getSender() -> pub AztecAddress { + fn getSender() -> pub AztecAddress { AvmContext::sender() } #[aztec(public-vm)] - fn getOrigin() -> pub AztecAddress { + fn getOrigin() -> pub AztecAddress { AvmContext::origin() } @@ -82,16 +82,6 @@ contract AvmTest { AvmContext::timestamp() } - // #[aztec(public-vm)] - // fn getIsStaticCall() -> pub Field { - // AvmContext::is_static_call() - // } - - // #[aztec(public-vm)] - // fn getIsDelegateCall() -> pub Field { - // AvmContext::is_delegate_call() - // } - // #[aztec(public-vm)] // fn getContractCallDepth() -> pub Field { // AvmContext::contract_call_depth() From 4561249f901b885b46a3d3b78ce933e7aa232c95 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 5 Feb 2024 23:29:07 +0000 Subject: [PATCH 5/6] whoopsie --- barretenberg/cpp/pil/avm/avm.pil | 191 ------------------------------- 1 file changed, 191 deletions(-) delete mode 100644 barretenberg/cpp/pil/avm/avm.pil diff --git a/barretenberg/cpp/pil/avm/avm.pil b/barretenberg/cpp/pil/avm/avm.pil deleted file mode 100644 index 26268fe25cd9..000000000000 --- a/barretenberg/cpp/pil/avm/avm.pil +++ /dev/null @@ -1,191 +0,0 @@ - -include "mem_trace.pil"; -include "alu_chip.pil"; - -namespace avmMini(256); - - //===== CONSTANT POLYNOMIALS ================================================== - pol constant clk(i) { i }; - pol constant first = [1] + [0]*; // Used mostly to toggle off the first row consisting - // only in first element of shifted polynomials. - - //===== CONTROL FLOW ========================================================== - // Program counter - pol commit pc; - // Return Pointer - pol commit internal_return_ptr; - - pol commit sel_internal_call; - pol commit sel_internal_return; - pol commit sel_jump; - - // Halt program execution - pol commit sel_halt; - - //===== TABLE SUBOP-TR ======================================================== - // Boolean selectors for (sub-)operations. Only one operation is activated at - // a time. - - // ADD - pol commit sel_op_add; - // SUB - pol commit sel_op_sub; - // MUL - pol commit sel_op_mul; - // DIV - pol commit sel_op_div; - - // Instruction memory tag (0: uninitialized, 1: u8, 2: u16, 3: u32, 4: u64, 5: u128, 6:field) - pol commit in_tag; - - // Errors - pol commit op_err; // Boolean flag pertaining to an operation error - pol commit tag_err; // Boolean flag (foreign key to memTrace.m_tag_err) - - // A helper witness being the inverse of some value - // to show a non-zero equality - pol commit inv; - - // Intermediate register values - pol commit ia; - pol commit ib; - pol commit ic; - - // Memory operation per intermediate register - pol commit mem_op_a; - pol commit mem_op_b; - pol commit mem_op_c; - - // Read-write flag per intermediate register: Read = 0, Write = 1 - pol commit rwa; - pol commit rwb; - pol commit rwc; - - // Memory index involved into a memory operation per pertaining intermediate register - // We should range constrain it to 32 bits ultimately. For first mini-AVM, - // we will assume that these columns are of the right type. - pol commit mem_idx_a; - pol commit mem_idx_b; - pol commit mem_idx_c; - - - // Track the last line of the execution trace. It does NOT correspond to the last row of the whole table - // of size N. As this depends on the supplied bytecode, this polynomial cannot be constant. - pol commit last; - - // Relations on type constraints - - sel_op_add * (1 - sel_op_add) = 0; - sel_op_sub * (1 - sel_op_sub) = 0; - sel_op_mul * (1 - sel_op_mul) = 0; - sel_op_div * (1 - sel_op_div) = 0; - - sel_internal_call * (1 - sel_internal_call) = 0; - sel_internal_return * (1 - sel_internal_return) = 0; - sel_jump * (1 - sel_jump) = 0; - sel_halt * (1 - sel_halt) = 0; - - op_err * (1 - op_err) = 0; - tag_err * (1 - tag_err) = 0; // Potential optimization (boolean constraint derivation from equivalence check to memTrace)? - - mem_op_a * (1 - mem_op_a) = 0; - mem_op_b * (1 - mem_op_b) = 0; - mem_op_c * (1 - mem_op_c) = 0; - - rwa * (1 - rwa) = 0; - rwb * (1 - rwb) = 0; - rwc * (1 - rwc) = 0; - - // TODO: Constrain rwa, rwb, rwc to u32 type and 0 <= in_tag <= 6 - - // Set intermediate registers to 0 whenever tag_err occurs - tag_err * ia = 0; - tag_err * ib = 0; - tag_err * ic = 0; - - // Relation for division over the finite field - // If tag_err == 1 in a division, then ib == 0 and op_err == 1. - #[SUBOP_DIVISION_FF] - sel_op_div * (1 - op_err) * (ic * ib - ia) = 0; - - // When sel_op_div == 1, we want ib == 0 <==> op_err == 1 - // This can be achieved with the 2 following relations. - // inv is an extra witness to show that we can invert ib, i.e., inv = ib^(-1) - // If ib == 0, we have to set inv = 1 to satisfy the second relation, - // because op_err == 1 from the first relation. - #[SUBOP_DIVISION_ZERO_ERR1] - sel_op_div * (ib * inv - 1 + op_err) = 0; - #[SUBOP_DIVISION_ZERO_ERR2] - sel_op_div * op_err * (1 - inv) = 0; - - // op_err cannot be maliciously activated for a non-relevant - // operation selector, i.e., op_err == 1 ==> sel_op_div || sel_op_XXX || ... - // op_err * (sel_op_div + sel_op_XXX + ... - 1) == 0 - // Note that the above is even a stronger constraint, as it shows - // that exactly one sel_op_XXX must be true. - // At this time, we have only division producing an error. - #[SUBOP_ERROR_RELEVANT_OP] - op_err * (sel_op_div - 1) = 0; - - // TODO: constraint that we stop execution at the first error (tag_err or op_err) - // An error can only happen at the last sub-operation row. - - // OPEN/POTENTIAL OPTIMIZATION: Dedicated error per relevant operation? - // For the division, we could lower the degree from 4 to 3 - // (sel_op_div - op_div_err) * (ic * ib - ia) = 0; - // Same for the relations related to the error activation: - // (ib * inv - 1 + op_div_err) = 0 && op_err * (1 - inv) = 0 - // This works in combination with op_div_err * (sel_op_div - 1) = 0; - // Drawback is the need to paralllelize the latter. - - //===== CONTROL FLOW ======================================================= - //===== JUMP =============================================================== - sel_jump * (pc' - ia) = 0; - - //===== INTERNAL_CALL ====================================================== - // - The program counter in the next row should be equal to the value loaded from the ia register - // - We then write the return location (pc + 1) into the call stack (in memory) - - #[RETURN_POINTER_INCREMENT] - sel_internal_call * (internal_return_ptr' - (internal_return_ptr + 1)) = 0; - sel_internal_call * (internal_return_ptr - mem_idx_b) = 0; - sel_internal_call * (pc' - ia) = 0; - sel_internal_call * ((pc + 1) - ib) = 0; - - // TODO(md): Below relations may be removed through sub-op table lookup - sel_internal_call * (rwb - 1) = 0; - sel_internal_call * (mem_op_b - 1) = 0; - - //===== INTERNAL_RETURN =================================================== - // - We load the memory pointer to be the internal_return_ptr - // - Constrain then next program counter to be the loaded value - // - decrement the internal_return_ptr - - #[RETURN_POINTER_DECREMENT] - sel_internal_return * (internal_return_ptr' - (internal_return_ptr - 1)) = 0; - sel_internal_return * ((internal_return_ptr - 1) - mem_idx_a) = 0; - sel_internal_return * (pc' - ia) = 0; - - // TODO(md): Below relations may be removed through sub-op table lookup - sel_internal_return * rwa = 0; - sel_internal_return * (mem_op_a - 1) = 0; - - //===== CONTROL_FLOW_CONSISTENCY ============================================ - pol INTERNAL_CALL_STACK_SELECTORS = (first + sel_internal_call + sel_internal_return + sel_halt); - pol OPCODE_SELECTORS = (sel_op_add + sel_op_sub + sel_op_div + sel_op_mul); - - // Program counter must increment if not jumping or returning - #[PC_INCREMENT] - (1 - first) * (1 - sel_halt) * OPCODE_SELECTORS * (pc' - (pc + 1)) = 0; - - // first == 0 && sel_internal_call == 0 && sel_internal_return == 0 && sel_halt == 0 ==> internal_return_ptr == internal_return_ptr' - #[INTERNAL_RETURN_POINTER_CONSISTENCY] - (1 - INTERNAL_CALL_STACK_SELECTORS) * (internal_return_ptr' - internal_return_ptr) = 0; - - // TODO: we want to set an initial number for the reserved memory of the jump pointer - - // Inter-table Constraints - - // TODO: tag_err {clk} IS memTrace.m_tag_err {memTrace.m_clk} - // TODO: Map memory trace with intermediate register values whenever there is no tag error, sthg like: - // mem_op_a * (1 - tag_err) {mem_idx_a, clk, ia, rwa} IS m_sub_clk == 0 && 1 - m_tag_err {m_addr, m_clk, m_val, m_rw} From ddd0cb653134533d5f9255dfd5138afaab632542 Mon Sep 17 00:00:00 2001 From: Maddiaa0 <47148561+Maddiaa0@users.noreply.github.com> Date: Mon, 5 Feb 2024 23:31:05 +0000 Subject: [PATCH 6/6] fix indent --- avm-transpiler/src/transpile.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/avm-transpiler/src/transpile.rs b/avm-transpiler/src/transpile.rs index 13364a9b2ce7..4a9da4b8f65e 100644 --- a/avm-transpiler/src/transpile.rs +++ b/avm-transpiler/src/transpile.rs @@ -255,8 +255,8 @@ pub fn brillig_to_avm(brillig: &Brillig) -> Vec { }, BrilligOpcode::ForeignCall { function, destinations, inputs } => { handle_foreign_call(&mut avm_instrs, function, destinations, inputs); - } - _ => panic!( + }, + _ => panic!( "Transpiler doesn't know how to process {:?} brillig instruction", brillig_instr ),