ergotree_interpreter/sigma_protocol/
unchecked_tree.rs

1//! Unchecked proof tree types
2
3use ergo_chain_types::Base16EncodedBytes;
4use ergotree_ir::sigma_protocol::sigma_boolean::ProveDhTuple;
5use ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
6use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
7use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjectureItems;
8use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
9use gf2_192::gf2_192poly::Gf2_192Poly;
10
11use super::dht_protocol::FirstDhTupleProverMessage;
12use super::dht_protocol::SecondDhTupleProverMessage;
13use super::proof_tree::ConjectureType;
14use super::proof_tree::ProofTree;
15use super::proof_tree::ProofTreeConjecture;
16use super::proof_tree::ProofTreeKind;
17use super::proof_tree::ProofTreeLeaf;
18use super::sig_serializer::serialize_sig;
19use super::{
20    dlog_protocol::{FirstDlogProverMessage, SecondDlogProverMessage},
21    Challenge, FirstProverMessage,
22};
23
24use derive_more::From;
25
26/// Unchecked sigma tree
27#[derive(PartialEq, Debug, Clone, From)]
28#[cfg_attr(
29    feature = "json",
30    derive(serde::Serialize),
31    serde(into = "ergo_chain_types::Base16EncodedBytes")
32)]
33pub enum UncheckedTree {
34    /// Unchecked leaf
35    UncheckedLeaf(UncheckedLeaf),
36    /// Unchecked conjecture (OR, AND, ...)
37    UncheckedConjecture(UncheckedConjecture),
38}
39
40impl UncheckedTree {
41    /// Get challenge
42    pub(crate) fn challenge(&self) -> Challenge {
43        match self {
44            UncheckedTree::UncheckedLeaf(ul) => ul.challenge(),
45            UncheckedTree::UncheckedConjecture(uc) => uc.challenge(),
46        }
47    }
48
49    pub(crate) fn as_tree_kind(&self) -> ProofTreeKind {
50        match self {
51            UncheckedTree::UncheckedLeaf(ul) => ProofTreeKind::Leaf(ul),
52            UncheckedTree::UncheckedConjecture(uc) => ProofTreeKind::Conjecture(uc),
53        }
54    }
55
56    pub(crate) fn with_challenge(self, challenge: Challenge) -> Self {
57        match self {
58            UncheckedTree::UncheckedLeaf(ul) => ul.with_challenge(challenge).into(),
59            UncheckedTree::UncheckedConjecture(uc) => uc.with_challenge(challenge).into(),
60        }
61    }
62}
63
64impl From<UncheckedTree> for Base16EncodedBytes {
65    fn from(tree: UncheckedTree) -> Self {
66        let bytes: Vec<u8> = serialize_sig(tree).into();
67        Base16EncodedBytes::from(bytes)
68    }
69}
70
71/// Unchecked leaf
72#[derive(PartialEq, Eq, Debug, Clone, From)]
73pub enum UncheckedLeaf {
74    /// Unchecked Schnorr
75    UncheckedSchnorr(UncheckedSchnorr),
76    /// Unchecked DhTuple
77    UncheckedDhTuple(UncheckedDhTuple),
78}
79
80impl UncheckedLeaf {
81    /// Challenge of FiatShamir
82    pub fn challenge(&self) -> Challenge {
83        match self {
84            UncheckedLeaf::UncheckedSchnorr(us) => us.challenge.clone(),
85            UncheckedLeaf::UncheckedDhTuple(udht) => udht.challenge.clone(),
86        }
87    }
88    /// Set Challenge
89    pub fn with_challenge(self, challenge: Challenge) -> Self {
90        match self {
91            UncheckedLeaf::UncheckedSchnorr(us) => us.with_challenge(challenge).into(),
92            UncheckedLeaf::UncheckedDhTuple(udht) => udht.with_challenge(challenge).into(),
93        }
94    }
95}
96
97impl ProofTreeLeaf for UncheckedLeaf {
98    fn proposition(&self) -> SigmaBoolean {
99        match self {
100            UncheckedLeaf::UncheckedSchnorr(us) => SigmaBoolean::ProofOfKnowledge(
101                SigmaProofOfKnowledgeTree::ProveDlog(us.proposition.clone()),
102            ),
103            UncheckedLeaf::UncheckedDhTuple(dhu) => SigmaBoolean::ProofOfKnowledge(
104                SigmaProofOfKnowledgeTree::ProveDhTuple(dhu.proposition.clone()),
105            ),
106        }
107    }
108    fn commitment_opt(&self) -> Option<FirstProverMessage> {
109        match self {
110            UncheckedLeaf::UncheckedSchnorr(us) => us.commitment_opt.clone().map(Into::into),
111            UncheckedLeaf::UncheckedDhTuple(udh) => udh.commitment_opt.clone().map(Into::into),
112        }
113    }
114}
115/// Unchecked Schnorr
116#[derive(PartialEq, Eq, Debug, Clone)]
117#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
118pub struct UncheckedSchnorr {
119    /// Proposition
120    pub proposition: ProveDlog,
121    /// Commitment FirstDlogProverMessage
122    pub commitment_opt: Option<FirstDlogProverMessage>,
123    /// Challenge
124    pub challenge: Challenge,
125    /// SecondMessage
126    pub second_message: SecondDlogProverMessage,
127}
128
129impl UncheckedSchnorr {
130    /// Set New Challenge
131    pub fn with_challenge(self, challenge: Challenge) -> Self {
132        UncheckedSchnorr { challenge, ..self }
133    }
134}
135
136impl From<UncheckedSchnorr> for UncheckedTree {
137    fn from(us: UncheckedSchnorr) -> Self {
138        UncheckedTree::UncheckedLeaf(us.into())
139    }
140}
141
142impl From<UncheckedDhTuple> for UncheckedTree {
143    fn from(dh: UncheckedDhTuple) -> Self {
144        UncheckedTree::UncheckedLeaf(dh.into())
145    }
146}
147
148/// UncheckedDhTuple
149#[derive(PartialEq, Eq, Debug, Clone)]
150#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
151pub struct UncheckedDhTuple {
152    /// Proposition
153    pub proposition: ProveDhTuple,
154    /// Commitment  FirstDhTupleProverMessage
155    pub commitment_opt: Option<FirstDhTupleProverMessage>,
156    /// Challenge
157    pub challenge: Challenge,
158    /// SecondMessage
159    pub second_message: SecondDhTupleProverMessage,
160}
161
162impl UncheckedDhTuple {
163    /// Set Challenge
164    pub fn with_challenge(self, challenge: Challenge) -> Self {
165        UncheckedDhTuple { challenge, ..self }
166    }
167}
168
169/// UncheckedConjecture
170#[derive(PartialEq, Debug, Clone)]
171#[allow(clippy::enum_variant_names)]
172pub enum UncheckedConjecture {
173    /// Unchecked And Conjecture
174    CandUnchecked {
175        /// Challenge
176        challenge: Challenge,
177        /// Children
178        children: SigmaConjectureItems<UncheckedTree>,
179    },
180    /// Unchecked Or Conjecture
181    CorUnchecked {
182        /// Challenge
183        challenge: Challenge,
184        /// Children
185        children: SigmaConjectureItems<UncheckedTree>,
186    },
187    /// Unchecked Cthreshold Conjecture
188    CthresholdUnchecked {
189        /// Challenge
190        challenge: Challenge,
191        /// Children
192        children: SigmaConjectureItems<UncheckedTree>,
193        /// K
194        k: u8,
195        /// Polynomial
196        polynomial: Gf2_192Poly,
197    },
198}
199
200impl UncheckedConjecture {
201    /// Set New Children
202    pub fn with_children(self, new_children: SigmaConjectureItems<UncheckedTree>) -> Self {
203        match self {
204            UncheckedConjecture::CandUnchecked {
205                challenge,
206                children: _,
207            } => UncheckedConjecture::CandUnchecked {
208                challenge,
209                children: new_children,
210            },
211            UncheckedConjecture::CorUnchecked {
212                challenge,
213                children: _,
214            } => UncheckedConjecture::CorUnchecked {
215                challenge,
216                children: new_children,
217            },
218            UncheckedConjecture::CthresholdUnchecked {
219                challenge,
220                children: _,
221                k,
222                polynomial: polynomial_opt,
223            } => UncheckedConjecture::CthresholdUnchecked {
224                challenge,
225                children: new_children,
226                k,
227                polynomial: polynomial_opt,
228            },
229        }
230    }
231    /// Get Children
232    pub fn children_ust(self) -> SigmaConjectureItems<UncheckedTree> {
233        match self {
234            UncheckedConjecture::CandUnchecked {
235                challenge: _,
236                children,
237            } => children,
238            UncheckedConjecture::CorUnchecked {
239                challenge: _,
240                children,
241            } => children,
242            UncheckedConjecture::CthresholdUnchecked {
243                challenge: _,
244                children,
245                k: _,
246                polynomial: _,
247            } => children,
248        }
249    }
250    /// Get Children
251    pub fn challenge(&self) -> Challenge {
252        match self {
253            UncheckedConjecture::CandUnchecked {
254                challenge,
255                children: _,
256            } => challenge.clone(),
257            UncheckedConjecture::CorUnchecked {
258                challenge,
259                children: _,
260            } => challenge.clone(),
261            UncheckedConjecture::CthresholdUnchecked {
262                challenge,
263                children: _,
264                k: _,
265                polynomial: _,
266            } => challenge.clone(),
267        }
268    }
269    /// Set Challenge
270    pub fn with_challenge(self, challenge: Challenge) -> Self {
271        match self {
272            UncheckedConjecture::CandUnchecked {
273                challenge: _,
274                children,
275            } => UncheckedConjecture::CandUnchecked {
276                challenge,
277                children,
278            },
279            UncheckedConjecture::CorUnchecked {
280                challenge: _,
281                children,
282            } => UncheckedConjecture::CorUnchecked {
283                challenge,
284                children,
285            },
286            UncheckedConjecture::CthresholdUnchecked {
287                challenge: _,
288                children,
289                k,
290                polynomial: polynomial_opt,
291            } => UncheckedConjecture::CthresholdUnchecked {
292                challenge,
293                children,
294                k,
295                polynomial: polynomial_opt,
296            },
297        }
298    }
299}
300
301impl ProofTreeConjecture for UncheckedConjecture {
302    /// Get Conjecture Type
303    fn conjecture_type(&self) -> ConjectureType {
304        match self {
305            UncheckedConjecture::CandUnchecked { .. } => ConjectureType::And,
306            UncheckedConjecture::CorUnchecked { .. } => ConjectureType::Or,
307            UncheckedConjecture::CthresholdUnchecked { .. } => ConjectureType::Threshold,
308        }
309    }
310
311    /// Get Children
312    fn children(&self) -> SigmaConjectureItems<ProofTree> {
313        match self {
314            UncheckedConjecture::CandUnchecked {
315                challenge: _,
316                children,
317            } => children.mapped_ref(|ust| ust.clone().into()),
318            UncheckedConjecture::CorUnchecked {
319                challenge: _,
320                children,
321            } => children.mapped_ref(|ust| ust.clone().into()),
322            UncheckedConjecture::CthresholdUnchecked {
323                challenge: _,
324                children,
325                k: _,
326                polynomial: _,
327            } => children.mapped_ref(|ust| ust.clone().into()),
328        }
329    }
330}
331
332#[cfg(feature = "arbitrary")]
333#[allow(clippy::unwrap_used)]
334mod arbitrary {
335    use std::convert::TryInto;
336
337    use crate::sigma_protocol::gf2_192::gf2_192poly_from_byte_array;
338
339    use super::*;
340    use proptest::collection::vec;
341    use proptest::prelude::*;
342
343    pub fn primitive_type_value() -> BoxedStrategy<UncheckedTree> {
344        prop_oneof![
345            any::<UncheckedSchnorr>().prop_map_into(),
346            any::<UncheckedDhTuple>().prop_map_into(),
347        ]
348        .boxed()
349    }
350
351    impl Arbitrary for UncheckedTree {
352        type Parameters = ();
353        type Strategy = BoxedStrategy<Self>;
354
355        fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
356            primitive_type_value()
357                .prop_recursive(1, 6, 4, |elem| {
358                    prop_oneof![
359                        (vec(elem.clone(), 2..=3), any::<Challenge>())
360                            .prop_map(|(elems, challenge)| UncheckedConjecture::CandUnchecked {
361                                children: elems.try_into().unwrap(),
362                                challenge,
363                            })
364                            .prop_map_into(),
365                        (vec(elem.clone(), 2..=3), any::<Challenge>())
366                            .prop_map(|(elems, challenge)| UncheckedConjecture::CorUnchecked {
367                                children: elems.try_into().unwrap(),
368                                challenge
369                            })
370                            .prop_map_into(),
371                        (vec(elem, 2..=4), any::<Challenge>(), vec(any::<u8>(), 24))
372                            .prop_map(|(elems, challenge, random_bytes_for_one_absent_signer)| {
373                                let polynomial = gf2_192poly_from_byte_array(
374                                    challenge.clone(),
375                                    random_bytes_for_one_absent_signer,
376                                )
377                                .unwrap();
378                                UncheckedConjecture::CthresholdUnchecked {
379                                    k: (elems.len() - 1) as u8,
380                                    children: elems.try_into().unwrap(),
381                                    challenge,
382                                    polynomial,
383                                }
384                            })
385                            .prop_map_into(),
386                    ]
387                })
388                .boxed()
389        }
390    }
391}