mod origin;
pub use origin::*;
mod bytes;
mod serialize;
mod string;
use console::{
network::prelude::*,
program::{Ciphertext, Plaintext},
types::Field,
};
type Variant = u16;
#[derive(Clone, PartialEq, Eq)]
pub enum Input<N: Network> {
Constant(Field<N>, Option<Plaintext<N>>),
Public(Field<N>, Option<Plaintext<N>>),
Private(Field<N>, Option<Ciphertext<N>>),
Record(Field<N>, Field<N>, Origin<N>),
ExternalRecord(Field<N>),
}
impl<N: Network> Input<N> {
pub const fn variant(&self) -> Variant {
match self {
Input::Constant(..) => 0,
Input::Public(..) => 1,
Input::Private(..) => 2,
Input::Record(..) => 3,
Input::ExternalRecord(..) => 4,
}
}
pub const fn id(&self) -> &Field<N> {
match self {
Input::Constant(id, ..) => id,
Input::Public(id, ..) => id,
Input::Private(id, ..) => id,
Input::Record(serial_number, ..) => serial_number,
Input::ExternalRecord(id) => id,
}
}
pub const fn origin(&self) -> Option<&Origin<N>> {
match self {
Input::Record(_, _, origin) => Some(origin),
_ => None,
}
}
pub fn into_origin(self) -> Option<Origin<N>> {
match self {
Input::Record(_, _, origin) => Some(origin),
_ => None,
}
}
pub const fn tag(&self) -> Option<&Field<N>> {
match self {
Input::Record(_, tag, _) => Some(tag),
_ => None,
}
}
pub fn into_tag(self) -> Option<Field<N>> {
match self {
Input::Record(_, tag, _) => Some(tag),
_ => None,
}
}
pub const fn serial_number(&self) -> Option<&Field<N>> {
match self {
Input::Record(serial_number, ..) => Some(serial_number),
_ => None,
}
}
pub fn into_serial_number(self) -> Option<Field<N>> {
match self {
Input::Record(serial_number, ..) => Some(serial_number),
_ => None,
}
}
pub fn verifier_inputs(&self) -> impl '_ + Iterator<Item = N::Field> {
[Some(self.id()), self.tag()].into_iter().flatten().map(|id| **id)
}
pub fn verify(&self, tcm: &Field<N>, index: usize) -> bool {
let result = || match self {
Input::Constant(hash, Some(input)) => {
match input.to_fields() {
Ok(fields) => {
let index = Field::from_u16(index as u16);
let mut preimage = fields;
preimage.push(*tcm);
preimage.push(index);
match N::hash_psd8(&preimage) {
Ok(candidate_hash) => Ok(hash == &candidate_hash),
Err(error) => Err(error),
}
}
Err(error) => Err(error),
}
}
Input::Public(hash, Some(input)) => {
match input.to_fields() {
Ok(fields) => {
let index = Field::from_u16(index as u16);
let mut preimage = fields;
preimage.push(*tcm);
preimage.push(index);
match N::hash_psd8(&preimage) {
Ok(candidate_hash) => Ok(hash == &candidate_hash),
Err(error) => Err(error),
}
}
Err(error) => Err(error),
}
}
Input::Private(hash, Some(value)) => {
match value.to_fields() {
Ok(fields) => match N::hash_psd8(&fields) {
Ok(candidate_hash) => Ok(hash == &candidate_hash),
Err(error) => Err(error),
},
Err(error) => Err(error),
}
}
_ => Ok(true),
};
match result() {
Ok(is_hash_valid) => is_hash_valid,
Err(error) => {
eprintln!("{error}");
false
}
}
}
}
#[cfg(test)]
pub(crate) mod test_helpers {
use super::*;
use console::{network::Testnet3, program::Literal};
type CurrentNetwork = Testnet3;
pub(crate) fn sample_inputs() -> Vec<(<CurrentNetwork as Network>::TransitionID, Input<CurrentNetwork>)> {
let transaction = crate::ledger::vm::test_helpers::sample_execution_transaction();
let transition = transaction.transitions().next().unwrap();
let transition_id = *transition.id();
let input = transition.inputs().iter().next().unwrap().clone();
let rng = &mut test_crypto_rng();
let plaintext = Plaintext::Literal(Literal::Field(Uniform::rand(rng)), Default::default());
let plaintext_hash = CurrentNetwork::hash_bhp1024(&plaintext.to_bits_le()).unwrap();
let ciphertext = Ciphertext::from_fields(&vec![Uniform::rand(rng); 10]).unwrap();
let ciphertext_hash = CurrentNetwork::hash_bhp1024(&ciphertext.to_bits_le()).unwrap();
let origin_commitment = Origin::Commitment(Uniform::rand(rng));
let origin_state_root = Origin::StateRoot(Uniform::rand(rng));
vec![
(transition_id, input),
(Uniform::rand(rng), Input::Constant(Uniform::rand(rng), None)),
(Uniform::rand(rng), Input::Constant(plaintext_hash, Some(plaintext.clone()))),
(Uniform::rand(rng), Input::Public(Uniform::rand(rng), None)),
(Uniform::rand(rng), Input::Public(plaintext_hash, Some(plaintext))),
(Uniform::rand(rng), Input::Private(Uniform::rand(rng), None)),
(Uniform::rand(rng), Input::Private(ciphertext_hash, Some(ciphertext))),
(Uniform::rand(rng), Input::Record(Uniform::rand(rng), Uniform::rand(rng), origin_commitment)),
(Uniform::rand(rng), Input::Record(Uniform::rand(rng), Uniform::rand(rng), origin_state_root)),
(Uniform::rand(rng), Input::ExternalRecord(Uniform::rand(rng))),
]
}
}