Skip to content

Commit

Permalink
feat: update args hash to be a flat poseidon (#8571)
Browse files Browse the repository at this point in the history
We used before a sort of tree structure for args hash to make an
incremental hash. Poseidon is incremental in noir, so we can get rid of
it and just use a flat poseidon hash.
  • Loading branch information
sirasistant authored Sep 16, 2024
1 parent bc8d461 commit 0c54224
Show file tree
Hide file tree
Showing 9 changed files with 34 additions and 62 deletions.
3 changes: 0 additions & 3 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -95,9 +95,6 @@ library Constants {
uint256 internal constant BLOCK_MERGE_ROLLUP_INDEX = 23;
uint256 internal constant ROOT_ROLLUP_INDEX = 24;
uint256 internal constant FUNCTION_SELECTOR_NUM_BYTES = 4;
uint256 internal constant ARGS_HASH_CHUNK_LENGTH = 16;
uint256 internal constant ARGS_HASH_CHUNK_COUNT = 16;
uint256 internal constant MAX_ARGS_LENGTH = 256;
uint256 internal constant INITIALIZATION_SLOT_SEPARATOR = 1000000000;
uint256 internal constant INITIAL_L2_BLOCK_NUM = 1;
uint256 internal constant BLOB_SIZE_IN_BYTES = 126976;
Expand Down
40 changes: 12 additions & 28 deletions noir-projects/aztec-nr/aztec/src/hash.nr
Original file line number Diff line number Diff line change
@@ -1,10 +1,8 @@
use dep::protocol_types::{
address::{AztecAddress, EthAddress},
constants::{
GENERATOR_INDEX__SECRET_HASH, GENERATOR_INDEX__MESSAGE_NULLIFIER, ARGS_HASH_CHUNK_COUNT,
GENERATOR_INDEX__FUNCTION_ARGS, ARGS_HASH_CHUNK_LENGTH, MAX_ARGS_LENGTH
},
point::Point, traits::Hash, hash::{sha256_to_field, poseidon2_hash_with_separator}
constants::{GENERATOR_INDEX__SECRET_HASH, GENERATOR_INDEX__MESSAGE_NULLIFIER, GENERATOR_INDEX__FUNCTION_ARGS},
point::Point, traits::Hash,
hash::{sha256_to_field, poseidon2_hash_with_separator, poseidon2_hash_with_separator_slice}
};
use crate::oracle::logs_traits::ToBytesForUnencryptedLog;

Expand Down Expand Up @@ -106,44 +104,30 @@ impl ArgsHasher {
}

pub fn hash_args_array<let N: u32>(args: [Field; N]) -> Field {
hash_args(args.as_slice())
if args.len() == 0 {
0
} else {
poseidon2_hash_with_separator(args, GENERATOR_INDEX__FUNCTION_ARGS)
}
}

pub fn hash_args(args: [Field]) -> Field {
if args.len() == 0 {
0
} else {
assert(args.len() <= MAX_ARGS_LENGTH, "Args length exceeds maximum");
let mut chunks_hashes = [0; ARGS_HASH_CHUNK_COUNT];
let mut current_chunk_values = [0; ARGS_HASH_CHUNK_LENGTH];

let mut current_chunk_index = 0;
let mut index_inside_current_chunk = 0;
for i in 0..args.len() {
current_chunk_values[index_inside_current_chunk] = args[i];
index_inside_current_chunk+=1;
if index_inside_current_chunk == ARGS_HASH_CHUNK_LENGTH {
chunks_hashes[current_chunk_index] = poseidon2_hash_with_separator(current_chunk_values, GENERATOR_INDEX__FUNCTION_ARGS);
current_chunk_values = [0; ARGS_HASH_CHUNK_LENGTH];
current_chunk_index+=1;
index_inside_current_chunk = 0;
}
}
if index_inside_current_chunk > 0 {
chunks_hashes[current_chunk_index] = poseidon2_hash_with_separator(current_chunk_values, GENERATOR_INDEX__FUNCTION_ARGS);
}
poseidon2_hash_with_separator(chunks_hashes, GENERATOR_INDEX__FUNCTION_ARGS)
poseidon2_hash_with_separator_slice(args, GENERATOR_INDEX__FUNCTION_ARGS)
}
}

#[test]
fn compute_var_args_hash() {
let mut input = ArgsHasher::new();
for i in 0..MAX_ARGS_LENGTH {
for i in 0..100 {
input.add(i as Field);
}
let hash = input.hash();
assert(hash == 0x1cce4dbf69f14c44865919991ee1057922e34d7310ba237d71759aa422621ca9);
dep::std::println(hash);
assert(hash == 0x19b0d74feb06ebde19edd85a28986c97063e84b3b351a8b666c7cac963ce655f);
}

#[test]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -123,9 +123,6 @@ global ROOT_ROLLUP_INDEX: u32 = 24;

// MISC CONSTANTS
global FUNCTION_SELECTOR_NUM_BYTES: Field = 4;
global ARGS_HASH_CHUNK_LENGTH: u32 = 16;
global ARGS_HASH_CHUNK_COUNT: u32 = 16;
global MAX_ARGS_LENGTH: u32 = ARGS_HASH_CHUNK_COUNT * ARGS_HASH_CHUNK_LENGTH;
// The following is used in immutable state variables to compute an initialization slot whose value is used to
// determine whether a given variable has been initialized (by asserting that the value in the slot is 0).
// The initialization slot is computed by adding the constant below to the variable's storage slot. This constant has
Expand Down
14 changes: 14 additions & 0 deletions noir-projects/noir-protocol-circuits/crates/types/src/hash.nr
Original file line number Diff line number Diff line change
Expand Up @@ -277,6 +277,20 @@ pub fn poseidon2_hash_with_separator<let N: u32, T>(
sponge.squeeze()
}

pub fn poseidon2_hash_with_separator_slice<T>(inputs: [Field], separator: T) -> Field where T: ToField {
let in_len = inputs.len() + 1;
let two_pow_64 = 18446744073709551616;
let iv : Field = (in_len as Field) * two_pow_64;
let mut sponge = std::hash::poseidon2::Poseidon2::new(iv);
sponge.absorb(separator.to_field());

for i in 0..inputs.len() {
sponge.absorb(inputs[i]);
}

sponge.squeeze()
}

#[no_predicates]
pub fn poseidon2_hash_bytes<let N: u32>(inputs: [u8; N]) -> Field {
// We manually hash the inputs here, since we cannot express with the type system a constant size inputs array of Math.ceil(N/31)
Expand Down
3 changes: 0 additions & 3 deletions yarn-project/circuits.js/src/constants.gen.ts
Original file line number Diff line number Diff line change
Expand Up @@ -81,9 +81,6 @@ export const BLOCK_ROOT_ROLLUP_INDEX = 22;
export const BLOCK_MERGE_ROLLUP_INDEX = 23;
export const ROOT_ROLLUP_INDEX = 24;
export const FUNCTION_SELECTOR_NUM_BYTES = 4;
export const ARGS_HASH_CHUNK_LENGTH = 16;
export const ARGS_HASH_CHUNK_COUNT = 16;
export const MAX_ARGS_LENGTH = 256;
export const INITIALIZATION_SLOT_SEPARATOR = 1000000000;
export const INITIAL_L2_BLOCK_NUM = 1;
export const BLOB_SIZE_IN_BYTES = 126976;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

exports[`ContractAddress computeContractAddressFromInstance 1`] = `"0x0ea56faa48431d99cc2d073463d1b718c11174bb551a3d1d6f296b0096089dbb"`;

exports[`ContractAddress computeInitializationHash 1`] = `Fr<0x0a79e35b159f2755e79e7ac21aed31964a6446d279670b499595da24c66144ff>`;
exports[`ContractAddress computeInitializationHash 1`] = `Fr<0x153329c6098512a53cb449057bb5adade93e360575b71192b7b304ace35b2b6b>`;

exports[`ContractAddress computePartialAddress 1`] = `Fr<0x2521255ebd14e8e3e7cd1e8a27d26a902ee9e74905b711950d580e826ba9010d>`;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`hash Var args hash matches noir 1`] = `Fr<0x1cce4dbf69f14c44865919991ee1057922e34d7310ba237d71759aa422621ca9>`;
exports[`hash Var args hash matches noir 1`] = `Fr<0x19b0d74feb06ebde19edd85a28986c97063e84b3b351a8b666c7cac963ce655f>`;

exports[`hash compute secret message hash 1`] = `Fr<0x211b950e538ee911389e441942d6646d13d725957a49d06500ae9bb673b0fbc2>`;

Expand All @@ -18,6 +18,6 @@ exports[`hash computes unique note hash 1`] = `Fr<0x2f9b80d22188c5383a577596538f

exports[`hash hashes empty function args 1`] = `Fr<0x0000000000000000000000000000000000000000000000000000000000000000>`;

exports[`hash hashes function args 1`] = `Fr<0x2cb19d7f1c57660c695e279c0163042f20dc89e4ae7bed9ada08b74790df3204>`;
exports[`hash hashes function args 1`] = `Fr<0x08fc05646caf2d63a8f3b424351783a521edaf28da0933d7c5b78a27e7497dac>`;

exports[`hash hashes many function args 1`] = `Fr<0x0f987cfa046685fd829f2cab0cc5e078941719d229df8292924178c77a6f886e>`;
exports[`hash hashes many function args 1`] = `Fr<0x03933d5a59efde5af91c47a93e6c4965f0506d160f76c701b2de1503d74c7775>`;
4 changes: 2 additions & 2 deletions yarn-project/circuits.js/src/hash/hash.test.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { times } from '@aztec/foundation/collection';
import { setupCustomSnapshotSerializers, updateInlineTestData } from '@aztec/foundation/testing';

import { AztecAddress, EthAddress, Fr, L2ToL1Message, MAX_ARGS_LENGTH, ScopedL2ToL1Message } from '../index.js';
import { AztecAddress, EthAddress, Fr, L2ToL1Message, ScopedL2ToL1Message } from '../index.js';
import { makeAztecAddress } from '../tests/factories.js';
import {
computeNoteHashNonce,
Expand Down Expand Up @@ -83,7 +83,7 @@ describe('hash', () => {
});

it('Var args hash matches noir', () => {
const args = times(MAX_ARGS_LENGTH, i => new Fr(i));
const args = times(100, i => new Fr(i));
const res = computeVarArgsHash(args);
expect(res).toMatchSnapshot();

Expand Down
21 changes: 2 additions & 19 deletions yarn-project/circuits.js/src/hash/hash.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import { type AztecAddress } from '@aztec/foundation/aztec-address';
import { padArrayEnd } from '@aztec/foundation/collection';
import { pedersenHashBuffer, poseidon2HashWithSeparator, sha256Trunc } from '@aztec/foundation/crypto';
import { Fr } from '@aztec/foundation/fields';
import { numToUInt8, numToUInt16BE, numToUInt32BE } from '@aztec/foundation/serialize';

import chunk from 'lodash.chunk';

import { ARGS_HASH_CHUNK_COUNT, ARGS_HASH_CHUNK_LENGTH, GeneratorIndex, MAX_ARGS_LENGTH } from '../constants.gen.js';
import { GeneratorIndex } from '../constants.gen.js';
import { type ScopedL2ToL1Message, VerificationKey } from '../structs/index.js';

/**
Expand Down Expand Up @@ -103,22 +100,8 @@ export function computeVarArgsHash(args: Fr[]) {
if (args.length === 0) {
return Fr.ZERO;
}
if (args.length > MAX_ARGS_LENGTH) {
throw new Error(`Hashing ${args.length} args exceeds max of ${MAX_ARGS_LENGTH}`);
}

let chunksHashes = chunk(args, ARGS_HASH_CHUNK_LENGTH).map((c: Fr[]) => {
if (c.length < ARGS_HASH_CHUNK_LENGTH) {
c = padArrayEnd(c, Fr.ZERO, ARGS_HASH_CHUNK_LENGTH);
}
return poseidon2HashWithSeparator(c, GeneratorIndex.FUNCTION_ARGS);
});

if (chunksHashes.length < ARGS_HASH_CHUNK_COUNT) {
chunksHashes = padArrayEnd(chunksHashes, Fr.ZERO, ARGS_HASH_CHUNK_COUNT);
}

return poseidon2HashWithSeparator(chunksHashes, GeneratorIndex.FUNCTION_ARGS);
return poseidon2HashWithSeparator(args, GeneratorIndex.FUNCTION_ARGS);
}

/**
Expand Down

0 comments on commit 0c54224

Please sign in to comment.