11use  std:: ops:: Deref ; 
22
3+ use  alloy_primitives:: keccak256; 
4+ use  sbv_helpers:: manually_drop_on_zkvm; 
35use  sbv_primitives:: { 
46    B256 ,  U256 , 
57    types:: { 
@@ -8,8 +10,11 @@ use sbv_primitives::{
810    } , 
911} ; 
1012
11- // FIXME as alloy-primitive 
12- use  tiny_keccak:: { Hasher ,  Keccak } ; 
13+ const  LEGACY_DA_HEADER_LEN :  usize  = size_of :: < u64 > ( )  // block number 
14+         + size_of :: < u64 > ( )  // timestamp 
15+         + U256 :: BYTES  // base fee per gas 
16+         + size_of :: < u64 > ( )  // gas limit 
17+         + size_of :: < u16 > ( ) ;  // l1 tx count 
1318
1419pub  trait  ChunkExt  { 
1520    /// Hash the transaction bytes. 
@@ -29,23 +34,35 @@ impl<T: Deref<Target = [RecoveredBlock<Block>]>> ChunkExt for T {
2934        blocks
3035            . iter ( ) 
3136            . flat_map ( |b| b. body ( ) . transactions . iter ( ) ) 
32-             . tx_bytes_hash_in ( rlp_buffer. as_mut ( ) ) 
37+             . tx_bytes_hash_in ( rlp_buffer) 
3338    } 
3439
3540    #[ inline]  
3641    fn  legacy_data_hash ( & self )  -> B256  { 
3742        let  blocks = self . as_ref ( ) ; 
3843
39-         let  mut  data_hasher = Keccak :: v256 ( ) ; 
44+         let  num_l1_txs:  usize  = blocks
45+             . iter ( ) 
46+             . map ( |b| { 
47+                 b. body ( ) 
48+                     . transactions 
49+                     . iter ( ) 
50+                     . filter ( |tx| tx. is_l1_message ( ) ) 
51+                     . count ( ) 
52+             } ) 
53+             . sum ( ) ; 
54+ 
55+         let  mut  buffer = manually_drop_on_zkvm ! ( Vec :: with_capacity( 
56+             blocks. len( )  *  LEGACY_DA_HEADER_LEN  + num_l1_txs *  size_of:: <B256 >( ) , 
57+         ) ) ; 
58+ 
4059        for  block in  blocks. iter ( )  { 
41-             block. legacy_hash_da_header ( & mut  data_hasher ) ; 
60+             block. encode_legacy_da_header ( & mut  buffer ) ; 
4261        } 
4362        for  block in  blocks. iter ( )  { 
44-             block. legacy_hash_l1_msg ( & mut  data_hasher ) ; 
63+             block. encode_legacy_l1_msg ( & mut  buffer ) ; 
4564        } 
46-         let  mut  data_hash = B256 :: ZERO ; 
47-         data_hasher. finalize ( & mut  data_hash. 0 ) ; 
48-         data_hash
65+         keccak256 ( & * buffer) 
4966    } 
5067
5168    #[ inline]  
@@ -66,82 +83,74 @@ trait TxBytesHashExt {
6683fn  tx_bytes_hash_in ( self ,  rlp_buffer :  & mut  Vec < u8 > )  -> ( usize ,  B256 ) ; 
6784} 
6885
69- impl < ' a ,  I :  IntoIterator < Item  = & ' a  TransactionSigned > >  TxBytesHashExt  for  I 
70- where 
71-     I :  IntoIterator < Item  = & ' a  TransactionSigned > , 
86+ impl < ' a ,  I :  Iterator < Item  = & ' a  TransactionSigned > >  TxBytesHashExt  for  I 
7287{ 
7388    #[ inline]  
7489    fn  tx_bytes_hash_in ( self ,  rlp_buffer :  & mut  Vec < u8 > )  -> ( usize ,  B256 )  { 
75-         use  tiny_keccak:: { Hasher ,  Keccak } ; 
76- 
77-         let  mut  tx_bytes_hasher = Keccak :: v256 ( ) ; 
78-         let  mut  len = 0 ; 
79- 
90+         rlp_buffer. clear ( ) ; 
8091        // Ignore L1 msg txs. 
81-         for  tx in  self . into_iter ( ) . filter ( |& tx| !tx. is_l1_message ( ) )  { 
92+         for  tx in  self . filter ( |& tx| !tx. is_l1_message ( ) )  { 
8293            tx. encode_2718 ( rlp_buffer) ; 
83-             len += rlp_buffer. len ( ) ; 
84-             tx_bytes_hasher. update ( rlp_buffer) ; 
85-             rlp_buffer. clear ( ) ; 
8694        } 
87- 
88-         let  mut  tx_bytes_hash = B256 :: ZERO ; 
89-         tx_bytes_hasher. finalize ( & mut  tx_bytes_hash. 0 ) ; 
90-         ( len,  tx_bytes_hash) 
95+         let  hash = keccak256 ( & rlp_buffer) ; 
96+         rlp_buffer. clear ( ) ; 
97+         ( rlp_buffer. len ( ) ,  hash) 
9198    } 
9299} 
93100
94101/// Chunk related extension methods for Block 
95102trait  BlockChunkExt  { 
96103    /// Hash the header of the block 
97- fn  legacy_hash_da_header ( & self ,  hasher :  & mut  impl  tiny_keccak :: Hasher ) ; 
104+ fn  encode_legacy_da_header ( & self ,  buffer :  & mut  Vec < u8 > ) ; 
98105    /// Hash the l1 messages of the block 
99- fn  legacy_hash_l1_msg ( & self ,  hasher :  & mut  impl   Hasher ) ; 
106+ fn  encode_legacy_l1_msg ( & self ,  buffer :  & mut  Vec < u8 > ) ; 
100107    /// Hash the l1 messages of the block 
101108fn  hash_msg_queue ( & self ,  initial_queue_hash :  & B256 )  -> B256 ; 
102109} 
103110
104111impl  BlockChunkExt  for  RecoveredBlock < Block >  { 
105112    #[ inline]  
106-     fn  legacy_hash_da_header ( & self ,  hasher :  & mut  impl   Hasher )  { 
107-         hasher . update ( & self . number . to_be_bytes ( ) ) ; 
108-         hasher . update ( & self . timestamp . to_be_bytes ( ) ) ; 
109-         hasher . update ( 
113+     fn  encode_legacy_da_header ( & self ,  buffer :  & mut  Vec < u8 > )  { 
114+         buffer . extend_from_slice ( & self . number . to_be_bytes ( ) ) ; 
115+         buffer . extend_from_slice ( & self . timestamp . to_be_bytes ( ) ) ; 
116+         buffer . extend_from_slice ( 
110117            & U256 :: from_limbs ( [ self . base_fee_per_gas . unwrap_or_default ( ) ,  0 ,  0 ,  0 ] ) 
111118                . to_be_bytes :: < {  U256 :: BYTES  } > ( ) , 
112119        ) ; 
113-         hasher . update ( & self . gas_limit . to_be_bytes ( ) ) ; 
120+         buffer . extend_from_slice ( & self . gas_limit . to_be_bytes ( ) ) ; 
114121        // FIXME: l1 tx could be skipped, the actual tx count needs to be calculated 
115-         hasher . update ( & ( self . body ( ) . transactions . len ( )  as  u16 ) . to_be_bytes ( ) ) ; 
122+         buffer . extend_from_slice ( & ( self . body ( ) . transactions . len ( )  as  u16 ) . to_be_bytes ( ) ) ; 
116123    } 
117124
118125    #[ inline]  
119-     fn  legacy_hash_l1_msg ( & self ,  hasher :  & mut  impl   Hasher )  { 
126+     fn  encode_legacy_l1_msg ( & self ,  buffer :  & mut  Vec < u8 > )  { 
120127        for  tx in  self 
121128            . body ( ) 
122129            . transactions 
123130            . iter ( ) 
124-             . filter ( |tx| tx. is_l1_message ( ) ) 
131+             . filter_map ( |tx| tx. as_l1_message ( ) ) 
125132        { 
126-             hasher . update ( tx. tx_hash ( ) . as_slice ( ) ) 
133+             buffer . extend_from_slice ( tx. hash_ref ( ) . as_ref ( ) ) ; 
127134        } 
128135    } 
129136
130137    #[ inline]  
131138    fn  hash_msg_queue ( & self ,  initial_queue_hash :  & B256 )  -> B256  { 
132139        let  mut  rolling_hash = * initial_queue_hash; 
140+ 
141+         let  mut  buffer = [ 0u8 ;  {  size_of :: < B256 > ( )  *  2  } ] ; 
142+         buffer[ ..32 ] . copy_from_slice ( rolling_hash. as_ref ( ) ) ; 
143+ 
133144        for  tx in  self 
134145            . body ( ) 
135146            . transactions 
136147            . iter ( ) 
137148            . filter ( |tx| tx. is_l1_message ( ) ) 
138149        { 
139-             let  mut  hasher = Keccak :: v256 ( ) ; 
140-             hasher. update ( rolling_hash. as_slice ( ) ) ; 
141-             hasher. update ( tx. tx_hash ( ) . as_slice ( ) ) ; 
142- 
143-             hasher. finalize ( rolling_hash. as_mut_slice ( ) ) ; 
150+             buffer[ ..size_of :: < B256 > ( ) ] . copy_from_slice ( rolling_hash. as_ref ( ) ) ; 
151+             buffer[ size_of :: < B256 > ( ) ..] . copy_from_slice ( tx. tx_hash ( ) . as_ref ( ) ) ; 
144152
153+             rolling_hash = keccak256 ( & buffer) ; 
145154            // clear last 32 bits, i.e. 4 bytes. 
146155            // https://github.com/scroll-tech/da-codec/blob/26dc8d575244560611548fada6a3a2745c60fe83/encoding/da.go#L817-L825 
147156            // see also https://github.com/scroll-tech/da-codec/pull/42 
0 commit comments