ics23/
compress.rs

1use alloc::borrow::ToOwned;
2use alloc::collections::btree_map::BTreeMap as HashMap;
3use alloc::vec::Vec;
4use prost::Message;
5
6use crate::helpers::Result;
7use crate::ics23;
8
9pub fn is_compressed(proof: &ics23::CommitmentProof) -> bool {
10    matches!(
11        &proof.proof,
12        Some(ics23::commitment_proof::Proof::Compressed(_))
13    )
14}
15
16pub fn compress(proof: &ics23::CommitmentProof) -> Result<ics23::CommitmentProof> {
17    if let Some(ics23::commitment_proof::Proof::Batch(batch)) = &proof.proof {
18        compress_batch(batch)
19    } else {
20        Ok(proof.to_owned())
21    }
22}
23
24pub fn decompress(proof: &ics23::CommitmentProof) -> Result<ics23::CommitmentProof> {
25    if let Some(ics23::commitment_proof::Proof::Compressed(compressed)) = &proof.proof {
26        decompress_batch(compressed)
27    } else {
28        Ok(proof.to_owned())
29    }
30}
31
32pub fn compress_batch(proof: &ics23::BatchProof) -> Result<ics23::CommitmentProof> {
33    let mut lookup = Vec::new();
34    let mut registry = HashMap::new();
35
36    let centries = proof
37        .entries
38        .iter()
39        .map(|entry| match &entry.proof {
40            Some(ics23::batch_entry::Proof::Exist(ex)) => {
41                let exist = compress_exist(ex, &mut lookup, &mut registry)?;
42                Ok(ics23::CompressedBatchEntry {
43                    proof: Some(ics23::compressed_batch_entry::Proof::Exist(exist)),
44                })
45            }
46            Some(ics23::batch_entry::Proof::Nonexist(non)) => {
47                let left = non
48                    .left
49                    .as_ref()
50                    .map(|l| compress_exist(l, &mut lookup, &mut registry))
51                    .transpose()?;
52                let right = non
53                    .right
54                    .as_ref()
55                    .map(|r| compress_exist(r, &mut lookup, &mut registry))
56                    .transpose()?;
57                let nonexist = ics23::CompressedNonExistenceProof {
58                    key: non.key.clone(),
59                    left,
60                    right,
61                };
62                Ok(ics23::CompressedBatchEntry {
63                    proof: Some(ics23::compressed_batch_entry::Proof::Nonexist(nonexist)),
64                })
65            }
66            None => Ok(ics23::CompressedBatchEntry { proof: None }),
67        })
68        .collect::<Result<_>>()?;
69
70    Ok(ics23::CommitmentProof {
71        proof: Some(ics23::commitment_proof::Proof::Compressed(
72            ics23::CompressedBatchProof {
73                entries: centries,
74                lookup_inners: lookup,
75            },
76        )),
77    })
78}
79
80pub fn compress_exist(
81    exist: &ics23::ExistenceProof,
82    lookup: &mut Vec<ics23::InnerOp>,
83    registry: &mut HashMap<Vec<u8>, i32>,
84) -> Result<ics23::CompressedExistenceProof> {
85    let path = exist
86        .path
87        .iter()
88        .map(|x| {
89            let buf = x.encode_to_vec();
90            let idx = *registry.entry(buf).or_insert_with(|| {
91                let idx = lookup.len() as i32;
92                lookup.push(x.to_owned());
93                idx
94            });
95            Ok(idx)
96        })
97        .collect::<Result<_>>()?;
98
99    Ok(ics23::CompressedExistenceProof {
100        key: exist.key.clone(),
101        value: exist.value.clone(),
102        leaf: exist.leaf.clone(),
103        path,
104    })
105}
106
107pub fn decompress_batch(proof: &ics23::CompressedBatchProof) -> Result<ics23::CommitmentProof> {
108    let lookup = &proof.lookup_inners;
109    let entries = proof
110        .entries
111        .iter()
112        .map(|cent| match &cent.proof {
113            Some(ics23::compressed_batch_entry::Proof::Exist(ex)) => {
114                let exist = decompress_exist(ex, lookup);
115                Ok(ics23::BatchEntry {
116                    proof: Some(ics23::batch_entry::Proof::Exist(exist)),
117                })
118            }
119            Some(ics23::compressed_batch_entry::Proof::Nonexist(non)) => {
120                let left = non.left.as_ref().map(|l| decompress_exist(l, lookup));
121                let right = non.right.as_ref().map(|r| decompress_exist(r, lookup));
122                let nonexist = ics23::NonExistenceProof {
123                    key: non.key.clone(),
124                    left,
125                    right,
126                };
127                Ok(ics23::BatchEntry {
128                    proof: Some(ics23::batch_entry::Proof::Nonexist(nonexist)),
129                })
130            }
131            None => Ok(ics23::BatchEntry { proof: None }),
132        })
133        .collect::<Result<_>>()?;
134
135    Ok(ics23::CommitmentProof {
136        proof: Some(ics23::commitment_proof::Proof::Batch(ics23::BatchProof {
137            entries,
138        })),
139    })
140}
141
142fn decompress_exist(
143    exist: &ics23::CompressedExistenceProof,
144    lookup: &[ics23::InnerOp],
145) -> ics23::ExistenceProof {
146    let path = exist
147        .path
148        .iter()
149        .map(|&x| lookup.get(x as usize).cloned())
150        .collect::<Option<Vec<_>>>()
151        .unwrap_or_default();
152    ics23::ExistenceProof {
153        key: exist.key.clone(),
154        value: exist.value.clone(),
155        leaf: exist.leaf.clone(),
156        path,
157    }
158}