1use 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#[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 UncheckedLeaf(UncheckedLeaf),
36 UncheckedConjecture(UncheckedConjecture),
38}
39
40impl UncheckedTree {
41 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#[derive(PartialEq, Eq, Debug, Clone, From)]
73pub enum UncheckedLeaf {
74 UncheckedSchnorr(UncheckedSchnorr),
76 UncheckedDhTuple(UncheckedDhTuple),
78}
79
80impl UncheckedLeaf {
81 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 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#[derive(PartialEq, Eq, Debug, Clone)]
117#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
118pub struct UncheckedSchnorr {
119 pub proposition: ProveDlog,
121 pub commitment_opt: Option<FirstDlogProverMessage>,
123 pub challenge: Challenge,
125 pub second_message: SecondDlogProverMessage,
127}
128
129impl UncheckedSchnorr {
130 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#[derive(PartialEq, Eq, Debug, Clone)]
150#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
151pub struct UncheckedDhTuple {
152 pub proposition: ProveDhTuple,
154 pub commitment_opt: Option<FirstDhTupleProverMessage>,
156 pub challenge: Challenge,
158 pub second_message: SecondDhTupleProverMessage,
160}
161
162impl UncheckedDhTuple {
163 pub fn with_challenge(self, challenge: Challenge) -> Self {
165 UncheckedDhTuple { challenge, ..self }
166 }
167}
168
169#[derive(PartialEq, Debug, Clone)]
171#[allow(clippy::enum_variant_names)]
172pub enum UncheckedConjecture {
173 CandUnchecked {
175 challenge: Challenge,
177 children: SigmaConjectureItems<UncheckedTree>,
179 },
180 CorUnchecked {
182 challenge: Challenge,
184 children: SigmaConjectureItems<UncheckedTree>,
186 },
187 CthresholdUnchecked {
189 challenge: Challenge,
191 children: SigmaConjectureItems<UncheckedTree>,
193 k: u8,
195 polynomial: Gf2_192Poly,
197 },
198}
199
200impl UncheckedConjecture {
201 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 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 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 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 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 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}