Skip to content

Commit

Permalink
chore: benchmark sha256 number of instructions executed in AVM (#11253)
Browse files Browse the repository at this point in the history
Also move hash stuff into another AVM test contract.

This lets us get stats like below, although note that this isn't
directly an output from the yarn tests:

For a `sha256` of N bytes, how many AVM/Brillig instructions are
executed and how much gas does it consume?
```N=  10 bytes:   3998 instructions,   69006 L2 Gas
N=  20 bytes:   4513 instructions,   77778 L2 Gas
N=  30 bytes:   5328 instructions,   91326 L2 Gas
N=  40 bytes:   5843 instructions,  100098 L2 Gas
N=  50 bytes:   6672 instructions,  113877 L2 Gas
N=  60 bytes:   7490 instructions,  127626 L2 Gas
N=  70 bytes:   8662 instructions,  147936 L2 Gas
N=  80 bytes:   9207 instructions,  157368 L2 Gas
N=  90 bytes:  10052 instructions,  171576 L2 Gas
N= 100 bytes:  10597 instructions,  181008 L2 Gas
N= 255 bytes:  23046 instructions,  392055 L2 Gas
N= 256 bytes:  23022 instructions,  392121 L2 Gas
N= 511 bytes:  43107 instructions,  732336 L2 Gas
N= 512 bytes:  42978 instructions,  731004 L2 Gas
N=2048 bytes: 162801 instructions, 2765820 L2 Gas```
  • Loading branch information
dbanks12 authored Feb 4, 2025
1 parent 2ba1e71 commit aaf0d8c
Show file tree
Hide file tree
Showing 6 changed files with 177 additions and 8 deletions.
1 change: 1 addition & 0 deletions noir-projects/noir-contracts/Nargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
[package]
name = "avm_gadgets_test_contract"
authors = [""]
compiler_version = ">=0.25.0"
type = "contract"

[dependencies]
aztec = { path = "../../../aztec-nr/aztec" }
Original file line number Diff line number Diff line change
@@ -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)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -297,6 +297,8 @@ pub contract AvmTest {
}

/************************************************************************
<<<<<<< HEAD
=======
* Hashing functions
************************************************************************/
#[public]
Expand Down Expand Up @@ -330,6 +332,7 @@ pub contract AvmTest {
}

/************************************************************************
>>>>>>> master
* Contract instance
************************************************************************/
#[public]
Expand Down Expand Up @@ -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,
Expand Down
31 changes: 28 additions & 3 deletions yarn-project/simulator/src/avm/avm_simulator.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down Expand Up @@ -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<Fr[]>) => {
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);
Expand Down
39 changes: 39 additions & 0 deletions yarn-project/simulator/src/avm/fixtures/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -169,6 +170,13 @@ export function getAvmTestContractFunctionSelector(functionName: string): Promis
return getFunctionSelector(functionName, AvmTestContractArtifact);
}

export function getAvmGadgetsTestContractFunctionSelector(functionName: string): Promise<FunctionSelector> {
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(
Expand All @@ -178,15 +186,46 @@ 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,
output: Fr[],
): 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);
}

0 comments on commit aaf0d8c

Please sign in to comment.