diff --git a/cspell.json b/cspell.json index f8f39c661ab0..f86fd034bcc9 100644 --- a/cspell.json +++ b/cspell.json @@ -231,6 +231,7 @@ "Reserialize", "retag", "rethrown", + "revertibles", "rollup", "rollups", "rushstack", diff --git a/noir-projects/aztec-nr/aztec/src/context/private_context.nr b/noir-projects/aztec-nr/aztec/src/context/private_context.nr index 5a492e7a35ef..2e4958b73ff5 100644 --- a/noir-projects/aztec-nr/aztec/src/context/private_context.nr +++ b/noir-projects/aztec-nr/aztec/src/context/private_context.nr @@ -271,7 +271,7 @@ impl PrivateContext { /// Safety: Kernels verify that the key validation request is valid and below we verify that a request /// for the correct public key has been received. let request = unsafe { get_key_validation_request(pk_m_hash, key_index) }; - assert(request.pk_m.hash() == pk_m_hash); + assert_eq(request.pk_m.hash(), pk_m_hash, "Obtained invalid key validation request"); self.key_validation_requests_and_generators.push( KeyValidationRequestAndGenerator { @@ -496,7 +496,7 @@ impl PrivateContext { let mut is_static_call = is_static_call | self.inputs.call_context.is_static_call; /// Safety: TODO(https://github.com/AztecProtocol/aztec-packages/issues/8985): Fix this. /// WARNING: This is insecure and should be temporary! - /// The oracle repacks the arguments and returns a new args_hash. + /// The oracle hashes the arguments and returns a new args_hash. /// new_args = [selector, ...old_args], so as to make it suitable to call the public dispatch function. /// We don't validate or compute it in the circuit because a) it's harder to do with slices, and /// b) this is only temporary. @@ -552,7 +552,7 @@ impl PrivateContext { let mut is_static_call = is_static_call | self.inputs.call_context.is_static_call; /// Safety: TODO(https://github.com/AztecProtocol/aztec-packages/issues/8985): Fix this. /// WARNING: This is insecure and should be temporary! - /// The oracle repacks the arguments and returns a new args_hash. + /// The oracle hashes the arguments and returns a new args_hash. /// new_args = [selector, ...old_args], so as to make it suitable to call the public dispatch function. /// We don't validate or compute it in the circuit because a) it's harder to do with slices, and /// b) this is only temporary. diff --git a/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr b/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr index 264f5ce4d6ab..f570ffd16f93 100644 --- a/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr +++ b/noir-projects/aztec-nr/aztec/src/encrypted_logs/payload.nr @@ -1,15 +1,10 @@ use dep::protocol_types::{ - address::AztecAddress, - constants::{GENERATOR_INDEX__SYMMETRIC_KEY, PRIVATE_LOG_SIZE_IN_FIELDS}, - hash::poseidon2_hash, - point::Point, - public_keys::AddressPoint, - scalar::Scalar, - utils::arrays::array_concat, + address::AztecAddress, constants::PRIVATE_LOG_SIZE_IN_FIELDS, hash::poseidon2_hash, + point::Point, public_keys::AddressPoint, scalar::Scalar, utils::arrays::array_concat, }; use std::{ aes128::aes128_encrypt, embedded_curve_ops::fixed_base_scalar_mul as derive_public_key, - field::bn254::decompose, hash::from_field_unsafe as fr_to_fq_unsafe, + hash::from_field_unsafe as fr_to_fq_unsafe, }; use crate::{ @@ -184,14 +179,6 @@ unconstrained fn get_random_bytes() -> [u8; N] { bytes } -/// Converts a base field element to scalar field element. -/// This is fine because modulus of the base field is smaller than the modulus of the scalar field. -fn fr_to_fq(r: Field) -> Scalar { - let (lo, hi) = decompose(r); - - Scalar { lo, hi } -} - fn generate_ephemeral_key_pair() -> (Scalar, Point) { // @todo Need to draw randomness from the full domain of Fq not only Fr diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr index 8aa051fe808d..cfec177f3765 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_inclusion.nr @@ -21,21 +21,21 @@ impl ProveNullifierInclusion for BlockHeader { // 2) First we prove that the tree leaf in the witness is present in the nullifier tree. This is expected to be // the leaf that contains the nullifier we're proving inclusion for. - assert( - self.state.partial.nullifier_tree.root - == root_from_sibling_path(witness.leaf_preimage.hash(), witness.index, witness.path) - , - "Proving nullifier inclusion failed", - ); - - // 3) Then we simply check that the value in the leaf is the expected one. Note that we don't need to perform - // any checks on the rest of the values in the leaf preimage (the next index or next nullifier), since all we - // care about is showing that the tree contains an entry with the expected nullifier. - assert( - witness.leaf_preimage.nullifier == nullifier, - "Nullifier does not match value in witness", - ); - } + assert_eq( + self.state.partial.nullifier_tree.root, + root_from_sibling_path(witness.leaf_preimage.hash(), witness.index, witness.path), + "Proving nullifier inclusion failed", + ); + + // 3) Then we simply check that the value in the leaf is the expected one. Note that we don't need to perform + // any checks on the rest of the values in the leaf preimage (the next index or next nullifier), since all we + // care about is showing that the tree contains an entry with the expected nullifier. + assert_eq( + witness.leaf_preimage.nullifier, + nullifier, + "Nullifier does not match value in witness", + ); + } } trait ProveNoteIsNullified { diff --git a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr index 2a786bafb268..80d9f2ffaab5 100644 --- a/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr +++ b/noir-projects/aztec-nr/aztec/src/history/nullifier_non_inclusion.nr @@ -28,9 +28,9 @@ impl ProveNullifierNonInclusion for BlockHeader { // the 'low leaf', i.e. the leaf that would come immediately before the nullifier's leaf, if the nullifier were // to be in the tree. let low_nullifier_leaf = witness.leaf_preimage; - assert( - self.state.partial.nullifier_tree.root - == root_from_sibling_path(low_nullifier_leaf.hash(), witness.index, witness.path), + assert_eq( + self.state.partial.nullifier_tree.root, + root_from_sibling_path(low_nullifier_leaf.hash(), witness.index, witness.path), "Proving nullifier non-inclusion failed: Could not prove low nullifier inclusion", ); diff --git a/noir-projects/aztec-nr/aztec/src/history/public_storage.nr b/noir-projects/aztec-nr/aztec/src/history/public_storage.nr index 4195674e9adb..0f88b46a5851 100644 --- a/noir-projects/aztec-nr/aztec/src/history/public_storage.nr +++ b/noir-projects/aztec-nr/aztec/src/history/public_storage.nr @@ -39,37 +39,35 @@ impl PublicStorageHistoricalRead for BlockHeader { // We first prove that the witness is indeed valid for the public data tree, i.e. that the preimage is of a // value present in the tree. Note that `hash` returns not just the hash of the value but also the metadata // (slot, next index and next slot). - assert( - self.state.partial.public_data_tree.root - == root_from_sibling_path(witness.leaf_preimage.hash(), witness.index, witness.path) - , - "Proving public value inclusion failed", - ); + assert_eq( + self.state.partial.public_data_tree.root, + root_from_sibling_path(witness.leaf_preimage.hash(), witness.index, witness.path), + "Proving public value inclusion failed", + ); - // 4) Now that we know the preimage is valid, we determine the value that's represented by this tree entry. Here - // we have two scenarios: - // 1. The tree entry is initialized, and the value is the same as the one in the witness - // 2. The entry was never initialized, and the value is default zero (the default) - // The code below is based on the same checks in `validate_public_data_reads` in `base_rollup_inputs`. - let preimage = witness.leaf_preimage; + // 4) Now that we know the preimage is valid, we determine the value that's represented by this tree entry. Here + // we have two scenarios: + // 1. The tree entry is initialized, and the value is the same as the one in the witness + // 2. The entry was never initialized, and the value is default zero (the default) + // The code below is based on the same checks in `validate_public_data_reads` in `base_rollup_inputs`. + let preimage = witness.leaf_preimage; - let is_less_than_slot = full_field_less_than(preimage.slot, public_data_tree_index); - let is_next_greater_than = - full_field_less_than(public_data_tree_index, preimage.next_slot); - let is_max = ((preimage.next_index == 0) & (preimage.next_slot == 0)); - let is_in_range = is_less_than_slot & (is_next_greater_than | is_max); + let is_less_than_slot = full_field_less_than(preimage.slot, public_data_tree_index); + let is_next_greater_than = full_field_less_than(public_data_tree_index, preimage.next_slot); + let is_max = ((preimage.next_index == 0) & (preimage.next_slot == 0)); + let is_in_range = is_less_than_slot & (is_next_greater_than | is_max); - let value = if is_in_range { - 0 - } else { - assert_eq( - preimage.slot, - public_data_tree_index, - "Public data tree index doesn't match witness", - ); - preimage.value - }; + let value = if is_in_range { + 0 + } else { + assert_eq( + preimage.slot, + public_data_tree_index, + "Public data tree index doesn't match witness", + ); + preimage.value + }; - value - } + value + } } diff --git a/noir-projects/aztec-nr/aztec/src/lib.nr b/noir-projects/aztec-nr/aztec/src/lib.nr index beb2d4b81dc1..9901cb7f64c2 100644 --- a/noir-projects/aztec-nr/aztec/src/lib.nr +++ b/noir-projects/aztec-nr/aztec/src/lib.nr @@ -3,7 +3,6 @@ mod deploy; mod generators; mod hash; mod history; -mod initializer; mod keys; mod messaging; mod note; diff --git a/noir-projects/aztec-nr/aztec/src/initializer.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/initialization_utils.nr similarity index 96% rename from noir-projects/aztec-nr/aztec/src/initializer.nr rename to noir-projects/aztec-nr/aztec/src/macros/functions/initialization_utils.nr index 36dc2b418938..b650a922a9ec 100644 --- a/noir-projects/aztec-nr/aztec/src/initializer.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/initialization_utils.nr @@ -60,10 +60,7 @@ pub fn assert_initialization_matches_address_preimage_private(context: PrivateCo ); } -pub fn compute_initialization_hash( - init_selector: FunctionSelector, - init_args_hash: Field, -) -> Field { +fn compute_initialization_hash(init_selector: FunctionSelector, init_args_hash: Field) -> Field { poseidon2_hash_with_separator( [init_selector.to_field(), init_args_hash], GENERATOR_INDEX__CONSTRUCTOR, diff --git a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr index 038fee019849..3f8f5c3817b6 100644 --- a/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr +++ b/noir-projects/aztec-nr/aztec/src/macros/functions/mod.nr @@ -1,4 +1,5 @@ pub mod interfaces; +pub mod initialization_utils; use super::utils::{ add_to_hasher, fn_has_noinitcheck, get_fn_visibility, is_fn_initializer, is_fn_internal, @@ -64,18 +65,19 @@ pub comptime fn noinitcheck(_f: FunctionDefinition) { comptime fn create_assert_correct_initializer_args(f: FunctionDefinition) -> Quoted { let fn_visibility = get_fn_visibility(f); - f"dep::aztec::initializer::assert_initialization_matches_address_preimage_{fn_visibility}(context);" + f"dep::aztec::macros::functions::initialization_utils::assert_initialization_matches_address_preimage_{fn_visibility}(context);" .quoted_contents() } comptime fn create_mark_as_initialized(f: FunctionDefinition) -> Quoted { let fn_visibility = get_fn_visibility(f); - f"dep::aztec::initializer::mark_as_initialized_{fn_visibility}(&mut context);".quoted_contents() + f"dep::aztec::macros::functions::initialization_utils::mark_as_initialized_{fn_visibility}(&mut context);" + .quoted_contents() } comptime fn create_init_check(f: FunctionDefinition) -> Quoted { let fn_visibility = get_fn_visibility(f); - f"dep::aztec::initializer::assert_is_initialized_{fn_visibility}(&mut context);" + f"dep::aztec::macros::functions::initialization_utils::assert_is_initialized_{fn_visibility}(&mut context);" .quoted_contents() } diff --git a/noir-projects/aztec-nr/aztec/src/messaging.nr b/noir-projects/aztec-nr/aztec/src/messaging.nr index 4fd9b7a80125..bf6be44dc939 100644 --- a/noir-projects/aztec-nr/aztec/src/messaging.nr +++ b/noir-projects/aztec-nr/aztec/src/messaging.nr @@ -36,7 +36,7 @@ pub fn process_l1_to_l2_message( unsafe { get_l1_to_l2_membership_witness(contract_address, message_hash, secret) }; let root = root_from_sibling_path(message_hash, leaf_index, sibling_path); - assert(root == l1_to_l2_root, "Message not in state"); + assert_eq(root, l1_to_l2_root, "Message not in state"); compute_l1_to_l2_message_nullifier(message_hash, secret) } diff --git a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr index 1b80000f315e..e1956a0056c4 100644 --- a/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr +++ b/noir-projects/aztec-nr/aztec/src/note/note_getter_options.nr @@ -3,9 +3,9 @@ use dep::protocol_types::{constants::MAX_NOTE_HASH_READ_REQUESTS_PER_CALL, trait use std::option::Option; pub struct PropertySelector { - pub(crate) index: u8, // index of the field in the serialized note array - pub(crate) offset: u8, // offset in the byte representation of the field (selected with index above) from which to reading - pub(crate) length: u8, // number of bytes to read after the offset + pub index: u8, // index of the field in the serialized note array + pub offset: u8, // offset in the byte representation of the field (selected with index above) from which to reading + pub length: u8, // number of bytes to read after the offset } pub struct Select { diff --git a/noir-projects/aztec-nr/aztec/src/oracle/block_header.nr b/noir-projects/aztec-nr/aztec/src/oracle/block_header.nr index 1f7d95863d79..88c306dbe2d6 100644 --- a/noir-projects/aztec-nr/aztec/src/oracle/block_header.nr +++ b/noir-projects/aztec-nr/aztec/src/oracle/block_header.nr @@ -66,14 +66,16 @@ fn constrain_get_block_header_at_internal( let witness = unsafe { get_archive_membership_witness(last_archive_block_number, block_hash) }; // 3) Check that the block is in the archive (i.e. the witness is valid) - assert( - last_archive_root == root_from_sibling_path(block_hash, witness.index, witness.path), + assert_eq( + last_archive_root, + root_from_sibling_path(block_hash, witness.index, witness.path), "Proving membership of a block in archive failed", ); // 4) Check that the header hint has the same block number as the block number we are looking for, ensuring we are actually grabbing the header we specify - assert( - header_hint.global_variables.block_number as u32 == block_number, + assert_eq( + header_hint.global_variables.block_number as u32, + block_number, "Block number provided is not the same as the block number from the header hint", ); } diff --git a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr index 4aeac993ff0f..29808aef30a3 100644 --- a/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr +++ b/noir-projects/aztec-nr/aztec/src/state_vars/shared_mutable/scheduled_delay_change.nr @@ -5,7 +5,7 @@ mod test; // This data structure is used by SharedMutable to store the minimum delay with which a ScheduledValueChange object can // schedule a change. -// This delay is initally equal to INITIAL_DELAY, and can be safely mutated to any other value over time. This mutation +// This delay is initially equal to INITIAL_DELAY, and can be safely mutated to any other value over time. This mutation // is performed via `schedule_change` in order to satisfy ScheduleValueChange constraints: if e.g. we allowed for the // delay to be decreased immediately then it'd be possible for the state variable to schedule a value change with a // reduced delay, invalidating prior private reads. diff --git a/noir-projects/aztec-nr/value-note/src/value_note.nr b/noir-projects/aztec-nr/value-note/src/value_note.nr index e5ebe0683738..f786a91e9ffd 100644 --- a/noir-projects/aztec-nr/value-note/src/value_note.nr +++ b/noir-projects/aztec-nr/value-note/src/value_note.nr @@ -13,7 +13,7 @@ use dep::aztec::{ }, }; -global VALUE_NOTE_LEN: u32 = 3; // 3 plus a header. +pub(crate) global VALUE_NOTE_LEN: u32 = 3; // 3 plus a header. // docs:start:value-note-def // ValueNote is used as fn parameter in the Claim contract, so it has to implement the Serialize trait. diff --git a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/test/utils.nr b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/test/utils.nr index 4a531d2e6ebb..8cd27d4b3a47 100644 --- a/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/test/utils.nr +++ b/noir-projects/noir-contracts/contracts/easy_private_voting_contract/src/test/utils.nr @@ -8,9 +8,8 @@ pub unconstrained fn setup() -> (&mut TestEnvironment, AztecAddress, AztecAddres let admin = env.create_account(); let initializer_call_interface = EasyPrivateVoting::interface().constructor(admin); - let voting_contract = unsafe { - env.deploy_self("EasyPrivateVoting").with_public_void_initializer(initializer_call_interface) - }; - // std::println(voting_contract); + let voting_contract = env.deploy_self("EasyPrivateVoting").with_public_void_initializer( + initializer_call_interface, + ); (&mut env, voting_contract.to_address(), admin) } diff --git a/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr index 7d5a92548103..af870d4665a5 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_k_account_contract/src/main.nr @@ -59,6 +59,8 @@ contract EcdsaKAccount { let public_key = storage.public_key.get_note(); // Load auth witness + /// Safety: The witness is only used as a "magical value" that makes the signature verification below pass. + /// Hence it's safe. let witness: [Field; 64] = unsafe { get_auth_witness(outer_hash) }; let mut signature: [u8; 64] = [0; 64]; for i in 0..64 { diff --git a/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr b/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr index db99f10a75b5..e401c1d0fece 100644 --- a/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/ecdsa_r_account_contract/src/main.nr @@ -57,6 +57,8 @@ contract EcdsaRAccount { let public_key = storage.public_key.get_note(); // Load auth witness + /// Safety: The witness is only used as a "magical value" that makes the signature verification below pass. + /// Hence it's safe. let witness: [Field; 64] = unsafe { get_auth_witness(outer_hash) }; let mut signature: [u8; 64] = [0; 64]; for i in 0..64 { diff --git a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr index f8f7fc8d15bd..54bcd858bd69 100644 --- a/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr +++ b/noir-projects/noir-contracts/contracts/stateful_test_contract/src/main.nr @@ -3,9 +3,12 @@ use dep::aztec::macros::aztec; #[aztec] contract StatefulTest { - use dep::aztec::{ - initializer::assert_is_initialized_private, - macros::{functions::{initializer, noinitcheck, private, public, view}, storage::storage}, + use dep::aztec::macros::{ + functions::{ + initialization_utils::assert_is_initialized_private, initializer, noinitcheck, private, + public, view, + }, + storage::storage, }; use dep::aztec::prelude::{AztecAddress, FunctionSelector, Map, PrivateSet, PublicMutable}; use dep::value_note::{balance_utils, utils::{decrement, increment}, value_note::ValueNote}; diff --git a/noir-projects/noir-protocol-circuits/crates/blob/src/blob.nr b/noir-projects/noir-protocol-circuits/crates/blob/src/blob.nr index 862dfad250c1..dc8b2a917666 100644 --- a/noir-projects/noir-protocol-circuits/crates/blob/src/blob.nr +++ b/noir-projects/noir-protocol-circuits/crates/blob/src/blob.nr @@ -12,13 +12,12 @@ use types::hash::poseidon2_hash_subarray; use std::ops::{Mul, Neg}; use types::{ abis::sponge_blob::SpongeBlob, - constants::{BLOBS_PER_BLOCK, FIELDS_PER_BLOB}, + constants::{BLOBS_PER_BLOCK, FIELDS_PER_BLOB, TWO_POW_64}, utils::arrays::array_splice, }; global LIMB_MAX: Field = 0x1000000000000000000000000000000; // 2^120 global TWO_POW_56: u64 = 0x100000000000000; // u64 to aid integer only modulo in __field_to_bignum_limbs -global TWO_POW_64: Field = 0x10000000000000000; unconstrained fn __batch_invert_impl(mut x: [F; N]) -> [F; N] { let mut accumulator: F = BigNum::one(); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/abis/sponge_blob.nr b/noir-projects/noir-protocol-circuits/crates/types/src/abis/sponge_blob.nr index 65078b66de61..e1b7aa2b1dad 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/abis/sponge_blob.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/abis/sponge_blob.nr @@ -1,5 +1,5 @@ use crate::{ - constants::{BLOBS_PER_BLOCK, FIELDS_PER_BLOB, SPONGE_BLOB_LENGTH}, + constants::{BLOBS_PER_BLOCK, FIELDS_PER_BLOB, SPONGE_BLOB_LENGTH, TWO_POW_64}, hash::poseidon2_absorb_chunks_existing_sponge, poseidon2::Poseidon2Sponge, traits::{Deserialize, Empty, Serialize}, @@ -19,7 +19,7 @@ use crate::{ // The hash is used as part of the blob challenge, as we've proven it encompasses all elts of the blob(s). // Init is given by input len * 2^64 (see noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr -> hash_internal) -global IV: Field = (FIELDS_PER_BLOB * BLOBS_PER_BLOCK) as Field * 18446744073709551616; +global IV: Field = (FIELDS_PER_BLOB * BLOBS_PER_BLOCK) as Field * TWO_POW_64; pub struct SpongeBlob { pub sponge: Poseidon2Sponge, @@ -34,7 +34,7 @@ impl SpongeBlob { pub fn new(expected_fields_hint: u32) -> Self { Self { - sponge: Poseidon2Sponge::new((expected_fields_hint as Field) * 18446744073709551616), + sponge: Poseidon2Sponge::new((expected_fields_hint as Field) * TWO_POW_64), fields: 0, expected_fields: expected_fields_hint, } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr index 49298426f4f3..1b8b8c7ab87d 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/constants.nr @@ -755,6 +755,8 @@ pub global PROOF_TYPE_AVM: u32 = 4; pub global PROOF_TYPE_ROLLUP_HONK: u32 = 5; pub global PROOF_TYPE_ROOT_ROLLUP_HONK: u32 = 6; +pub global TWO_POW_64: Field = 2.pow_32(64); + mod test { use crate::constants::{ MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_CALL, MAX_PUBLIC_DATA_UPDATE_REQUESTS_PER_TX, diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr index 9913030f1ebb..d73964db0dbf 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/hash.nr @@ -19,7 +19,7 @@ use crate::{ traits::{FromField, Hash, is_empty, ToField}, utils::field::field_from_bytes_32_trunc, }; -use super::utils::{arrays::array_concat, field::field_from_bytes}; +use super::{constants::TWO_POW_64, utils::{arrays::array_concat, field::field_from_bytes}}; pub fn sha256_to_field(bytes_to_hash: [u8; N]) -> Field { let sha256_hashed = std::hash::sha256(bytes_to_hash); @@ -288,8 +288,7 @@ fn poseidon2_absorb_chunks( in_len: u32, variable: bool, ) -> Poseidon2Sponge { - let two_pow_64 = 18446744073709551616; - let iv: Field = (in_len as Field) * two_pow_64; + let iv: Field = (in_len as Field) * TWO_POW_64; let mut sponge = Poseidon2Sponge::new(iv); // Even though shift is always 1 here, if we input in_len = 0 we get an underflow // since we cannot isolate computation branches. The below is just to avoid that. @@ -424,8 +423,7 @@ 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 iv: Field = (in_len as Field) * TWO_POW_64; let mut sponge = Poseidon2Sponge::new(iv); sponge.absorb(separator.to_field()); @@ -492,8 +490,7 @@ fn existing_sponge_poseidon_chunks_matches_fixed() { input[i] = 3; } // absorb 250 of the 501 things - let two_pow_64 = 18446744073709551616; - let empty_sponge = Poseidon2Sponge::new((in_len as Field) * two_pow_64); + let empty_sponge = Poseidon2Sponge::new((in_len as Field) * TWO_POW_64); let first_sponge = poseidon2_absorb_chunks_existing_sponge(empty_sponge, input, 250, true); // now absorb the final 251 (since they are all 3s, im being lazy and not making a new array) let mut final_sponge = poseidon2_absorb_chunks_existing_sponge(first_sponge, input, 251, true); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr b/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr index ede4d196c41f..257f295a3698 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/poseidon2.nr @@ -1,5 +1,7 @@ +use crate::constants::TWO_POW_64; + // NB: This is a clone of noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr -// It exists as we sometimes need to perform custom absorbtion, but the stdlib version +// It exists as we sometimes need to perform custom absorption, but the stdlib version // has a private absorb() method (it's also designed to just be a hasher) // Can be removed when standalone noir poseidon lib exists: See noir#6679 @@ -66,8 +68,7 @@ impl Poseidon2Sponge { in_len: u32, is_variable_length: bool, ) -> Field { - let two_pow_64 = 18446744073709551616; - let iv: Field = (in_len as Field) * two_pow_64; + let iv: Field = (in_len as Field) * TWO_POW_64; let mut sponge = Poseidon2Sponge::new(iv); for i in 0..input.len() { if i < in_len { diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr index d8093ba1fb67..44a76b077121 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays.nr @@ -65,12 +65,15 @@ where BoundedVec::from_parts_unchecked(array, len) } +// Helper function to find the index of the first element in an array that satisfies a given predicate. If the element +// is not found, the function returns N as the index. pub unconstrained fn find_index_hint( array: [T; N], find: fn[Env](T) -> bool, ) -> u32 { let mut index = N; for i in 0..N { + // We check `index == N` to ensure that we only update the index if we haven't found a match yet. if (index == N) & find(array[i]) { index = i; } diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_array.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_array.nr index 920b40c3e166..940c6f81540c 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_array.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_array.nr @@ -111,7 +111,7 @@ mod tests { builder.check_and_execute(); } - #[test(should_fail_with = "hinted item in the commbined array does not match")] + #[test(should_fail_with = "hinted item in the combined array does not match")] fn assert_combined_array_extra_item_fails() { let mut builder = TestBuilder::new(); @@ -121,7 +121,7 @@ mod tests { builder.execute(); } - #[test(should_fail_with = "hinted item in the commbined array does not match")] + #[test(should_fail_with = "hinted item in the combined array does not match")] fn assert_combined_array_missing_item_fails() { let mut builder = TestBuilder::new(); @@ -131,7 +131,7 @@ mod tests { builder.execute(); } - #[test(should_fail_with = "hinted item in the commbined array does not match")] + #[test(should_fail_with = "hinted item in the combined array does not match")] fn assert_combined_array_unordered_fails() { let mut builder = TestBuilder::new(); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_transformed_array.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_transformed_array.nr index 36e2acb084e3..c252e8359dc8 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_transformed_array.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/arrays/assert_combined_transformed_array.nr @@ -24,7 +24,7 @@ where let to = combined_array[i]; - assert(is_transformed(from, to), "hinted item in the commbined array does not match"); + assert(is_transformed(from, to), "hinted item in the combined array does not match"); } } @@ -140,7 +140,7 @@ mod tests { builder.check_and_execute(); } - #[test(should_fail_with = "hinted item in the commbined array does not match")] + #[test(should_fail_with = "hinted item in the combined array does not match")] unconstrained fn assert_combined_transformed_array_extra_item_fails() { let mut builder = TestBuilder::new(); @@ -150,7 +150,7 @@ mod tests { builder.execute(); } - #[test(should_fail_with = "hinted item in the commbined array does not match")] + #[test(should_fail_with = "hinted item in the combined array does not match")] unconstrained fn assert_combined_transformed_array_missing_item_fails() { let mut builder = TestBuilder::new(); @@ -160,7 +160,7 @@ mod tests { builder.execute(); } - #[test(should_fail_with = "hinted item in the commbined array does not match")] + #[test(should_fail_with = "hinted item in the combined array does not match")] unconstrained fn assert_combined_transformed_array_unordered_fails() { let mut builder = TestBuilder::new(); diff --git a/noir-projects/noir-protocol-circuits/crates/types/src/utils/uint256.nr b/noir-projects/noir-protocol-circuits/crates/types/src/utils/uint256.nr index bf0fbaf2844e..a87fda738427 100644 --- a/noir-projects/noir-protocol-circuits/crates/types/src/utils/uint256.nr +++ b/noir-projects/noir-protocol-circuits/crates/types/src/utils/uint256.nr @@ -1,3 +1,5 @@ +use crate::constants::TWO_POW_64; + // This is a quick struct made to pack 32 bytes into 4 u64s // and then pack those into two u128s. // @@ -62,10 +64,8 @@ impl U256 { // // TODO: Add a test for this. pub fn to_u128_limbs(self) -> [Field; 2] { - let two_pow_64 = 2.pow_32(64); - - let high = (self.inner[0] as Field) * two_pow_64 + self.inner[1] as Field; - let low = (self.inner[2] as Field) * two_pow_64 + self.inner[3] as Field; + let high = (self.inner[0] as Field) * TWO_POW_64 + self.inner[1] as Field; + let low = (self.inner[2] as Field) * TWO_POW_64 + self.inner[3] as Field; [high, low] } diff --git a/noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr b/noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr index 419f07a2aca5..ad4476f0d7c1 100644 --- a/noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr +++ b/noir/noir-repo/noir_stdlib/src/hash/poseidon2.nr @@ -16,7 +16,7 @@ impl Poseidon2 { Poseidon2::hash_internal(input, message_size, message_size != N) } - pub(crate) fn new(iv: Field) -> Poseidon2 { + pub fn new(iv: Field) -> Poseidon2 { let mut result = Poseidon2 { cache: [0; 3], state: [0; 4], cache_size: 0, squeeze_mode: false }; result.state[RATE] = iv; diff --git a/noir/noir-repo/noir_stdlib/src/uint128.nr b/noir/noir-repo/noir_stdlib/src/uint128.nr index 814797c1e028..bcb0746832ef 100644 --- a/noir/noir-repo/noir_stdlib/src/uint128.nr +++ b/noir/noir-repo/noir_stdlib/src/uint128.nr @@ -95,7 +95,7 @@ impl U128 { U128 { lo: lo as Field, hi: hi as Field } } - unconstrained fn uconstrained_check_is_upper_ascii(ascii: u8) -> bool { + unconstrained fn unconstrained_check_is_upper_ascii(ascii: u8) -> bool { ((ascii >= 65) & (ascii <= 90)) // Between 'A' and 'Z' } @@ -106,7 +106,7 @@ impl U128 { } else { /// Safety: optionally adds 32 and then check (below) the result is in 'a..f' range let ascii = - ascii + 32 * (unsafe { U128::uconstrained_check_is_upper_ascii(ascii) as u8 }); + ascii + 32 * (unsafe { U128::unconstrained_check_is_upper_ascii(ascii) as u8 }); assert(ascii >= 97); // enforce >= 'a' assert(ascii <= 102); // enforce <= 'f' ascii - 87