Integrate recursion into MainPod (#243)
* calculate MainPod id in a dynamic-friendly way The MainPod id is now calculated with front padding and a fixed size independent of max_public_statements so that introduction gadgets can be verified by a MainPod while paying only for the number of statements they use. This is because with front padding of none-statements we can precompute the poseidon state corresponding to absorbing all the padding statements and only pay constraints for the non-padding statements. The id is calculated as follows: `id = hash(serialize(reverse(statements || none-statements)))` * add time feature and disable timing by default * apply suggestions from @arnaucube * link issues in todos
This commit is contained in:
parent
d3fef8392e
commit
88a75986b8
23 changed files with 1405 additions and 729 deletions
93
src/backends/plonky2/mock/emptypod.rs
Normal file
93
src/backends/plonky2/mock/emptypod.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
|||
use itertools::Itertools;
|
||||
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
basetypes::{Proof, VerifierOnlyCircuitData},
|
||||
error::{Error, Result},
|
||||
mainpod::{self, calculate_id},
|
||||
},
|
||||
middleware::{
|
||||
AnchoredKey, DynError, Hash, Params, Pod, PodId, PodType, RecursivePod, Statement, Value,
|
||||
KEY_TYPE, SELF,
|
||||
},
|
||||
};
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct MockEmptyPod {
|
||||
params: Params,
|
||||
id: PodId,
|
||||
}
|
||||
|
||||
fn type_statement() -> Statement {
|
||||
Statement::ValueOf(
|
||||
AnchoredKey::from((SELF, KEY_TYPE)),
|
||||
Value::from(PodType::Empty),
|
||||
)
|
||||
}
|
||||
|
||||
impl MockEmptyPod {
|
||||
pub fn new_boxed(params: &Params) -> Box<dyn RecursivePod> {
|
||||
let statements = [mainpod::Statement::from(type_statement())];
|
||||
let id = PodId(calculate_id(&statements, params));
|
||||
Box::new(Self {
|
||||
params: params.clone(),
|
||||
id,
|
||||
})
|
||||
}
|
||||
fn _verify(&self) -> Result<()> {
|
||||
let statements = self
|
||||
.pub_self_statements()
|
||||
.into_iter()
|
||||
.map(mainpod::Statement::from)
|
||||
.collect_vec();
|
||||
let id = PodId(calculate_id(&statements, &self.params));
|
||||
if id != self.id {
|
||||
return Err(Error::id_not_equal(self.id, id));
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl Pod for MockEmptyPod {
|
||||
fn params(&self) -> &Params {
|
||||
&self.params
|
||||
}
|
||||
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||
Ok(self._verify()?)
|
||||
}
|
||||
fn id(&self) -> PodId {
|
||||
self.id
|
||||
}
|
||||
fn pub_self_statements(&self) -> Vec<Statement> {
|
||||
vec![type_statement()]
|
||||
}
|
||||
|
||||
fn serialized_proof(&self) -> String {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl RecursivePod for MockEmptyPod {
|
||||
fn verifier_data(&self) -> VerifierOnlyCircuitData {
|
||||
panic!("MockEmptyPod can't be verified in a recursive MainPod circuit");
|
||||
}
|
||||
fn proof(&self) -> Proof {
|
||||
panic!("MockEmptyPod can't be verified in a recursive MainPod circuit");
|
||||
}
|
||||
fn vds_root(&self) -> Hash {
|
||||
panic!("MockEmptyPod can't be verified in a recursive MainPod circuit");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_mock_empty_pod() {
|
||||
let params = Params::default();
|
||||
|
||||
let empty_pod = MockEmptyPod::new_boxed(¶ms);
|
||||
empty_pod.verify().unwrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -9,17 +9,18 @@ use serde::{Deserialize, Serialize};
|
|||
|
||||
use crate::{
|
||||
backends::plonky2::{
|
||||
basetypes::{Proof, VerifierOnlyCircuitData},
|
||||
error::{Error, Result},
|
||||
mainpod::{
|
||||
calculate_id, extract_merkle_proofs, layout_statements, normalize_statement,
|
||||
calculate_id, extract_merkle_proofs, layout_statements,
|
||||
process_private_statements_operations, process_public_statements_operations, Operation,
|
||||
Statement,
|
||||
},
|
||||
primitives::merkletree::MerkleClaimAndProof,
|
||||
},
|
||||
middleware::{
|
||||
self, hash_str, AnchoredKey, DynError, MainPodInputs, NativePredicate, Params, Pod, PodId,
|
||||
PodProver, Predicate, StatementArg, KEY_TYPE, SELF,
|
||||
self, hash_str, AnchoredKey, DynError, Hash, MainPodInputs, NativePredicate, Params, Pod,
|
||||
PodId, PodProver, Predicate, RecursivePod, StatementArg, KEY_TYPE, SELF,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -27,10 +28,10 @@ pub struct MockProver {}
|
|||
|
||||
impl PodProver for MockProver {
|
||||
fn prove(
|
||||
&mut self,
|
||||
&self,
|
||||
params: &Params,
|
||||
inputs: MainPodInputs,
|
||||
) -> Result<Box<dyn Pod>, Box<DynError>> {
|
||||
) -> Result<Box<dyn RecursivePod>, Box<DynError>> {
|
||||
Ok(Box::new(MockMainPod::new(params, inputs)?))
|
||||
}
|
||||
}
|
||||
|
|
@ -73,7 +74,8 @@ impl fmt::Display for MockMainPod {
|
|||
}
|
||||
if (i >= offset_input_main_pods)
|
||||
&& (i < offset_input_statements)
|
||||
&& ((i - offset_input_main_pods) % self.params.max_public_statements == 0)
|
||||
&& ((i - offset_input_main_pods) % self.params.max_input_pods_public_statements
|
||||
== 0)
|
||||
{
|
||||
writeln!(
|
||||
f,
|
||||
|
|
@ -137,7 +139,7 @@ impl MockMainPod {
|
|||
}
|
||||
fn offset_input_statements(&self) -> usize {
|
||||
self.offset_input_main_pods()
|
||||
+ self.params.max_input_main_pods * self.params.max_public_statements
|
||||
+ self.params.max_input_recursive_pods * self.params.max_input_pods_public_statements
|
||||
}
|
||||
fn offset_public_statements(&self) -> usize {
|
||||
self.offset_input_statements() + self.params.max_priv_statements()
|
||||
|
|
@ -146,7 +148,7 @@ impl MockMainPod {
|
|||
pub fn new(params: &Params, inputs: MainPodInputs) -> Result<Self> {
|
||||
// TODO: Insert a new public statement of ValueOf with `key=KEY_TYPE,
|
||||
// value=PodType::MockMainPod`
|
||||
let statements = layout_statements(params, &inputs);
|
||||
let statements = layout_statements(params, true, &inputs)?;
|
||||
// Extract Merkle proofs and pad.
|
||||
let merkle_proofs = extract_merkle_proofs(params, inputs.operations)?;
|
||||
|
||||
|
|
@ -278,20 +280,20 @@ impl MockMainPod {
|
|||
}
|
||||
|
||||
impl Pod for MockMainPod {
|
||||
fn params(&self) -> &Params {
|
||||
&self.params
|
||||
}
|
||||
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||
Ok(self._verify()?)
|
||||
}
|
||||
fn id(&self) -> PodId {
|
||||
self.id
|
||||
}
|
||||
fn pub_statements(&self) -> Vec<middleware::Statement> {
|
||||
// return the public statements, where when origin=SELF is replaced by origin=self.id()
|
||||
// By convention we expect the KEY_TYPE to be the first statement
|
||||
self.statements
|
||||
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
||||
self.public_statements
|
||||
.iter()
|
||||
.skip(self.offset_public_statements())
|
||||
.cloned()
|
||||
.map(|statement| normalize_statement(&statement, self.id()))
|
||||
.map(|st| st.try_into().expect("valid statement"))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
@ -300,6 +302,18 @@ impl Pod for MockMainPod {
|
|||
}
|
||||
}
|
||||
|
||||
impl RecursivePod for MockMainPod {
|
||||
fn verifier_data(&self) -> VerifierOnlyCircuitData {
|
||||
panic!("MockMainPod can't be verified in a recursive MainPod circuit");
|
||||
}
|
||||
fn proof(&self) -> Proof {
|
||||
panic!("MockMainPod can't be verified in a recursive MainPod circuit");
|
||||
}
|
||||
fn vds_root(&self) -> Hash {
|
||||
panic!("MockMainPod can't be verified in a recursive MainPod circuit");
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
pub mod tests {
|
||||
use std::any::Any;
|
||||
|
|
|
|||
|
|
@ -1,2 +1,3 @@
|
|||
pub mod emptypod;
|
||||
pub mod mainpod;
|
||||
pub mod signedpod;
|
||||
|
|
|
|||
|
|
@ -10,7 +10,7 @@ use crate::{
|
|||
constants::MAX_DEPTH,
|
||||
middleware::{
|
||||
containers::Dictionary, hash_str, AnchoredKey, DynError, Hash, Key, Params, Pod, PodId,
|
||||
PodSigner, PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE,
|
||||
PodSigner, PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE, SELF,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -111,6 +111,9 @@ impl MockSignedPod {
|
|||
}
|
||||
|
||||
impl Pod for MockSignedPod {
|
||||
fn params(&self) -> &Params {
|
||||
panic!("MockSignedPod doesn't have params");
|
||||
}
|
||||
fn verify(&self) -> Result<(), Box<DynError>> {
|
||||
Ok(self._verify()?)
|
||||
}
|
||||
|
|
@ -119,8 +122,7 @@ impl Pod for MockSignedPod {
|
|||
self.id
|
||||
}
|
||||
|
||||
fn pub_statements(&self) -> Vec<Statement> {
|
||||
let id = self.id();
|
||||
fn pub_self_statements(&self) -> Vec<Statement> {
|
||||
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
||||
let mut kvs = self.kvs.clone();
|
||||
let key_type = Key::from(KEY_TYPE);
|
||||
|
|
@ -130,7 +132,7 @@ impl Pod for MockSignedPod {
|
|||
[(key_type, value_type), (key_signer, value_signer)]
|
||||
.into_iter()
|
||||
.chain(kvs.into_iter().sorted_by_key(|kv| kv.0.hash()))
|
||||
.map(|(k, v)| Statement::ValueOf(AnchoredKey::from((id, k)), v))
|
||||
.map(|(k, v)| Statement::ValueOf(AnchoredKey::from((SELF, k)), v))
|
||||
.collect()
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue