use ergo_chain_types::Base16EncodedBytes;
use ergotree_ir::sigma_protocol::sigma_boolean::ProveDhTuple;
use ergotree_ir::sigma_protocol::sigma_boolean::ProveDlog;
use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
use ergotree_ir::sigma_protocol::sigma_boolean::SigmaConjectureItems;
use ergotree_ir::sigma_protocol::sigma_boolean::SigmaProofOfKnowledgeTree;
use gf2_192::gf2_192poly::Gf2_192Poly;
use super::dht_protocol::FirstDhTupleProverMessage;
use super::dht_protocol::SecondDhTupleProverMessage;
use super::proof_tree::ConjectureType;
use super::proof_tree::ProofTree;
use super::proof_tree::ProofTreeConjecture;
use super::proof_tree::ProofTreeKind;
use super::proof_tree::ProofTreeLeaf;
use super::sig_serializer::serialize_sig;
use super::{
dlog_protocol::{FirstDlogProverMessage, SecondDlogProverMessage},
Challenge, FirstProverMessage,
};
use derive_more::From;
#[derive(PartialEq, Debug, Clone, From)]
#[cfg_attr(
feature = "json",
derive(serde::Serialize),
serde(into = "ergo_chain_types::Base16EncodedBytes")
)]
pub enum UncheckedTree {
UncheckedLeaf(UncheckedLeaf),
UncheckedConjecture(UncheckedConjecture),
}
impl UncheckedTree {
pub(crate) fn challenge(&self) -> Challenge {
match self {
UncheckedTree::UncheckedLeaf(ul) => ul.challenge(),
UncheckedTree::UncheckedConjecture(uc) => uc.challenge(),
}
}
pub(crate) fn as_tree_kind(&self) -> ProofTreeKind {
match self {
UncheckedTree::UncheckedLeaf(ul) => ProofTreeKind::Leaf(ul),
UncheckedTree::UncheckedConjecture(uc) => ProofTreeKind::Conjecture(uc),
}
}
pub(crate) fn with_challenge(self, challenge: Challenge) -> Self {
match self {
UncheckedTree::UncheckedLeaf(ul) => ul.with_challenge(challenge).into(),
UncheckedTree::UncheckedConjecture(uc) => uc.with_challenge(challenge).into(),
}
}
}
impl From<UncheckedTree> for Base16EncodedBytes {
fn from(tree: UncheckedTree) -> Self {
let bytes: Vec<u8> = serialize_sig(tree).into();
Base16EncodedBytes::from(bytes)
}
}
#[derive(PartialEq, Eq, Debug, Clone, From)]
pub enum UncheckedLeaf {
UncheckedSchnorr(UncheckedSchnorr),
UncheckedDhTuple(UncheckedDhTuple),
}
impl UncheckedLeaf {
pub fn challenge(&self) -> Challenge {
match self {
UncheckedLeaf::UncheckedSchnorr(us) => us.challenge.clone(),
UncheckedLeaf::UncheckedDhTuple(udht) => udht.challenge.clone(),
}
}
pub fn with_challenge(self, challenge: Challenge) -> Self {
match self {
UncheckedLeaf::UncheckedSchnorr(us) => us.with_challenge(challenge).into(),
UncheckedLeaf::UncheckedDhTuple(udht) => udht.with_challenge(challenge).into(),
}
}
}
impl ProofTreeLeaf for UncheckedLeaf {
fn proposition(&self) -> SigmaBoolean {
match self {
UncheckedLeaf::UncheckedSchnorr(us) => SigmaBoolean::ProofOfKnowledge(
SigmaProofOfKnowledgeTree::ProveDlog(us.proposition.clone()),
),
UncheckedLeaf::UncheckedDhTuple(dhu) => SigmaBoolean::ProofOfKnowledge(
SigmaProofOfKnowledgeTree::ProveDhTuple(dhu.proposition.clone()),
),
}
}
fn commitment_opt(&self) -> Option<FirstProverMessage> {
match self {
UncheckedLeaf::UncheckedSchnorr(us) => us.commitment_opt.clone().map(Into::into),
UncheckedLeaf::UncheckedDhTuple(udh) => udh.commitment_opt.clone().map(Into::into),
}
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
pub struct UncheckedSchnorr {
pub proposition: ProveDlog,
pub commitment_opt: Option<FirstDlogProverMessage>,
pub challenge: Challenge,
pub second_message: SecondDlogProverMessage,
}
impl UncheckedSchnorr {
pub fn with_challenge(self, challenge: Challenge) -> Self {
UncheckedSchnorr { challenge, ..self }
}
}
impl From<UncheckedSchnorr> for UncheckedTree {
fn from(us: UncheckedSchnorr) -> Self {
UncheckedTree::UncheckedLeaf(us.into())
}
}
impl From<UncheckedDhTuple> for UncheckedTree {
fn from(dh: UncheckedDhTuple) -> Self {
UncheckedTree::UncheckedLeaf(dh.into())
}
}
#[derive(PartialEq, Eq, Debug, Clone)]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
pub struct UncheckedDhTuple {
pub proposition: ProveDhTuple,
pub commitment_opt: Option<FirstDhTupleProverMessage>,
pub challenge: Challenge,
pub second_message: SecondDhTupleProverMessage,
}
impl UncheckedDhTuple {
pub fn with_challenge(self, challenge: Challenge) -> Self {
UncheckedDhTuple { challenge, ..self }
}
}
#[derive(PartialEq, Debug, Clone)]
#[allow(clippy::enum_variant_names)]
pub enum UncheckedConjecture {
CandUnchecked {
challenge: Challenge,
children: SigmaConjectureItems<UncheckedTree>,
},
CorUnchecked {
challenge: Challenge,
children: SigmaConjectureItems<UncheckedTree>,
},
CthresholdUnchecked {
challenge: Challenge,
children: SigmaConjectureItems<UncheckedTree>,
k: u8,
polynomial: Gf2_192Poly,
},
}
impl UncheckedConjecture {
pub fn with_children(self, new_children: SigmaConjectureItems<UncheckedTree>) -> Self {
match self {
UncheckedConjecture::CandUnchecked {
challenge,
children: _,
} => UncheckedConjecture::CandUnchecked {
challenge,
children: new_children,
},
UncheckedConjecture::CorUnchecked {
challenge,
children: _,
} => UncheckedConjecture::CorUnchecked {
challenge,
children: new_children,
},
UncheckedConjecture::CthresholdUnchecked {
challenge,
children: _,
k,
polynomial: polynomial_opt,
} => UncheckedConjecture::CthresholdUnchecked {
challenge,
children: new_children,
k,
polynomial: polynomial_opt,
},
}
}
pub fn children_ust(self) -> SigmaConjectureItems<UncheckedTree> {
match self {
UncheckedConjecture::CandUnchecked {
challenge: _,
children,
} => children,
UncheckedConjecture::CorUnchecked {
challenge: _,
children,
} => children,
UncheckedConjecture::CthresholdUnchecked {
challenge: _,
children,
k: _,
polynomial: _,
} => children,
}
}
pub fn challenge(&self) -> Challenge {
match self {
UncheckedConjecture::CandUnchecked {
challenge,
children: _,
} => challenge.clone(),
UncheckedConjecture::CorUnchecked {
challenge,
children: _,
} => challenge.clone(),
UncheckedConjecture::CthresholdUnchecked {
challenge,
children: _,
k: _,
polynomial: _,
} => challenge.clone(),
}
}
pub fn with_challenge(self, challenge: Challenge) -> Self {
match self {
UncheckedConjecture::CandUnchecked {
challenge: _,
children,
} => UncheckedConjecture::CandUnchecked {
challenge,
children,
},
UncheckedConjecture::CorUnchecked {
challenge: _,
children,
} => UncheckedConjecture::CorUnchecked {
challenge,
children,
},
UncheckedConjecture::CthresholdUnchecked {
challenge: _,
children,
k,
polynomial: polynomial_opt,
} => UncheckedConjecture::CthresholdUnchecked {
challenge,
children,
k,
polynomial: polynomial_opt,
},
}
}
}
impl ProofTreeConjecture for UncheckedConjecture {
fn conjecture_type(&self) -> ConjectureType {
match self {
UncheckedConjecture::CandUnchecked { .. } => ConjectureType::And,
UncheckedConjecture::CorUnchecked { .. } => ConjectureType::Or,
UncheckedConjecture::CthresholdUnchecked { .. } => ConjectureType::Threshold,
}
}
fn children(&self) -> SigmaConjectureItems<ProofTree> {
match self {
UncheckedConjecture::CandUnchecked {
challenge: _,
children,
} => children.mapped_ref(|ust| ust.clone().into()),
UncheckedConjecture::CorUnchecked {
challenge: _,
children,
} => children.mapped_ref(|ust| ust.clone().into()),
UncheckedConjecture::CthresholdUnchecked {
challenge: _,
children,
k: _,
polynomial: _,
} => children.mapped_ref(|ust| ust.clone().into()),
}
}
}
#[cfg(feature = "arbitrary")]
#[allow(clippy::unwrap_used)]
mod arbitrary {
use std::convert::TryInto;
use crate::sigma_protocol::gf2_192::gf2_192poly_from_byte_array;
use super::*;
use proptest::collection::vec;
use proptest::prelude::*;
pub fn primitive_type_value() -> BoxedStrategy<UncheckedTree> {
prop_oneof![
any::<UncheckedSchnorr>().prop_map_into(),
any::<UncheckedDhTuple>().prop_map_into(),
]
.boxed()
}
impl Arbitrary for UncheckedTree {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
primitive_type_value()
.prop_recursive(1, 6, 4, |elem| {
prop_oneof![
(vec(elem.clone(), 2..=3), any::<Challenge>())
.prop_map(|(elems, challenge)| UncheckedConjecture::CandUnchecked {
children: elems.try_into().unwrap(),
challenge,
})
.prop_map_into(),
(vec(elem.clone(), 2..=3), any::<Challenge>())
.prop_map(|(elems, challenge)| UncheckedConjecture::CorUnchecked {
children: elems.try_into().unwrap(),
challenge
})
.prop_map_into(),
(vec(elem, 2..=4), any::<Challenge>(), vec(any::<u8>(), 24))
.prop_map(|(elems, challenge, random_bytes_for_one_absent_signer)| {
let polynomial = gf2_192poly_from_byte_array(
challenge.clone(),
random_bytes_for_one_absent_signer,
)
.unwrap();
UncheckedConjecture::CthresholdUnchecked {
k: (elems.len() - 1) as u8,
children: elems.try_into().unwrap(),
challenge,
polynomial,
}
})
.prop_map_into(),
]
})
.boxed()
}
}
}