Implement generic serialization/deserialization (#260)
* complete general serialization * bump default params temporarily * disable recursion in great_boy_pod example
This commit is contained in:
parent
c66506c048
commit
621f8be6b5
14 changed files with 392 additions and 253 deletions
|
|
@ -1,6 +1,5 @@
|
||||||
use std::{collections::HashMap, sync::Mutex};
|
use std::{collections::HashMap, sync::Mutex};
|
||||||
|
|
||||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
hash::hash_types::HashOutTarget,
|
hash::hash_types::HashOutTarget,
|
||||||
|
|
@ -11,6 +10,7 @@ use plonky2::{
|
||||||
proof::ProofWithPublicInputs,
|
proof::ProofWithPublicInputs,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
|
|
@ -19,10 +19,11 @@ use crate::{
|
||||||
common::{Flattenable, StatementTarget},
|
common::{Flattenable, StatementTarget},
|
||||||
mainpod::{CalculateIdGadget, PI_OFFSET_ID},
|
mainpod::{CalculateIdGadget, PI_OFFSET_ID},
|
||||||
},
|
},
|
||||||
|
deserialize_proof,
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
mainpod::{self, calculate_id},
|
mainpod::{self, calculate_id},
|
||||||
recursion::pad_circuit,
|
recursion::pad_circuit,
|
||||||
LazyLock, DEFAULT_PARAMS, STANDARD_REC_MAIN_POD_CIRCUIT_DATA,
|
serialize_proof, LazyLock, DEFAULT_PARAMS, STANDARD_REC_MAIN_POD_CIRCUIT_DATA,
|
||||||
},
|
},
|
||||||
middleware::{
|
middleware::{
|
||||||
self, AnchoredKey, DynError, Hash, Params, Pod, PodId, PodType, RecursivePod, Statement,
|
self, AnchoredKey, DynError, Hash, Params, Pod, PodId, PodType, RecursivePod, Statement,
|
||||||
|
|
@ -154,6 +155,28 @@ impl EmptyPod {
|
||||||
})
|
})
|
||||||
.map_err(|e| Error::custom(format!("EmptyPod proof verification failure: {:?}", e)))
|
.map_err(|e| Error::custom(format!("EmptyPod proof verification failure: {:?}", e)))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn deserialize(
|
||||||
|
params: Params,
|
||||||
|
id: PodId,
|
||||||
|
vds_root: Hash,
|
||||||
|
data: serde_json::Value,
|
||||||
|
) -> Result<Box<dyn RecursivePod>> {
|
||||||
|
let data: Data = serde_json::from_value(data)?;
|
||||||
|
let circuit_data = &*STANDARD_REC_MAIN_POD_CIRCUIT_DATA;
|
||||||
|
let proof = deserialize_proof(&circuit_data.common, &data.proof)?;
|
||||||
|
Ok(Box::new(Self {
|
||||||
|
params,
|
||||||
|
id,
|
||||||
|
vds_root,
|
||||||
|
proof,
|
||||||
|
}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Data {
|
||||||
|
proof: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for EmptyPod {
|
impl Pod for EmptyPod {
|
||||||
|
|
@ -167,16 +190,19 @@ impl Pod for EmptyPod {
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
fn pod_type(&self) -> (usize, &'static str) {
|
||||||
|
(PodType::Empty as usize, "Empty")
|
||||||
|
}
|
||||||
|
|
||||||
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
||||||
vec![type_statement()]
|
vec![type_statement()]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialized_proof(&self) -> String {
|
fn serialize_data(&self) -> serde_json::Value {
|
||||||
let mut buffer = Vec::new();
|
serde_json::to_value(Data {
|
||||||
use plonky2::util::serialization::Write;
|
proof: serialize_proof(&self.proof),
|
||||||
buffer.write_proof(&self.proof).unwrap();
|
})
|
||||||
BASE64_STANDARD.encode(buffer)
|
.expect("serialization to json")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,6 +43,8 @@ pub enum Error {
|
||||||
Plonky2ProofFail(anyhow::Error),
|
Plonky2ProofFail(anyhow::Error),
|
||||||
#[error("base64::DecodeError: {0}")]
|
#[error("base64::DecodeError: {0}")]
|
||||||
Base64Decode(#[from] base64::DecodeError),
|
Base64Decode(#[from] base64::DecodeError),
|
||||||
|
#[error("serde_json::Error: {0}")]
|
||||||
|
SerdeJson(#[from] serde_json::Error),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
Tree(#[from] crate::backends::plonky2::primitives::merkletree::error::TreeError),
|
Tree(#[from] crate::backends::plonky2::primitives::merkletree::error::TreeError),
|
||||||
#[error(transparent)]
|
#[error(transparent)]
|
||||||
|
|
|
||||||
|
|
@ -2,25 +2,26 @@ pub mod operation;
|
||||||
pub mod statement;
|
pub mod statement;
|
||||||
use std::{any::Any, iter, sync::Arc};
|
use std::{any::Any, iter, sync::Arc};
|
||||||
|
|
||||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
pub use operation::*;
|
pub use operation::*;
|
||||||
use plonky2::{
|
use plonky2::{
|
||||||
hash::poseidon::PoseidonHash,
|
hash::poseidon::PoseidonHash,
|
||||||
plonk::{circuit_data::CommonCircuitData, config::Hasher},
|
plonk::{circuit_data::CommonCircuitData, config::Hasher},
|
||||||
util::serialization::{Buffer, Read},
|
|
||||||
};
|
};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
pub use statement::*;
|
pub use statement::*;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::{Proof, ProofWithPublicInputs, VerifierOnlyCircuitData, D},
|
basetypes::{Proof, ProofWithPublicInputs, VerifierOnlyCircuitData, D},
|
||||||
circuits::mainpod::{CustomPredicateVerification, MainPodVerifyInput, MainPodVerifyTarget},
|
circuits::mainpod::{CustomPredicateVerification, MainPodVerifyInput, MainPodVerifyTarget},
|
||||||
|
deserialize_proof,
|
||||||
emptypod::EmptyPod,
|
emptypod::EmptyPod,
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
mock::emptypod::MockEmptyPod,
|
mock::emptypod::MockEmptyPod,
|
||||||
primitives::merkletree::MerkleClaimAndProof,
|
primitives::merkletree::MerkleClaimAndProof,
|
||||||
recursion::{RecursiveCircuit, RecursiveParams},
|
recursion::{RecursiveCircuit, RecursiveParams},
|
||||||
|
serialize_proof,
|
||||||
signedpod::SignedPod,
|
signedpod::SignedPod,
|
||||||
STANDARD_REC_MAIN_POD_CIRCUIT_DATA,
|
STANDARD_REC_MAIN_POD_CIRCUIT_DATA,
|
||||||
},
|
},
|
||||||
|
|
@ -241,13 +242,14 @@ fn pad_operation_args(params: &Params, args: &mut Vec<OperationArg>) {
|
||||||
fill_pad(args, OperationArg::None, params.max_operation_args)
|
fill_pad(args, OperationArg::None, params.max_operation_args)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the statements from the given MainPodInputs, padding to the
|
/// Returns the statements from the given MainPodInputs, padding to the respective max lengths
|
||||||
/// respective max lengths defined at the given Params.
|
/// defined at the given Params. Also returns a copy of the dynamic-length public statements from
|
||||||
|
/// the list of statements.
|
||||||
pub(crate) fn layout_statements(
|
pub(crate) fn layout_statements(
|
||||||
params: &Params,
|
params: &Params,
|
||||||
mock: bool,
|
mock: bool,
|
||||||
inputs: &MainPodInputs,
|
inputs: &MainPodInputs,
|
||||||
) -> Result<Vec<Statement>> {
|
) -> Result<(Vec<Statement>, Vec<Statement>)> {
|
||||||
let mut statements = Vec::new();
|
let mut statements = Vec::new();
|
||||||
|
|
||||||
// Statement at index 0 is always None to be used for padding operation arguments in custom
|
// Statement at index 0 is always None to be used for padding operation arguments in custom
|
||||||
|
|
@ -334,7 +336,11 @@ pub(crate) fn layout_statements(
|
||||||
statements.push(st);
|
statements.push(st);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(statements)
|
let offset_public_statements = statements.len() - params.max_public_statements;
|
||||||
|
let public_statements = statements
|
||||||
|
[offset_public_statements..offset_public_statements + 1 + inputs.public_statements.len()]
|
||||||
|
.to_vec();
|
||||||
|
Ok((statements, public_statements))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn process_private_statements_operations(
|
pub(crate) fn process_private_statements_operations(
|
||||||
|
|
@ -469,7 +475,7 @@ impl Prover {
|
||||||
&custom_predicate_batches,
|
&custom_predicate_batches,
|
||||||
)?;
|
)?;
|
||||||
|
|
||||||
let statements = layout_statements(params, false, &inputs)?;
|
let (statements, public_statements) = layout_statements(params, false, &inputs)?;
|
||||||
let operations = process_private_statements_operations(
|
let operations = process_private_statements_operations(
|
||||||
params,
|
params,
|
||||||
&statements,
|
&statements,
|
||||||
|
|
@ -479,8 +485,6 @@ impl Prover {
|
||||||
)?;
|
)?;
|
||||||
let operations = process_public_statements_operations(params, &statements, operations)?;
|
let operations = process_public_statements_operations(params, &statements, operations)?;
|
||||||
|
|
||||||
let public_statements =
|
|
||||||
statements[statements.len() - params.max_public_statements..].to_vec();
|
|
||||||
// get the id out of the public statements
|
// get the id out of the public statements
|
||||||
let id: PodId = PodId(calculate_id(&public_statements, params));
|
let id: PodId = PodId(calculate_id(&public_statements, params));
|
||||||
|
|
||||||
|
|
@ -558,6 +562,12 @@ fn get_common_data(params: &Params) -> Result<CommonCircuitData<F, D>, Error> {
|
||||||
Ok(circuit_data.common.clone())
|
Ok(circuit_data.common.clone())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Data {
|
||||||
|
public_statements: Vec<Statement>,
|
||||||
|
proof: String,
|
||||||
|
}
|
||||||
|
|
||||||
impl MainPod {
|
impl MainPod {
|
||||||
fn _verify(&self) -> Result<()> {
|
fn _verify(&self) -> Result<()> {
|
||||||
// 2. get the id out of the public statements
|
// 2. get the id out of the public statements
|
||||||
|
|
@ -602,40 +612,22 @@ impl MainPod {
|
||||||
&self.params
|
&self.params
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn new(
|
pub(crate) fn deserialize(
|
||||||
proof: Proof,
|
params: Params,
|
||||||
public_statements: Vec<Statement>,
|
|
||||||
id: PodId,
|
id: PodId,
|
||||||
vds_root: Hash,
|
vds_root: Hash,
|
||||||
params: Params,
|
data: serde_json::Value,
|
||||||
) -> Self {
|
) -> Result<Box<dyn RecursivePod>> {
|
||||||
Self {
|
let data: Data = serde_json::from_value(data)?;
|
||||||
|
let common = get_common_data(¶ms)?;
|
||||||
|
let proof = deserialize_proof(&common, &data.proof)?;
|
||||||
|
Ok(Box::new(Self {
|
||||||
params,
|
params,
|
||||||
id,
|
id,
|
||||||
vds_root,
|
vds_root,
|
||||||
public_statements,
|
|
||||||
proof,
|
proof,
|
||||||
}
|
public_statements: data.public_statements,
|
||||||
}
|
}))
|
||||||
|
|
||||||
pub fn decode_proof(proof: &str, params: &Params) -> Result<Proof, Error> {
|
|
||||||
let decoded = BASE64_STANDARD.decode(proof).map_err(|e| {
|
|
||||||
Error::custom(format!(
|
|
||||||
"Failed to decode proof from base64: {}. Value: {}",
|
|
||||||
e, proof
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
let mut buf = Buffer::new(&decoded);
|
|
||||||
let common = get_common_data(params)?;
|
|
||||||
|
|
||||||
let proof = buf.read_proof(&common).map_err(|e| {
|
|
||||||
Error::custom(format!(
|
|
||||||
"Failed to read proof from buffer: {}. Value: {}",
|
|
||||||
e, proof
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(proof)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -650,6 +642,9 @@ impl Pod for MainPod {
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
fn pod_type(&self) -> (usize, &'static str) {
|
||||||
|
(PodType::Main as usize, "Main")
|
||||||
|
}
|
||||||
|
|
||||||
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
||||||
self.public_statements
|
self.public_statements
|
||||||
|
|
@ -659,11 +654,12 @@ impl Pod for MainPod {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialized_proof(&self) -> String {
|
fn serialize_data(&self) -> serde_json::Value {
|
||||||
let mut buffer = Vec::new();
|
serde_json::to_value(Data {
|
||||||
use plonky2::util::serialization::Write;
|
proof: serialize_proof(&self.proof),
|
||||||
buffer.write_proof(&self.proof).unwrap();
|
public_statements: self.public_statements.clone(),
|
||||||
BASE64_STANDARD.encode(buffer)
|
})
|
||||||
|
.expect("serialization to json")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,14 @@ impl MockEmptyPod {
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
pub(crate) fn deserialize(
|
||||||
|
params: Params,
|
||||||
|
id: PodId,
|
||||||
|
_vds_root: Hash,
|
||||||
|
_data: serde_json::Value,
|
||||||
|
) -> Result<Box<dyn RecursivePod>> {
|
||||||
|
Ok(Box::new(Self { params, id }))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for MockEmptyPod {
|
impl Pod for MockEmptyPod {
|
||||||
|
|
@ -58,12 +66,15 @@ impl Pod for MockEmptyPod {
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
fn pod_type(&self) -> (usize, &'static str) {
|
||||||
|
(PodType::MockEmpty as usize, "MockEmpty")
|
||||||
|
}
|
||||||
fn pub_self_statements(&self) -> Vec<Statement> {
|
fn pub_self_statements(&self) -> Vec<Statement> {
|
||||||
vec![type_statement()]
|
vec![type_statement()]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialized_proof(&self) -> String {
|
fn serialize_data(&self) -> serde_json::Value {
|
||||||
todo!()
|
serde_json::Value::Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -20,7 +19,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
middleware::{
|
middleware::{
|
||||||
self, hash_str, AnchoredKey, DynError, Hash, MainPodInputs, NativePredicate, Params, Pod,
|
self, hash_str, AnchoredKey, DynError, Hash, MainPodInputs, NativePredicate, Params, Pod,
|
||||||
PodId, PodProver, Predicate, RecursivePod, StatementArg, KEY_TYPE, SELF,
|
PodId, PodProver, PodType, Predicate, RecursivePod, StatementArg, KEY_TYPE, SELF,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -40,6 +39,7 @@ impl PodProver for MockProver {
|
||||||
pub struct MockMainPod {
|
pub struct MockMainPod {
|
||||||
params: Params,
|
params: Params,
|
||||||
id: PodId,
|
id: PodId,
|
||||||
|
vds_root: Hash,
|
||||||
// input_signed_pods: Vec<Box<dyn Pod>>,
|
// input_signed_pods: Vec<Box<dyn Pod>>,
|
||||||
// input_main_pods: Vec<Box<dyn Pod>>,
|
// input_main_pods: Vec<Box<dyn Pod>>,
|
||||||
// New statements introduced by this pod
|
// New statements introduced by this pod
|
||||||
|
|
@ -51,6 +51,7 @@ pub struct MockMainPod {
|
||||||
// All Merkle proofs
|
// All Merkle proofs
|
||||||
// TODO: Use a backend-specific representation
|
// TODO: Use a backend-specific representation
|
||||||
merkle_proofs: Vec<MerkleClaimAndProof>,
|
merkle_proofs: Vec<MerkleClaimAndProof>,
|
||||||
|
// TODO: Add input pods
|
||||||
}
|
}
|
||||||
|
|
||||||
impl fmt::Display for MockMainPod {
|
impl fmt::Display for MockMainPod {
|
||||||
|
|
@ -124,6 +125,14 @@ fn fmt_statement_index(
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Data {
|
||||||
|
public_statements: Vec<Statement>,
|
||||||
|
operations: Vec<Operation>,
|
||||||
|
statements: Vec<Statement>,
|
||||||
|
merkle_proofs: Vec<MerkleClaimAndProof>,
|
||||||
|
}
|
||||||
|
|
||||||
/// Inputs are sorted as:
|
/// Inputs are sorted as:
|
||||||
/// - SignedPods
|
/// - SignedPods
|
||||||
/// - MainPods
|
/// - MainPods
|
||||||
|
|
@ -148,7 +157,7 @@ impl MockMainPod {
|
||||||
pub fn new(params: &Params, inputs: MainPodInputs) -> Result<Self> {
|
pub fn new(params: &Params, inputs: MainPodInputs) -> Result<Self> {
|
||||||
// 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 = layout_statements(params, true, &inputs)?;
|
let (statements, public_statements) = layout_statements(params, true, &inputs)?;
|
||||||
// Extract Merkle proofs and pad.
|
// Extract Merkle proofs and pad.
|
||||||
let merkle_proofs = extract_merkle_proofs(params, inputs.operations)?;
|
let merkle_proofs = extract_merkle_proofs(params, inputs.operations)?;
|
||||||
|
|
||||||
|
|
@ -161,15 +170,13 @@ impl MockMainPod {
|
||||||
)?;
|
)?;
|
||||||
let operations = process_public_statements_operations(params, &statements, operations)?;
|
let operations = process_public_statements_operations(params, &statements, operations)?;
|
||||||
|
|
||||||
let public_statements =
|
|
||||||
statements[statements.len() - params.max_public_statements..].to_vec();
|
|
||||||
|
|
||||||
// get the id out of the public statements
|
// get the id out of the public statements
|
||||||
let id: PodId = PodId(calculate_id(&public_statements, params));
|
let id: PodId = PodId(calculate_id(&public_statements, params));
|
||||||
|
|
||||||
Ok(Self {
|
Ok(Self {
|
||||||
params: params.clone(),
|
params: params.clone(),
|
||||||
id,
|
id,
|
||||||
|
vds_root: inputs.vds_root,
|
||||||
// input_signed_pods,
|
// input_signed_pods,
|
||||||
// input_main_pods,
|
// input_main_pods,
|
||||||
// input_statements,
|
// input_statements,
|
||||||
|
|
@ -183,13 +190,27 @@ impl MockMainPod {
|
||||||
// MockMainPods include some internal private state which is necessary
|
// MockMainPods include some internal private state which is necessary
|
||||||
// for verification. In non-mock Pods, this state will not be necessary,
|
// for verification. In non-mock Pods, this state will not be necessary,
|
||||||
// as the public statements can be verified using a ZK proof.
|
// as the public statements can be verified using a ZK proof.
|
||||||
pub(crate) fn deserialize(serialized: String) -> Result<Self> {
|
pub(crate) fn deserialize(
|
||||||
let proof = String::from_utf8(BASE64_STANDARD.decode(&serialized)?)
|
params: Params,
|
||||||
.map_err(|e| anyhow::anyhow!("Invalid base64 encoding: {}", e))?;
|
id: PodId,
|
||||||
let pod: MockMainPod = serde_json::from_str(&proof)
|
vds_root: Hash,
|
||||||
.map_err(|e| anyhow::anyhow!("Failed to parse proof: {}", e))?;
|
data: serde_json::Value,
|
||||||
|
) -> Result<Box<dyn RecursivePod>> {
|
||||||
Ok(pod)
|
let Data {
|
||||||
|
public_statements,
|
||||||
|
operations,
|
||||||
|
statements,
|
||||||
|
merkle_proofs,
|
||||||
|
} = serde_json::from_value(data)?;
|
||||||
|
Ok(Box::new(Self {
|
||||||
|
params,
|
||||||
|
id,
|
||||||
|
vds_root,
|
||||||
|
public_statements,
|
||||||
|
operations,
|
||||||
|
statements,
|
||||||
|
merkle_proofs,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn _verify(&self) -> Result<()> {
|
fn _verify(&self) -> Result<()> {
|
||||||
|
|
@ -289,6 +310,9 @@ impl Pod for MockMainPod {
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
fn pod_type(&self) -> (usize, &'static str) {
|
||||||
|
(PodType::MockMain as usize, "MockMain")
|
||||||
|
}
|
||||||
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
fn pub_self_statements(&self) -> Vec<middleware::Statement> {
|
||||||
self.public_statements
|
self.public_statements
|
||||||
.iter()
|
.iter()
|
||||||
|
|
@ -297,8 +321,14 @@ impl Pod for MockMainPod {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialized_proof(&self) -> String {
|
fn serialize_data(&self) -> serde_json::Value {
|
||||||
BASE64_STANDARD.encode(serde_json::to_string(self).unwrap())
|
serde_json::to_value(Data {
|
||||||
|
public_statements: self.public_statements.clone(),
|
||||||
|
operations: self.operations.clone(),
|
||||||
|
statements: self.statements.clone(),
|
||||||
|
merkle_proofs: self.merkle_proofs.clone(),
|
||||||
|
})
|
||||||
|
.expect("serialization to json")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -310,7 +340,7 @@ impl RecursivePod for MockMainPod {
|
||||||
panic!("MockMainPod can't be verified in a recursive MainPod circuit");
|
panic!("MockMainPod can't be verified in a recursive MainPod circuit");
|
||||||
}
|
}
|
||||||
fn vds_root(&self) -> Hash {
|
fn vds_root(&self) -> Hash {
|
||||||
panic!("MockMainPod can't be verified in a recursive MainPod circuit");
|
self.vds_root
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
|
|
@ -9,8 +10,9 @@ use crate::{
|
||||||
},
|
},
|
||||||
constants::MAX_DEPTH,
|
constants::MAX_DEPTH,
|
||||||
middleware::{
|
middleware::{
|
||||||
containers::Dictionary, hash_str, AnchoredKey, DynError, Hash, Key, Params, Pod, PodId,
|
containers::Dictionary, hash_str, serialization::ordered_map, AnchoredKey, DynError, Hash,
|
||||||
PodSigner, PodType, RawValue, Statement, Value, KEY_SIGNER, KEY_TYPE, SELF,
|
Key, Params, Pod, PodId, PodSigner, PodType, RawValue, Statement, Value, KEY_SIGNER,
|
||||||
|
KEY_TYPE, SELF,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -55,17 +57,18 @@ pub struct MockSignedPod {
|
||||||
kvs: HashMap<Key, Value>,
|
kvs: HashMap<Key, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl MockSignedPod {
|
#[derive(Serialize, Deserialize)]
|
||||||
pub(crate) fn new(id: PodId, signature: String, kvs: HashMap<Key, Value>) -> Self {
|
struct Data {
|
||||||
Self { id, signature, kvs }
|
signature: String,
|
||||||
|
#[serde(serialize_with = "ordered_map")]
|
||||||
|
kvs: HashMap<Key, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl MockSignedPod {
|
||||||
pub fn signature(&self) -> String {
|
pub fn signature(&self) -> String {
|
||||||
self.signature.clone()
|
self.signature.clone()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl MockSignedPod {
|
|
||||||
fn _verify(&self) -> Result<()> {
|
fn _verify(&self) -> Result<()> {
|
||||||
// 1. Verify id
|
// 1. Verify id
|
||||||
let mt = MerkleTree::new(
|
let mt = MerkleTree::new(
|
||||||
|
|
@ -108,6 +111,15 @@ impl MockSignedPod {
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(crate) fn deserialize(id: PodId, data: serde_json::Value) -> Result<Box<dyn Pod>> {
|
||||||
|
let data: Data = serde_json::from_value(data)?;
|
||||||
|
Ok(Box::new(Self {
|
||||||
|
id,
|
||||||
|
signature: data.signature,
|
||||||
|
kvs: data.kvs,
|
||||||
|
}))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for MockSignedPod {
|
impl Pod for MockSignedPod {
|
||||||
|
|
@ -121,6 +133,9 @@ impl Pod for MockSignedPod {
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
fn pod_type(&self) -> (usize, &'static str) {
|
||||||
|
(PodType::MockSigned as usize, "MockSigned")
|
||||||
|
}
|
||||||
|
|
||||||
fn pub_self_statements(&self) -> Vec<Statement> {
|
fn pub_self_statements(&self) -> Vec<Statement> {
|
||||||
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
||||||
|
|
@ -136,8 +151,12 @@ impl Pod for MockSignedPod {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialized_proof(&self) -> String {
|
fn serialize_data(&self) -> serde_json::Value {
|
||||||
serde_json::to_string(&self.signature).unwrap()
|
serde_json::to_value(Data {
|
||||||
|
signature: self.signature.clone(),
|
||||||
|
kvs: self.kvs.clone(),
|
||||||
|
})
|
||||||
|
.expect("serialization to json")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -10,11 +10,13 @@ pub mod signedpod;
|
||||||
|
|
||||||
use std::sync::LazyLock;
|
use std::sync::LazyLock;
|
||||||
|
|
||||||
|
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
|
use plonky2::util::serialization::{Buffer, Read};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
basetypes::CircuitData,
|
basetypes::{CircuitData, CommonCircuitData, Proof},
|
||||||
circuits::mainpod::{MainPodVerifyTarget, NUM_PUBLIC_INPUTS},
|
circuits::mainpod::{MainPodVerifyTarget, NUM_PUBLIC_INPUTS},
|
||||||
recursion::RecursiveCircuit,
|
recursion::RecursiveCircuit,
|
||||||
},
|
},
|
||||||
|
|
@ -37,3 +39,36 @@ pub static STANDARD_REC_MAIN_POD_CIRCUIT_DATA: LazyLock<CircuitData> = LazyLock:
|
||||||
.1
|
.1
|
||||||
)
|
)
|
||||||
});
|
});
|
||||||
|
|
||||||
|
pub fn serialize_bytes(bytes: &[u8]) -> String {
|
||||||
|
BASE64_STANDARD.encode(bytes)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_bytes(data: &str) -> Result<Vec<u8>> {
|
||||||
|
BASE64_STANDARD.decode(data).map_err(|e| {
|
||||||
|
Error::custom(format!(
|
||||||
|
"Failed to decode data from base64: {}. Value: {}",
|
||||||
|
e, data
|
||||||
|
))
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_proof(common: &CommonCircuitData, proof: &str) -> Result<Proof> {
|
||||||
|
let decoded = deserialize_bytes(proof)?;
|
||||||
|
let mut buf = Buffer::new(&decoded);
|
||||||
|
let proof = buf.read_proof(common).map_err(|e| {
|
||||||
|
Error::custom(format!(
|
||||||
|
"Failed to read proof from buffer: {}. Value: {}",
|
||||||
|
e, proof
|
||||||
|
))
|
||||||
|
})?;
|
||||||
|
|
||||||
|
Ok(proof)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn serialize_proof(proof: &Proof) -> String {
|
||||||
|
let mut buffer = Vec::new();
|
||||||
|
use plonky2::util::serialization::Write;
|
||||||
|
buffer.write_proof(proof).unwrap();
|
||||||
|
serialize_bytes(&buffer)
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,12 +1,13 @@
|
||||||
use std::collections::HashMap;
|
use std::collections::HashMap;
|
||||||
|
|
||||||
use base64::{prelude::BASE64_STANDARD, Engine};
|
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
use num_bigint::RandBigInt;
|
use num_bigint::RandBigInt;
|
||||||
use rand::rngs::OsRng;
|
use rand::rngs::OsRng;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
|
deserialize_bytes,
|
||||||
error::{Error, Result},
|
error::{Error, Result},
|
||||||
primitives::{
|
primitives::{
|
||||||
ec::{
|
ec::{
|
||||||
|
|
@ -15,6 +16,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
merkletree::MerkleTree,
|
merkletree::MerkleTree,
|
||||||
},
|
},
|
||||||
|
serialize_bytes,
|
||||||
},
|
},
|
||||||
constants::MAX_DEPTH,
|
constants::MAX_DEPTH,
|
||||||
middleware::{
|
middleware::{
|
||||||
|
|
@ -68,6 +70,13 @@ pub struct SignedPod {
|
||||||
pub dict: Dictionary,
|
pub dict: Dictionary,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Serialize, Deserialize)]
|
||||||
|
struct Data {
|
||||||
|
signer: String,
|
||||||
|
signature: String,
|
||||||
|
kvs: Dictionary,
|
||||||
|
}
|
||||||
|
|
||||||
impl SignedPod {
|
impl SignedPod {
|
||||||
fn _verify(&self) -> Result<()> {
|
fn _verify(&self) -> Result<()> {
|
||||||
// 1. Verify type
|
// 1. Verify type
|
||||||
|
|
@ -107,23 +116,31 @@ impl SignedPod {
|
||||||
.ok_or(Error::custom("Invalid signature!".into()))
|
.ok_or(Error::custom("Invalid signature!".into()))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn decode_proof(signature: &str) -> Result<(Point, Signature), Error> {
|
pub(crate) fn deserialize(id: PodId, data: serde_json::Value) -> Result<Box<dyn Pod>> {
|
||||||
let proof_bytes = BASE64_STANDARD.decode(signature).map_err(|e| {
|
let data: Data = serde_json::from_value(data)?;
|
||||||
Error::custom(format!(
|
let signer_bytes = deserialize_bytes(&data.signer)?;
|
||||||
"Failed to decode proof from base64: {}. Value: {}",
|
let signature_bytes = deserialize_bytes(&data.signature)?;
|
||||||
e, signature
|
|
||||||
))
|
|
||||||
})?;
|
|
||||||
|
|
||||||
if proof_bytes.len() != 160 {
|
if signer_bytes.len() != 80 {
|
||||||
return Err(Error::custom(
|
return Err(Error::custom(
|
||||||
"Invalid byte encoding of signed POD proof.".to_string(),
|
"Invalid byte encoding of signed POD signer.".to_string(),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
if signature_bytes.len() != 80 {
|
||||||
|
return Err(Error::custom(
|
||||||
|
"Invalid byte encoding of signed POD signature.".to_string(),
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
let signer = Point::from_bytes(&proof_bytes[..80])?;
|
let signer = Point::from_bytes(&signer_bytes)?;
|
||||||
let signature = Signature::from_bytes(&proof_bytes[80..])?;
|
let signature = Signature::from_bytes(&signature_bytes)?;
|
||||||
Ok((signer, signature))
|
|
||||||
|
Ok(Box::new(Self {
|
||||||
|
id,
|
||||||
|
signature,
|
||||||
|
signer,
|
||||||
|
dict: data.kvs,
|
||||||
|
}))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -138,6 +155,9 @@ impl Pod for SignedPod {
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
fn pod_type(&self) -> (usize, &'static str) {
|
||||||
|
(PodType::Signed as usize, "Signed")
|
||||||
|
}
|
||||||
|
|
||||||
fn pub_self_statements(&self) -> Vec<Statement> {
|
fn pub_self_statements(&self) -> Vec<Statement> {
|
||||||
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
// By convention we put the KEY_TYPE first and KEY_SIGNER second
|
||||||
|
|
@ -153,10 +173,15 @@ impl Pod for SignedPod {
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialized_proof(&self) -> String {
|
fn serialize_data(&self) -> serde_json::Value {
|
||||||
// Serialise signer + signature.
|
let signer = serialize_bytes(&self.signer.as_bytes());
|
||||||
let proof_bytes = [self.signer.as_bytes(), self.signature.as_bytes()].concat();
|
let signature = serialize_bytes(&self.signature.as_bytes());
|
||||||
BASE64_STANDARD.encode(&proof_bytes)
|
serde_json::to_value(Data {
|
||||||
|
signer,
|
||||||
|
signature,
|
||||||
|
kvs: self.dict.clone(),
|
||||||
|
})
|
||||||
|
.expect("serialization to json")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -299,6 +299,7 @@ pub fn great_boy_pod_builder(
|
||||||
pub fn great_boy_pod_full_flow() -> Result<(Params, MainPodBuilder)> {
|
pub fn great_boy_pod_full_flow() -> Result<(Params, MainPodBuilder)> {
|
||||||
let params = Params {
|
let params = Params {
|
||||||
max_input_signed_pods: 6,
|
max_input_signed_pods: 6,
|
||||||
|
max_input_recursive_pods: 0,
|
||||||
max_statements: 100,
|
max_statements: 100,
|
||||||
max_public_statements: 50,
|
max_public_statements: 50,
|
||||||
num_public_statements_id: 50,
|
num_public_statements_id: 50,
|
||||||
|
|
|
||||||
|
|
@ -61,7 +61,7 @@ impl SignedPodBuilder {
|
||||||
/// SignedPod is a wrapper on top of backend::SignedPod, which additionally stores the
|
/// SignedPod is a wrapper on top of backend::SignedPod, which additionally stores the
|
||||||
/// string<-->hash relation of the keys.
|
/// string<-->hash relation of the keys.
|
||||||
#[derive(Debug, Clone, Serialize, Deserialize)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
#[serde(from = "SerializedSignedPod", into = "SerializedSignedPod")]
|
#[serde(try_from = "SerializedSignedPod", into = "SerializedSignedPod")]
|
||||||
pub struct SignedPod {
|
pub struct SignedPod {
|
||||||
pub pod: Box<dyn middleware::Pod>,
|
pub pod: Box<dyn middleware::Pod>,
|
||||||
// We store a copy of the key values for quick access
|
// We store a copy of the key values for quick access
|
||||||
|
|
|
||||||
|
|
@ -1,20 +1,10 @@
|
||||||
use std::{any::Any, collections::HashMap};
|
|
||||||
|
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use super::Error;
|
use super::Error;
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
|
||||||
mainpod::{pad_statement, MainPod as Plonky2MainPod, Statement as BackendStatement},
|
|
||||||
mock::{mainpod::MockMainPod, signedpod::MockSignedPod},
|
|
||||||
signedpod::SignedPod as Plonky2SignedPod,
|
|
||||||
},
|
|
||||||
frontend::{MainPod, SignedPod},
|
frontend::{MainPod, SignedPod},
|
||||||
middleware::{
|
middleware::{deserialize_pod, deserialize_signed_pod, Hash, Params, PodId},
|
||||||
self, containers::Dictionary, serialization::ordered_map, AnchoredKey, Hash, Key, Params,
|
|
||||||
PodId, Statement, StatementArg, Value, EMPTY_HASH, SELF,
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||||
|
|
@ -27,102 +17,54 @@ pub enum SignedPodType {
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[schemars(rename = "SignedPod")]
|
#[schemars(rename = "SignedPod")]
|
||||||
pub struct SerializedSignedPod {
|
pub struct SerializedSignedPod {
|
||||||
|
pod_type: (usize, String),
|
||||||
id: PodId,
|
id: PodId,
|
||||||
#[serde(serialize_with = "ordered_map")]
|
data: serde_json::Value,
|
||||||
entries: HashMap<Key, Value>,
|
|
||||||
proof: String,
|
|
||||||
pod_type: SignedPodType,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
|
||||||
pub enum MainPodType {
|
|
||||||
Main,
|
|
||||||
MockMain,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||||
#[serde(rename_all = "camelCase")]
|
#[serde(rename_all = "camelCase")]
|
||||||
#[schemars(rename = "MainPod")]
|
#[schemars(rename = "MainPod")]
|
||||||
pub struct SerializedMainPod {
|
pub struct SerializedMainPod {
|
||||||
|
params: Params,
|
||||||
|
pod_type: (usize, String),
|
||||||
id: PodId,
|
id: PodId,
|
||||||
vds_root: Hash,
|
vds_root: Hash,
|
||||||
public_statements: Vec<Statement>,
|
data: serde_json::Value,
|
||||||
proof: String,
|
|
||||||
params: Params,
|
|
||||||
pod_type: MainPodType,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SignedPod> for SerializedSignedPod {
|
impl From<SignedPod> for SerializedSignedPod {
|
||||||
fn from(pod: SignedPod) -> Self {
|
fn from(pod: SignedPod) -> Self {
|
||||||
|
let (pod_type, pod_type_name_str) = pod.pod.pod_type();
|
||||||
|
let data = pod.pod.serialize_data();
|
||||||
SerializedSignedPod {
|
SerializedSignedPod {
|
||||||
|
pod_type: (pod_type, pod_type_name_str.to_string()),
|
||||||
id: pod.id(),
|
id: pod.id(),
|
||||||
entries: pod.kvs,
|
data,
|
||||||
proof: pod.pod.serialized_proof(),
|
|
||||||
pod_type: if (&*pod.pod as &dyn Any)
|
|
||||||
.downcast_ref::<Plonky2SignedPod>()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
SignedPodType::Signed
|
|
||||||
} else if (&*pod.pod as &dyn Any)
|
|
||||||
.downcast_ref::<MockSignedPod>()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
SignedPodType::MockSigned
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<SerializedSignedPod> for SignedPod {
|
impl TryFrom<SerializedSignedPod> for SignedPod {
|
||||||
fn from(serialized: SerializedSignedPod) -> Self {
|
type Error = Error;
|
||||||
match serialized.pod_type {
|
|
||||||
SignedPodType::Signed => {
|
fn try_from(serialized: SerializedSignedPod) -> Result<Self, Self::Error> {
|
||||||
let (signer, signature) =
|
let pod = deserialize_signed_pod(serialized.pod_type.0, serialized.id, serialized.data)?;
|
||||||
Plonky2SignedPod::decode_proof(&serialized.proof).unwrap();
|
let kvs = pod.kvs().into_iter().map(|(ak, v)| (ak.key, v)).collect();
|
||||||
SignedPod {
|
Ok(Self { pod, kvs })
|
||||||
pod: Box::new(Plonky2SignedPod {
|
|
||||||
id: serialized.id,
|
|
||||||
signer,
|
|
||||||
signature,
|
|
||||||
dict: Dictionary::new(serialized.entries.clone()).unwrap(),
|
|
||||||
}),
|
|
||||||
kvs: serialized.entries,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
SignedPodType::MockSigned => SignedPod {
|
|
||||||
pod: Box::new(MockSignedPod::new(
|
|
||||||
serialized.id,
|
|
||||||
serde_json::from_str(&serialized.proof).unwrap(),
|
|
||||||
serialized.entries.clone(),
|
|
||||||
)),
|
|
||||||
kvs: serialized.entries,
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl From<MainPod> for SerializedMainPod {
|
impl From<MainPod> for SerializedMainPod {
|
||||||
fn from(pod: MainPod) -> Self {
|
fn from(pod: MainPod) -> Self {
|
||||||
let (pod_type, vds_root) =
|
let (pod_type, pod_type_name_str) = pod.pod.pod_type();
|
||||||
if let Some(pod) = (&*pod.pod as &dyn Any).downcast_ref::<Plonky2MainPod>() {
|
let data = pod.pod.serialize_data();
|
||||||
(MainPodType::Main, pod.vds_root())
|
|
||||||
} else if (&*pod.pod as &dyn Any)
|
|
||||||
.downcast_ref::<MockMainPod>()
|
|
||||||
.is_some()
|
|
||||||
{
|
|
||||||
(MainPodType::MockMain, EMPTY_HASH)
|
|
||||||
} else {
|
|
||||||
unreachable!()
|
|
||||||
};
|
|
||||||
SerializedMainPod {
|
SerializedMainPod {
|
||||||
|
pod_type: (pod_type, pod_type_name_str.to_string()),
|
||||||
id: pod.id(),
|
id: pod.id(),
|
||||||
vds_root,
|
vds_root: pod.pod.vds_root(),
|
||||||
proof: pod.pod.serialized_proof(),
|
|
||||||
params: pod.params.clone(),
|
params: pod.params.clone(),
|
||||||
pod_type,
|
data,
|
||||||
public_statements: pod.public_statements.clone(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -131,76 +73,20 @@ impl TryFrom<SerializedMainPod> for MainPod {
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
||||||
fn try_from(serialized: SerializedMainPod) -> Result<Self, Self::Error> {
|
fn try_from(serialized: SerializedMainPod) -> Result<Self, Self::Error> {
|
||||||
match serialized.pod_type {
|
let pod = deserialize_pod(
|
||||||
MainPodType::Main => Ok(MainPod {
|
serialized.pod_type.0,
|
||||||
pod: Box::new(Plonky2MainPod::new(
|
serialized.params.clone(),
|
||||||
Plonky2MainPod::decode_proof(&serialized.proof, &serialized.params).map_err(
|
|
||||||
|e| {
|
|
||||||
Error::custom(format!(
|
|
||||||
"Failed to deserialize MainPod proof: {}. Value: {}",
|
|
||||||
e, serialized.proof
|
|
||||||
))
|
|
||||||
},
|
|
||||||
)?,
|
|
||||||
middleware_statements_to_backend(
|
|
||||||
serialized.public_statements.clone(),
|
|
||||||
&serialized.params,
|
|
||||||
serialized.id,
|
|
||||||
),
|
|
||||||
serialized.id,
|
serialized.id,
|
||||||
serialized.vds_root,
|
serialized.vds_root,
|
||||||
serialized.params.clone(),
|
serialized.data,
|
||||||
)),
|
)?;
|
||||||
public_statements: serialized.public_statements,
|
let public_statements = pod.pub_statements();
|
||||||
|
Ok(Self {
|
||||||
|
pod,
|
||||||
|
public_statements,
|
||||||
params: serialized.params,
|
params: serialized.params,
|
||||||
}),
|
|
||||||
MainPodType::MockMain => Ok(MainPod {
|
|
||||||
pod: Box::new(
|
|
||||||
MockMainPod::deserialize(serialized.proof.clone()).map_err(|e| {
|
|
||||||
Error::custom(format!(
|
|
||||||
"Failed to deserialize MockMainPod: {}. Value: {}",
|
|
||||||
e, serialized.proof
|
|
||||||
))
|
|
||||||
})?,
|
|
||||||
),
|
|
||||||
public_statements: serialized.public_statements,
|
|
||||||
params: serialized.params,
|
|
||||||
}),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// To deserialize a backend MainPod, we need to convert the middleware
|
|
||||||
// statements to backend statements, and padding the list with None statements.
|
|
||||||
fn middleware_statements_to_backend(
|
|
||||||
mid_statements: Vec<Statement>,
|
|
||||||
params: &Params,
|
|
||||||
id: PodId,
|
|
||||||
) -> Vec<BackendStatement> {
|
|
||||||
let mut statements = Vec::new();
|
|
||||||
for i in 0..(params.max_public_statements) {
|
|
||||||
let mut st: BackendStatement = mid_statements
|
|
||||||
.get(i)
|
|
||||||
.unwrap_or(&middleware::Statement::None)
|
|
||||||
.clone()
|
|
||||||
.into();
|
|
||||||
|
|
||||||
st = BackendStatement(
|
|
||||||
st.0.clone(),
|
|
||||||
st.1.iter()
|
|
||||||
.map(|sa| match &sa {
|
|
||||||
StatementArg::Key(AnchoredKey { pod_id, key }) if *pod_id == id => {
|
|
||||||
StatementArg::Key(AnchoredKey::new(SELF, key.clone()))
|
|
||||||
}
|
|
||||||
_ => sa.clone(),
|
|
||||||
})
|
})
|
||||||
.collect(),
|
|
||||||
);
|
|
||||||
pad_statement(params, &mut st);
|
|
||||||
statements.push(st);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
statements
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
|
|
@ -225,7 +111,7 @@ mod tests {
|
||||||
frontend::{Result, SignedPodBuilder},
|
frontend::{Result, SignedPodBuilder},
|
||||||
middleware::{
|
middleware::{
|
||||||
self,
|
self,
|
||||||
containers::{Array, Set},
|
containers::{Array, Dictionary, Set},
|
||||||
Params, TypedValue,
|
Params, TypedValue,
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -46,6 +46,8 @@ use super::serialization::*;
|
||||||
// types would come from the plonky3 backend.
|
// types would come from the plonky3 backend.
|
||||||
#[cfg(feature = "backend_plonky2")]
|
#[cfg(feature = "backend_plonky2")]
|
||||||
pub use crate::backends::plonky2::basetypes::*;
|
pub use crate::backends::plonky2::basetypes::*;
|
||||||
|
#[cfg(feature = "backend_plonky2")]
|
||||||
|
pub use crate::backends::plonky2::{Error as BackendError, Result as BackendResult};
|
||||||
use crate::middleware::{Params, ToFields, Value};
|
use crate::middleware::{Params, ToFields, Value};
|
||||||
|
|
||||||
pub const HASH_SIZE: usize = 4;
|
pub const HASH_SIZE: usize = 4;
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,8 @@
|
||||||
//! the backend.
|
//! the backend.
|
||||||
|
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use strum_macros::FromRepr;
|
||||||
mod basetypes;
|
mod basetypes;
|
||||||
use std::{
|
use std::{
|
||||||
cmp::{Ordering, PartialEq, PartialOrd},
|
cmp::{Ordering, PartialEq, PartialOrd},
|
||||||
|
|
@ -15,6 +17,7 @@ pub mod containers;
|
||||||
mod custom;
|
mod custom;
|
||||||
mod error;
|
mod error;
|
||||||
mod operation;
|
mod operation;
|
||||||
|
mod pod_deserialization;
|
||||||
pub mod serialization;
|
pub mod serialization;
|
||||||
mod statement;
|
mod statement;
|
||||||
use std::{any::Any, collections::HashMap, fmt};
|
use std::{any::Any, collections::HashMap, fmt};
|
||||||
|
|
@ -24,6 +27,7 @@ pub use custom::*;
|
||||||
use dyn_clone::DynClone;
|
use dyn_clone::DynClone;
|
||||||
pub use error::*;
|
pub use error::*;
|
||||||
pub use operation::*;
|
pub use operation::*;
|
||||||
|
pub use pod_deserialization::*;
|
||||||
use serialization::*;
|
use serialization::*;
|
||||||
pub use statement::*;
|
pub use statement::*;
|
||||||
|
|
||||||
|
|
@ -565,7 +569,7 @@ impl ToFields for PodId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, FromRepr, Serialize, Deserialize, JsonSchema)]
|
||||||
pub enum PodType {
|
pub enum PodType {
|
||||||
None = 0,
|
None = 0,
|
||||||
MockSigned = 1,
|
MockSigned = 1,
|
||||||
|
|
@ -636,7 +640,8 @@ impl Default for Params {
|
||||||
max_signed_pod_values: 8,
|
max_signed_pod_values: 8,
|
||||||
max_public_statements: 10,
|
max_public_statements: 10,
|
||||||
num_public_statements_id: 16,
|
num_public_statements_id: 16,
|
||||||
max_statement_args: 5,
|
// TODO: Reduce to 5 or less after https://github.com/0xPARC/pod2/issues/229
|
||||||
|
max_statement_args: 6,
|
||||||
max_operation_args: 5,
|
max_operation_args: 5,
|
||||||
max_custom_predicate_batches: 2,
|
max_custom_predicate_batches: 2,
|
||||||
max_custom_predicate_verifications: 5,
|
max_custom_predicate_verifications: 5,
|
||||||
|
|
@ -735,6 +740,8 @@ pub trait Pod: fmt::Debug + DynClone + Any {
|
||||||
fn params(&self) -> &Params;
|
fn params(&self) -> &Params;
|
||||||
fn verify(&self) -> Result<(), Box<DynError>>;
|
fn verify(&self) -> Result<(), Box<DynError>>;
|
||||||
fn id(&self) -> PodId;
|
fn id(&self) -> PodId;
|
||||||
|
/// Return a uuid of the pod type and its name. The name is only used as metadata.
|
||||||
|
fn pod_type(&self) -> (usize, &'static str);
|
||||||
/// Statements as internally generated, where self-referencing arguments use SELF in the
|
/// Statements as internally generated, where self-referencing arguments use SELF in the
|
||||||
/// anchored key. The serialization of these statements is used to calculate the id.
|
/// anchored key. The serialization of these statements is used to calculate the id.
|
||||||
fn pub_self_statements(&self) -> Vec<Statement>;
|
fn pub_self_statements(&self) -> Vec<Statement>;
|
||||||
|
|
@ -746,6 +753,9 @@ pub trait Pod: fmt::Debug + DynClone + Any {
|
||||||
.map(|statement| normalize_statement(&statement, self.id()))
|
.map(|statement| normalize_statement(&statement, self.id()))
|
||||||
.collect()
|
.collect()
|
||||||
}
|
}
|
||||||
|
/// Return this Pods data serialized into a json value. This serialization can skip `params,
|
||||||
|
/// id, vds_root`
|
||||||
|
fn serialize_data(&self) -> serde_json::Value;
|
||||||
/// Extract key-values from ValueOf public statements
|
/// Extract key-values from ValueOf public statements
|
||||||
fn kvs(&self) -> HashMap<AnchoredKey, Value> {
|
fn kvs(&self) -> HashMap<AnchoredKey, Value> {
|
||||||
self.pub_statements()
|
self.pub_statements()
|
||||||
|
|
@ -767,7 +777,7 @@ pub trait Pod: fmt::Debug + DynClone + Any {
|
||||||
// reconstruct the proof.
|
// reconstruct the proof.
|
||||||
// It is an important principle that this data is opaque to the front-end
|
// It is an important principle that this data is opaque to the front-end
|
||||||
// and any third-party code.
|
// and any third-party code.
|
||||||
fn serialized_proof(&self) -> String;
|
// fn serialized_proof(&self) -> String;
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl Clone for Box<dyn Pod>
|
// impl Clone for Box<dyn Pod>
|
||||||
|
|
@ -810,11 +820,14 @@ impl Pod for NonePod {
|
||||||
fn id(&self) -> PodId {
|
fn id(&self) -> PodId {
|
||||||
PodId(EMPTY_HASH)
|
PodId(EMPTY_HASH)
|
||||||
}
|
}
|
||||||
|
fn pod_type(&self) -> (usize, &'static str) {
|
||||||
|
(PodType::None as usize, "None")
|
||||||
|
}
|
||||||
fn pub_self_statements(&self) -> Vec<Statement> {
|
fn pub_self_statements(&self) -> Vec<Statement> {
|
||||||
Vec::new()
|
Vec::new()
|
||||||
}
|
}
|
||||||
fn serialized_proof(&self) -> String {
|
fn serialize_data(&self) -> serde_json::Value {
|
||||||
"".to_string()
|
serde_json::Value::Null
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
93
src/middleware/pod_deserialization.rs
Normal file
93
src/middleware/pod_deserialization.rs
Normal file
|
|
@ -0,0 +1,93 @@
|
||||||
|
use std::{
|
||||||
|
collections::HashMap,
|
||||||
|
sync::{LazyLock, Mutex},
|
||||||
|
};
|
||||||
|
|
||||||
|
use crate::middleware::{
|
||||||
|
BackendResult, Error, Hash, Params, Pod, PodId, PodType, RecursivePod, Result,
|
||||||
|
};
|
||||||
|
|
||||||
|
type DeserializeFn = fn(
|
||||||
|
params: Params,
|
||||||
|
id: PodId,
|
||||||
|
vds_root: Hash,
|
||||||
|
data: serde_json::Value,
|
||||||
|
) -> BackendResult<Box<dyn RecursivePod>>;
|
||||||
|
|
||||||
|
static DESERIALIZERS: LazyLock<Mutex<HashMap<usize, DeserializeFn>>> =
|
||||||
|
LazyLock::new(backend::deserializers_default);
|
||||||
|
|
||||||
|
pub fn register_pod_deserializer(pod_type: usize, deserialize_fn: DeserializeFn) {
|
||||||
|
DESERIALIZERS
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.insert(pod_type, deserialize_fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_pod(
|
||||||
|
pod_type: usize,
|
||||||
|
params: Params,
|
||||||
|
id: PodId,
|
||||||
|
vds_root: Hash,
|
||||||
|
data: serde_json::Value,
|
||||||
|
) -> Result<Box<dyn RecursivePod>> {
|
||||||
|
let deserialize_fn: DeserializeFn =
|
||||||
|
*DESERIALIZERS
|
||||||
|
.lock()
|
||||||
|
.unwrap()
|
||||||
|
.get(&pod_type)
|
||||||
|
.ok_or(Error::custom(format!(
|
||||||
|
"pod deserializer for pod_type={} not registered. See https://github.com/0xPARC/pod2/wiki/PodType for pod type assignments.",
|
||||||
|
pod_type
|
||||||
|
)))?;
|
||||||
|
|
||||||
|
deserialize_fn(params, id, vds_root, data)
|
||||||
|
.map_err(|e| Error::custom(format!("deserialize error: {:?}", e)))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_signed_pod(
|
||||||
|
pod_type: usize,
|
||||||
|
id: PodId,
|
||||||
|
data: serde_json::Value,
|
||||||
|
) -> Result<Box<dyn Pod>> {
|
||||||
|
backend::deserialize_signed_pod(pod_type, id, data)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(feature = "backend_plonky2")]
|
||||||
|
mod backend {
|
||||||
|
use super::*;
|
||||||
|
use crate::backends::plonky2::{
|
||||||
|
emptypod::EmptyPod,
|
||||||
|
mainpod::MainPod,
|
||||||
|
mock::{emptypod::MockEmptyPod, mainpod::MockMainPod, signedpod::MockSignedPod},
|
||||||
|
signedpod::SignedPod,
|
||||||
|
};
|
||||||
|
|
||||||
|
pub(super) fn deserializers_default() -> Mutex<HashMap<usize, DeserializeFn>> {
|
||||||
|
let mut map: HashMap<usize, DeserializeFn> = HashMap::new();
|
||||||
|
map.insert(PodType::Empty as usize, EmptyPod::deserialize);
|
||||||
|
map.insert(PodType::Main as usize, MainPod::deserialize);
|
||||||
|
map.insert(PodType::MockEmpty as usize, MockEmptyPod::deserialize);
|
||||||
|
map.insert(PodType::MockMain as usize, MockMainPod::deserialize);
|
||||||
|
Mutex::new(map)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn deserialize_signed_pod(
|
||||||
|
pod_type: usize,
|
||||||
|
id: PodId,
|
||||||
|
data: serde_json::Value,
|
||||||
|
) -> Result<Box<dyn Pod>> {
|
||||||
|
if pod_type == PodType::MockSigned as usize {
|
||||||
|
MockSignedPod::deserialize(id, data)
|
||||||
|
.map_err(|e| Error::custom(format!("deserialize error: {:?}", e)))
|
||||||
|
} else if pod_type == PodType::Signed as usize {
|
||||||
|
SignedPod::deserialize(id, data)
|
||||||
|
.map_err(|e| Error::custom(format!("deserialize error: {:?}", e)))
|
||||||
|
} else {
|
||||||
|
Err(Error::custom(format!(
|
||||||
|
"unexpected pod_type={} for deserialize_signed_pod",
|
||||||
|
pod_type
|
||||||
|
)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue