diff --git a/crypto/crypto/src/merkle_tree/backends/field_element_vector.rs b/crypto/crypto/src/merkle_tree/backends/field_element_vector.rs index a97c0ce37..1023b3a03 100644 --- a/crypto/crypto/src/merkle_tree/backends/field_element_vector.rs +++ b/crypto/crypto/src/merkle_tree/backends/field_element_vector.rs @@ -71,6 +71,23 @@ impl Default for FieldElementVectorBackend } } +impl FieldElementVectorBackend +where + [u8; NUM_BYTES]: From>, +{ + /// Hash raw bytes using the same digest (`D`) as this backend's leaf hashing. + /// Enables callers to pre-serialize field elements into a byte buffer and hash + /// once, avoiding per-element allocations while staying consistent with the + /// backend's hash function. + pub fn hash_bytes(data: &[u8]) -> [u8; NUM_BYTES] { + let mut hasher = D::new(); + hasher.update(data); + let mut result = [0u8; NUM_BYTES]; + result.copy_from_slice(&hasher.finalize()); + result + } +} + impl IsMerkleTreeBackend for FieldElementVectorBackend where diff --git a/crypto/stark/src/prover.rs b/crypto/stark/src/prover.rs index 9a6604d3b..66e76ca1e 100644 --- a/crypto/stark/src/prover.rs +++ b/crypto/stark/src/prover.rs @@ -31,7 +31,7 @@ use crate::proof::stark::{DeepPolynomialOpenings, PolynomialOpenings}; use crate::table::Table; use crate::trace::LDETraceTable; -use super::config::{BatchedMerkleTree, Commitment}; +use super::config::{BatchedMerkleTree, BatchedMerkleTreeBackend, Commitment}; use super::constraints::evaluator::ConstraintEvaluator; use super::domain::Domain; use super::fri::fri_decommit::FriDecommitment; @@ -373,7 +373,6 @@ pub trait IsStarkProver< E: IsField, { use math::traits::WriteBytes; - use sha3::Digest; if columns.is_empty() || columns[0].is_empty() { return None; @@ -383,6 +382,11 @@ pub trait IsStarkProver< let num_cols = columns.len(); let byte_len = as WriteBytes>::BYTE_LEN; + debug_assert!( + num_rows.is_power_of_two(), + "num_rows must be a power of two for reverse_index" + ); + #[cfg(feature = "parallel")] let iter = (0..num_rows).into_par_iter(); #[cfg(not(feature = "parallel"))] @@ -399,9 +403,7 @@ pub trait IsStarkProver< columns[col_idx][br_idx] .write_bytes_be(&mut buf[col_idx * byte_len..(col_idx + 1) * byte_len]); } - let mut hasher = sha3::Keccak256::new(); - hasher.update(&buf); - hasher.finalize().into() + BatchedMerkleTreeBackend::::hash_bytes(&buf) }) .collect(); @@ -694,7 +696,6 @@ pub trait IsStarkProver< FieldElement: AsBytes + Sync + Send + math::traits::WriteBytes, { use math::traits::WriteBytes; - use sha3::Digest; let num_parts = lde_composition_poly_parts_evaluations.len(); if num_parts == 0 { @@ -735,9 +736,7 @@ pub trait IsStarkProver< part[br_1].write_bytes_be(&mut buf[offset..offset + byte_len]); offset += byte_len; } - let mut hasher = sha3::Keccak256::new(); - hasher.update(&buf); - hasher.finalize().into() + BatchedMerkleTreeBackend::::hash_bytes(&buf) }) .collect();