@@ -218,30 +218,38 @@ impl Eip712 for NoncedVerificationData {
218218 }
219219
220220 fn struct_hash ( & self ) -> Result < [ u8 ; 32 ] , Self :: Error > {
221+ //EIP requires big endian for u256
222+ let mut nonce_bytes = [ 0u8 ; 32 ] ;
223+ self . nonce . to_big_endian ( & mut nonce_bytes) ;
224+
225+ let mut max_fee_bytes = [ 0u8 ; 32 ] ;
226+ self . max_fee . to_big_endian ( & mut max_fee_bytes) ;
227+
228+ // This hashes the data of the task the user wants solved
229+ // This is the data that is the leaf on the batch merkle tree
221230 let verification_data_hash =
222231 VerificationCommitmentBatch :: hash_data ( & self . verification_data . clone ( ) . into ( ) ) ;
223232
224233 let mut hasher = Keccak256 :: new ( ) ;
225234
235+ // As per the EIP, first we generate the type hash
236+ // hashStruct(s : 𝕊) = keccak256(typeHash ‖ encodeData(s))
226237 hasher. update ( NONCED_VERIFICATION_DATA_TYPE ) ;
227- let nonced_verification_data_type_hash = hasher. finalize_reset ( ) ;
238+ let type_hash = hasher. finalize_reset ( ) ;
228239
229- let mut nonce_bytes = [ 0u8 ; 32 ] ;
230- self . nonce . to_big_endian ( & mut nonce_bytes ) ;
240+ // Then hash is resetted, so we start hashing the second term of the encodedData(s)
241+ hasher . update ( verification_data_hash ) ;
231242 hasher. update ( nonce_bytes) ;
232- let nonce_hash = hasher. finalize_reset ( ) ;
233-
234- let mut max_fee_bytes = [ 0u8 ; 32 ] ;
235- self . max_fee . to_big_endian ( & mut max_fee_bytes) ;
236243 hasher. update ( max_fee_bytes) ;
237- let max_fee_hash = hasher. finalize_reset ( ) ;
244+ let encoded_data_hash = hasher. finalize_reset ( ) ;
238245
239- hasher. update ( nonced_verification_data_type_hash. as_slice ( ) ) ;
240- hasher. update ( verification_data_hash. as_slice ( ) ) ;
241- hasher. update ( nonce_hash. as_slice ( ) ) ;
242- hasher. update ( max_fee_hash. as_slice ( ) ) ;
246+ // Now we do the actual final
247+ // keccak256(typeHash ‖ encodeData(s))
248+ hasher. update ( type_hash) ;
249+ hasher. update ( encoded_data_hash) ;
250+ let hash_struct = hasher. finalize_reset ( ) ;
243251
244- Ok ( hasher . finalize ( ) . into ( ) )
252+ Ok ( hash_struct . into ( ) )
245253 }
246254}
247255
@@ -266,6 +274,7 @@ impl ClientMessage {
266274 /// The signature of the message is verified, and when it correct, the
267275 /// recovered address from the signature is returned.
268276 pub fn verify_signature ( & self ) -> Result < Address , VerifySignatureError > {
277+ // Recovers the address from the signed data
269278 let recovered = self . signature . recover_typed_data ( & self . verification_data ) ?;
270279
271280 let hashed_data = self . verification_data . encode_eip712 ( ) ?;
@@ -329,3 +338,51 @@ pub enum Chain {
329338 Holesky ,
330339 HoleskyStage ,
331340}
341+
342+ #[ cfg( test) ]
343+ mod tests {
344+ use ethers:: signers:: LocalWallet ;
345+ use std:: str:: FromStr ;
346+
347+ use super :: * ;
348+
349+ #[ tokio:: test]
350+ async fn eip_712_recovers_same_address_as_signed ( ) {
351+ const ANVIL_PRIVATE_KEY : & str =
352+ "2a871d0798f97d79848a013d4936a73bf4cc922c825d33c1cf7073dff6d409c6" ; // Anvil address 9
353+ let wallet = LocalWallet :: from_str ( ANVIL_PRIVATE_KEY ) . expect ( "Failed to create wallet" ) ;
354+
355+ let proof = [ 42 , 42 , 42 , 42 ] . to_vec ( ) ;
356+ let pub_input = Some ( [ 32 , 32 , 32 , 32 ] . to_vec ( ) ) ;
357+ let verification_key = Some ( [ 8 , 8 , 8 , 8 ] . to_vec ( ) ) ;
358+ let proving_system = ProvingSystemId :: Groth16Bn254 ;
359+
360+ let verification_data = VerificationData {
361+ proving_system,
362+ proof,
363+ pub_input,
364+ verification_key,
365+ vm_program_code : None ,
366+ proof_generator_addr : wallet. address ( ) ,
367+ } ;
368+
369+ let nonced_verification_data = NoncedVerificationData :: new (
370+ verification_data,
371+ 1 . into ( ) ,
372+ 2 . into ( ) ,
373+ 3 . into ( ) ,
374+ wallet. address ( ) ,
375+ ) ;
376+
377+ let signed_data = wallet
378+ . sign_typed_data ( & nonced_verification_data)
379+ . await
380+ . unwrap ( ) ;
381+
382+ let recovered_address = signed_data
383+ . recover_typed_data ( & nonced_verification_data)
384+ . unwrap ( ) ;
385+
386+ assert_eq ! ( recovered_address, wallet. address( ) )
387+ }
388+ }
0 commit comments