Skip to content

Commit 7615bf4

Browse files
committed
feat(tee-proof-verifier): add support for Solidity-compatible pubkey in report_data
This PR is part of the effort to implement on-chain TEE proof verification. This PR goes hand in hand with: - matter-labs/zksync-era#3414 - #228
1 parent a9b89ef commit 7615bf4

File tree

1 file changed

+39
-16
lines changed

1 file changed

+39
-16
lines changed

bin/verify-era-proof-attestation/src/verification.rs

Lines changed: 39 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -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

4851
pub 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-
9491
fn 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

Comments
 (0)