use std::ops::Deref;
use std::ops::DerefMut;
use get_size2::GetSize;
use serde::Deserialize;
use serde::Serialize;
use tasm_lib::prelude::Library;
use tasm_lib::structure::tasm_object::TasmObject;
use tasm_lib::triton_vm::prelude::LabelledInstruction;
use tasm_lib::triton_vm::proof::Proof as VmProof;
use tasm_lib::twenty_first::math::b_field_element::BFieldElement;
use crate::transaction::BFieldCodec;
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, BFieldCodec)]
enum MockProofBehavior {
ValidMock,
InvalidMock,
}
#[derive(Debug, Clone, Serialize, Deserialize, PartialEq, Eq, GetSize)]
#[cfg_attr(any(test, feature = "arbitrary-impls"), derive(arbitrary::Arbitrary))]
pub struct NeptuneProof {
proof: VmProof,
}
impl BFieldCodec for NeptuneProof {
type Error = <VmProof as BFieldCodec>::Error;
fn decode(sequence: &[BFieldElement]) -> Result<Box<Self>, Self::Error> {
Ok(Box::new(Self {
proof: *VmProof::decode(sequence)?,
}))
}
fn encode(&self) -> Vec<BFieldElement> {
self.proof.encode()
}
fn static_length() -> Option<usize> {
VmProof::static_length()
}
}
impl TasmObject for NeptuneProof {
fn label_friendly_name() -> String {
VmProof::label_friendly_name()
}
fn compute_size_and_assert_valid_size_indicator(
library: &mut Library,
) -> Vec<LabelledInstruction> {
VmProof::compute_size_and_assert_valid_size_indicator(library)
}
fn decode_iter<Itr: Iterator<Item = BFieldElement>>(
iterator: &mut Itr,
) -> Result<Box<Self>, Box<dyn std::error::Error + Send + Sync>> {
let elems: Vec<BFieldElement> = iterator.collect();
let mockable_proof = Self::decode(&elems)?;
Ok(mockable_proof)
}
}
impl Deref for NeptuneProof {
type Target = VmProof;
fn deref(&self) -> &Self::Target {
&self.proof
}
}
impl DerefMut for NeptuneProof {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.proof
}
}
impl From<NeptuneProof> for VmProof {
fn from(mp: NeptuneProof) -> VmProof {
mp.proof
}
}
impl From<Vec<BFieldElement>> for NeptuneProof {
fn from(v: Vec<BFieldElement>) -> Self {
Self { proof: VmProof(v) }
}
}
impl From<VmProof> for NeptuneProof {
fn from(proof: VmProof) -> Self {
Self { proof }
}
}
impl NeptuneProof {
pub fn invalid() -> Self {
Self {
proof: VmProof(vec![]),
}
}
#[cfg(any(test, feature = "test-helpers"))]
pub fn invalid_with_size(len: usize) -> Self {
use num_traits::ConstZero;
Self {
proof: VmProof(vec![BFieldElement::ZERO; len]),
}
}
pub fn mock(valid: bool) -> Self {
let behavior = if valid {
MockProofBehavior::ValidMock
} else {
MockProofBehavior::InvalidMock
};
Self {
proof: VmProof(behavior.encode()),
}
}
pub fn valid_mock() -> Self {
Self {
proof: VmProof(MockProofBehavior::ValidMock.encode()),
}
}
pub fn invalid_mock() -> Self {
Self {
proof: VmProof(MockProofBehavior::InvalidMock.encode()),
}
}
pub fn is_standard(&self) -> bool {
!self.is_valid_mock() && !self.is_invalid_mock()
}
pub fn is_mock(&self) -> bool {
self.is_valid_mock() || self.is_invalid_mock()
}
pub fn is_valid_mock(&self) -> bool {
self.matches_behavior(MockProofBehavior::ValidMock)
}
pub fn is_invalid_mock(&self) -> bool {
self.matches_behavior(MockProofBehavior::InvalidMock)
}
fn matches_behavior(&self, target: MockProofBehavior) -> bool {
if let Ok(behavior) = MockProofBehavior::decode(&self.proof.0) {
*behavior == target
} else {
false
}
}
}
pub type Proof = NeptuneProof;