Skip to content

Commit a41bdf8

Browse files
authored
refactor: make prover leaf-hashing hash-agnostic via backend's hash_bytes (#506)
Add hash_bytes() inherent method to FieldElementVectorBackend that surfaces the generic digest parameter D. The prover now calls BatchedMerkleTreeBackend::<E>::hash_bytes() instead of hardcoding sha3::Keccak256, so changing the config.rs type alias automatically propagates the hash function to the commit hot paths. Also adds missing debug_assert for power-of-two in commit_columns_bit_reversed for consistency with commit_composition_polynomial.
1 parent 33b6e50 commit a41bdf8

2 files changed

Lines changed: 25 additions & 9 deletions

File tree

crypto/crypto/src/merkle_tree/backends/field_element_vector.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,23 @@ impl<F, D: Digest, const NUM_BYTES: usize> Default for FieldElementVectorBackend
7171
}
7272
}
7373

74+
impl<F, D: Digest, const NUM_BYTES: usize> FieldElementVectorBackend<F, D, NUM_BYTES>
75+
where
76+
[u8; NUM_BYTES]: From<Output<D>>,
77+
{
78+
/// Hash raw bytes using the same digest (`D`) as this backend's leaf hashing.
79+
/// Enables callers to pre-serialize field elements into a byte buffer and hash
80+
/// once, avoiding per-element allocations while staying consistent with the
81+
/// backend's hash function.
82+
pub fn hash_bytes(data: &[u8]) -> [u8; NUM_BYTES] {
83+
let mut hasher = D::new();
84+
hasher.update(data);
85+
let mut result = [0u8; NUM_BYTES];
86+
result.copy_from_slice(&hasher.finalize());
87+
result
88+
}
89+
}
90+
7491
impl<F, D: Digest, const NUM_BYTES: usize> IsMerkleTreeBackend
7592
for FieldElementVectorBackend<F, D, NUM_BYTES>
7693
where

crypto/stark/src/prover.rs

Lines changed: 8 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ use crate::proof::stark::{DeepPolynomialOpenings, PolynomialOpenings};
3131
use crate::table::Table;
3232
use crate::trace::LDETraceTable;
3333

34-
use super::config::{BatchedMerkleTree, Commitment};
34+
use super::config::{BatchedMerkleTree, BatchedMerkleTreeBackend, Commitment};
3535
use super::constraints::evaluator::ConstraintEvaluator;
3636
use super::domain::Domain;
3737
use super::fri::fri_decommit::FriDecommitment;
@@ -373,7 +373,6 @@ pub trait IsStarkProver<
373373
E: IsField,
374374
{
375375
use math::traits::WriteBytes;
376-
use sha3::Digest;
377376

378377
if columns.is_empty() || columns[0].is_empty() {
379378
return None;
@@ -383,6 +382,11 @@ pub trait IsStarkProver<
383382
let num_cols = columns.len();
384383
let byte_len = <FieldElement<E> as WriteBytes>::BYTE_LEN;
385384

385+
debug_assert!(
386+
num_rows.is_power_of_two(),
387+
"num_rows must be a power of two for reverse_index"
388+
);
389+
386390
#[cfg(feature = "parallel")]
387391
let iter = (0..num_rows).into_par_iter();
388392
#[cfg(not(feature = "parallel"))]
@@ -399,9 +403,7 @@ pub trait IsStarkProver<
399403
columns[col_idx][br_idx]
400404
.write_bytes_be(&mut buf[col_idx * byte_len..(col_idx + 1) * byte_len]);
401405
}
402-
let mut hasher = sha3::Keccak256::new();
403-
hasher.update(&buf);
404-
hasher.finalize().into()
406+
BatchedMerkleTreeBackend::<E>::hash_bytes(&buf)
405407
})
406408
.collect();
407409

@@ -694,7 +696,6 @@ pub trait IsStarkProver<
694696
FieldElement<FieldExtension>: AsBytes + Sync + Send + math::traits::WriteBytes,
695697
{
696698
use math::traits::WriteBytes;
697-
use sha3::Digest;
698699

699700
let num_parts = lde_composition_poly_parts_evaluations.len();
700701
if num_parts == 0 {
@@ -735,9 +736,7 @@ pub trait IsStarkProver<
735736
part[br_1].write_bytes_be(&mut buf[offset..offset + byte_len]);
736737
offset += byte_len;
737738
}
738-
let mut hasher = sha3::Keccak256::new();
739-
hasher.update(&buf);
740-
hasher.finalize().into()
739+
BatchedMerkleTreeBackend::<FieldExtension>::hash_bytes(&buf)
741740
})
742741
.collect();
743742

0 commit comments

Comments
 (0)