pessimistic_proof_core/local_state/
commitment.rs1use agglayer_primitives::{keccak::keccak256_combine, Digest};
6use agglayer_tries::roots::{LocalBalanceRoot, LocalExitRoot, LocalNullifierRoot};
7use alloy_primitives::B256;
8use serde::{Deserialize, Serialize};
9use unified_bridge::{
10 ImportedBridgeExitCommitmentValues, ImportedBridgeExitCommitmentVersion, NetworkId,
11};
12
13use crate::{
14 aggchain_data::AggchainHashValues,
15 proof::{ConstrainedValues, EMPTY_PP_ROOT_V2},
16 ProofError,
17};
18
19#[derive(Debug, Clone, Copy)]
21pub enum PessimisticRootCommitmentVersion {
22 V2,
24 V3,
26}
27
28#[derive(Default, Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
30pub struct StateCommitment {
31 pub exit_root: LocalExitRoot,
32 pub ler_leaf_count: u32,
33 pub balance_root: LocalBalanceRoot,
34 pub nullifier_root: LocalNullifierRoot,
35}
36
37#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
39pub struct PessimisticRootCommitmentValues {
40 pub balance_root: LocalBalanceRoot,
41 pub nullifier_root: LocalNullifierRoot,
42 pub ler_leaf_count: u32,
43 pub height: u64,
44 pub origin_network: NetworkId,
45}
46
47impl PessimisticRootCommitmentValues {
48 pub fn infer_settled_pp_root_version(
50 &self,
51 settled_pp_root: Digest,
52 ) -> Result<PessimisticRootCommitmentVersion, ProofError> {
53 let computed_v3 = self.compute_pp_root(PessimisticRootCommitmentVersion::V3);
54 if computed_v3 == settled_pp_root {
55 return Ok(PessimisticRootCommitmentVersion::V3);
56 }
57
58 let computed_v2 = self.compute_pp_root(PessimisticRootCommitmentVersion::V2);
59 if computed_v2 == settled_pp_root {
60 return Ok(PessimisticRootCommitmentVersion::V2);
61 }
62
63 let is_initial_state = computed_v2 == EMPTY_PP_ROOT_V2 && self.height == 0;
65
66 if settled_pp_root.0 == [0u8; 32] && is_initial_state {
67 return Ok(PessimisticRootCommitmentVersion::V2);
68 }
69
70 Err(ProofError::InvalidPreviousPessimisticRoot {
71 declared: settled_pp_root,
72 computed_v2,
73 computed_v3,
74 })
75 }
76
77 pub fn compute_pp_root(&self, version: PessimisticRootCommitmentVersion) -> Digest {
79 match version {
80 PessimisticRootCommitmentVersion::V2 => keccak256_combine([
81 self.balance_root.as_ref(),
82 self.nullifier_root.as_ref(),
83 self.ler_leaf_count.to_le_bytes().as_slice(),
84 ]),
85 PessimisticRootCommitmentVersion::V3 => keccak256_combine([
86 self.balance_root.as_ref(),
87 self.nullifier_root.as_ref(),
88 self.ler_leaf_count.to_le_bytes().as_slice(),
89 self.height.to_le_bytes().as_slice(),
90 self.origin_network.to_le_bytes().as_slice(),
91 ]),
92 }
93 }
94}
95
96#[derive(Debug, Clone, Copy)]
97pub enum SignatureCommitmentVersion {
98 V2,
100 V3,
102 V4,
104 V5,
106}
107
108pub struct SignatureCommitmentValues {
110 pub new_local_exit_root: LocalExitRoot,
111 pub commit_imported_bridge_exits: ImportedBridgeExitCommitmentValues,
112 pub height: u64,
113 pub aggchain_params: Option<Digest>,
114 pub certificate_id: Digest,
115}
116
117impl SignatureCommitmentValues {
118 pub fn new(constrained_values: &ConstrainedValues, aggchain_params: Option<Digest>) -> Self {
119 Self {
120 new_local_exit_root: constrained_values.final_state_commitment.exit_root,
121 commit_imported_bridge_exits: constrained_values.commit_imported_bridge_exits.clone(),
122 height: constrained_values.height,
123 aggchain_params,
124 certificate_id: constrained_values.certificate_id,
125 }
126 }
127}
128
129impl SignatureCommitmentValues {
130 #[inline]
132 pub fn commitment(&self, version: SignatureCommitmentVersion) -> B256 {
133 let commitment = match version {
134 SignatureCommitmentVersion::V2 => keccak256_combine([
135 self.new_local_exit_root.as_ref(),
136 self.commit_imported_bridge_exits
137 .commitment(ImportedBridgeExitCommitmentVersion::V2)
138 .as_slice(),
139 ]),
140 SignatureCommitmentVersion::V3 => {
141 keccak256_combine([
143 self.new_local_exit_root.as_ref(),
144 self.commit_imported_bridge_exits
145 .commitment(ImportedBridgeExitCommitmentVersion::V3)
146 .as_slice(),
147 self.height.to_le_bytes().as_slice(),
148 ])
149 }
150 SignatureCommitmentVersion::V4 => {
151 keccak256_combine([
155 self.new_local_exit_root.as_ref(),
156 self.commit_imported_bridge_exits
157 .commitment(ImportedBridgeExitCommitmentVersion::V3)
158 .as_slice(),
159 self.height.to_le_bytes().as_slice(),
160 self.aggchain_params
161 .unwrap_or(AggchainHashValues::EMPTY_AGGCHAIN_PARAMS)
162 .as_slice(),
163 ])
164 }
165 SignatureCommitmentVersion::V5 => {
166 keccak256_combine([
168 self.new_local_exit_root.as_ref(),
169 self.commit_imported_bridge_exits
170 .commitment(ImportedBridgeExitCommitmentVersion::V3)
171 .as_slice(),
172 self.height.to_le_bytes().as_slice(),
173 self.aggchain_params
174 .unwrap_or(AggchainHashValues::EMPTY_AGGCHAIN_PARAMS)
175 .as_slice(),
176 self.certificate_id.as_slice(),
177 ])
178 }
179 };
180
181 B256::new(commitment.0)
182 }
183
184 #[inline]
185 pub fn multisig_commitment(&self) -> B256 {
186 self.commitment(SignatureCommitmentVersion::V5)
187 }
188}