compute MainPod.id from pub_statements; and introduce the trait ToFields (#35)
* compute MainPod.id from pub_statements; and introduce the trait `ToFields` Compute MainPod.id from pub_statements hash; for it, introduce the trait `ToFields` at the middleware and implement it for the Statement related types. * cleaner statements tofield iter Co-authored-by: Ahmad Afuni <root@ahmadafuni.com> --------- Co-authored-by: Ahmad Afuni <root@ahmadafuni.com>
This commit is contained in:
parent
8945d7f8a1
commit
ca1be65b85
3 changed files with 99 additions and 19 deletions
|
|
@ -1,9 +1,11 @@
|
||||||
use crate::middleware::{
|
use crate::middleware::{
|
||||||
self, MainPod, MainPodInputs, NativeOperation, NativeStatement, NoneMainPod, NoneSignedPod,
|
self, Hash, MainPod, MainPodInputs, NativeOperation, NativeStatement, NoneMainPod,
|
||||||
Params, PodId, PodProver, SignedPod, Statement, StatementArg,
|
NoneSignedPod, Params, PodId, PodProver, SignedPod, Statement, StatementArg, ToFields,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use plonky2::hash::poseidon::PoseidonHash;
|
||||||
|
use plonky2::plonk::config::Hasher;
|
||||||
use std::any::Any;
|
use std::any::Any;
|
||||||
use std::io::{self, Write};
|
use std::io::{self, Write};
|
||||||
|
|
||||||
|
|
@ -156,7 +158,7 @@ impl MockMainPod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn process_priavte_statements_operations(
|
fn process_private_statements_operations(
|
||||||
params: &Params,
|
params: &Params,
|
||||||
statements: &[Statement],
|
statements: &[Statement],
|
||||||
input_operations: &[middleware::Operation],
|
input_operations: &[middleware::Operation],
|
||||||
|
|
@ -207,12 +209,12 @@ impl MockMainPod {
|
||||||
pub fn new(params: &Params, inputs: MainPodInputs) -> Result<Self> {
|
pub fn new(params: &Params, inputs: MainPodInputs) -> Result<Self> {
|
||||||
// TODO: Figure out a way to handle public statements. For example, in the public slots
|
// 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
|
// use copy operations taking the private statements that need to be public. We may change
|
||||||
// the MainPodInputs type to accomodate for that.
|
// the MainPodInputs type to accommodate for that.
|
||||||
// TODO: Insert a new public statement of ValueOf with `key=KEY_TYPE,
|
// TODO: Insert a new public statement of ValueOf with `key=KEY_TYPE,
|
||||||
// value=PodType::MockMainPod`
|
// value=PodType::MockMainPod`
|
||||||
let statements = Self::layout_statements(params, &inputs);
|
let statements = Self::layout_statements(params, &inputs);
|
||||||
let operations =
|
let operations =
|
||||||
Self::process_priavte_statements_operations(params, &statements, inputs.operations);
|
Self::process_private_statements_operations(params, &statements, inputs.operations);
|
||||||
let operations =
|
let operations =
|
||||||
Self::process_public_statements_operations(params, &statements, operations);
|
Self::process_public_statements_operations(params, &statements, operations);
|
||||||
|
|
||||||
|
|
@ -225,12 +227,12 @@ impl MockMainPod {
|
||||||
let input_statements = inputs.statements.iter().cloned().collect_vec();
|
let input_statements = inputs.statements.iter().cloned().collect_vec();
|
||||||
let public_statements = inputs.public_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
|
// get the id out of the public statements
|
||||||
// could be the public subset (which is the last `params.max_public_statements` of the
|
let id: PodId = PodId(hash_statements(&public_statements)?);
|
||||||
// vector`).
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
id: PodId::default(), // TODO
|
id,
|
||||||
input_signed_pods,
|
input_signed_pods,
|
||||||
input_main_pods,
|
input_main_pods,
|
||||||
input_statements,
|
input_statements,
|
||||||
|
|
@ -265,6 +267,14 @@ impl MockMainPod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn hash_statements(statements: &[middleware::Statement]) -> Result<middleware::Hash> {
|
||||||
|
let field_elems = statements
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|statement| statement.clone().to_fields().0)
|
||||||
|
.collect::<Vec<_>>();
|
||||||
|
Ok(Hash(PoseidonHash::hash_no_pad(&field_elems).elements))
|
||||||
|
}
|
||||||
|
|
||||||
impl MainPod for MockMainPod {
|
impl MainPod for MockMainPod {
|
||||||
fn verify(&self) -> bool {
|
fn verify(&self) -> bool {
|
||||||
// TODO
|
// TODO
|
||||||
|
|
@ -410,20 +420,20 @@ pub mod tests {
|
||||||
fn test_mock_main_0() {
|
fn test_mock_main_0() {
|
||||||
let params = middleware::Params::default();
|
let params = middleware::Params::default();
|
||||||
|
|
||||||
let (gov_id, pay_stub) = frontend::tests::zu_kyc_sign_pod_builders(¶ms);
|
let (gov_id_builder, pay_stub_builder) = frontend::tests::zu_kyc_sign_pod_builders(¶ms);
|
||||||
let mut signer = MockSigner {
|
let mut signer = MockSigner {
|
||||||
pk: "ZooGov".into(),
|
pk: "ZooGov".into(),
|
||||||
};
|
};
|
||||||
let gov_id = gov_id.sign(&mut signer).unwrap();
|
let gov_id_pod = gov_id_builder.sign(&mut signer).unwrap();
|
||||||
let mut signer = MockSigner {
|
let mut signer = MockSigner {
|
||||||
pk: "ZooDeel".into(),
|
pk: "ZooDeel".into(),
|
||||||
};
|
};
|
||||||
let pay_stub = pay_stub.sign(&mut signer).unwrap();
|
let pay_stub_pod = pay_stub_builder.sign(&mut signer).unwrap();
|
||||||
let kyc = frontend::tests::zu_kyc_pod_builder(¶ms, &gov_id, &pay_stub);
|
let kyc_builder = frontend::tests::zu_kyc_pod_builder(¶ms, &gov_id_pod, &pay_stub_pod);
|
||||||
|
|
||||||
let mut prover = MockProver {};
|
let mut prover = MockProver {};
|
||||||
let kyc = kyc.prove(&mut prover).unwrap();
|
let kyc_pod = kyc_builder.prove(&mut prover).unwrap();
|
||||||
let pod = kyc.pod.into_any().downcast::<MockMainPod>().unwrap();
|
let pod = kyc_pod.pod.into_any().downcast::<MockMainPod>().unwrap();
|
||||||
|
|
||||||
let printer = Printer { skip_none: false };
|
let printer = Printer { skip_none: false };
|
||||||
let mut w = io::stdout();
|
let mut w = io::stdout();
|
||||||
|
|
|
||||||
|
|
@ -343,7 +343,6 @@ impl MainPodBuilder {
|
||||||
};
|
};
|
||||||
let (statements, operations, public_statements) = compiler.compile(inputs)?;
|
let (statements, operations, public_statements) = compiler.compile(inputs)?;
|
||||||
|
|
||||||
// TODO: Add API to specify public/private statement
|
|
||||||
let inputs = MainPodInputs {
|
let inputs = MainPodInputs {
|
||||||
signed_pods: &self.input_signed_pods.iter().map(|p| &p.pod).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(),
|
main_pods: &self.input_main_pods.iter().map(|p| &p.pod).collect_vec(),
|
||||||
|
|
|
||||||
|
|
@ -17,6 +17,7 @@ use strum_macros::FromRepr;
|
||||||
|
|
||||||
pub const KEY_SIGNER: &str = "_signer";
|
pub const KEY_SIGNER: &str = "_signer";
|
||||||
pub const KEY_TYPE: &str = "_type";
|
pub const KEY_TYPE: &str = "_type";
|
||||||
|
pub const STATEMENT_ARG_F_LEN: usize = 8;
|
||||||
|
|
||||||
/// F is the native field we use everywhere. Currently it's Goldilocks from plonky2
|
/// F is the native field we use everywhere. Currently it's Goldilocks from plonky2
|
||||||
pub type F = GoldilocksField;
|
pub type F = GoldilocksField;
|
||||||
|
|
@ -74,6 +75,12 @@ impl fmt::Display for Value {
|
||||||
#[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq)]
|
||||||
pub struct Hash(pub [F; 4]);
|
pub struct Hash(pub [F; 4]);
|
||||||
|
|
||||||
|
impl ToFields for Hash {
|
||||||
|
fn to_fields(self) -> (Vec<F>, usize) {
|
||||||
|
(self.0.to_vec(), 4)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Ord for Hash {
|
impl Ord for Hash {
|
||||||
fn cmp(&self, other: &Self) -> Ordering {
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
Value(self.0).cmp(&Value(other.0))
|
Value(self.0).cmp(&Value(other.0))
|
||||||
|
|
@ -117,6 +124,12 @@ impl FromHex for Hash {
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
||||||
pub struct PodId(pub Hash);
|
pub struct PodId(pub Hash);
|
||||||
|
|
||||||
|
impl ToFields for PodId {
|
||||||
|
fn to_fields(self) -> (Vec<F>, usize) {
|
||||||
|
self.0.to_fields()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub const SELF: PodId = PodId(Hash([F::ONE, F::ZERO, F::ZERO, F::ZERO]));
|
pub const SELF: PodId = PodId(Hash([F::ONE, F::ZERO, F::ZERO, F::ZERO]));
|
||||||
|
|
||||||
impl fmt::Display for PodId {
|
impl fmt::Display for PodId {
|
||||||
|
|
@ -264,6 +277,12 @@ pub enum NativeStatement {
|
||||||
MaxOf = 10,
|
MaxOf = 10,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToFields for NativeStatement {
|
||||||
|
fn to_fields(self) -> (Vec<F>, usize) {
|
||||||
|
(vec![F::from_canonical_u64(self as u64)], 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
||||||
pub struct AnchoredKey(pub PodId, pub Hash);
|
pub struct AnchoredKey(pub PodId, pub Hash);
|
||||||
|
|
||||||
|
|
@ -280,6 +299,36 @@ impl StatementArg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToFields for StatementArg {
|
||||||
|
fn to_fields(self) -> (Vec<F>, usize) {
|
||||||
|
// NOTE: current version returns always the same amount of field elements in the returned
|
||||||
|
// vector, which means that the `None` case is padded with 8 zeroes, and the `Literal` case
|
||||||
|
// is padded with 4 zeroes. Since the returned vector will mostly be hashed (and reproduced
|
||||||
|
// in-circuit), we might be interested into reducing the length of it. If that's the case,
|
||||||
|
// we can check if it makes sense to make it dependant on the concrete StatementArg; that
|
||||||
|
// is, when dealing with a `None` it would be a single field element (zero value), and when
|
||||||
|
// dealing with `Literal` it would be of length 4.
|
||||||
|
let f = match self {
|
||||||
|
StatementArg::None => vec![F::ZERO; STATEMENT_ARG_F_LEN],
|
||||||
|
StatementArg::Literal(v) => {
|
||||||
|
let value_f = v.0.to_vec();
|
||||||
|
[
|
||||||
|
value_f.clone(),
|
||||||
|
vec![F::ZERO; STATEMENT_ARG_F_LEN - value_f.len()],
|
||||||
|
]
|
||||||
|
.concat()
|
||||||
|
}
|
||||||
|
StatementArg::Key(ak) => {
|
||||||
|
let (podid_f, _) = ak.0.to_fields();
|
||||||
|
let (hash_f, _) = ak.1.to_fields();
|
||||||
|
[podid_f, hash_f].concat()
|
||||||
|
}
|
||||||
|
};
|
||||||
|
assert_eq!(f.len(), STATEMENT_ARG_F_LEN); // sanity check
|
||||||
|
(f, STATEMENT_ARG_F_LEN)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||||
pub struct Statement(pub NativeStatement, pub Vec<StatementArg>);
|
pub struct Statement(pub NativeStatement, pub Vec<StatementArg>);
|
||||||
|
|
||||||
|
|
@ -289,6 +338,25 @@ impl Statement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToFields for Statement {
|
||||||
|
fn to_fields(self) -> (Vec<F>, usize) {
|
||||||
|
let (native_statement_f, native_statement_f_len) = self.0.to_fields();
|
||||||
|
let (vec_statementarg_f, vec_statementarg_f_len) = self
|
||||||
|
.1
|
||||||
|
.into_iter()
|
||||||
|
.map(|statement_arg| statement_arg.to_fields())
|
||||||
|
.fold((Vec::new(), 0), |mut acc, (f, l)| {
|
||||||
|
acc.0.extend(f);
|
||||||
|
acc.1 += l;
|
||||||
|
acc
|
||||||
|
});
|
||||||
|
(
|
||||||
|
[native_statement_f, vec_statementarg_f].concat(),
|
||||||
|
native_statement_f_len + vec_statementarg_f_len,
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
||||||
pub enum NativeOperation {
|
pub enum NativeOperation {
|
||||||
None = 0,
|
None = 0,
|
||||||
|
|
@ -350,9 +418,6 @@ impl MainPod for NoneMainPod {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// 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)]
|
#[derive(Debug)]
|
||||||
pub struct MainPodInputs<'a> {
|
pub struct MainPodInputs<'a> {
|
||||||
pub signed_pods: &'a [&'a Box<dyn SignedPod>],
|
pub signed_pods: &'a [&'a Box<dyn SignedPod>],
|
||||||
|
|
@ -367,3 +432,9 @@ pub struct MainPodInputs<'a> {
|
||||||
pub trait PodProver {
|
pub trait PodProver {
|
||||||
fn prove(&mut self, params: &Params, inputs: MainPodInputs) -> Result<Box<dyn MainPod>>;
|
fn prove(&mut self, params: &Params, inputs: MainPodInputs) -> Result<Box<dyn MainPod>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub trait ToFields {
|
||||||
|
/// returns Vec<F> representation of the type, and a usize indicating how many field elements
|
||||||
|
/// does the vector contain
|
||||||
|
fn to_fields(self) -> (Vec<F>, usize);
|
||||||
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue