diff --git a/noir-projects/noir-contracts/Nargo.toml b/noir-projects/noir-contracts/Nargo.toml index 18ba10820a7..263c45bba62 100644 --- a/noir-projects/noir-contracts/Nargo.toml +++ b/noir-projects/noir-contracts/Nargo.toml @@ -5,6 +5,7 @@ members = [ "contracts/auth_contract", "contracts/auth_registry_contract", "contracts/auth_wit_test_contract", + "contracts/avm_gadgets_test_contract", "contracts/avm_initializer_test_contract", "contracts/avm_test_contract", "contracts/fpc_contract", diff --git a/noir-projects/noir-contracts/contracts/avm_gadgets_test_contract/Nargo.toml b/noir-projects/noir-contracts/contracts/avm_gadgets_test_contract/Nargo.toml new file mode 100644 index 00000000000..ca88c967955 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/avm_gadgets_test_contract/Nargo.toml @@ -0,0 +1,8 @@ +[package] +name = "avm_gadgets_test_contract" +authors = [""] +compiler_version = ">=0.25.0" +type = "contract" + +[dependencies] +aztec = { path = "../../../aztec-nr/aztec" } diff --git a/noir-projects/noir-contracts/contracts/avm_gadgets_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/avm_gadgets_test_contract/src/main.nr new file mode 100644 index 00000000000..0a353249339 --- /dev/null +++ b/noir-projects/noir-contracts/contracts/avm_gadgets_test_contract/src/main.nr @@ -0,0 +1,93 @@ +use dep::aztec::macros::aztec; + +#[aztec] +contract AvmGadgetsTest { + use dep::aztec::macros::functions::public; + + #[public] + fn keccak_hash(data: [u8; 10]) -> [u8; 32] { + std::hash::keccak256(data, data.len() as u32) + } + + #[public] + fn keccak_f1600(data: [u64; 25]) -> [u64; 25] { + std::hash::keccak::keccakf1600(data) + } + + #[public] + fn poseidon2_hash(data: [Field; 10]) -> Field { + std::hash::poseidon2::Poseidon2::hash(data, data.len()) + } + + #[public] + fn sha256_hash_10(data: [u8; 10]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_20(data: [u8; 20]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_30(data: [u8; 30]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_40(data: [u8; 40]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_50(data: [u8; 50]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_60(data: [u8; 60]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_70(data: [u8; 70]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_80(data: [u8; 80]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_90(data: [u8; 90]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_100(data: [u8; 100]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_255(data: [u8; 255]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_256(data: [u8; 256]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_511(data: [u8; 511]) -> [u8; 32] { + std::hash::sha256(data) + } + #[public] + fn sha256_hash_512(data: [u8; 512]) -> [u8; 32] { + std::hash::sha256(data) + } + + #[public] + fn sha256_hash_2048(data: [u8; 2048]) -> [u8; 32] { + std::hash::sha256(data) + } + + #[public] + fn pedersen_hash(data: [Field; 10]) -> Field { + std::hash::pedersen_hash(data) + } + + #[public] + fn pedersen_hash_with_index(data: [Field; 10]) -> Field { + std::hash::pedersen_hash_with_separator(data, /*index=*/ 20) + } +} 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 e3d45c694ea..5fd24054467 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 @@ -297,6 +297,8 @@ pub contract AvmTest { } /************************************************************************ +<<<<<<< HEAD +======= * Hashing functions ************************************************************************/ #[public] @@ -330,6 +332,7 @@ pub contract AvmTest { } /************************************************************************ +>>>>>>> master * Contract instance ************************************************************************/ #[public] @@ -660,15 +663,15 @@ pub contract AvmTest { dep::aztec::oracle::debug_log::debug_log("read_storage_map"); let _ = read_storage_map(context.this_address()); dep::aztec::oracle::debug_log::debug_log("keccak_hash"); - let _ = keccak_hash(args_u8); + let _ = std::hash::keccak256(args_u8, args_u8.len() as u32); dep::aztec::oracle::debug_log::debug_log("sha256_hash"); - let _ = sha256_hash(args_u8); + let _ = std::hash::sha256(args_u8); dep::aztec::oracle::debug_log::debug_log("poseidon2_hash"); - let _ = poseidon2_hash(args_field); + let _ = std::hash::poseidon2::Poseidon2::hash(args_field, args_field.len()); dep::aztec::oracle::debug_log::debug_log("pedersen_hash"); - let _ = pedersen_hash(args_field); + let _ = std::hash::pedersen_hash(args_field); dep::aztec::oracle::debug_log::debug_log("pedersen_hash_with_index"); - let _ = pedersen_hash_with_index(args_field); + let _ = std::hash::pedersen_hash_with_separator(args_field, /*index=*/ 20); dep::aztec::oracle::debug_log::debug_log("test_get_contract_instance"); test_get_contract_instance_matches( get_instance_for_address, diff --git a/yarn-project/simulator/src/avm/avm_simulator.test.ts b/yarn-project/simulator/src/avm/avm_simulator.test.ts index ab3b1946c34..255420c45a2 100644 --- a/yarn-project/simulator/src/avm/avm_simulator.test.ts +++ b/yarn-project/simulator/src/avm/avm_simulator.test.ts @@ -36,6 +36,7 @@ import { AvmSimulator } from './avm_simulator.js'; import { AvmEphemeralForest } from './avm_tree.js'; import { isAvmBytecode, markBytecodeAsAvm } from './bytecode_utils.js'; import { + getAvmGadgetsTestContractBytecode, getAvmTestContractArtifact, getAvmTestContractBytecode, initContext, @@ -384,19 +385,43 @@ describe('AVM simulator: transpiled Noir contracts', () => { }); }); + /* + * Can run these as follows to measure sha256 instruction execution counts: + * for i in 10 20 30 40 50 60 70 80 90 100 255 256 511 512 2048; do + * echo sha-ing $i...; + * LOG_LEVEL=debug yarn test src/avm/avm_simulator.test.ts -t "sha256_hash_$i " &> sha$i.log; + * done + * for i in 10 20 30 40 50 60 70 80 90 100 255 256 511 512 2048; do + * echo sha256 of $i bytes $(grep -Eo 'Executed .* instructions.* Gas' sha$i.log); + * done + */ describe.each([ - ['sha256_hash', /*input=*/ randomMemoryBytes(10), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_10', /*input=*/ randomMemoryBytes(10), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_20', /*input=*/ randomMemoryBytes(20), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_30', /*input=*/ randomMemoryBytes(30), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_40', /*input=*/ randomMemoryBytes(40), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_50', /*input=*/ randomMemoryBytes(50), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_60', /*input=*/ randomMemoryBytes(60), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_70', /*input=*/ randomMemoryBytes(70), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_80', /*input=*/ randomMemoryBytes(80), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_90', /*input=*/ randomMemoryBytes(90), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_100', /*input=*/ randomMemoryBytes(100), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_255', /*input=*/ randomMemoryBytes(255), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_256', /*input=*/ randomMemoryBytes(256), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_511', /*input=*/ randomMemoryBytes(511), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_512', /*input=*/ randomMemoryBytes(512), /*output=*/ sha256FromMemoryBytes], + ['sha256_hash_2048', /*input=*/ randomMemoryBytes(2048), /*output=*/ sha256FromMemoryBytes], ['keccak_hash', /*input=*/ randomMemoryBytes(10), /*output=*/ keccak256FromMemoryBytes], ['keccak_f1600', /*input=*/ randomMemoryUint64s(25), /*output=*/ keccakF1600FromMemoryUint64s], ['poseidon2_hash', /*input=*/ randomMemoryFields(10), /*output=*/ poseidon2FromMemoryFields], ['pedersen_hash', /*input=*/ randomMemoryFields(10), /*output=*/ pedersenFromMemoryFields], ['pedersen_hash_with_index', /*input=*/ randomMemoryFields(10), /*output=*/ indexedPedersenFromMemoryFields], ])('Hashes in noir contracts', (name: string, input: MemoryValue[], output: (msg: any[]) => Promise) => { - it(`Should execute contract function that performs ${name}`, async () => { + it(`Should execute contract function that performs ${name} on input of length ${input.length}`, async () => { const calldata = input.map(e => e.toFr()); const context = initContext({ env: initExecutionEnvironment({ calldata }) }); - const bytecode = getAvmTestContractBytecode(name); + const bytecode = getAvmGadgetsTestContractBytecode(name); const results = await new AvmSimulator(context).executeBytecode(bytecode); expect(results.reverted).toBe(false); diff --git a/yarn-project/simulator/src/avm/fixtures/index.ts b/yarn-project/simulator/src/avm/fixtures/index.ts index 938bebf2a2c..8ef8937470e 100644 --- a/yarn-project/simulator/src/avm/fixtures/index.ts +++ b/yarn-project/simulator/src/avm/fixtures/index.ts @@ -4,6 +4,7 @@ import { type ContractArtifact, type FunctionArtifact, FunctionSelector } from ' import { AztecAddress } from '@aztec/foundation/aztec-address'; import { EthAddress } from '@aztec/foundation/eth-address'; import { Fr } from '@aztec/foundation/fields'; +import { AvmGadgetsTestContractArtifact } from '@aztec/noir-contracts.js/AvmGadgetsTest'; import { AvmTestContractArtifact } from '@aztec/noir-contracts.js/AvmTest'; import { strict as assert } from 'assert'; @@ -169,6 +170,13 @@ export function getAvmTestContractFunctionSelector(functionName: string): Promis return getFunctionSelector(functionName, AvmTestContractArtifact); } +export function getAvmGadgetsTestContractFunctionSelector(functionName: string): Promise { + const artifact = AvmGadgetsTestContractArtifact.functions.find(f => f.name === functionName)!; + assert(!!artifact, `Function ${functionName} not found in AvmGadgetsTestContractArtifact`); + const params = artifact.parameters; + return FunctionSelector.fromNameAndParameters(artifact.name, params); +} + export function getAvmTestContractArtifact(functionName: string): FunctionArtifact { const artifact = getContractFunctionArtifact(functionName, AvmTestContractArtifact); assert( @@ -178,11 +186,25 @@ export function getAvmTestContractArtifact(functionName: string): FunctionArtifa return artifact; } +export function getAvmGadgetsTestContractArtifact(functionName: string): FunctionArtifact { + const artifact = AvmGadgetsTestContractArtifact.functions.find(f => f.name === functionName)!; + assert( + !!artifact?.bytecode, + `No bytecode found for function ${functionName}. Try re-running bootstrap.sh on the repository root.`, + ); + return artifact; +} + export function getAvmTestContractBytecode(functionName: string): Buffer { const artifact = getAvmTestContractArtifact(functionName); return artifact.bytecode; } +export function getAvmGadgetsTestContractBytecode(functionName: string): Buffer { + const artifact = getAvmGadgetsTestContractArtifact(functionName); + return artifact.bytecode; +} + export function resolveAvmTestContractAssertionMessage( functionName: string, revertReason: AvmRevertReason, @@ -190,3 +212,20 @@ export function resolveAvmTestContractAssertionMessage( ): string | undefined { return resolveContractAssertionMessage(functionName, revertReason, output, AvmTestContractArtifact); } + +export function resolveAvmGadgetsTestContractAssertionMessage( + functionName: string, + revertReason: AvmRevertReason, + output: Fr[], +): string | undefined { + traverseCauseChain(revertReason, cause => { + revertReason = cause as AvmRevertReason; + }); + + const functionArtifact = AvmGadgetsTestContractArtifact.functions.find(f => f.name === functionName); + if (!functionArtifact || !revertReason.noirCallStack || !isNoirCallStackUnresolved(revertReason.noirCallStack)) { + return undefined; + } + + return resolveAssertionMessageFromRevertData(output, functionArtifact); +}