willow_data_model/private_encodings/
path.rs

1#[cfg(feature = "dev")]
2use arbitrary::Arbitrary;
3use compact_u64::CompactU64;
4use ufotofu_codec::{
5    Blame, Decodable, DecodeError, Encodable, RelativeDecodable, RelativeEncodable,
6};
7
8use crate::{decode_path_extends_path, encode_path_extends_path, Path};
9
10#[derive(Debug)]
11/// The context necessary to privately encode Paths.
12pub struct PrivatePathContext<const MCL: usize, const MCC: usize, const MPL: usize> {
13    /// The Path whose Components are to be kept private.
14    private: Path<MCL, MCC, MPL>,
15    /// The prefix relative to which we encode.
16    rel: Path<MCL, MCC, MPL>,
17}
18
19#[derive(Debug)]
20pub struct ComponentsNotRelatedError {}
21
22impl<const MCL: usize, const MCC: usize, const MPL: usize> PrivatePathContext<MCL, MCC, MPL> {
23    pub fn new(
24        private: Path<MCL, MCC, MPL>,
25        rel: Path<MCL, MCC, MPL>,
26    ) -> Result<Self, ComponentsNotRelatedError> {
27        if !private.is_related(&rel) {
28            return Err(ComponentsNotRelatedError {});
29        }
30
31        Ok(Self { private, rel })
32    }
33
34    pub fn new_unchecked(private: Path<MCL, MCC, MPL>, rel: Path<MCL, MCC, MPL>) -> Self {
35        Self { private, rel }
36    }
37
38    pub fn private(&self) -> &Path<MCL, MCC, MPL> {
39        &self.private
40    }
41
42    pub fn rel(&self) -> &Path<MCL, MCC, MPL> {
43        &self.rel
44    }
45}
46
47#[cfg(feature = "dev")]
48impl<'a, const MCL: usize, const MCC: usize, const MPL: usize> Arbitrary<'a>
49    for PrivatePathContext<MCL, MCC, MPL>
50{
51    fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
52        let private: Path<MCL, MCC, MPL> = Arbitrary::arbitrary(u)?;
53        let rel: Path<MCL, MCC, MPL> = Arbitrary::arbitrary(u)?;
54
55        Ok(Self { private, rel })
56    }
57}
58
59impl<const MCL: usize, const MCC: usize, const MPL: usize>
60    RelativeEncodable<PrivatePathContext<MCL, MCC, MPL>> for Path<MCL, MCC, MPL>
61{
62    async fn relative_encode<C>(
63        &self,
64        consumer: &mut C,
65        r: &PrivatePathContext<MCL, MCC, MPL>,
66    ) -> Result<(), C::Error>
67    where
68        C: ufotofu::BulkConsumer<Item = u8>,
69    {
70        if !r.rel.is_prefix_of(self) {
71            panic!("Tried to encode a path relative to a PrivatePathContext.rel path it is not prefixed by")
72        }
73
74        if !self.is_related(&r.private) {
75            panic!("Tried to encode a path relative to a PrivatePathContext.private pat it is not related to")
76        }
77
78        let rel_count = r.rel.component_count();
79        let private_count = r.private.component_count();
80
81        if private_count <= rel_count {
82            // path extends path val <> rel
83            encode_path_extends_path(consumer, self, &r.rel).await?;
84        } else {
85            let lcp = self.longest_common_prefix(&r.private);
86
87            let lcp_len = lcp.component_count();
88            CompactU64(lcp.component_count() as u64)
89                .encode(consumer)
90                .await?;
91
92            if lcp_len >= private_count {
93                // path extends path val <> priv
94                encode_path_extends_path(consumer, self, r.private()).await?;
95            }
96        }
97
98        Ok(())
99    }
100}
101
102impl<const MCL: usize, const MCC: usize, const MPL: usize>
103    RelativeDecodable<PrivatePathContext<MCL, MCC, MPL>, Blame> for Path<MCL, MCC, MPL>
104{
105    async fn relative_decode<P>(
106        producer: &mut P,
107        r: &PrivatePathContext<MCL, MCC, MPL>,
108    ) -> Result<Self, DecodeError<P::Final, P::Error, Blame>>
109    where
110        P: ufotofu::BulkProducer<Item = u8>,
111        Self: Sized,
112    {
113        let rel_count = r.rel.component_count();
114        let private_count = r.private.component_count();
115
116        if private_count <= rel_count {
117            decode_path_extends_path(producer, r.rel()).await
118        } else {
119            // Decode C64 of length of longest common prefix of priv with val
120            let private_component_count = CompactU64::decode(producer)
121                .await
122                .map_err(DecodeError::map_other_from)?;
123
124            if private_component_count.0 >= private_count as u64 {
125                decode_path_extends_path(producer, r.private()).await
126            } else {
127                // We can unwrap here because we know private_component_count will be less than the component count of r.private
128                r.private
129                    .create_prefix(private_component_count.0 as usize)
130                    .ok_or(DecodeError::Other(Blame::TheirFault))
131            }
132        }
133    }
134}