Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: Use poseidon for fn selectors #8239

Merged
merged 14 commits into from
Sep 15, 2024
18 changes: 9 additions & 9 deletions l1-contracts/src/core/libraries/ConstantsGen.sol
Original file line number Diff line number Diff line change
Expand Up @@ -134,17 +134,17 @@ library Constants {
uint256 internal constant L2_GAS_PER_NOTE_HASH = 32;
uint256 internal constant L2_GAS_PER_NULLIFIER = 64;
uint256 internal constant CANONICAL_KEY_REGISTRY_ADDRESS =
9694109890306420370616891858093188542026876097103155811681068343994212062621;
6823425185167517386380694778823032861295161686691976789058601691508103815523;
uint256 internal constant CANONICAL_AUTH_REGISTRY_ADDRESS =
16522644890256297179255458951626875692461008240031142745359776058397274208468;
19361441716519463065948254497947932755739298943049449145365332870925554042208;
uint256 internal constant DEPLOYER_CONTRACT_ADDRESS =
19310994760783330368337163480198602393920956587162708699802190083077641908361;
17119407406465801909352274670277571579675739451008438338071219340964365249977;
uint256 internal constant REGISTERER_CONTRACT_ADDRESS =
2631409926445785927331173506476539962589925110142857699603561302478860342858;
12405643717676802437578418009978929188439257864607100766293128479227092050857;
uint256 internal constant FEE_JUICE_ADDRESS =
10248142274714515101077825679585135641434041564851038865006795089686437446849;
12096583827711775893711303288210371301779120762215263550909768879597884314839;
uint256 internal constant ROUTER_ADDRESS =
7268799613082469933251235702514160327341161584122631177360064643484764773587;
13369993014609648298719593339393818582619449364029983937306132176549332172208;
uint256 internal constant AZTEC_ADDRESS_LENGTH = 1;
uint256 internal constant GAS_FEES_LENGTH = 2;
uint256 internal constant GAS_LENGTH = 2;
Expand Down Expand Up @@ -193,16 +193,16 @@ library Constants {
uint256 internal constant PUBLIC_CONTEXT_INPUTS_LENGTH = 42;
uint256 internal constant AGGREGATION_OBJECT_LENGTH = 16;
uint256 internal constant SCOPED_READ_REQUEST_LEN = 3;
uint256 internal constant PUBLIC_DATA_READ_LENGTH = 2;
uint256 internal constant PUBLIC_DATA_READ_LENGTH = 3;
uint256 internal constant PRIVATE_VALIDATION_REQUESTS_LENGTH = 772;
uint256 internal constant PUBLIC_VALIDATION_REQUESTS_LENGTH = 770;
uint256 internal constant PUBLIC_VALIDATION_REQUESTS_LENGTH = 834;
uint256 internal constant PUBLIC_DATA_UPDATE_REQUEST_LENGTH = 3;
uint256 internal constant COMBINED_ACCUMULATED_DATA_LENGTH = 610;
uint256 internal constant COMBINED_CONSTANT_DATA_LENGTH = 43;
uint256 internal constant PRIVATE_ACCUMULATED_DATA_LENGTH = 1336;
uint256 internal constant PRIVATE_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 2167;
uint256 internal constant PUBLIC_ACCUMULATED_DATA_LENGTH = 1311;
uint256 internal constant PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 3885;
uint256 internal constant PUBLIC_KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 3949;
uint256 internal constant KERNEL_CIRCUIT_PUBLIC_INPUTS_LENGTH = 663;
uint256 internal constant CONSTANT_ROLLUP_DATA_LENGTH = 12;
uint256 internal constant BASE_OR_MERGE_PUBLIC_INPUTS_LENGTH = 29;
Expand Down
4 changes: 2 additions & 2 deletions noir-projects/aztec-nr/authwit/src/auth.nr
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ use dep::aztec::{prelude::Deserialize, context::{PrivateContext, PublicContext,
*
*
* --- FAQ ---
* Q: Why are we using a success flag of `keccak256("IS_VALID()")` instead of just returning a boolean?
* Q: Why are we using a success flag of `poseidon2_hash_bytes("IS_VALID()")` instead of just returning a boolean?
* A: We want to make sure that we don't accidentally return `true` if there is a collision in the function selector.
* By returning a hash of `IS_VALID()`, it becomes very unlikely that there is both a collision and we return
* a success flag.
Expand All @@ -189,7 +189,7 @@ use dep::aztec::{prelude::Deserialize, context::{PrivateContext, PublicContext,
* chain to avoid a case where the same message could be used across multiple chains.
*/

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

/**
* Assert that `on_behalf_of` have authorized the current call with a valid authentication witness
Expand Down
4 changes: 3 additions & 1 deletion noir-projects/aztec-nr/aztec/src/deploy.nr
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,9 @@ pub fn deploy_contract(context: &mut PrivateContext, target: AztecAddress) {

let _call_result = context.call_private_function(
DEPLOYER_CONTRACT_ADDRESS,
FunctionSelector::from_field(0x7ebd3690),
comptime {
FunctionSelector::from_signature("deploy(Field,(Field),Field,(Field),bool)")
},
serialized_args
);
}
Original file line number Diff line number Diff line change
Expand Up @@ -273,7 +273,7 @@ mod test {
// The following value was generated by `encrypted_event_log_incoming_body.test.ts`
// --> Run the test with AZTEC_GENERATE_TEST_DATA=1 flag to update test data.
let event_body_ciphertext_from_typescript = [
226, 240, 253, 6, 28, 52, 19, 131, 33, 132, 178, 212, 245, 62, 14, 190, 147, 228, 160, 190, 146, 61, 95, 203, 124, 153, 68, 168, 17, 150, 92, 0, 99, 214, 85, 64, 191, 78, 157, 131, 149, 96, 236, 253, 96, 172, 157, 30, 185, 29, 14, 152, 216, 130, 219, 151, 80, 185, 43, 223, 167, 8, 89, 189, 88, 188, 101, 137, 255, 136, 84, 252, 79, 18, 52, 3, 110, 54, 54, 206, 244, 209, 246, 226, 207, 247, 143, 253, 211, 75, 160, 224, 172, 41, 45, 7, 208, 137, 90, 56, 59, 4, 234, 48, 53, 23, 130, 230, 49, 249, 142, 243, 170, 72, 183, 242, 49, 124, 46, 52, 198, 75, 55, 102, 56, 89, 254, 67, 59, 157, 249, 120, 184, 67, 154, 16, 148, 227, 93, 37, 120, 199, 93, 166, 80, 127, 173, 52, 80, 135, 87, 1, 168, 164, 51, 48, 126, 120, 47, 102, 211, 227, 234, 170, 208, 99, 111, 198, 170, 226, 156, 244, 241, 174, 206, 30
226, 240, 253, 6, 28, 52, 19, 131, 33, 132, 178, 212, 245, 62, 14, 190, 147, 228, 160, 190, 146, 61, 95, 203, 124, 153, 68, 168, 17, 150, 92, 0, 99, 214, 85, 64, 191, 78, 157, 131, 149, 96, 236, 253, 96, 172, 157, 30, 201, 247, 40, 80, 60, 188, 158, 251, 242, 103, 197, 79, 165, 195, 10, 160, 255, 35, 167, 152, 25, 233, 77, 145, 214, 243, 210, 119, 0, 20, 29, 95, 15, 63, 33, 190, 184, 67, 254, 96, 128, 243, 220, 228, 201, 130, 86, 163, 52, 127, 111, 10, 212, 7, 160, 16, 87, 13, 39, 11, 5, 1, 164, 65, 8, 56, 82, 245, 13, 68, 176, 90, 100, 69, 243, 78, 117, 188, 221, 34, 178, 31, 155, 89, 143, 176, 129, 118, 36, 236, 64, 179, 52, 239, 184, 51, 51, 199, 221, 49, 81, 197, 17, 199, 192, 99, 49, 168, 157, 164, 190, 33, 240, 182, 214, 173, 7, 156, 102, 95, 65, 217, 225, 123, 42, 21, 124, 144
];

assert_eq(event_body_ciphertext_from_typescript.len(), ciphertext.len());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,14 +51,12 @@ impl EventSelector {

pub fn from_signature<let N: u32>(signature: str<N>) -> Self {
let bytes = signature.as_bytes();
let hash = std::hash::keccak256(bytes, bytes.len() as u32);
let hash = crate::hash::poseidon2_hash_bytes(bytes);

let mut selector_be_bytes = [0; SELECTOR_SIZE];
for i in 0..SELECTOR_SIZE {
selector_be_bytes[i] = hash[i];
}
// We choose the last SELECTOR_SIZE bytes of the hash to avoid getting the first byte that is not full
let hash_bytes = hash.to_be_bytes::<SELECTOR_SIZE>();

EventSelector::from_field(field_from_bytes(selector_be_bytes, true))
EventSelector::from_field(field_from_bytes(hash_bytes, true))
}

pub fn zero() -> Self {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -51,17 +51,27 @@ impl FunctionSelector {

pub fn from_signature<let N: u32>(signature: str<N>) -> Self {
let bytes = signature.as_bytes();
let hash = std::hash::keccak256(bytes, bytes.len() as u32);
let hash = crate::hash::poseidon2_hash_bytes(bytes);

let mut selector_be_bytes = [0; SELECTOR_SIZE];
for i in 0..SELECTOR_SIZE {
selector_be_bytes[i] = hash[i];
}
// We choose the last SELECTOR_SIZE bytes of the hash to avoid getting the first byte that is not full
let hash_bytes = hash.to_be_bytes::<SELECTOR_SIZE>();

FunctionSelector::from_field(field_from_bytes(selector_be_bytes, true))
FunctionSelector::from_field(field_from_bytes(hash_bytes, true))
}

pub fn zero() -> Self {
Self { inner: 0 }
}
}

#[test]
fn test_is_valid_selector() {
let selector = FunctionSelector::from_signature("IS_VALID()");
assert_eq(selector.to_field(), 0x73cdda47);
}

#[test]
fn test_long_selector() {
let selector = FunctionSelector::from_signature("foo_and_bar_and_baz_and_foo_bar_baz_and_bar_foo");
assert_eq(selector.to_field(), 0x7590a997);
}
Original file line number Diff line number Diff line change
Expand Up @@ -191,12 +191,12 @@ global L2_GAS_PER_NOTE_HASH: u32 = 32;
global L2_GAS_PER_NULLIFIER: u32 = 64;

// CANONICAL CONTRACT ADDRESSES
global CANONICAL_KEY_REGISTRY_ADDRESS = AztecAddress::from_field(0x156eabf84e3ea50d40e3330224f2d2e81648fff8f1f7ec1bc6d2873cca6e959d);
global CANONICAL_AUTH_REGISTRY_ADDRESS = AztecAddress::from_field(0x24877c50868f86712240eb535d90d1c97403d074805dd3758c3aecb02958f8d4);
global DEPLOYER_CONTRACT_ADDRESS = AztecAddress::from_field(0x2ab1a2bd6d07d8d61ea56d85861446349e52c6b7c0612b702cb1e6db6ad0b089);
global REGISTERER_CONTRACT_ADDRESS = AztecAddress::from_field(0x05d15342d76e46e5be07d3cda0d753158431cdc5e39d29ce4e8fe1f5c070564a);
global FEE_JUICE_ADDRESS = AztecAddress::from_field(0x16a83e3395bc921a2441db55dce24f0e0932636901a2e676fa68b9b2b9a644c1);
global ROUTER_ADDRESS = AztecAddress::from_field(0x1011feaa54609098a884322267ec754c637b280c15aa79c3be9f1394e2b29cd3);
global CANONICAL_KEY_REGISTRY_ADDRESS = AztecAddress::from_field(0x0f15ebfaa7e1bb0d1c542c954a8f605909d0fa0a5fd829122bfdec15b4ada163);
global CANONICAL_AUTH_REGISTRY_ADDRESS = AztecAddress::from_field(0x2ace300b02ca5ab0a25052b1e852913a47292096997ca09f758c0e3624e84560);
global DEPLOYER_CONTRACT_ADDRESS = AztecAddress::from_field(0x25d93dc07b5baaf53a98caeae2679df3528cb83e11e2640a57a0a53abbaaadb9);
global REGISTERER_CONTRACT_ADDRESS = AztecAddress::from_field(0x1b6d5873cef5a35f681ab9468527f356c96e09b3c64603aef404ec2ad80aa3a9);
global FEE_JUICE_ADDRESS = AztecAddress::from_field(0x1abe6c7f5c4caf04cbf7556495e08ad9c0a225a5f9d33554ae07285b13c494d7);
global ROUTER_ADDRESS = AztecAddress::from_field(0x1d8f25db3e8faa6a96cb1ecf57876a2ee04581deb3c4f181488ccd817abcbdb0);

// LENGTH OF STRUCTS SERIALIZED TO FIELDS
global AZTEC_ADDRESS_LENGTH = 1;
Expand Down
31 changes: 31 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 @@ -15,6 +15,7 @@ use crate::{
recursion::verification_key::VerificationKey, traits::{is_empty, ToField},
utils::field::field_from_bytes_32_trunc
};
use super::utils::field::field_from_bytes;

pub fn sha256_to_field<let N: u32>(bytes_to_hash: [u8; N]) -> Field {
let sha256_hashed = std::hash::sha256(bytes_to_hash);
Expand Down Expand Up @@ -276,6 +277,36 @@ pub fn poseidon2_hash_with_separator<let N: u32, T>(
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)
let mut in_len = N / 31;
let mut has_padding = false;
if N % 31 != 0 {
in_len += 1;
has_padding = true;
}

let two_pow_64 = 18446744073709551616;
let iv : Field = (in_len as Field) * two_pow_64;
let mut sponge = std::hash::poseidon2::Poseidon2::new(iv);

let mut current_field = [0; 31];
for i in 0..inputs.len() {
let index = i % 31;
current_field[index] = inputs[i];
if index == 30 {
sponge.absorb(field_from_bytes(current_field, false));
current_field = [0; 31];
}
}
if has_padding {
sponge.absorb(field_from_bytes(current_field, false));
}

sponge.squeeze()
}

#[test]
fn smoke_sha256_to_field() {
let full_buffer = [
Expand Down
19 changes: 3 additions & 16 deletions noir/noir-repo/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 4 additions & 1 deletion noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,10 @@ mod schnorr;
use ark_ec::AffineRepr;
pub use embedded_curve_ops::{embedded_curve_add, multi_scalar_mul};
pub use generator::generators::derive_generators;
pub use poseidon2::{field_from_hex, poseidon2_permutation, Poseidon2Config, POSEIDON2_CONFIG};
pub use poseidon2::{
field_from_hex, poseidon2_permutation, poseidon_hash, Poseidon2Config, Poseidon2Sponge,
POSEIDON2_CONFIG,
};

// Temporary hack, this ensure that we always use a bn254 field here
// without polluting the feature flags of the `acir_field` crate.
Expand Down
84 changes: 84 additions & 0 deletions noir/noir-repo/acvm-repo/bn254_blackbox_solver/src/poseidon2.rs
Original file line number Diff line number Diff line change
Expand Up @@ -543,6 +543,75 @@ impl<'a> Poseidon2<'a> {
}
}

/// Performs a poseidon hash with a sponge construction equivalent to the one in poseidon2.nr
pub fn poseidon_hash(inputs: &[FieldElement]) -> Result<FieldElement, BlackBoxResolutionError> {
let two_pow_64 = 18446744073709551616_u128.into();
let iv = FieldElement::from(inputs.len()) * two_pow_64;
let mut sponge = Poseidon2Sponge::new(iv, 3);
for input in inputs.iter() {
sponge.absorb(*input)?;
}
sponge.squeeze()
}

pub struct Poseidon2Sponge<'a> {
rate: usize,
poseidon: Poseidon2<'a>,
squeezed: bool,
cache: Vec<FieldElement>,
state: Vec<FieldElement>,
}

impl<'a> Poseidon2Sponge<'a> {
pub fn new(iv: FieldElement, rate: usize) -> Poseidon2Sponge<'a> {
let mut result = Poseidon2Sponge {
cache: Vec::with_capacity(rate),
state: vec![FieldElement::zero(); rate + 1],
squeezed: false,
rate,
poseidon: Poseidon2::new(),
};
result.state[rate] = iv;
result
}

fn perform_duplex(&mut self) -> Result<(), BlackBoxResolutionError> {
// zero-pad the cache
for _ in self.cache.len()..self.rate {
self.cache.push(FieldElement::zero());
}
// add the cache into sponge state
for i in 0..self.rate {
self.state[i] += self.cache[i];
}
self.state = self.poseidon.permutation(&self.state, 4)?;
Ok(())
}

pub fn absorb(&mut self, input: FieldElement) -> Result<(), BlackBoxResolutionError> {
assert!(!self.squeezed);
if self.cache.len() == self.rate {
// If we're absorbing, and the cache is full, apply the sponge permutation to compress the cache
self.perform_duplex()?;
self.cache = vec![input];
} else {
// If we're absorbing, and the cache is not full, add the input into the cache
self.cache.push(input);
}
Ok(())
}

pub fn squeeze(&mut self) -> Result<FieldElement, BlackBoxResolutionError> {
assert!(!self.squeezed);
// If we're in absorb mode, apply sponge permutation to compress the cache.
self.perform_duplex()?;
self.squeezed = true;

// Pop one item off the top of the permutation and return it.
Ok(self.state[0])
}
}

#[cfg(test)]
mod test {
use acir::AcirField;
Expand All @@ -562,4 +631,19 @@ mod test {
];
assert_eq!(result, expected_result);
}

#[test]
fn hash_smoke_test() {
let fields = [
FieldElement::from(1u128),
FieldElement::from(2u128),
FieldElement::from(3u128),
FieldElement::from(4u128),
];
let result = super::poseidon_hash(&fields).expect("should hash successfully");
assert_eq!(
result,
field_from_hex("130bf204a32cac1f0ace56c78b731aa3809f06df2731ebcf6b3464a15788b1b9"),
);
}
}
4 changes: 3 additions & 1 deletion noir/noir-repo/aztec_macros/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,9 @@ acvm.workspace = true
noirc_frontend.workspace = true
noirc_errors.workspace = true
iter-extended.workspace = true
bn254_blackbox_solver.workspace = true
convert_case = "0.6.0"
im.workspace = true
regex = "1.10"
tiny-keccak = { version = "2.0.0", features = ["keccak"] }
itertools = "^0.10"
hex.workspace = true
Loading
Loading