@@ -4,7 +4,6 @@ use std::sync::Arc;
44use std:: time:: Instant ;
55
66use crypto:: fiat_shamir:: is_transcript:: IsStarkTranscript ;
7- use crypto:: merkle_tree:: traits:: IsMerkleTreeBackend ;
87use math:: fft:: cpu:: bit_reversing:: { in_place_bit_reverse_permute, reverse_index} ;
98use math:: fft:: cpu:: bowers_fft:: LayerTwiddles ;
109use math:: fft:: errors:: FFTError ;
6362 FieldExtension : Send + Sync + IsField ,
6463 PI ,
6564> IsStarkProver < Field , FieldExtension , PI > for Prover < Field , FieldExtension , PI >
65+ where
66+ FieldElement < Field > : math:: traits:: ByteConversion ,
67+ FieldElement < FieldExtension > : math:: traits:: ByteConversion ,
6668{
6769}
6870
@@ -352,22 +354,10 @@ pub trait IsStarkProver<
352354 Field : IsSubFieldOf < FieldExtension > + IsFFTField + Send + Sync ,
353355 FieldExtension : Send + Sync + IsField ,
354356 PI ,
355- >
357+ > where
358+ FieldElement < Field > : math:: traits:: ByteConversion ,
359+ FieldElement < FieldExtension > : math:: traits:: ByteConversion ,
356360{
357- /// Returns the Merkle tree and the commitment to the vectors `vectors`.
358- fn batch_commit_extension (
359- vectors : & [ Vec < FieldElement < FieldExtension > > ] ,
360- ) -> Option < ( BatchedMerkleTree < FieldExtension > , Commitment ) >
361- where
362- FieldElement < Field > : AsBytes + Sync + Send ,
363- FieldElement < FieldExtension > : AsBytes + Sync + Send ,
364- {
365- let tree = BatchedMerkleTree :: build ( vectors) ?;
366-
367- let commitment = tree. root ;
368- Some ( ( tree, commitment) )
369- }
370-
371361 /// Builds a Merkle tree commitment from column-major LDE evaluations with
372362 /// bit-reverse permutation, without cloning the full evaluation matrix.
373363 ///
@@ -379,28 +369,41 @@ pub trait IsStarkProver<
379369 columns : & [ Vec < FieldElement < E > > ] ,
380370 ) -> Option < ( BatchedMerkleTree < E > , Commitment ) >
381371 where
382- FieldElement < E > : AsBytes + Sync + Send ,
372+ FieldElement < E > : AsBytes + Sync + Send + math :: traits :: ByteConversion ,
383373 E : IsField ,
384374 {
375+ use math:: traits:: ByteConversion ;
376+
385377 if columns. is_empty ( ) || columns[ 0 ] . is_empty ( ) {
386378 return None ;
387379 }
388380
389381 let num_rows = columns[ 0 ] . len ( ) ;
390382 let num_cols = columns. len ( ) ;
383+ let byte_len = <FieldElement < E > as ByteConversion >:: BYTE_LEN ;
384+
385+ debug_assert ! (
386+ num_rows. is_power_of_two( ) ,
387+ "num_rows must be a power of two for reverse_index"
388+ ) ;
391389
392390 #[ cfg( feature = "parallel" ) ]
393391 let iter = ( 0 ..num_rows) . into_par_iter ( ) ;
394392 #[ cfg( not( feature = "parallel" ) ) ]
395393 let iter = 0 ..num_rows;
396394
395+ // One allocation per row (was one per field element): write all columns
396+ // into a single buffer, then hash once.
397397 let hashed_leaves: Vec < Commitment > = iter
398398 . map ( |row_idx| {
399399 let br_idx = reverse_index ( row_idx, num_rows as u64 ) ;
400- let row: Vec < FieldElement < E > > = ( 0 ..num_cols)
401- . map ( |col_idx| columns[ col_idx] [ br_idx] . clone ( ) )
402- . collect ( ) ;
403- BatchedMerkleTreeBackend :: < E > :: hash_data ( & row)
400+ let total_bytes = num_cols * byte_len;
401+ let mut buf = vec ! [ 0u8 ; total_bytes] ;
402+ for col_idx in 0 ..num_cols {
403+ columns[ col_idx] [ br_idx]
404+ . write_bytes_be ( & mut buf[ col_idx * byte_len..( col_idx + 1 ) * byte_len] ) ;
405+ }
406+ BatchedMerkleTreeBackend :: < E > :: hash_bytes ( & buf)
404407 } )
405408 . collect ( ) ;
406409
@@ -690,8 +693,10 @@ pub trait IsStarkProver<
690693 ) -> Option < ( BatchedMerkleTree < FieldExtension > , Commitment ) >
691694 where
692695 FieldElement < Field > : AsBytes + Sync + Send ,
693- FieldElement < FieldExtension > : AsBytes + Sync + Send ,
696+ FieldElement < FieldExtension > : AsBytes + Sync + Send + math :: traits :: ByteConversion ,
694697 {
698+ use math:: traits:: ByteConversion ;
699+
695700 let num_parts = lde_composition_poly_parts_evaluations. len ( ) ;
696701 if num_parts == 0 {
697702 return None ;
@@ -702,18 +707,15 @@ pub trait IsStarkProver<
702707 }
703708
704709 let num_leaves = num_rows / 2 ;
705- debug_assert ! (
706- num_rows. is_power_of_two( ) ,
707- "num_rows must be a power of two for reverse_index to be correct"
708- ) ;
709710 debug_assert ! (
710711 num_rows. is_power_of_two( ) ,
711712 "num_rows must be a power of two for reverse_index"
712713 ) ;
713714
714- // Skip the transpose + merge by computing leaf data inline.
715- // Each leaf = row_pair[2*i] ++ row_pair[2*i+1] after bit-reverse.
716- // Build the merged leaf data and hash in one pass.
715+ let byte_len = <FieldElement < FieldExtension > as ByteConversion >:: BYTE_LEN ;
716+
717+ // One allocation per leaf (was one per field element): write all parts
718+ // into a single buffer. Each leaf = row_pair[2*i] ++ row_pair[2*i+1] after bit-reverse.
717719 #[ cfg( feature = "parallel" ) ]
718720 let iter = ( 0 ..num_leaves) . into_par_iter ( ) ;
719721 #[ cfg( not( feature = "parallel" ) ) ]
@@ -723,14 +725,18 @@ pub trait IsStarkProver<
723725 . map ( |leaf_idx| {
724726 let br_0 = reverse_index ( 2 * leaf_idx, num_rows as u64 ) ;
725727 let br_1 = reverse_index ( 2 * leaf_idx + 1 , num_rows as u64 ) ;
726- let mut leaf = Vec :: with_capacity ( 2 * num_parts) ;
728+ let total_bytes = 2 * num_parts * byte_len;
729+ let mut buf = vec ! [ 0u8 ; total_bytes] ;
730+ let mut offset = 0 ;
727731 for part in lde_composition_poly_parts_evaluations. iter ( ) {
728- leaf. push ( part[ br_0] . clone ( ) ) ;
732+ part[ br_0] . write_bytes_be ( & mut buf[ offset..offset + byte_len] ) ;
733+ offset += byte_len;
729734 }
730735 for part in lde_composition_poly_parts_evaluations. iter ( ) {
731- leaf. push ( part[ br_1] . clone ( ) ) ;
736+ part[ br_1] . write_bytes_be ( & mut buf[ offset..offset + byte_len] ) ;
737+ offset += byte_len;
732738 }
733- BatchedMerkleTreeBackend :: < FieldExtension > :: hash_data ( & leaf )
739+ BatchedMerkleTreeBackend :: < FieldExtension > :: hash_bytes ( & buf )
734740 } )
735741 . collect ( ) ;
736742
0 commit comments