use derive_more::From;
use ergotree_ir::sigma_protocol::sigma_boolean::SigmaBoolean;
use crate::sigma_protocol::challenge::Challenge;
use crate::sigma_protocol::unchecked_tree::UncheckedTree;
use crate::sigma_protocol::unproven_tree::NodePosition;
use crate::sigma_protocol::wscalar::Wscalar;
use crate::sigma_protocol::FirstProverMessage;
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
#[cfg_attr(feature = "json", serde(untagged))]
#[derive(PartialEq, Debug, Clone, From)]
pub enum Hint {
SecretProven(SecretProven),
CommitmentHint(CommitmentHint),
}
#[cfg_attr(
feature = "json",
derive(serde::Serialize, serde::Deserialize),
serde(try_from = "crate::json::hint::RealSecretProofJson")
)]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
#[derive(PartialEq, Debug, Clone)]
pub struct RealSecretProof {
#[cfg_attr(feature = "json", serde(rename = "pubkey"))]
pub image: SigmaBoolean,
#[cfg_attr(feature = "json", serde(rename = "challenge"))]
pub challenge: Challenge,
#[cfg_attr(feature = "json", serde(rename = "proof"))]
pub unchecked_tree: UncheckedTree,
#[cfg_attr(feature = "json", serde(rename = "position"))]
pub position: NodePosition,
}
#[cfg_attr(
feature = "json",
derive(serde::Serialize, serde::Deserialize),
serde(try_from = "crate::json::hint::SimulatedSecretProofJson")
)]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
#[derive(PartialEq, Debug, Clone)]
pub struct SimulatedSecretProof {
#[cfg_attr(feature = "json", serde(rename = "pubkey"))]
pub image: SigmaBoolean,
#[cfg_attr(feature = "json", serde(rename = "challenge"))]
pub challenge: Challenge,
#[cfg_attr(feature = "json", serde(rename = "proof"))]
pub unchecked_tree: UncheckedTree,
#[cfg_attr(feature = "json", serde(rename = "position"))]
pub position: NodePosition,
}
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "json", serde(tag = "hint"))]
#[derive(PartialEq, Debug, Clone, From)]
pub enum SecretProven {
#[cfg_attr(feature = "json", serde(rename = "proofReal"))]
RealSecretProof(RealSecretProof),
#[cfg_attr(feature = "json", serde(rename = "proofSimulated"))]
SimulatedSecretProof(SimulatedSecretProof),
}
impl SecretProven {
pub fn position(&self) -> &NodePosition {
match self {
SecretProven::RealSecretProof(proof) => &proof.position,
SecretProven::SimulatedSecretProof(proof) => &proof.position,
}
}
pub fn challenge(&self) -> &Challenge {
match self {
SecretProven::RealSecretProof(proof) => &proof.challenge,
SecretProven::SimulatedSecretProof(proof) => &proof.challenge,
}
}
}
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct RealCommitment {
#[cfg_attr(feature = "json", serde(rename = "pubkey"))]
pub image: SigmaBoolean,
#[cfg_attr(feature = "json", serde(flatten))]
pub commitment: FirstProverMessage,
#[cfg_attr(feature = "json", serde(rename = "position"))]
pub position: NodePosition,
}
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct OwnCommitment {
#[cfg_attr(feature = "json", serde(rename = "pubkey"))]
pub image: SigmaBoolean,
#[cfg_attr(feature = "json", serde(rename = "secret"))]
pub secret_randomness: Wscalar,
#[cfg_attr(feature = "json", serde(flatten))]
pub commitment: FirstProverMessage,
#[cfg_attr(feature = "json", serde(rename = "position"))]
pub position: NodePosition,
}
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
#[derive(PartialEq, Eq, Debug, Clone)]
pub struct SimulatedCommitment {
#[cfg_attr(feature = "json", serde(rename = "pubkey"))]
pub image: SigmaBoolean,
#[cfg_attr(feature = "json", serde(flatten))]
pub commitment: FirstProverMessage,
#[cfg_attr(feature = "json", serde(rename = "position"))]
pub position: NodePosition,
}
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
#[cfg_attr(feature = "json", serde(tag = "hint"))]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
#[derive(PartialEq, Eq, Debug, Clone, From)]
pub enum CommitmentHint {
#[cfg_attr(feature = "json", serde(rename = "cmtWithSecret"))]
OwnCommitment(OwnCommitment),
#[cfg_attr(feature = "json", serde(rename = "cmtReal"))]
RealCommitment(RealCommitment),
#[cfg_attr(feature = "json", serde(rename = "cmtSimulated"))]
SimulatedCommitment(SimulatedCommitment),
}
impl CommitmentHint {
pub fn position(&self) -> &NodePosition {
match self {
CommitmentHint::OwnCommitment(comm) => &comm.position,
CommitmentHint::RealCommitment(comm) => &comm.position,
CommitmentHint::SimulatedCommitment(comm) => &comm.position,
}
}
pub fn commitment(&self) -> &FirstProverMessage {
match self {
CommitmentHint::OwnCommitment(comm) => &comm.commitment,
CommitmentHint::RealCommitment(comm) => &comm.commitment,
CommitmentHint::SimulatedCommitment(comm) => &comm.commitment,
}
}
}
impl From<RealCommitment> for Hint {
fn from(c: RealCommitment) -> Self {
Hint::CommitmentHint(CommitmentHint::RealCommitment(c))
}
}
impl From<OwnCommitment> for Hint {
fn from(c: OwnCommitment) -> Self {
Hint::CommitmentHint(CommitmentHint::OwnCommitment(c))
}
}
impl From<RealSecretProof> for Hint {
fn from(p: RealSecretProof) -> Self {
Hint::SecretProven(p.into())
}
}
#[cfg_attr(feature = "json", derive(serde::Serialize, serde::Deserialize))]
#[derive(PartialEq, Debug, Clone)]
#[cfg_attr(feature = "arbitrary", derive(proptest_derive::Arbitrary))]
pub struct HintsBag {
#[cfg_attr(
feature = "arbitrary",
proptest(strategy = "proptest::collection::vec(proptest::prelude::any::<Hint>(), 0..3)")
)]
pub hints: Vec<Hint>,
}
impl HintsBag {
pub fn empty() -> Self {
HintsBag { hints: vec![] }
}
pub fn from_bags(hints_bags: Vec<HintsBag>) -> Self {
let mut hints = vec![];
for hints_bag in hints_bags {
hints.extend(hints_bag.hints);
}
HintsBag { hints }
}
pub fn add_hint(&mut self, hint: Hint) {
self.hints.push(hint);
}
pub fn commitments(&self) -> Vec<CommitmentHint> {
self.hints
.clone()
.into_iter()
.filter_map(|hint| {
if let Hint::CommitmentHint(v) = hint {
Some(v)
} else {
None
}
})
.collect()
}
pub fn real_proofs(&self) -> Vec<RealSecretProof> {
self.hints
.clone()
.into_iter()
.filter_map(|hint| {
if let Hint::SecretProven(SecretProven::RealSecretProof(v)) = hint {
Some(v)
} else {
None
}
})
.collect()
}
pub fn real_commitments(&self) -> Vec<RealCommitment> {
self.hints
.clone()
.into_iter()
.filter_map(|hint| {
if let Hint::CommitmentHint(CommitmentHint::RealCommitment(v)) = hint {
Some(v)
} else {
None
}
})
.collect()
}
pub fn own_commitments(&self) -> Vec<OwnCommitment> {
self.hints
.clone()
.into_iter()
.filter_map(|hint| {
if let Hint::CommitmentHint(CommitmentHint::OwnCommitment(v)) = hint {
Some(v)
} else {
None
}
})
.collect()
}
pub fn real_images(&self) -> Vec<SigmaBoolean> {
let mut from_proofs: Vec<SigmaBoolean> =
self.real_proofs().iter().map(|p| p.image.clone()).collect();
let mut from_comms: Vec<SigmaBoolean> = self
.real_commitments()
.iter()
.map(|c| c.image.clone())
.collect();
from_proofs.append(&mut from_comms);
from_proofs
}
pub fn simulated_proofs(&self) -> Vec<SimulatedSecretProof> {
self.hints
.clone()
.into_iter()
.filter_map(|hint| {
if let Hint::SecretProven(SecretProven::SimulatedSecretProof(v)) = hint {
Some(v)
} else {
None
}
})
.collect()
}
pub fn proofs(&self) -> Vec<SecretProven> {
self.hints
.clone()
.into_iter()
.filter_map(|hint| {
if let Hint::SecretProven(sp) = hint {
Some(sp)
} else {
None
}
})
.collect()
}
}
#[cfg(feature = "arbitrary")]
#[allow(clippy::unwrap_used)]
mod arbitrary {
use crate::sigma_protocol::proof_tree::ProofTreeLeaf;
use crate::sigma_protocol::sig_serializer::parse_sig_compute_challenges;
use crate::sigma_protocol::sig_serializer::serialize_sig;
use crate::sigma_protocol::unchecked_tree::UncheckedConjecture;
use super::*;
use ergotree_ir::sigma_protocol::sigma_boolean::cand::Cand;
use ergotree_ir::sigma_protocol::sigma_boolean::cor::Cor;
use ergotree_ir::sigma_protocol::sigma_boolean::cthreshold::Cthreshold;
use proptest::prelude::*;
fn extract_sigma_boolean(unchecked_tree: &UncheckedTree) -> SigmaBoolean {
match unchecked_tree {
UncheckedTree::UncheckedLeaf(ul) => ul.proposition(),
UncheckedTree::UncheckedConjecture(UncheckedConjecture::CandUnchecked {
challenge: _,
children,
}) => Cand {
items: children.mapped_ref(extract_sigma_boolean),
}
.into(),
UncheckedTree::UncheckedConjecture(UncheckedConjecture::CorUnchecked {
challenge: _,
children,
}) => Cor {
items: children.mapped_ref(extract_sigma_boolean),
}
.into(),
UncheckedTree::UncheckedConjecture(UncheckedConjecture::CthresholdUnchecked {
k,
children,
polynomial: _,
challenge: _,
}) => Cthreshold {
children: children.mapped_ref(extract_sigma_boolean),
k: *k,
}
.into(),
}
}
impl Arbitrary for SecretProven {
type Parameters = ();
type Strategy = BoxedStrategy<Self>;
fn arbitrary_with(_: Self::Parameters) -> Self::Strategy {
(
any::<UncheckedTree>(),
any::<Challenge>(),
any::<NodePosition>(),
)
.prop_flat_map(|(unchecked_tree, challenge, position)| {
let sigma_boolean = extract_sigma_boolean(&unchecked_tree);
let unchecked_tree_norm = parse_sig_compute_challenges(
&sigma_boolean,
serialize_sig(unchecked_tree).to_bytes(),
)
.unwrap();
prop_oneof![
Just(
RealSecretProof {
image: sigma_boolean.clone(),
challenge: challenge.clone(),
unchecked_tree: unchecked_tree_norm.clone(),
position: position.clone()
}
.into()
),
Just(
SimulatedSecretProof {
image: sigma_boolean,
challenge,
unchecked_tree: unchecked_tree_norm,
position
}
.into()
),
]
})
.boxed()
}
}
}