Serialization of Signed and Main Pods (#128)

This commit is contained in:
Rob Knight 2025-03-21 14:42:16 +01:00 committed by GitHub
parent fee70af12b
commit 9afc43675d
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
16 changed files with 817 additions and 189 deletions

View file

@ -4,18 +4,19 @@ use std::{fmt, hash as h, iter, iter::zip};
use anyhow::{anyhow, Result};
use plonky2::field::types::Field;
use crate::backends::plonky2::basetypes::HASH_SIZE;
use crate::util::hashmap_insert_no_dupe;
use schemars::JsonSchema;
use super::{
hash_fields, AnchoredKey, Hash, NativePredicate, Params, PodId, Statement, StatementArg,
ToFields, Value, F,
};
use crate::backends::plonky2::basetypes::HASH_SIZE;
use crate::util::hashmap_insert_no_dupe;
use serde::{Deserialize, Serialize};
// BEGIN Custom 1b
#[derive(Clone, Debug, PartialEq, Eq, h::Hash)]
#[derive(Clone, Debug, PartialEq, Eq, h::Hash, Serialize, Deserialize, JsonSchema)]
pub enum HashOrWildcard {
Hash(Hash),
Wildcard(usize),
@ -59,7 +60,7 @@ impl ToFields for HashOrWildcard {
}
}
#[derive(Clone, Debug, PartialEq, Eq, h::Hash)]
#[derive(Clone, Debug, PartialEq, Eq, h::Hash, Serialize, Deserialize, JsonSchema)]
pub enum StatementTmplArg {
None,
Literal(Value),
@ -145,7 +146,7 @@ impl fmt::Display for StatementTmplArg {
// END
/// Statement Template for a Custom Predicate
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct StatementTmpl(pub Predicate, pub Vec<StatementTmplArg>);
impl StatementTmpl {
@ -199,7 +200,7 @@ impl ToFields for StatementTmpl {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct CustomPredicate {
/// NOTE: fields are not public (outside of crate) to enforce the struct instantiation through
/// the `::and/or` methods, which performs checks on the values.
@ -287,7 +288,7 @@ impl fmt::Display for CustomPredicate {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct CustomPredicateBatch {
pub name: String,
pub predicates: Vec<CustomPredicate>,
@ -324,7 +325,7 @@ impl CustomPredicateBatch {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
pub struct CustomPredicateRef(pub Arc<CustomPredicateBatch>, pub usize);
impl CustomPredicateRef {
@ -383,7 +384,8 @@ impl CustomPredicateRef {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
#[serde(tag = "type", content = "value")]
pub enum Predicate {
Native(NativePredicate),
BatchSelf(usize),

View file

@ -5,14 +5,17 @@ mod basetypes;
pub mod containers;
mod custom;
mod operation;
pub mod serialization;
mod statement;
pub use basetypes::*;
pub use custom::*;
pub use operation::*;
use schemars::JsonSchema;
pub use statement::*;
use anyhow::Result;
use dyn_clone::DynClone;
use serde::{Deserialize, Serialize};
use std::any::Any;
use std::collections::HashMap;
use std::fmt;
@ -32,7 +35,7 @@ impl fmt::Display for PodId {
}
/// AnchoredKey is a tuple containing (OriginId: PodId, key: Hash)
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct AnchoredKey(pub PodId, pub Hash);
impl AnchoredKey {
@ -54,7 +57,7 @@ impl fmt::Display for AnchoredKey {
/// An entry consists of a key-value pair.
pub type Entry = (String, Value);
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize, JsonSchema)]
pub struct PodId(pub Hash);
impl ToFields for PodId {
@ -77,7 +80,7 @@ impl From<PodType> for Value {
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct Params {
pub max_input_signed_pods: usize,
pub max_input_main_pods: usize,
@ -166,6 +169,15 @@ pub trait Pod: fmt::Debug + DynClone {
}
// Used for downcasting
fn into_any(self: Box<Self>) -> Box<dyn Any>;
// Front-end Pods keep references to middleware Pods. Most of the
// middleware data can be derived directly from front-end data, but the
// "proof" data is only created at the point of proving/signing, and
// cannot be reconstructed. As such, we need to serialize it whenever
// we serialize a front-end Pod. Since the front-end does not understand
// the implementation details of the middleware, this method allows the
// middleware to provide some serialized data that can be used to
// reconstruct the proof.
fn serialized_proof(&self) -> String;
}
// impl Clone for Box<dyn SignedPod>
@ -193,6 +205,9 @@ impl Pod for NonePod {
fn into_any(self: Box<Self>) -> Box<dyn Any> {
self
}
fn serialized_proof(&self) -> String {
"".to_string()
}
}
#[derive(Debug)]

View file

@ -1,18 +1,18 @@
use std::fmt;
use anyhow::{anyhow, Result};
use log::error;
use serde::{Deserialize, Serialize};
use std::fmt;
use super::{CustomPredicateRef, NativePredicate, Statement, StatementArg};
use crate::middleware::{AnchoredKey, Params, Predicate, Value, SELF};
#[derive(Clone, Debug, PartialEq, Eq)]
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum OperationType {
Native(NativeOperation),
Custom(CustomPredicateRef),
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum NativeOperation {
None = 0,
NewEntry = 1,
@ -91,7 +91,7 @@ pub enum Operation {
}
impl Operation {
pub fn code(&self) -> OperationType {
pub fn predicate(&self) -> OperationType {
type OT = OperationType;
use NativeOperation::*;
match self {
@ -178,7 +178,7 @@ impl Operation {
/// The outer Result is error handling
pub fn output_statement(&self) -> Result<Option<Statement>> {
use Statement::*;
let pred: Option<Predicate> = self.code().output_predicate();
let pred: Option<Predicate> = self.predicate().output_predicate();
let st_args: Option<Vec<StatementArg>> = match self {
Self::None => Some(vec![]),
@ -404,7 +404,7 @@ impl Operation {
impl fmt::Display for Operation {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
writeln!(f, "middleware::Operation:")?;
writeln!(f, " {:?} ", self.code())?;
writeln!(f, " {:?} ", self.predicate())?;
for arg in self.args().iter() {
writeln!(f, " {}", arg)?;
}

View file

@ -0,0 +1,69 @@
use plonky2::field::types::Field;
use serde::Deserialize;
use super::{F, HASH_SIZE, VALUE_SIZE};
fn serialize_field_tuple<S, const N: usize>(
value: &[F; N],
serializer: S,
) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.serialize_str(&format!(
"{:016x}{:016x}{:016x}{:016x}",
value[0].0, value[1].0, value[2].0, value[3].0
))
}
fn deserialize_field_tuple<'de, D, const N: usize>(deserializer: D) -> Result<[F; N], D::Error>
where
D: serde::Deserializer<'de>,
{
let hex_str = String::deserialize(deserializer)?;
if !hex_str.chars().count() == 64 || !hex_str.chars().all(|c| c.is_ascii_hexdigit()) {
return Err(serde::de::Error::custom(
"Invalid hex string format - expected 64 hexadecimal characters",
));
}
let mut v = [F::ZERO; N];
for i in 0..N {
let start = i * 16;
let end = start + 16;
let hex_part = &hex_str[start..end];
v[i] = F::from_canonical_u64(
u64::from_str_radix(hex_part, 16).map_err(serde::de::Error::custom)?,
);
}
Ok(v)
}
pub fn serialize_hash_tuple<S>(value: &[F; HASH_SIZE], serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serialize_field_tuple::<S, HASH_SIZE>(value, serializer)
}
pub fn deserialize_hash_tuple<'de, D>(deserializer: D) -> Result<[F; HASH_SIZE], D::Error>
where
D: serde::Deserializer<'de>,
{
deserialize_field_tuple::<D, HASH_SIZE>(deserializer)
}
pub fn serialize_value_tuple<S>(value: &[F; VALUE_SIZE], serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serialize_field_tuple::<S, VALUE_SIZE>(value, serializer)
}
pub fn deserialize_value_tuple<'de, D>(deserializer: D) -> Result<[F; VALUE_SIZE], D::Error>
where
D: serde::Deserializer<'de>,
{
deserialize_field_tuple::<D, VALUE_SIZE>(deserializer)
}

View file

@ -1,5 +1,7 @@
use anyhow::{anyhow, Result};
use plonky2::field::types::Field;
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use std::{fmt, iter};
use strum_macros::FromRepr;
@ -9,7 +11,7 @@ pub const KEY_SIGNER: &str = "_signer";
pub const KEY_TYPE: &str = "_type";
pub const STATEMENT_ARG_F_LEN: usize = 8;
#[derive(Clone, Copy, Debug, FromRepr, PartialEq, Eq, Hash)]
#[derive(Clone, Copy, Debug, FromRepr, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
pub enum NativePredicate {
None = 0,
ValueOf = 1,
@ -203,7 +205,7 @@ impl fmt::Display for Statement {
}
/// Statement argument type. Useful for statement decompositions.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum StatementArg {
None,
Literal(Value),