ibc_relayer_types/core/ics23_commitment/
merkle.rs

1use tendermint::merkle::proof::ProofOps as TendermintProof;
2
3use ibc_proto::ibc::core::commitment::v1::MerklePath;
4use ibc_proto::ibc::core::commitment::v1::MerkleProof as RawMerkleProof;
5use ibc_proto::ibc::core::commitment::v1::MerkleRoot;
6use ics23::commitment_proof::Proof;
7use ics23::{
8    calculate_existence_root, verify_membership, verify_non_membership, CommitmentProof,
9    NonExistenceProof,
10};
11
12use crate::core::ics23_commitment::commitment::{CommitmentPrefix, CommitmentRoot};
13use crate::core::ics23_commitment::error::Error;
14use crate::core::ics23_commitment::specs::ProofSpecs;
15
16pub fn apply_prefix(prefix: &CommitmentPrefix, mut path: Vec<String>) -> MerklePath {
17    let mut key_path: Vec<String> = vec![format!("{prefix:?}")];
18    key_path.append(&mut path);
19    MerklePath { key_path }
20}
21
22impl From<CommitmentRoot> for MerkleRoot {
23    fn from(root: CommitmentRoot) -> Self {
24        Self {
25            hash: root.into_vec(),
26        }
27    }
28}
29
30#[derive(Clone, Debug, PartialEq)]
31pub struct MerkleProof {
32    pub proofs: Vec<CommitmentProof>,
33}
34
35/// Convert to ics23::CommitmentProof
36impl From<RawMerkleProof> for MerkleProof {
37    fn from(proof: RawMerkleProof) -> Self {
38        Self {
39            proofs: proof.proofs,
40        }
41    }
42}
43
44impl From<MerkleProof> for RawMerkleProof {
45    fn from(proof: MerkleProof) -> Self {
46        Self {
47            proofs: proof.proofs,
48        }
49    }
50}
51
52impl MerkleProof {
53    pub fn verify_membership(
54        &self,
55        specs: &ProofSpecs,
56        root: MerkleRoot,
57        keys: MerklePath,
58        value: Vec<u8>,
59        start_index: usize,
60    ) -> Result<(), Error> {
61        // validate arguments
62        if self.proofs.is_empty() {
63            return Err(Error::empty_merkle_proof());
64        }
65        if root.hash.is_empty() {
66            return Err(Error::empty_merkle_root());
67        }
68        let num = self.proofs.len();
69        let ics23_specs = Vec::<ics23::ProofSpec>::from(specs.clone());
70        if ics23_specs.len() != num {
71            return Err(Error::number_of_specs_mismatch());
72        }
73        if keys.key_path.len() != num {
74            return Err(Error::number_of_keys_mismatch());
75        }
76        if value.is_empty() {
77            return Err(Error::empty_verified_value());
78        }
79
80        let mut subroot = value.clone();
81        let mut value = value;
82        // keys are represented from root-to-leaf
83        for ((proof, spec), key) in self
84            .proofs
85            .iter()
86            .zip(ics23_specs.iter())
87            .zip(keys.key_path.iter().rev())
88            .skip(start_index)
89        {
90            match &proof.proof {
91                Some(Proof::Exist(existence_proof)) => {
92                    subroot =
93                        calculate_existence_root::<ics23::HostFunctionsManager>(existence_proof)
94                            .map_err(|_| Error::invalid_merkle_proof())?;
95
96                    if !verify_membership::<ics23::HostFunctionsManager>(
97                        proof,
98                        spec,
99                        &subroot,
100                        key.as_bytes(),
101                        &value,
102                    ) {
103                        return Err(Error::verification_failure());
104                    }
105                    value.clone_from(&subroot);
106                }
107                _ => return Err(Error::invalid_merkle_proof()),
108            }
109        }
110
111        if root.hash != subroot {
112            return Err(Error::verification_failure());
113        }
114
115        Ok(())
116    }
117
118    pub fn verify_non_membership(
119        &self,
120        specs: &ProofSpecs,
121        root: MerkleRoot,
122        keys: MerklePath,
123    ) -> Result<(), Error> {
124        // validate arguments
125        if self.proofs.is_empty() {
126            return Err(Error::empty_merkle_proof());
127        }
128        if root.hash.is_empty() {
129            return Err(Error::empty_merkle_root());
130        }
131        let num = self.proofs.len();
132        let ics23_specs = Vec::<ics23::ProofSpec>::from(specs.clone());
133        if ics23_specs.len() != num {
134            return Err(Error::number_of_specs_mismatch());
135        }
136        if keys.key_path.len() != num {
137            return Err(Error::number_of_keys_mismatch());
138        }
139
140        // verify the absence of key in lowest subtree
141        let proof = self
142            .proofs
143            .first()
144            .ok_or_else(Error::invalid_merkle_proof)?;
145        let spec = ics23_specs
146            .first()
147            .ok_or_else(Error::invalid_merkle_proof)?;
148        // keys are represented from root-to-leaf
149        let key = keys
150            .key_path
151            .get(num - 1)
152            .ok_or_else(Error::invalid_merkle_proof)?;
153        match &proof.proof {
154            Some(Proof::Nonexist(non_existence_proof)) => {
155                let subroot = calculate_non_existence_root(non_existence_proof)?;
156
157                if !verify_non_membership::<ics23::HostFunctionsManager>(
158                    proof,
159                    spec,
160                    &subroot,
161                    key.as_bytes(),
162                ) {
163                    return Err(Error::verification_failure());
164                }
165
166                // verify membership proofs starting from index 1 with value = subroot
167                self.verify_membership(specs, root, keys, subroot, 1)
168            }
169            _ => Err(Error::invalid_merkle_proof()),
170        }
171    }
172}
173
174// TODO move to ics23
175fn calculate_non_existence_root(proof: &NonExistenceProof) -> Result<Vec<u8>, Error> {
176    if let Some(left) = &proof.left {
177        calculate_existence_root::<ics23::HostFunctionsManager>(left)
178            .map_err(|_| Error::invalid_merkle_proof())
179    } else if let Some(right) = &proof.right {
180        calculate_existence_root::<ics23::HostFunctionsManager>(right)
181            .map_err(|_| Error::invalid_merkle_proof())
182    } else {
183        Err(Error::invalid_merkle_proof())
184    }
185}
186
187// Merkle Proof serialization notes:
188// "Proof" id currently defined in a number of forms and included in a number of places
189// - TmProof: in tendermint-rs/src/merkle/proof.rs:Proof
190// - RawProofOps: in tendermint-proto/tendermint.crypto.rs:ProofOps
191// - RawMerkleProof: in ibc-proto/ibc.core.commitment.v1.rs:MerkleProof
192//     - structure that includes a RawProofOps in its only `proof` field.
193//         #[derive(Clone, PartialEq, ::prost::Message)]
194//         pub struct MerkleProof {
195//             #[prost(message, optional, tag="1")]
196//             pub proof: ::core::option::Option<::tendermint_proto::crypto::ProofOps>,
197//         }
198//  - Vec<u8>: RawMerkleProof is not explicitly used but, serialized as Vec<u8>, it is
199//       included in all handshake messages that require proofs (i.e. all except the two `OpenInit`),
200//       and also in all queries that require proofs
201//  - MerkleProof: Domain type for RawMerkleProof, currently not used and identical to RawMerkleProof.
202//       This will change with verification implementation.
203//  - CommitmentProof: Defined in ibc-rs as Vec<u8> and currently used in all its messages
204//
205// Here are a couple of flows that illustrate the different conversions:
206// IBC Messages and Handlers: sink happens in the handle verification
207//    Vec<u8> -> CommitmentProof -> RawMerkleProof -> MerkleProof
208//
209// Relayer: from the proof in the  query response to the proof being included in a message
210//    TmProof -> RawProofOps => RawMerkleProof -> MerkleProof -> verify()
211//      -> MerkleProof -> RawMerkleProof -> CommitmentProof -> Vec<u8>
212// Note: current implementation for ^ is simplified since verification is not yet implemented:
213//    TmProof -> RawProofOps => RawMerkleProof -> CommitmentProof -> Vec<u8>
214//
215// Implementations of (de)serializers and conversions:
216//  - commitment.rs:
217//      Vec<u8> <-> CommitmentProof
218//      CommitmentProof <-> RawMerkleProof
219//  - merkle.rs:
220//      RawMerkleProof <-> MerkleProof
221//  - tendermint-rs/src/merkle/proof.rs:
222//      TmProof <-> RawProofOps
223//  - cosmos.rs:abci_query() converts from query proof to Merkle proof:
224//      RawProofOps => RawMerkleProof
225//
226// impl TryFrom<RawMerkleProof> for MerkleProof {
227//     type Error = Error;
228//     fn try_from(value: RawMerkleProof) -> Result<Self, Self::Error> {
229//         Ok(MerkleProof { proof: value.proofs.into_iter().map(|v| v.into()).collect() })
230//     }
231// }
232//
233// impl From<MerkleProof> for RawMerkleProof {
234//     fn from(value: MerkleProof) -> Self {
235//         RawMerkleProof { proof: value.proof }
236//     }
237// }
238
239pub fn convert_tm_to_ics_merkle_proof(tm_proof: &TendermintProof) -> Result<MerkleProof, Error> {
240    let mut proofs = Vec::new();
241
242    for op in &tm_proof.ops {
243        let mut parsed = CommitmentProof { proof: None };
244
245        prost::Message::merge(&mut parsed, op.data.as_slice())
246            .map_err(Error::commitment_proof_decoding_failed)?;
247
248        proofs.push(parsed);
249    }
250
251    Ok(MerkleProof::from(RawMerkleProof { proofs }))
252}