willow_data_model/test_parameters/
subspace.rs

1use core::convert::Infallible;
2
3use arbitrary::Arbitrary;
4
5use order_theory::*;
6
7use signature::{Keypair, Signer, Verifier};
8use ufotofu::codec_prelude::*;
9
10use super::TestDigest;
11use crate::prelude::*;
12
13/// A subspace id for testing.
14#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Arbitrary)]
15#[allow(missing_docs)]
16pub enum TestSubspace {
17    Alfie,
18    Betty,
19    Gemma,
20    Dalton,
21}
22
23pub use TestSubspace::*;
24
25impl Encodable for TestSubspace {
26    async fn encode<C>(&self, consumer: &mut C) -> Result<(), C::Error>
27    where
28        C: BulkConsumer<Item = u8> + ?Sized,
29    {
30        match self {
31            Alfie => consumer.consume_item(0).await,
32            Betty => consumer.consume_item(1).await,
33            Gemma => consumer.consume_item(2).await,
34            Dalton => consumer.consume_item(3).await,
35        }
36    }
37}
38
39impl EncodableKnownLength for TestSubspace {
40    fn len_of_encoding(&self) -> usize {
41        1
42    }
43}
44
45impl Decodable for TestSubspace {
46    type ErrorReason = Blame;
47
48    async fn decode<P>(
49        producer: &mut P,
50    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
51    where
52        P: BulkProducer<Item = u8> + ?Sized,
53        Self: Sized,
54    {
55        let byte = producer.produce_item().await?;
56
57        match byte {
58            0 => Ok(Alfie),
59            1 => Ok(Betty),
60            2 => Ok(Gemma),
61            3 => Ok(Dalton),
62            _ => Err(DecodeError::Other(Blame::TheirFault)),
63        }
64    }
65}
66
67impl DecodableCanonic for TestSubspace {
68    type ErrorCanonic = Blame;
69
70    async fn decode_canonic<P>(
71        producer: &mut P,
72    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorCanonic>>
73    where
74        P: BulkProducer<Item = u8> + ?Sized,
75        Self: Sized,
76    {
77        Self::decode(producer).await
78    }
79}
80
81impl Verifier<TestSubspaceSignature> for TestSubspace {
82    fn verify(
83        &self,
84        _msg: &[u8],
85        signature: &TestSubspaceSignature,
86    ) -> Result<(), signature::Error> {
87        match (self, signature) {
88            (Alfie, AlfieSignature) => Ok(()),
89            (Betty, BettySignature) => Ok(()),
90            (Gemma, GemmaSignature) => Ok(()),
91            (Dalton, DaltonSignature) => Ok(()),
92            _ => Err(signature::Error::new()),
93        }
94    }
95}
96
97impl GreatestElement for TestSubspace {
98    fn greatest() -> Self {
99        Dalton
100    }
101}
102
103impl TrySuccessor for TestSubspace {
104    fn try_successor(&self) -> Option<Self> {
105        match self {
106            Alfie => Some(Betty),
107            Betty => Some(Gemma),
108            Gemma => Some(Dalton),
109            Dalton => None,
110        }
111    }
112}
113
114impl SuccessorExceptForGreatest for TestSubspace {}
115
116impl LeastElement for TestSubspace {
117    fn least() -> Self {
118        Alfie
119    }
120}
121
122impl TryPredecessor for TestSubspace {
123    fn try_predecessor(&self) -> Option<Self> {
124        match self {
125            Alfie => None,
126            Betty => Some(Alfie),
127            Gemma => Some(Betty),
128            Dalton => Some(Gemma),
129        }
130    }
131}
132
133impl PredecessorExceptForLeast for TestSubspace {}
134
135/// A "private key" corresponding to a subspace, used for issuing [`TestSubspaceSignature`]s.
136#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Arbitrary)]
137#[allow(missing_docs)]
138pub enum TestSubspaceSecret {
139    AlfieSecret,
140    BettySecret,
141    GemmaSecret,
142    DaltonSecret,
143}
144
145pub use TestSubspaceSecret::*;
146
147impl Signer<TestSubspaceSignature> for TestSubspaceSecret {
148    fn try_sign(&self, _msg: &[u8]) -> Result<TestSubspaceSignature, signature::Error> {
149        Ok(match self {
150            AlfieSecret => AlfieSignature,
151            BettySecret => BettySignature,
152            GemmaSecret => GemmaSignature,
153            DaltonSecret => DaltonSignature,
154        })
155    }
156}
157
158impl Keypair for TestSubspaceSecret {
159    type VerifyingKey = TestSubspace;
160
161    fn verifying_key(&self) -> Self::VerifyingKey {
162        match self {
163            AlfieSecret => Alfie,
164            BettySecret => Betty,
165            GemmaSecret => Gemma,
166            DaltonSecret => Dalton,
167        }
168    }
169}
170
171/// A "signature" issued by a [`TestSubspaceSecret`]. Implements [`AuthorisationToken`].
172///
173/// The signing process ignores the actual details of the payload.
174#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Arbitrary)]
175#[allow(missing_docs)]
176pub enum TestSubspaceSignature {
177    AlfieSignature,
178    BettySignature,
179    GemmaSignature,
180    DaltonSignature,
181}
182
183impl AuthorisationToken<4, 4, 4, TestNamespace, TestSubspace, TestDigest>
184    for TestSubspaceSignature
185{
186    type Ingredients = TestSubspaceSecret;
187
188    /// Emitted when the secret does not correspond to the subspace of the entry to authorise.
189    type CreationError = ();
190
191    fn new_for_entry<E>(
192        entry: &E,
193        ingredients: &Self::Ingredients,
194    ) -> Result<Self, Self::CreationError>
195    where
196        E: Entrylike<4, 4, 4, TestNamespace, TestSubspace, TestDigest> + ?Sized,
197    {
198        match (entry.wdm_subspace_id(), ingredients) {
199            (Alfie, AlfieSecret) => Ok(AlfieSignature),
200            (Betty, BettySecret) => Ok(BettySignature),
201            (Gemma, GemmaSecret) => Ok(GemmaSignature),
202            (Dalton, DaltonSecret) => Ok(DaltonSignature),
203            _ => Err(()),
204        }
205    }
206
207    /// Determines whether `self` [authorises](https://willowprotocol.org/specs/data-model/index.html#is_authorised_write) the given entry.
208    fn does_authorise<E>(&self, entry: &E) -> bool
209    where
210        E: Entrylike<4, 4, 4, TestNamespace, TestSubspace, TestDigest> + ?Sized,
211    {
212        matches!(
213            (entry.wdm_subspace_id(), self),
214            (Alfie, AlfieSignature)
215                | (Betty, BettySignature)
216                | (Gemma, GemmaSignature)
217                | (Dalton, DaltonSignature)
218        )
219    }
220}
221
222pub use TestSubspaceSignature::*;
223
224impl Encodable for TestSubspaceSignature {
225    async fn encode<C>(&self, consumer: &mut C) -> Result<(), C::Error>
226    where
227        C: BulkConsumer<Item = u8> + ?Sized,
228    {
229        match self {
230            AlfieSignature => consumer.consume_item(0).await,
231            BettySignature => consumer.consume_item(1).await,
232            GemmaSignature => consumer.consume_item(2).await,
233            DaltonSignature => consumer.consume_item(3).await,
234        }
235    }
236}
237
238impl EncodableKnownLength for TestSubspaceSignature {
239    fn len_of_encoding(&self) -> usize {
240        1
241    }
242}
243
244impl Decodable for TestSubspaceSignature {
245    type ErrorReason = Blame;
246
247    async fn decode<P>(
248        producer: &mut P,
249    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
250    where
251        P: BulkProducer<Item = u8> + ?Sized,
252        Self: Sized,
253    {
254        let byte = producer.produce_item().await?;
255
256        match byte {
257            0 => Ok(AlfieSignature),
258            1 => Ok(BettySignature),
259            2 => Ok(GemmaSignature),
260            3 => Ok(DaltonSignature),
261            _ => Err(DecodeError::Other(Blame::TheirFault)),
262        }
263    }
264}
265
266impl DecodableCanonic for TestSubspaceSignature {
267    type ErrorCanonic = Blame;
268
269    async fn decode_canonic<P>(
270        producer: &mut P,
271    ) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorCanonic>>
272    where
273        P: BulkProducer<Item = u8> + ?Sized,
274        Self: Sized,
275    {
276        Self::decode(producer).await
277    }
278}
279
280impl AuthorisationToken<4, 4, 4, TestSubspace, TestSubspace, TestDigest> for TestSubspaceSignature {
281    type Ingredients = ();
282
283    type CreationError = Infallible;
284
285    fn new_for_entry<E>(
286        entry: &E,
287        _ingredients: &Self::Ingredients,
288    ) -> Result<Self, Self::CreationError>
289    where
290        E: Entrylike<4, 4, 4, TestSubspace, TestSubspace, TestDigest> + ?Sized,
291    {
292        match entry.wdm_subspace_id() {
293            TestSubspace::Alfie => Ok(TestSubspaceSignature::AlfieSignature),
294            TestSubspace::Betty => Ok(TestSubspaceSignature::BettySignature),
295            TestSubspace::Gemma => Ok(TestSubspaceSignature::GemmaSignature),
296            TestSubspace::Dalton => Ok(TestSubspaceSignature::DaltonSignature),
297        }
298    }
299
300    fn does_authorise<E>(&self, entry: &E) -> bool
301    where
302        E: Entrylike<4, 4, 4, TestSubspace, TestSubspace, TestDigest> + ?Sized,
303    {
304        match entry.wdm_subspace_id() {
305            TestSubspace::Alfie => self == &TestSubspaceSignature::AlfieSignature,
306            TestSubspace::Betty => self == &TestSubspaceSignature::BettySignature,
307            TestSubspace::Gemma => self == &TestSubspaceSignature::GemmaSignature,
308            TestSubspace::Dalton => self == &TestSubspaceSignature::DaltonSignature,
309        }
310    }
311}