11// Modules
2-
32mod helpers;
43mod types;
54
65// Makes only the two types on this use public
76pub use types:: { AggregationModeVerificationData , ProofVerificationAggModeError } ;
87
9- use helpers:: { fetch_verified_proofs_events, get_blob_data_from_verified_proof_event} ;
10- use types:: Hash32 ;
11-
12- //
138use crate :: {
149 common:: types:: Network , eth:: aligned_proof_agg_service:: aligned_proof_aggregation_service,
1510} ;
1611use ethers:: {
1712 providers:: { Http , Provider } ,
1813 types:: Bytes ,
1914} ;
15+ use helpers:: { fetch_verified_proofs_events, get_blob_data_from_verified_proof_event} ;
2016use lambdaworks_crypto:: merkle_tree:: merkle:: MerkleTree ;
17+ use types:: Hash32 ;
18+
19+ pub enum ProofStatus {
20+ Verified {
21+ merkle_root : [ u8 ; 32 ] ,
22+ merkle_path : Vec < [ u8 ; 32 ] > ,
23+ } ,
24+ Invalid ,
25+ NotFound ,
26+ }
2127
2228/// Given the [`AggregationModeVerificationData`], this function checks whether the proof was included in a
2329/// in a recent aggregated proof and verifies the corresponding Merkle root commitment.
2430///
25- /// Note: This functionality is currently in Beta. As a result, we cannot determine with certainty
26- /// which specific aggregation a proof belongs to. Instead , we check the events from the specified `from_block` .
27- ///
28- /// Note: The `from_block` must not be older than 18 days,
31+ /// ### Notes
32+ /// - This functionality is currently in Beta. As a result , we cannot determine with certainty .
33+ /// which specific aggregation a proof belongs to. Instead, we check the events from the specified `from_block`.
34+ /// - The `from_block` must not be older than 18 days,
2935/// as blobs expire after that period and will no longer be retrievable.
30- /// If not provided, it defaults to fetch logs from [`FROM_BLOCKS_AGO_DEFAULT`]
36+ /// - If not provided, it defaults to fetch logs from [`FROM_BLOCKS_AGO_DEFAULT`]
3137///
32- /// The step-by-step verification process includes:
38+ /// ### The verification process includes:
3339/// 1. Querying the blob versioned hash from the events emitted by the aligned proof aggregation service contract since `from_block`
3440/// 2. Retrieving the corresponding beacon block using the block's parent beacon root
3541/// 3. Fetching the blobs associated with that slot
3642/// 4. Filtering the blob that matches the queried blob versioned hash
3743/// 5. Decoding the blob to extract the proofs commitments
3844/// 6. Checking if the given proof commitment exists within the blob's proofs
3945/// 7. Reconstructing the Merkle root and verifying it against the root stored in the contract
40- pub async fn is_proof_verified (
41- verification_data : AggregationModeVerificationData ,
46+ ///
47+ /// This function is typically used in conjunction with `verifyProofInclusion` for complete on-chain verification.
48+ pub async fn check_proof_verification (
49+ verification_data : & AggregationModeVerificationData ,
4250 network : Network ,
4351 eth_rpc_url : String ,
4452 beacon_client_url : String ,
4553 from_block : Option < u64 > ,
46- ) -> Result < [ u8 ; 32 ] , ProofVerificationAggModeError > {
54+ ) -> Result < ProofStatus , ProofVerificationAggModeError > {
4755 let logs = fetch_verified_proofs_events ( network, eth_rpc_url. clone ( ) , from_block) . await ?;
56+ let proof_commitment = verification_data. commitment ( ) ;
4857
4958 for log in logs {
50- let Ok ( ( merkle_root, leaves) ) = get_blob_data_from_verified_proof_event (
59+ let ( merkle_root, leaves) = get_blob_data_from_verified_proof_event (
5160 eth_rpc_url. clone ( ) ,
5261 beacon_client_url. clone ( ) ,
5362 log,
5463 )
55- . await
56- else {
57- continue ;
58- } ;
64+ . await ?;
5965
6066 let leaves: Vec < Hash32 > = leaves. iter ( ) . map ( |leaf| Hash32 ( * leaf) ) . collect ( ) ;
6167 let Some ( merkle_tree) = MerkleTree :: < Hash32 > :: build ( & leaves) else {
6268 continue ;
6369 } ;
6470
65- if leaves. contains ( & Hash32 ( verification_data. commitment ( ) ) ) {
66- return if merkle_tree. root == merkle_root {
67- Ok ( merkle_root)
68- } else {
69- Err ( ProofVerificationAggModeError :: MerkleTreeProofVerification )
70- } ;
71+ let Some ( pos) = leaves. iter ( ) . position ( |p| p. 0 == proof_commitment) else {
72+ continue ;
73+ } ;
74+ let Some ( proof) = merkle_tree. get_proof_by_pos ( pos) else {
75+ continue ;
76+ } ;
77+
78+ let result = proof. verify :: < Hash32 > ( & merkle_root, pos, & Hash32 ( proof_commitment) ) ;
79+ if !result {
80+ return Ok ( ProofStatus :: Invalid ) ;
7181 }
82+
83+ return Ok ( ProofStatus :: Verified {
84+ merkle_path : proof. merkle_path ,
85+ merkle_root : merkle_root,
86+ } ) ;
7287 }
7388
74- Err ( ProofVerificationAggModeError :: ProofNotFoundInLogs )
89+ Ok ( ProofStatus :: NotFound )
7590}
7691
77- /// Performs the same verification as [`is_proof_verified`], but instead of verifying locally, it simulates
78- /// an on-chain verification by calling the `verifyProofInclusion` function on the `ProofAggregationService` contract.
92+ /// Simulates an on-chain verification of the proof by calling the `verifyProofInclusion` function
93+ /// on the `ProofAggregationService` contract.
94+ ///
95+ /// This function is intended to complement [`check_proof_verification`], which performs off-chain verification.
96+ /// After calling `check_proof_verification` to confirm the proof's inclusion and obtain the Merkle path,
97+ /// this function can be used to simulate the corresponding contract call.
7998///
80- /// This function :
81- /// 1. Fetches the aggregated proof blob from the blockchain .
82- /// 2. Constructs the corresponding Merkle tree from the proof commitments.
83- /// 3. Calls the contract's `verifyProofInclusion` function with:
84- /// - The Merkle path corresponding to the given [`AggregationModeVerificationData`] .
85- /// - The proof commitment, computed from the program ID and public inputs.
99+ /// ### How it works :
100+ /// 1. Uses the provided Merkle path (as returned by [`check_proof_verification`]) .
101+ /// 2. Calls the `verifyProofInclusion` function on the contract with:
102+ /// - The Merkle path,
103+ /// - The proof program id .
104+ /// - The proof public inputs bytes
86105///
87- /// This is mainly useful for testing and simulation purposes to ensure that a given proof commitment
88- /// would be accepted by the contract on-chain. For typical off-chain verification (e.g., in services or indexers),
89- /// prefer using [`is_proof_verified`].
106+ /// ### Purpose:
107+ /// This is mainly useful for **testing or simulation**, to confirm that the on-chain contract would
108+ /// accept a given proof commitment and Merkle path. It does **not** perform an actual transaction on-chain,
109+ /// but instead simulates the call via `eth_call`.
90110///
91- /// Note: This function does not perform the actual on -chain transaction but simulates the contract call .
111+ /// For off -chain verification use cases, prefer using [`check_proof_verification`] .
92112pub async fn is_proof_verified_on_chain (
93113 verification_data : AggregationModeVerificationData ,
114+ merkle_path : Vec < [ u8 ; 32 ] > ,
94115 network : Network ,
95116 eth_rpc_url : String ,
96- beacon_client_url : String ,
97- from_block : Option < u64 > ,
98117) -> Result < bool , ProofVerificationAggModeError > {
99- let Some ( merkle_path) = get_merkle_path_for_proof (
100- network. clone ( ) ,
101- eth_rpc_url. clone ( ) ,
102- beacon_client_url,
103- from_block,
104- & verification_data,
105- )
106- . await ?
107- else {
108- return Ok ( false ) ;
109- } ;
110-
111118 let eth_rpc_provider = Provider :: < Http > :: try_from ( eth_rpc_url)
112119 . map_err ( |e| ProofVerificationAggModeError :: EthereumProviderError ( e. to_string ( ) ) ) ?;
113120 let contract_provider = aligned_proof_aggregation_service (
@@ -129,54 +136,3 @@ pub async fn is_proof_verified_on_chain(
129136
130137 Ok ( res)
131138}
132-
133- /// Given the [`AggregationModeVerificationData`], this function queries the blockchain logs starting from the
134- /// specified `from_block` until it founds the proof.
135- ///
136- /// Once the proof is found:
137- /// 1. It retrieves the corresponding proof blob.
138- /// 2. Constructs the Merkle tree based on the proof blob.
139- /// 3. Returns the Merkle proof needed for verifying the proof.
140- ///
141- /// Note: This function prepares the Merkle path for on-chain verification, and is typically used in combination with
142- /// `verifyProofInclusion` to confirm proof validity within the ProofAggregationService contract.
143- pub async fn get_merkle_path_for_proof (
144- network : Network ,
145- eth_rpc_url : String ,
146- beacon_client_url : String ,
147- from_block : Option < u64 > ,
148- verification_data : & AggregationModeVerificationData ,
149- ) -> Result < Option < Vec < [ u8 ; 32 ] > > , ProofVerificationAggModeError > {
150- let logs = fetch_verified_proofs_events ( network, eth_rpc_url. clone ( ) , from_block) . await ?;
151- let proof_commitment = verification_data. commitment ( ) ;
152-
153- for log in logs {
154- let ( merkle_root, leaves) = get_blob_data_from_verified_proof_event (
155- eth_rpc_url. clone ( ) ,
156- beacon_client_url. clone ( ) ,
157- log,
158- )
159- . await ?;
160-
161- let leaves: Vec < Hash32 > = leaves. iter ( ) . map ( |leaf| Hash32 ( * leaf) ) . collect ( ) ;
162- let Some ( merkle_tree) = MerkleTree :: < Hash32 > :: build ( & leaves) else {
163- continue ;
164- } ;
165-
166- let Some ( pos) = leaves. iter ( ) . position ( |p| p. 0 == proof_commitment) else {
167- continue ;
168- } ;
169- let Some ( proof) = merkle_tree. get_proof_by_pos ( pos) else {
170- continue ;
171- } ;
172-
173- let result = proof. verify :: < Hash32 > ( & merkle_root, pos, & Hash32 ( proof_commitment) ) ;
174- if !result {
175- return Err ( ProofVerificationAggModeError :: MerkleTreeProofVerification ) ;
176- }
177-
178- return Ok ( Some ( proof. merkle_path ) ) ;
179- }
180-
181- Ok ( None )
182- }
0 commit comments