Skip to content

Commit c77c0dc

Browse files
committed
feat: update optimistic mode
1 parent 4d2e584 commit c77c0dc

File tree

2 files changed

+66
-39
lines changed

2 files changed

+66
-39
lines changed

crates/aggchain-proof-core/src/full_execution_proof.rs

+54-4
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,13 @@ use serde::{Deserialize, Serialize};
33
use sha2::{Digest as Sha256Digest, Sha256};
44

55
use crate::Digest;
6-
use crate::{error::ProofError, keccak::keccak256_combine, vkey_hash::HashU32};
7-
6+
use crate::{
7+
error::ProofError,
8+
keccak::keccak256_combine,
9+
local_exit_tree::{hasher::Keccak256Hasher, proof::LETMerkleProof},
10+
vkey_hash::HashU32,
11+
L1InfoTreeLeaf,
12+
};
813
/// Hardcoded hash of the "aggregation vkey".
914
/// NOTE: Format being `hash_u32()` of the `SP1StarkVerifyingKey`.
1015
pub const AGGREGATION_VKEY_HASH: HashU32 = [0u32; 8]; // TODO: to put the right value
@@ -18,6 +23,7 @@ pub const OUTPUT_ROOT_VERSION: [u8; 32] = [0u8; 32];
1823
/// Public values to verify the FEP.
1924
#[derive(Serialize, Deserialize, Clone, Debug)]
2025
pub struct FepPublicValues {
26+
/// OP succint values.
2127
pub l1_head: Digest,
2228
pub claim_block_num: u32,
2329
pub rollup_config_hash: Digest,
@@ -28,6 +34,10 @@ pub struct FepPublicValues {
2834
pub new_withdrawal_storage_root: Digest,
2935
pub new_block_hash: Digest,
3036

37+
/// L1 info tree leaf and index containing the `l1Head` as block hash.
38+
pub l1_info_tree_leaf: (u32, L1InfoTreeLeaf),
39+
/// Inclusion proof of the leaf to the l1 info root.
40+
pub l1_head_inclusion_proof: LETMerkleProof<Keccak256Hasher>,
3141
/// Trusted sequencer address.
3242
pub trusted_sequencer: Address,
3343
/// Signature in the "OptimisticMode" case.
@@ -81,11 +91,22 @@ impl FepPublicValues {
8191
}
8292

8393
/// Verify one ECDSA or the sp1 proof.
84-
pub fn verify(&self) -> Result<(), ProofError> {
94+
pub fn verify(
95+
&self,
96+
l1_info_root: Digest,
97+
new_local_exit_root: Digest,
98+
commit_imported_bridge_exits: Digest,
99+
) -> Result<(), ProofError> {
85100
if let Some(signature) = self.signature_optimistic_mode {
86101
// Verify only one ECDSA on the public inputs
102+
let signature_commitment = keccak256_combine([
103+
self.hash(),
104+
new_local_exit_root.0,
105+
commit_imported_bridge_exits.0,
106+
]);
107+
87108
let recovered_signer = signature
88-
.recover_address_from_prehash(&B256::new(self.hash()))
109+
.recover_address_from_prehash(&B256::new(signature_commitment.0))
89110
.map_err(|_| ProofError::InvalidSignature)?;
90111

91112
if recovered_signer != self.trusted_sequencer {
@@ -97,6 +118,9 @@ impl FepPublicValues {
97118

98119
Ok(())
99120
} else {
121+
// Verify l1 head
122+
self.verify_l1_head(l1_info_root)?;
123+
100124
// Verify the FEP stark proof.
101125
#[cfg(not(target_os = "zkvm"))]
102126
unreachable!("verify_sp1_proof is not callable outside of SP1");
@@ -115,6 +139,32 @@ impl FepPublicValues {
115139
}
116140

117141
impl FepPublicValues {
142+
// Verify that the `l1Head` considered by the FEP exists in the L1 Info Tree
143+
pub fn verify_l1_head(&self, l1_info_root: Digest) -> Result<(), ProofError> {
144+
if self.l1_head != self.l1_info_tree_leaf.1.block_hash {
145+
return Err(ProofError::MismatchL1Head {
146+
from_l1_info_tree_leaf: self.l1_info_tree_leaf.1.block_hash,
147+
from_fep_public_values: self.l1_head,
148+
});
149+
}
150+
151+
let inclusion_proof_valid = self.l1_head_inclusion_proof.verify(
152+
self.l1_info_tree_leaf.1.hash(),
153+
self.l1_info_tree_leaf.0,
154+
l1_info_root,
155+
);
156+
157+
if !inclusion_proof_valid {
158+
return Err(ProofError::InvalidInclusionProofL1Head {
159+
index: self.l1_info_tree_leaf.0,
160+
l1_leaf_hash: self.l1_info_tree_leaf.1.hash(),
161+
l1_info_root: l1_info_root,
162+
});
163+
}
164+
165+
Ok(())
166+
}
167+
118168
/// Compute l2 pre root.
119169
pub fn compute_l2_pre_root(&self) -> Digest {
120170
compute_output_root(

crates/aggchain-proof-core/src/proof.rs

+12-35
Original file line numberDiff line numberDiff line change
@@ -7,8 +7,6 @@ use crate::{
77
error::ProofError,
88
full_execution_proof::FepPublicValues,
99
keccak::keccak256_combine,
10-
local_exit_tree::{hasher::Keccak256Hasher, proof::LETMerkleProof},
11-
L1InfoTreeLeaf,
1210
};
1311

1412
/// Aggchain proof is generated from the FEP proof and additional
@@ -31,10 +29,6 @@ pub struct AggchainProofWitness {
3129
pub origin_network: u32,
3230
/// Full execution proof with its metadata.
3331
pub fep: FepPublicValues,
34-
/// L1 info tree leaf and index containing the `l1Head` as block hash.
35-
pub l1_info_tree_leaf: (u32, L1InfoTreeLeaf),
36-
/// Inclusion proof of the leaf to the l1 info root.
37-
pub l1_head_inclusion_proof: LETMerkleProof<Keccak256Hasher>,
3832
/// List of the global index of each imported bridge exit.
3933
pub global_indices: Vec<B256>,
4034
/// Bridge witness related data.
@@ -44,31 +38,11 @@ pub struct AggchainProofWitness {
4438
impl AggchainProofWitness {
4539
pub fn verify_aggchain_inputs(&self) -> Result<AggchainProofPublicValues, ProofError> {
4640
// Verify the FEP proof or ECDSA signature.
47-
self.fep.verify()?;
48-
49-
// Verify that the `l1Head` considered by the FEP exists in the L1 Info Tree
50-
{
51-
if self.fep.l1_head != self.l1_info_tree_leaf.1.block_hash {
52-
return Err(ProofError::MismatchL1Head {
53-
from_l1_info_tree_leaf: self.l1_info_tree_leaf.1.block_hash,
54-
from_fep_public_values: self.fep.l1_head,
55-
});
56-
}
57-
58-
let inclusion_proof_valid = self.l1_head_inclusion_proof.verify(
59-
self.l1_info_tree_leaf.1.hash(),
60-
self.l1_info_tree_leaf.0,
61-
self.l1_info_root,
62-
);
63-
64-
if !inclusion_proof_valid {
65-
return Err(ProofError::InvalidInclusionProofL1Head {
66-
index: self.l1_info_tree_leaf.0,
67-
l1_leaf_hash: self.l1_info_tree_leaf.1.hash(),
68-
l1_info_root: self.l1_info_root,
69-
});
70-
}
71-
}
41+
self.fep.verify(
42+
self.l1_info_root,
43+
self.new_local_exit_root,
44+
compute_commit_imported_bridge_exits(&self.global_indices),
45+
)?;
7246

7347
// Verify the bridge constraints
7448
self.bridge_constraints_input().verify()?;
@@ -84,10 +58,8 @@ impl AggchainProofWitness {
8458
new_local_exit_root: self.new_local_exit_root,
8559
l1_info_root: self.l1_info_root,
8660
origin_network: self.origin_network,
87-
commit_imported_bridge_exits: keccak256_combine(
88-
self.global_indices
89-
.iter()
90-
.map(|idx| keccak256(idx.as_slice())),
61+
commit_imported_bridge_exits: compute_commit_imported_bridge_exits(
62+
&self.global_indices,
9163
),
9264
aggchain_params: self.fep.aggchain_params(),
9365
}
@@ -124,3 +96,8 @@ pub struct AggchainProofPublicValues {
12496
/// Chain-specific commitment forwarded by the PP.
12597
pub aggchain_params: Digest,
12698
}
99+
100+
/// Helper function to compute the commitment for global indices.
101+
pub fn compute_commit_imported_bridge_exits(global_indices: &[B256]) -> Digest {
102+
keccak256_combine(global_indices.iter().map(|idx| keccak256(idx.as_slice())))
103+
}

0 commit comments

Comments
 (0)