@@ -27,22 +27,25 @@ pub async fn verify_batch_proof(
2727 }
2828
2929 let batch_no = batch_number. 0 ;
30-
31- let public_key = PublicKey :: from_slice (
32- & quote_verification_result. quote . get_report_data ( ) [ ..PUBLIC_KEY_SIZE ] ,
33- ) ?;
34- debug ! ( batch_no, "public key: {}" , public_key) ;
35-
3630 let root_hash = node_client. get_root_hash ( batch_number) . await ?;
37- debug ! ( batch_no, "root hash: {}" , root_hash) ;
31+ let ethereum_address_from_quote =
32+ PublicKey :: from_slice ( & quote_verification_result. quote . get_report_data ( ) [ ..20 ] ) ?;
33+ let ethereum_address_from_signature = recover_signer ( signature, root_hash) ;
34+ let verification_successful = ethereum_address_from_signature == ethereum_address_from_quote;
35+ debug ! (
36+ batch_no,
37+ root_hash,
38+ "Ethereum address from the attestation quote: {}. Ethereum address from the signature: {}." ,
39+ encode( ethereum_address_from_quote) ,
40+ encode( ethereum_address_from_signature) ,
41+ ) ;
3842
39- let is_verified = verify_signature ( signature, public_key, root_hash) ?;
40- if is_verified {
43+ if verification_successful {
4144 info ! ( batch_no, signature = %encode( signature) , "Signature verified successfully." ) ;
4245 } else {
4346 warn ! ( batch_no, signature = %encode( signature) , "Failed to verify signature!" ) ;
4447 }
45- Ok ( is_verified )
48+ Ok ( verification_successful )
4649}
4750
4851pub fn verify_attestation_quote ( attestation_quote_bytes : & [ u8 ] ) -> Result < QuoteVerificationResult > {
@@ -85,12 +88,6 @@ pub fn log_quote_verification_summary(quote_verification_result: &QuoteVerificat
8588 ) ;
8689}
8790
88- fn verify_signature ( signature : & [ u8 ] , public_key : PublicKey , root_hash : H256 ) -> Result < bool > {
89- let signature = Signature :: from_compact ( signature) ?;
90- let root_hash_msg = Message :: from_digest_slice ( & root_hash. 0 ) ?;
91- Ok ( signature. verify ( & root_hash_msg, & public_key) . is_ok ( ) )
92- }
93-
9491fn is_quote_matching_policy (
9592 attestation_policy : & AttestationPolicyArgs ,
9693 quote_verification_result : & QuoteVerificationResult ,
@@ -136,3 +133,29 @@ fn check_policy(policy: Option<&str>, actual_value: &[u8], field_name: &str) ->
136133 }
137134 true
138135}
136+
137+ /// Equivalent to the ecrecover precompile, ensuring that the signatures we produce off-chain
138+ /// can be recovered on-chain.
139+ pub fn recover_signer ( sig : & [ u8 ; 65 ] , root_hash : H256 ) -> Result < [ u8 ; 20 ] > {
140+ let root_hash_bytes = root_hash. as_bytes ( ) ;
141+ let msg = Message :: from_slice ( root_hash_bytes) ?;
142+ let sig = RecoverableSignature :: from_compact (
143+ & sig[ 0 ..64 ] ,
144+ RecoveryId :: from_i32 ( sig[ 64 ] as i32 - 27 ) ?,
145+ ) ?;
146+ let public = SECP256K1 . recover_ecdsa ( msg, & sig) ?;
147+ Ok ( public_key_to_ethereum_address ( & public) )
148+ }
149+
150+ /// Converts a public key into an Ethereum address by hashing the encoded public key with Keccak256.
151+ fn public_key_to_ethereum_address ( public : & PublicKey ) -> [ u8 ; 20 ] {
152+ let public_key_bytes = public. serialize_uncompressed ( ) ;
153+
154+ // Skip the first byte (0x04) which indicates uncompressed key
155+ let hash: [ u8 ; 32 ] = Keccak256 :: digest ( & public_key_bytes[ 1 ..] ) . into ( ) ;
156+
157+ // Take the last 20 bytes of the hash to get the Ethereum address
158+ let mut address = [ 0u8 ; 20 ] ;
159+ address. copy_from_slice ( & hash[ 12 ..] ) ;
160+ address
161+ }
0 commit comments