1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
//! ProverResult
use ergotree_ir::serialization::sigma_byte_reader::SigmaByteRead;
use ergotree_ir::serialization::sigma_byte_writer::SigmaByteWrite;
use ergotree_ir::serialization::SerializationError;
use ergotree_ir::serialization::SigmaSerializable;

use super::ContextExtension;
use std::convert::TryFrom;
use std::io;

/// Serialized proof generated by ['Prover']
#[derive(PartialEq, Eq, Hash, Debug, Clone)]
pub enum ProofBytes {
    /// Empty proof
    Empty,
    /// Non-empty proof
    Some(Vec<u8>),
}

impl From<ProofBytes> for Vec<u8> {
    fn from(v: ProofBytes) -> Self {
        match v {
            ProofBytes::Empty => Vec::new(),
            ProofBytes::Some(bytes) => bytes,
        }
    }
}

impl From<Vec<u8>> for ProofBytes {
    fn from(bytes: Vec<u8>) -> Self {
        if bytes.is_empty() {
            ProofBytes::Empty
        } else {
            ProofBytes::Some(bytes)
        }
    }
}

// for JSON encoding in ergo-lib as Base16-encoded string
impl From<ProofBytes> for String {
    fn from(v: ProofBytes) -> Self {
        match v {
            ProofBytes::Empty => "".to_string(),
            ProofBytes::Some(bytes) => base16::encode_lower(&bytes),
        }
    }
}

// for JSON encoding in ergo-lib
impl TryFrom<String> for ProofBytes {
    type Error = base16::DecodeError;

    fn try_from(value: String) -> Result<Self, Self::Error> {
        base16::decode(&value).map(|bytes| bytes.into())
    }
}

impl SigmaSerializable for ProofBytes {
    fn sigma_serialize<W: SigmaByteWrite>(&self, w: &mut W) -> Result<(), io::Error> {
        match self {
            ProofBytes::Empty => w.put_u16(0)?,
            ProofBytes::Some(bytes) => {
                w.put_u16(bytes.len() as u16)?;
                w.write_all(&bytes)?;
            }
        }
        Ok(())
    }

    fn sigma_parse<R: SigmaByteRead>(r: &mut R) -> Result<Self, SerializationError> {
        let proof_len = r.get_u16()?;
        Ok(if proof_len == 0 {
            ProofBytes::Empty
        } else {
            let mut bytes = vec![0; proof_len as usize];
            r.read_exact(&mut bytes)?;
            ProofBytes::Some(bytes)
        })
    }
}

/// Proof of correctness of tx spending
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct ProverResult {
    /// proof that satisfies final sigma proposition
    pub proof: ProofBytes,
    /// user-defined variables to be put into context
    pub extension: ContextExtension,
}

#[cfg(feature = "arbitrary")]
/// Arbitrary impl
mod arbitrary {
    use super::*;
    use proptest::{collection::vec, prelude::*};

    impl Arbitrary for ProofBytes {
        type Parameters = ();
        type Strategy = BoxedStrategy<Self>;

        fn arbitrary_with(_args: Self::Parameters) -> Self::Strategy {
            prop_oneof![
                Just(ProofBytes::Empty),
                (vec(any::<u8>(), 32..100))
                    .prop_map(ProofBytes::Some)
                    .boxed()
            ]
            .boxed()
        }
    }
}