diff --git a/src/backend.rs b/src/backend.rs deleted file mode 100644 index bf42b28..0000000 --- a/src/backend.rs +++ /dev/null @@ -1,229 +0,0 @@ -// TODO: Move the MainPod logic to mock_main and implement the MainPod trait -/* -use anyhow::Result; -use itertools::Itertools; -use plonky2::field::types::{Field, PrimeField64}; -use std::collections::HashMap; -use std::io::{self, Write}; -use std::iter; - -use crate::merkletree::MerkleTree; -use crate::middleware::{Hash, Params, PodId, Value, NULL}; - -#[derive(Clone, Debug)] -pub struct MainPod { - pub params: Params, - pub id: PodId, - pub input_signed_pods: Vec, - pub statements: Vec, -} - -fn fill_pad(v: &mut Vec, pad_value: T, len: usize) { - if v.len() > len { - panic!("length exceeded"); - } - while v.len() < len { - v.push(pad_value.clone()); - } -} - -impl MainPod { - pub fn new( - params: Params, - mut input_signed_pods: Vec, - input_main_pods: Vec, - mut statements: Vec, - ) -> Result { - Self::pad_statements(¶ms, &mut statements, params.max_statements); - Self::pad_input_signed_pods(¶ms, &mut input_signed_pods)?; - Ok(Self { - params, - id: PodId::default(), // TODO - input_signed_pods, - statements, - }) - } - - fn statement_none(params: &Params) -> Statement { - let mut args = Vec::with_capacity(params.max_statement_args); - Self::pad_statement_args(¶ms, &mut args); - Statement(NativeStatement::None, args) - } - - fn pad_statements(params: &Params, statements: &mut Vec, len: usize) { - for st in statements.iter_mut() { - fill_pad(&mut st.1, StatementArg::None, params.max_statement_args) - } - fill_pad(statements, Self::statement_none(params), len) - } - - fn pad_statement_args(params: &Params, args: &mut Vec) { - fill_pad(args, StatementArg::None, params.max_statement_args) - } - - fn pad_input_signed_pods(params: &Params, pods: &mut Vec) -> Result<()> { - let pod_none = SignedPod::new(params, HashMap::new())?; - Ok(fill_pad(pods, pod_none, params.max_input_signed_pods)) - } - - pub fn input_signed_pods_statements(&self) -> Vec> { - let mut pods_statements = Vec::new(); - let st_none = Self::statement_none(&self.params); - for pod in &self.input_signed_pods { - let mut pod_statements: Vec = Vec::new(); - for kv in &pod.kvs { - let args = vec![ - StatementArg::Ref(AnchoredKey(pod.id, *kv.0)), - StatementArg::Literal(*kv.1), - ]; - pod_statements.push(Statement(NativeStatement::ValueOf, args)); - } - Self::pad_statements( - &self.params, - &mut pod_statements, - self.params.max_signed_pod_values, - ); - pods_statements.push(pod_statements); - } - let statements_none: Vec = iter::repeat(st_none.clone()) - .take(self.params.max_signed_pod_values) - .collect(); - fill_pad( - &mut pods_statements, - statements_none, - self.params.max_input_signed_pods, - ); - pods_statements - } - - pub fn prv_statements(&self) -> Vec { - self.statements - .iter() - .take(self.params.max_priv_statements()) - .cloned() - .collect() - } - - pub fn pub_statements(&self) -> Vec { - self.statements - .iter() - .skip(self.params.max_priv_statements()) - .cloned() - .collect() - } -} - -pub struct Printer { - pub skip_none: bool, -} - -impl Printer { - pub fn fmt_arg(&self, w: &mut dyn Write, arg: &StatementArg) -> io::Result<()> { - match arg { - StatementArg::None => write!(w, "none"), - StatementArg::Literal(v) => write!(w, "{}", v), - StatementArg::Ref(r) => write!(w, "{}.{}", r.0, r.1), - } - } - - pub fn fmt_signed_pod(&self, w: &mut dyn Write, pod: &SignedPod) -> io::Result<()> { - writeln!(w, "SignedPod ({}):", pod.id)?; - // Note: current version iterates sorting by keys of the kvs, but the merkletree defined at - // https://0xparc.github.io/pod2/merkletree.html will not need it since it will be - // deterministic based on the keys values not on the order of the keys when added into the - // tree. - for (k, v) in pod.kvs.iter().sorted_by_key(|kv| kv.0) { - writeln!(w, " - {}: {}", k, v)?; - } - Ok(()) - } - - pub fn fmt_statement(&self, w: &mut dyn Write, st: &Statement) -> io::Result<()> { - write!(w, "{:?} ", st.0)?; - for (i, arg) in st.1.iter().enumerate() { - if !(self.skip_none && arg.is_none()) { - if i != 0 { - write!(w, " ")?; - } - self.fmt_arg(w, arg)?; - } - } - Ok(()) - } - - pub fn fmt_statement_index( - &self, - w: &mut dyn Write, - st: &Statement, - index: usize, - ) -> io::Result<()> { - if !(self.skip_none && st.is_none()) { - write!(w, " {:03}. ", index)?; - self.fmt_statement(w, &st)?; - write!(w, "\n")?; - } - Ok(()) - } - - pub fn fmt_main_pod(&self, w: &mut dyn Write, pod: &MainPod) -> io::Result<()> { - writeln!(w, "MainPod ({}):", pod.id)?; - // TODO - // writeln!(w, " input_main_pods:")?; - // for in_pod in &pod.input_main_pods { - // writeln!(w, " - {}", in_pod.id)?; - // } - let mut st_index = 0; - for (i, (pod, statements)) in pod - .input_signed_pods - .iter() - .zip(pod.input_signed_pods_statements()) - .enumerate() - { - if !(self.skip_none && pod.is_null()) { - writeln!(w, " in sig_pod {:02} (id:{}) statements:", i, pod.id)?; - for st in statements { - self.fmt_statement_index(w, &st, st_index)?; - st_index += 1; - } - } else { - st_index += pod.params.max_signed_pod_values; - } - } - writeln!(w, " prv statements:")?; - for st in pod.prv_statements() { - self.fmt_statement_index(w, &st, st_index)?; - st_index += 1; - } - writeln!(w, " pub statements:")?; - for st in pod.pub_statements() { - self.fmt_statement_index(w, &st, st_index)?; - st_index += 1; - } - Ok(()) - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::frontend; - - #[test] - fn test_back_0() -> Result<()> { - let params = Params::default(); - let (front_gov_id, front_pay_stub, front_kyc) = frontend::tests::data_zu_kyc(params)?; - let gov_id = front_gov_id.pod; // get backend's pod - let pay_stub = front_pay_stub.pod; // get backend's pod - let kyc = front_kyc.compile()?; - // println!("{:#?}", kyc); - - let printer = Printer { skip_none: true }; - let mut w = io::stdout(); - printer.fmt_signed_pod(&mut w, &gov_id)?; - printer.fmt_signed_pod(&mut w, &pay_stub)?; - printer.fmt_main_pod(&mut w, &kyc)?; - - Ok(()) - } -} -*/ diff --git a/src/backends/mock_main.rs b/src/backends/mock_main.rs index e69de29..9d4d0d4 100644 --- a/src/backends/mock_main.rs +++ b/src/backends/mock_main.rs @@ -0,0 +1,436 @@ +use crate::middleware::{ + self, MainPod, MainPodInputs, NativeOperation, NativeStatement, NoneMainPod, NoneSignedPod, + Params, PodId, PodProver, SignedPod, Statement, StatementArg, +}; +use anyhow::Result; +use itertools::Itertools; +use std::any::Any; +use std::io::{self, Write}; + +pub struct MockProver {} + +impl PodProver for MockProver { + fn prove(&mut self, params: &Params, inputs: MainPodInputs) -> Result> { + Ok(Box::new(MockMainPod::new(params, inputs)?)) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +enum OperationArg { + None, + Index(usize), +} + +impl OperationArg { + fn is_none(&self) -> bool { + matches!(self, OperationArg::None) + } +} + +#[derive(Clone, Debug, PartialEq, Eq)] +struct Operation(pub NativeOperation, pub Vec); + +#[derive(Clone, Debug)] +pub struct MockMainPod { + params: Params, + id: PodId, + input_signed_pods: Vec>, + input_main_pods: Vec>, + // New statements introduced by this pod + input_statements: Vec, + public_statements: Vec, + operations: Vec, + // All statements (inherited + new) + statements: Vec, +} + +fn fill_pad(v: &mut Vec, pad_value: T, len: usize) { + if v.len() > len { + panic!("length exceeded"); + } + while v.len() < len { + v.push(pad_value.clone()); + } +} + +impl MockMainPod { + fn offset_input_signed_pods(&self) -> usize { + 0 + } + fn offset_input_main_pods(&self) -> usize { + self.params.max_input_signed_pods * self.params.max_signed_pod_values + } + fn offset_input_statements(&self) -> usize { + self.offset_input_main_pods() + + self.params.max_input_main_pods * self.params.max_public_statements + } + fn offset_public_statements(&self) -> usize { + self.offset_input_statements() + self.params.max_priv_statements() + } + + fn layout_statements(params: &Params, inputs: &MainPodInputs) -> Vec { + let mut statements = Vec::new(); + + let st_none = Self::statement_none(params); + + // Input signed pods region + let none_sig_pod: Box = Box::new(NoneSignedPod {}); + assert!(inputs.signed_pods.len() <= params.max_input_signed_pods); + for i in 0..params.max_input_signed_pods { + let pod = inputs + .signed_pods + .get(i) + .map(|p| *p) + .unwrap_or(&none_sig_pod); + let sts = pod.pub_statements(); + assert!(sts.len() <= params.max_signed_pod_values); + for j in 0..params.max_signed_pod_values { + let mut st = sts.get(j).unwrap_or(&st_none).clone(); + Self::pad_statement_args(params, &mut st.1); + statements.push(st); + } + } + + // Input main pods region + let none_main_pod: Box = Box::new(NoneMainPod {}); + assert!(inputs.main_pods.len() <= params.max_input_main_pods); + for i in 0..params.max_input_main_pods { + let pod = inputs + .main_pods + .get(i) + .map(|p| *p) + .unwrap_or(&none_main_pod); + let sts = pod.pub_statements(); + assert!(sts.len() <= params.max_public_statements); + for j in 0..params.max_public_statements { + let mut st = sts.get(j).unwrap_or(&st_none).clone(); + Self::pad_statement_args(params, &mut st.1); + statements.push(st); + } + } + + // Input statements + assert!(inputs.statements.len() <= params.max_priv_statements()); + for i in 0..params.max_priv_statements() { + let mut st = inputs.statements.get(i).unwrap_or(&st_none).clone(); + Self::pad_statement_args(params, &mut st.1); + statements.push(st); + } + + // Public statements + assert!(inputs.public_statements.len() <= params.max_public_statements); + for i in 0..params.max_public_statements { + let mut st = inputs.public_statements.get(i).unwrap_or(&st_none).clone(); + Self::pad_statement_args(params, &mut st.1); + statements.push(st); + } + + statements + } + + fn find_op_arg(statements: &[Statement], op_arg: &middleware::OperationArg) -> OperationArg { + match op_arg { + middleware::OperationArg::None => OperationArg::None, + middleware::OperationArg::Key(k) => OperationArg::Index( + // TODO: Error handling when the key is not found in any ValueOf statement + statements + .iter() + .enumerate() + .find_map(|(i, s)| match s.0 { + NativeStatement::ValueOf => match &s.1[0] { + StatementArg::Key(sk) => (sk == k).then_some(i), + _ => None, + }, + _ => None, + }) + .unwrap(), + ), + middleware::OperationArg::Statement(st) => OperationArg::Index( + // TODO: Error handling when the statement is not found + statements + .iter() + .enumerate() + .find_map(|(i, s)| (s == st).then_some(i)) + .unwrap(), + ), + } + } + + fn process_priavte_statements_operations( + params: &Params, + statements: &[Statement], + input_operations: &[middleware::Operation], + ) -> Vec { + let op_none = Self::operation_none(params); + + let mut operations = Vec::new(); + for i in 0..params.max_priv_statements() { + let op = input_operations.get(i).unwrap_or(&op_none).clone(); + let mut mid_args = op.1; + Self::pad_operation_args(params, &mut mid_args); + let mut args = Vec::with_capacity(mid_args.len()); + for mid_arg in &mid_args { + args.push(Self::find_op_arg(statements, mid_arg)); + } + operations.push(Operation(op.0, args)); + } + operations + } + + // NOTE: In this implementation public statements are always copies from previous statements, + // so we fill in the operations accordingly. + fn process_public_statements_operations( + params: &Params, + statements: &[Statement], + mut operations: Vec, + ) -> Vec { + let op_none = Self::operation_none(params); + + let offset_public_statements = statements.len() - params.max_public_statements; + for i in 0..params.max_public_statements { + let st = &statements[offset_public_statements + i]; + let mut op = if st.is_none() { + Operation(NativeOperation::None, vec![]) + } else { + let mid_arg = middleware::OperationArg::Statement(st.clone()); + Operation( + NativeOperation::CopyStatement, + vec![Self::find_op_arg(statements, &mid_arg)], + ) + }; + fill_pad(&mut op.1, OperationArg::None, params.max_operation_args); + operations.push(op); + } + operations + } + + pub fn new(params: &Params, inputs: MainPodInputs) -> Result { + // TODO: Figure out a way to handle public statements. For example, in the public slots + // use copy operations taking the private statements that need to be public. We may change + // the MainPodInputs type to accomodate for that. + // TODO: Insert a new public statement of ValueOf with `key=KEY_TYPE, + // value=PodType::MockMainPod` + let statements = Self::layout_statements(params, &inputs); + let operations = + Self::process_priavte_statements_operations(params, &statements, inputs.operations); + let operations = + Self::process_public_statements_operations(params, &statements, operations); + + let input_signed_pods = inputs + .signed_pods + .iter() + .map(|p| (*p).clone()) + .collect_vec(); + let input_main_pods = inputs.main_pods.iter().map(|p| (*p).clone()).collect_vec(); + let input_statements = inputs.statements.iter().cloned().collect_vec(); + let public_statements = inputs.public_statements.iter().cloned().collect_vec(); + + // TODO: Calculate the PodId from a subset of the `statements` vector. For example it + // could be the public subset (which is the last `params.max_public_statements` of the + // vector`). + Ok(Self { + params: params.clone(), + id: PodId::default(), // TODO + input_signed_pods, + input_main_pods, + input_statements, + public_statements, + statements, + operations, + }) + } + + fn statement_none(params: &Params) -> Statement { + let mut args = Vec::with_capacity(params.max_statement_args); + Self::pad_statement_args(¶ms, &mut args); + Statement(NativeStatement::None, args) + } + + fn operation_none(params: &Params) -> middleware::Operation { + let mut args = Vec::with_capacity(params.max_operation_args); + Self::pad_operation_args(¶ms, &mut args); + middleware::Operation(NativeOperation::None, args) + } + + fn pad_statement_args(params: &Params, args: &mut Vec) { + fill_pad(args, StatementArg::None, params.max_statement_args) + } + + fn pad_operation_args(params: &Params, args: &mut Vec) { + fill_pad( + args, + middleware::OperationArg::None, + params.max_operation_args, + ) + } +} + +impl MainPod for MockMainPod { + fn verify(&self) -> bool { + // TODO + // - define input_statements as `statements.[self.offset_input_statements()..]` + // - Calculate the id from a subset of the statements. Check it's equal to self.id + // - Find a ValueOf statement from the public statements with key=KEY_TYPE and check that + // the value is PodType::MockMainPod + // - Check that all `input_statements` of type `ValueOf` with origin=SELF have unique keys + // (no duplicates) + // - Verify that all `input_statements` are correctly generated + // by `self.operations` (where each operation can only access previous statements) + todo!() + } + fn id(&self) -> PodId { + self.id + } + fn pub_statements(&self) -> Vec { + // TODO: All arguments that use origin=SELF need to be replaced by origin=self.id() + self.statements + .iter() + .skip(self.offset_public_statements()) + .cloned() + .collect() + } + + fn into_any(self: Box) -> Box { + self + } +} + +/// Useful for debugging +pub struct Printer { + pub skip_none: bool, +} + +impl Printer { + fn fmt_arg(&self, w: &mut dyn Write, arg: &StatementArg) -> io::Result<()> { + match arg { + StatementArg::None => write!(w, "none"), + StatementArg::Literal(v) => write!(w, "{}", v), + StatementArg::Key(r) => write!(w, "{}.{}", r.0, r.1), + } + } + + fn fmt_statement(&self, w: &mut dyn Write, st: &Statement) -> io::Result<()> { + write!(w, "{:?} ", st.0)?; + for (i, arg) in st.1.iter().enumerate() { + if !(self.skip_none && arg.is_none()) { + if i != 0 { + write!(w, " ")?; + } + self.fmt_arg(w, arg)?; + } + } + Ok(()) + } + + fn fmt_operation(&self, w: &mut dyn Write, op: &Operation) -> io::Result<()> { + write!(w, "{:?} ", op.0)?; + for (i, arg) in op.1.iter().enumerate() { + if !(self.skip_none && arg.is_none()) { + if i != 0 { + write!(w, " ")?; + } + match arg { + OperationArg::None => write!(w, "none")?, + OperationArg::Index(i) => write!(w, "{:02}", i)?, + } + } + } + Ok(()) + } + + fn fmt_statement_index( + &self, + w: &mut dyn Write, + st: &Statement, + op: Option<&Operation>, + index: usize, + ) -> io::Result<()> { + if !(self.skip_none && st.is_none()) { + write!(w, " {:03}. ", index)?; + self.fmt_statement(w, &st)?; + if let Some(op) = op { + write!(w, " <- ")?; + self.fmt_operation(w, op)?; + } + write!(w, "\n")?; + } + Ok(()) + } + + pub fn fmt_mock_main_pod(&self, w: &mut dyn Write, pod: &MockMainPod) -> io::Result<()> { + writeln!(w, "MockMainPod ({}):", pod.id)?; + // TODO print input signed pods id and type + // TODO print input main pods id and type + let offset_input_main_pods = pod.offset_input_main_pods(); + let offset_input_statements = pod.offset_input_statements(); + let offset_public_statements = pod.offset_public_statements(); + for (i, st) in pod.statements.iter().enumerate() { + if (i < pod.offset_input_main_pods()) && (i % pod.params.max_signed_pod_values == 0) { + writeln!( + w, + " from input SignedPod {}:", + i / pod.params.max_signed_pod_values + )?; + } + if (i >= offset_input_main_pods) + && (i < offset_input_statements) + && (i % pod.params.max_public_statements == 0) + { + writeln!( + w, + " from input MainPod {}:", + (i - offset_input_main_pods) / pod.params.max_signed_pod_values + )?; + } + if i == offset_input_statements { + writeln!(w, " private statements:")?; + } + if i == offset_public_statements { + writeln!(w, " public statements:")?; + } + + let op = (i >= offset_input_statements) + .then(|| &pod.operations[i - offset_input_statements]); + if !(self.skip_none && st.is_none()) { + self.fmt_statement_index(w, &st, op, i)?; + } + } + Ok(()) + } +} + +#[cfg(test)] +pub mod tests { + use super::*; + use crate::backends::mock_signed::MockSigner; + use crate::frontend; + use crate::middleware; + + #[test] + fn test_mock_main_0() { + let params = middleware::Params::default(); + + let (gov_id, pay_stub) = frontend::tests::zu_kyc_sign_pod_builders(¶ms); + let mut signer = MockSigner { + pk: "ZooGov".into(), + }; + let gov_id = gov_id.sign(&mut signer).unwrap(); + let mut signer = MockSigner { + pk: "ZooDeel".into(), + }; + let pay_stub = pay_stub.sign(&mut signer).unwrap(); + let kyc = frontend::tests::zu_kyc_pod_builder(¶ms, &gov_id, &pay_stub); + + let mut prover = MockProver {}; + let kyc = kyc.prove(&mut prover).unwrap(); + let pod = kyc.pod.into_any().downcast::().unwrap(); + + let printer = Printer { skip_none: false }; + let mut w = io::stdout(); + printer.fmt_mock_main_pod(&mut w, &pod).unwrap(); + + // assert_eq!(pod.verify(), true); // TODO + // println!("id: {}", pod.id()); + // println!("kvs: {:?}", pod.pub_statements()); + } +} diff --git a/src/backends/mock_signed.rs b/src/backends/mock_signed.rs index 4cfeb82..4080025 100644 --- a/src/backends/mock_signed.rs +++ b/src/backends/mock_signed.rs @@ -26,9 +26,9 @@ impl PodSigner for MockSigner { #[derive(Clone, Debug)] pub struct MockSignedPod { - pub id: PodId, - pub signature: String, - pub mt: MerkleTree, + id: PodId, + signature: String, + mt: MerkleTree, } impl SignedPod for MockSignedPod { diff --git a/src/frontend.rs b/src/frontend.rs index 96b3f8a..8b41802 100644 --- a/src/frontend.rs +++ b/src/frontend.rs @@ -222,6 +222,7 @@ pub struct MainPodBuilder { pub input_main_pods: Vec, pub statements: Vec, pub operations: Vec, + pub public_statements: Vec, // Internal state const_cnt: usize, } @@ -234,6 +235,7 @@ impl MainPodBuilder { input_main_pods: Vec::new(), statements: Vec::new(), operations: Vec::new(), + public_statements: Vec::new(), const_cnt: 0, } } @@ -250,7 +252,7 @@ impl MainPodBuilder { } /// Convert [OperationArg]s to [StatementArg]s for the operations that work with entries - fn op_args_entries(&mut self, args: &mut [OperationArg]) -> Vec { + fn op_args_entries(&mut self, public: bool, args: &mut [OperationArg]) -> Vec { let mut st_args = Vec::new(); for arg in args.iter_mut() { match arg { @@ -259,10 +261,13 @@ impl MainPodBuilder { OperationArg::Literal(v) => { let k = format!("c{}", self.const_cnt); self.const_cnt += 1; - let value_of_st = self.op(Operation( - NativeOperation::NewEntry, - vec![OperationArg::Entry(k.clone(), v.clone())], - )); + let value_of_st = self.op( + public, + Operation( + NativeOperation::NewEntry, + vec![OperationArg::Entry(k.clone(), v.clone())], + ), + ); *arg = OperationArg::Key(AnchoredKey(Origin(PodClass::Main, SELF), k.clone())); st_args.push(value_of_st.1[0].clone()) } @@ -278,33 +283,53 @@ impl MainPodBuilder { st_args } - pub fn op(&mut self, mut op: Operation) -> &Statement { + pub fn pub_op(&mut self, op: Operation) -> Statement { + self.op(true, op) + } + + pub fn op(&mut self, public: bool, mut op: Operation) -> Statement { use NativeOperation::*; let Operation(op_type, ref mut args) = op; // TODO: argument type checking let st = match op_type { None => Statement(NativeStatement::None, vec![]), - NewEntry => Statement(NativeStatement::ValueOf, self.op_args_entries(args)), + NewEntry => Statement(NativeStatement::ValueOf, self.op_args_entries(public, args)), CopyStatement => todo!(), - EqualFromEntries => Statement(NativeStatement::Equal, self.op_args_entries(args)), - NotEqualFromEntries => Statement(NativeStatement::NotEqual, self.op_args_entries(args)), - GtFromEntries => Statement(NativeStatement::Gt, self.op_args_entries(args)), - LtFromEntries => Statement(NativeStatement::Lt, self.op_args_entries(args)), + EqualFromEntries => { + Statement(NativeStatement::Equal, self.op_args_entries(public, args)) + } + NotEqualFromEntries => Statement( + NativeStatement::NotEqual, + self.op_args_entries(public, args), + ), + GtFromEntries => Statement(NativeStatement::Gt, self.op_args_entries(public, args)), + LtFromEntries => Statement(NativeStatement::Lt, self.op_args_entries(public, args)), TransitiveEqualFromStatements => todo!(), GtToNotEqual => todo!(), LtToNotEqual => todo!(), - ContainsFromEntries => Statement(NativeStatement::Contains, self.op_args_entries(args)), - NotContainsFromEntries => { - Statement(NativeStatement::NotContains, self.op_args_entries(args)) - } + ContainsFromEntries => Statement( + NativeStatement::Contains, + self.op_args_entries(public, args), + ), + NotContainsFromEntries => Statement( + NativeStatement::NotContains, + self.op_args_entries(public, args), + ), RenameContainedBy => todo!(), SumOf => todo!(), ProductOf => todo!(), MaxOf => todo!(), }; self.operations.push(op); + if public { + self.public_statements.push(st.clone()); + } self.statements.push(st); - &self.statements[self.statements.len() - 1] + self.statements[self.statements.len() - 1].clone() + } + + pub fn reveal(&mut self, st: &Statement) { + self.public_statements.push(st.clone()); } pub fn prove(&self, prover: &mut P) -> Result { @@ -314,22 +339,17 @@ impl MainPodBuilder { // main_pods: &self.input_main_pods, statements: &self.statements, operations: &self.operations, + public_statements: &self.public_statements, }; - let (statements, operations) = compiler.compile(inputs)?; + let (statements, operations, public_statements) = compiler.compile(inputs)?; + // TODO: Add API to specify public/private statement let inputs = MainPodInputs { - signed_pods: &self - .input_signed_pods - .iter() - .map(|p| p.pod.as_ref()) - .collect_vec(), - main_pods: &self - .input_main_pods - .iter() - .map(|p| p.pod.as_ref()) - .collect_vec(), + signed_pods: &self.input_signed_pods.iter().map(|p| &p.pod).collect_vec(), + main_pods: &self.input_main_pods.iter().map(|p| &p.pod).collect_vec(), statements: &statements, operations: &operations, + public_statements: &public_statements, }; let pod = prover.prove(&self.params, inputs)?; Ok(MainPod { pod }) @@ -356,6 +376,7 @@ struct MainPodCompilerInputs<'a> { // pub main_pods: &'a [Box], pub statements: &'a [Statement], pub operations: &'a [Operation], + pub public_statements: &'a [Statement], } struct MainPodCompiler { @@ -438,12 +459,17 @@ impl MainPodCompiler { pub fn compile<'a>( mut self, inputs: MainPodCompilerInputs<'a>, - ) -> Result<(Vec, Vec)> { + ) -> Result<( + Vec, // input statements + Vec, + Vec, // public statements + )> { let MainPodCompilerInputs { // signed_pods: _, // main_pods: _, statements, operations, + public_statements, } = inputs; for (st, op) in statements.iter().zip_eq(operations.iter()) { self.compile_st_op(st, op); @@ -451,7 +477,11 @@ impl MainPodCompiler { panic!("too many statements"); } } - Ok((self.statements, self.operations)) + let public_statements = public_statements + .iter() + .map(|st| self.compile_st(st)) + .collect_vec(); + Ok((self.statements, self.operations, public_statements)) } } @@ -558,14 +588,14 @@ pub mod tests { let mut kyc = MainPodBuilder::new(¶ms); kyc.add_signed_pod(&gov_id); kyc.add_signed_pod(&pay_stub); - kyc.op(op!(not_contains, &sanction_list, (gov_id, "idNumber"))); - kyc.op(op!(lt, (gov_id, "dateOfBirth"), now_minus_18y)); - kyc.op(op!( + kyc.pub_op(op!(not_contains, &sanction_list, (gov_id, "idNumber"))); + kyc.pub_op(op!(lt, (gov_id, "dateOfBirth"), now_minus_18y)); + kyc.pub_op(op!( eq, (gov_id, "socialSecurityNumber"), (pay_stub, "socialSecurityNumber") )); - kyc.op(op!(eq, (pay_stub, "startDate"), now_minus_1y)); + kyc.pub_op(op!(eq, (pay_stub, "startDate"), now_minus_1y)); kyc } diff --git a/src/lib.rs b/src/lib.rs index 46f0741..a092ae4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,4 +1,3 @@ -pub mod backend; pub mod backends; pub mod frontend; pub mod merkletree; diff --git a/src/middleware.rs b/src/middleware.rs index 8ab468b..e38a91d 100644 --- a/src/middleware.rs +++ b/src/middleware.rs @@ -171,6 +171,7 @@ pub struct Params { pub max_signed_pod_values: usize, pub max_public_statements: usize, pub max_statement_args: usize, + pub max_operation_args: usize, } impl Params { @@ -188,6 +189,7 @@ impl Default for Params { max_signed_pod_values: 8, max_public_statements: 10, max_statement_args: 5, + max_operation_args: 5, } } } @@ -220,6 +222,29 @@ pub trait SignedPod: fmt::Debug + DynClone { // impl Clone for Box dyn_clone::clone_trait_object!(SignedPod); +/// This is a filler type that fulfills the SignedPod trait and always verifies. It's empty. This +/// can be used to simulate padding in a circuit. +#[derive(Debug, Clone)] +pub struct NoneSignedPod {} + +impl SignedPod for NoneSignedPod { + fn verify(&self) -> bool { + true + } + fn id(&self) -> PodId { + PodId(NULL) + } + fn kvs(&self) -> HashMap { + HashMap::new() + } + fn pub_statements(&self) -> Vec { + Vec::new() + } + fn into_any(self: Box) -> Box { + self + } +} + pub trait PodSigner { fn sign(&mut self, params: &Params, kvs: &HashMap) -> Result>; } @@ -305,12 +330,38 @@ pub trait MainPod: fmt::Debug + DynClone { // impl Clone for Box dyn_clone::clone_trait_object!(MainPod); +/// This is a filler type that fulfills the MainPod trait and always verifies. It's empty. This +/// can be used to simulate padding in a circuit. +#[derive(Debug, Clone)] +pub struct NoneMainPod {} + +impl MainPod for NoneMainPod { + fn verify(&self) -> bool { + true + } + fn id(&self) -> PodId { + PodId(NULL) + } + fn pub_statements(&self) -> Vec { + Vec::new() + } + fn into_any(self: Box) -> Box { + self + } +} + +// TODO: Figure out a way to signal which signed_pods entries and which main_pods statements need +// to be made public. Idea: introduce an operation called reveal, which the backend translates to +// CopyOf but moves copies that statement to a public slot? #[derive(Debug)] pub struct MainPodInputs<'a> { - pub signed_pods: &'a [&'a dyn SignedPod], - pub main_pods: &'a [&'a dyn MainPod], + pub signed_pods: &'a [&'a Box], + pub main_pods: &'a [&'a Box], 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 {