//! The middleware includes the type definitions and the traits used to connect the frontend and //! the backend. mod basetypes; pub mod containers; mod custom; mod operation; pub mod serialization; mod statement; use std::{any::Any, collections::HashMap, fmt}; use anyhow::Result; pub use basetypes::*; pub use custom::*; use dyn_clone::DynClone; pub use operation::*; use schemars::JsonSchema; use serde::{Deserialize, Serialize}; pub use statement::*; pub const SELF: PodId = PodId(SELF_ID_HASH); impl fmt::Display for PodId { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { if *self == SELF { write!(f, "self") } else if self.0 == EMPTY_HASH { write!(f, "null") } else { write!(f, "{}", self.0) } } } /// AnchoredKey is a tuple containing (OriginId: PodId, key: Hash) #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)] pub struct AnchoredKey(pub PodId, pub Hash); impl AnchoredKey { pub fn origin(&self) -> PodId { self.0 } pub fn key(&self) -> Hash { self.1 } } impl fmt::Display for AnchoredKey { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}.{}", self.0, self.1)?; Ok(()) } } /// An entry consists of a key-value pair. pub type Entry = (String, Value); #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize, JsonSchema)] pub struct PodId(pub Hash); impl ToFields for PodId { fn to_fields(&self, params: &Params) -> Vec { self.0.to_fields(params) } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum PodType { None = 0, MockSigned = 1, MockMain = 2, Signed = 3, Main = 4, } impl fmt::Display for PodType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match self { PodType::None => write!(f, "None"), PodType::MockSigned => write!(f, "MockSigned"), PodType::MockMain => write!(f, "MockMain"), PodType::Signed => write!(f, "Signed"), PodType::Main => write!(f, "Main"), } } } impl From for Value { fn from(v: PodType) -> Self { Value::from(v as i64) } } #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] pub struct Params { pub max_input_signed_pods: usize, pub max_input_main_pods: usize, pub max_statements: usize, pub max_signed_pod_values: usize, pub max_public_statements: usize, pub max_statement_args: usize, pub max_operation_args: usize, // max number of statements that can be ANDed or ORed together // in a custom predicate pub max_custom_predicate_arity: usize, pub max_custom_batch_size: usize, // maximum number of merkle proofs pub max_merkle_proofs: usize, // maximum depth for merkle tree gadget pub max_depth_mt_gadget: usize, } impl Default for Params { fn default() -> Self { Self { max_input_signed_pods: 3, max_input_main_pods: 3, max_statements: 20, max_signed_pod_values: 8, max_public_statements: 10, max_statement_args: 5, max_operation_args: 5, max_custom_predicate_arity: 5, max_custom_batch_size: 5, max_merkle_proofs: 5, max_depth_mt_gadget: 32, } } } impl Params { pub fn max_priv_statements(&self) -> usize { self.max_statements - self.max_public_statements } pub const fn statement_tmpl_arg_size() -> usize { 2 * HASH_SIZE + 1 } pub const fn predicate_size() -> usize { HASH_SIZE + 2 } pub const fn operation_type_size() -> usize { HASH_SIZE + 2 } pub fn statement_size(&self) -> usize { Self::predicate_size() + STATEMENT_ARG_F_LEN * self.max_statement_args } pub fn operation_size(&self) -> usize { Self::operation_type_size() + OPERATION_ARG_F_LEN * self.max_operation_args } pub const fn statement_tmpl_size(&self) -> usize { Self::predicate_size() + self.max_statement_args * Self::statement_tmpl_arg_size() } pub fn custom_predicate_size(&self) -> usize { self.max_custom_predicate_arity * self.statement_tmpl_size() + 2 } pub fn custom_predicate_batch_size_field_elts(&self) -> usize { self.max_custom_batch_size * self.custom_predicate_size() } pub fn print_serialized_sizes(&self) { println!("Parameter sizes:"); println!( " Statement template argument: {}", Self::statement_tmpl_arg_size() ); println!(" Predicate: {}", Self::predicate_size()); println!(" Statement template: {}", self.statement_tmpl_size()); println!(" Custom predicate: {}", self.custom_predicate_size()); println!( " Custom predicate batch: {}", self.custom_predicate_batch_size_field_elts() ); println!(); } } pub trait Pod: fmt::Debug + DynClone { fn verify(&self) -> Result<()>; fn id(&self) -> PodId; fn pub_statements(&self) -> Vec; /// Extract key-values from ValueOf public statements fn kvs(&self) -> HashMap { self.pub_statements() .into_iter() .filter_map(|st| match st { Statement::ValueOf(ak, v) => Some((ak, v)), _ => None, }) .collect() } // Used for downcasting fn into_any(self: Box) -> Box; fn as_any(&self) -> &dyn Any; // Front-end Pods keep references to middleware Pods. Most of the // middleware data can be derived directly from front-end data, but the // "proof" data is only created at the point of proving/signing, and // cannot be reconstructed. As such, we need to serialize it whenever // we serialize a front-end Pod. Since the front-end does not understand // the implementation details of the middleware, this method allows the // middleware to provide some serialized data that can be used to // reconstruct the proof. fn serialized_proof(&self) -> String; } // impl Clone for Box dyn_clone::clone_trait_object!(Pod); pub trait PodSigner { fn sign(&mut self, params: &Params, kvs: &HashMap) -> Result>; } /// This is a filler type that fulfills the Pod trait and always verifies. It's empty. This /// can be used to simulate padding in a circuit. #[derive(Debug, Clone)] pub struct NonePod {} impl Pod for NonePod { fn verify(&self) -> Result<()> { Ok(()) } fn id(&self) -> PodId { PodId(EMPTY_HASH) } fn pub_statements(&self) -> Vec { Vec::new() } fn into_any(self: Box) -> Box { self } fn as_any(&self) -> &dyn Any { self } fn serialized_proof(&self) -> String { "".to_string() } } #[derive(Debug)] pub struct MainPodInputs<'a> { pub signed_pods: &'a [&'a dyn Pod], pub main_pods: &'a [&'a dyn Pod], pub statements: &'a [Statement], pub operations: &'a [Operation], /// Statements that need to be made public (they can come from input pods or input /// statements) pub public_statements: &'a [Statement], } pub trait PodProver { fn prove(&mut self, params: &Params, inputs: MainPodInputs) -> Result>; } pub trait ToFields { /// returns Vec representation of the type fn to_fields(&self, params: &Params) -> Vec; }