Re-implement serialization (#201)
* Serialization tests now pass again * Tidy up and test more edge-cases * Use attributes rather than custom serializer for arrays * Add JSON Schema support * Tests for JSON Schema generation and validation * Add comments * Support custom predicates * Clippy fixes * Make deserialization/constructor functions pub(crate)
This commit is contained in:
parent
26a6b2d143
commit
bf6d8aee8b
17 changed files with 554 additions and 255 deletions
|
|
@ -22,12 +22,17 @@ plonky2 = { git = "https://github.com/0xPolygonZero/plonky2", optional = true }
|
||||||
serde = "1.0.219"
|
serde = "1.0.219"
|
||||||
serde_json = "1.0.140"
|
serde_json = "1.0.140"
|
||||||
base64 = "0.22.1"
|
base64 = "0.22.1"
|
||||||
schemars = "1.0.0-alpha.17"
|
schemars = "0.8.22"
|
||||||
|
|
||||||
# Uncomment for debugging with https://github.com/ed255/plonky2/ at branch `feat/debug`. The repo directory needs to be checked out next to the pod2 repo directory.
|
# Uncomment for debugging with https://github.com/ed255/plonky2/ at branch `feat/debug`. The repo directory needs to be checked out next to the pod2 repo directory.
|
||||||
# [patch."https://github.com/0xPolygonZero/plonky2"]
|
# [patch."https://github.com/0xPolygonZero/plonky2"]
|
||||||
# plonky2 = { path = "../plonky2/plonky2" }
|
# plonky2 = { path = "../plonky2/plonky2" }
|
||||||
|
|
||||||
|
[dev-dependencies]
|
||||||
|
pretty_assertions = "1.4.1"
|
||||||
|
# Used only for testing JSON Schema generation and validation.
|
||||||
|
jsonschema = "0.30.0"
|
||||||
|
|
||||||
[features]
|
[features]
|
||||||
default = ["backend_plonky2"]
|
default = ["backend_plonky2"]
|
||||||
backend_plonky2 = ["plonky2"]
|
backend_plonky2 = ["plonky2"]
|
||||||
|
|
|
||||||
|
|
@ -2,14 +2,14 @@ use std::fmt;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// use serde::{Deserialize, Serialize};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{mainpod::Statement, primitives::merkletree::MerkleClaimAndProof},
|
backends::plonky2::{mainpod::Statement, primitives::merkletree::MerkleClaimAndProof},
|
||||||
middleware::{self, OperationType, Params, ToFields, F},
|
middleware::{self, OperationType, Params, ToFields, F},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum OperationArg {
|
pub enum OperationArg {
|
||||||
None,
|
None,
|
||||||
Index(usize),
|
Index(usize),
|
||||||
|
|
@ -31,7 +31,7 @@ impl OperationArg {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum OperationAux {
|
pub enum OperationAux {
|
||||||
None,
|
None,
|
||||||
MerkleProofIndex(usize),
|
MerkleProofIndex(usize),
|
||||||
|
|
@ -47,7 +47,7 @@ impl ToFields for OperationAux {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Operation(pub OperationType, pub Vec<OperationArg>, pub OperationAux);
|
pub struct Operation(pub OperationType, pub Vec<OperationArg>, pub OperationAux);
|
||||||
|
|
||||||
impl Operation {
|
impl Operation {
|
||||||
|
|
|
||||||
|
|
@ -1,13 +1,13 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// use serde::{Deserialize, Serialize};
|
|
||||||
use crate::middleware::{
|
use crate::middleware::{
|
||||||
self, NativePredicate, Params, Predicate, StatementArg, ToFields, WildcardValue,
|
self, NativePredicate, Params, Predicate, StatementArg, ToFields, WildcardValue,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct Statement(pub Predicate, pub Vec<StatementArg>);
|
pub struct Statement(pub Predicate, pub Vec<StatementArg>);
|
||||||
|
|
||||||
impl Statement {
|
impl Statement {
|
||||||
|
|
|
||||||
|
|
@ -5,15 +5,15 @@
|
||||||
use std::{any::Any, fmt};
|
use std::{any::Any, fmt};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
use base64::{prelude::BASE64_STANDARD, Engine};
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// use base64::prelude::*;
|
|
||||||
// use serde::{Deserialize, Serialize};
|
|
||||||
use crate::backends::plonky2::mainpod::process_private_statements_operations;
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::{
|
backends::plonky2::{
|
||||||
mainpod::{
|
mainpod::{
|
||||||
extract_merkle_proofs, hash_statements, layout_statements, normalize_statement,
|
extract_merkle_proofs, hash_statements, layout_statements, normalize_statement,
|
||||||
process_public_statements_operations, Operation, Statement,
|
process_private_statements_operations, process_public_statements_operations, Operation,
|
||||||
|
Statement,
|
||||||
},
|
},
|
||||||
primitives::merkletree::MerkleClaimAndProof,
|
primitives::merkletree::MerkleClaimAndProof,
|
||||||
},
|
},
|
||||||
|
|
@ -31,7 +31,7 @@ impl PodProver for MockProver {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||||
pub struct MockMainPod {
|
pub struct MockMainPod {
|
||||||
params: Params,
|
params: Params,
|
||||||
id: PodId,
|
id: PodId,
|
||||||
|
|
@ -166,14 +166,17 @@ impl MockMainPod {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
// pub fn deserialize(serialized: String) -> Result<Self> {
|
// MockMainPods include some internal private state which is necessary
|
||||||
// let proof = String::from_utf8(BASE64_STANDARD.decode(&serialized)?)
|
// for verification. In non-mock Pods, this state will not be necessary,
|
||||||
// .map_err(|e| anyhow::anyhow!("Invalid base64 encoding: {}", e))?;
|
// as the public statements can be verified using a ZK proof.
|
||||||
// let pod: MockMainPod = serde_json::from_str(&proof)
|
pub(crate) fn deserialize(serialized: String) -> Result<Self> {
|
||||||
// .map_err(|e| anyhow::anyhow!("Failed to parse proof: {}", e))?;
|
let proof = String::from_utf8(BASE64_STANDARD.decode(&serialized)?)
|
||||||
|
.map_err(|e| anyhow::anyhow!("Invalid base64 encoding: {}", e))?;
|
||||||
|
let pod: MockMainPod = serde_json::from_str(&proof)
|
||||||
|
.map_err(|e| anyhow::anyhow!("Failed to parse proof: {}", e))?;
|
||||||
|
|
||||||
// Ok(pod)
|
Ok(pod)
|
||||||
// }
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Pod for MockMainPod {
|
impl Pod for MockMainPod {
|
||||||
|
|
@ -282,8 +285,7 @@ impl Pod for MockMainPod {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn serialized_proof(&self) -> String {
|
fn serialized_proof(&self) -> String {
|
||||||
todo!()
|
BASE64_STANDARD.encode(serde_json::to_string(self).unwrap())
|
||||||
// BASE64_STANDARD.encode(serde_json::to_string(self).unwrap())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,15 +43,11 @@ pub struct MockSignedPod {
|
||||||
kvs: HashMap<Key, Value>,
|
kvs: HashMap<Key, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl MockSignedPod {
|
impl MockSignedPod {
|
||||||
// pub fn deserialize(id: PodId, signature: String, dict: Dictionary) -> Self {
|
pub(crate) fn new(id: PodId, signature: String, kvs: HashMap<Key, Value>) -> Self {
|
||||||
// Self {
|
Self { id, signature, kvs }
|
||||||
// id,
|
}
|
||||||
// signature,
|
}
|
||||||
// dict,
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
impl Pod for MockSignedPod {
|
impl Pod for MockSignedPod {
|
||||||
fn verify(&self) -> Result<()> {
|
fn verify(&self) -> Result<()> {
|
||||||
|
|
|
||||||
|
|
@ -4,8 +4,8 @@ use std::{collections::HashMap, fmt, iter::IntoIterator};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// use serde::{Deserialize, Serialize};
|
|
||||||
pub use super::merkletree_circuit::*;
|
pub use super::merkletree_circuit::*;
|
||||||
use crate::middleware::{hash_fields, Hash, RawValue, EMPTY_HASH, EMPTY_VALUE, F};
|
use crate::middleware::{hash_fields, Hash, RawValue, EMPTY_HASH, EMPTY_VALUE, F};
|
||||||
|
|
||||||
|
|
@ -208,7 +208,7 @@ impl fmt::Display for MerkleTree {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct MerkleProof {
|
pub struct MerkleProof {
|
||||||
// note: currently we don't use the `_existence` field, we would use if we merge the methods
|
// note: currently we don't use the `_existence` field, we would use if we merge the methods
|
||||||
// `verify` and `verify_nonexistence` into a single one
|
// `verify` and `verify_nonexistence` into a single one
|
||||||
|
|
@ -260,7 +260,7 @@ impl MerkleProof {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub struct MerkleClaimAndProof {
|
pub struct MerkleClaimAndProof {
|
||||||
pub root: Hash,
|
pub root: Hash,
|
||||||
pub key: RawValue,
|
pub key: RawValue,
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ use std::{collections::HashMap, fmt, hash as h, iter, iter::zip, sync::Arc};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
|
|
||||||
// use serde::{Deserialize, Serialize};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
frontend::{AnchoredKey, Statement, StatementArg},
|
frontend::{AnchoredKey, Statement, StatementArg},
|
||||||
middleware::{
|
middleware::{
|
||||||
|
|
|
||||||
|
|
@ -5,10 +5,8 @@ use std::{collections::HashMap, convert::From, fmt};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// use schemars::JsonSchema;
|
|
||||||
|
|
||||||
// use serde::{Deserialize, Serialize};
|
|
||||||
use crate::middleware::{
|
use crate::middleware::{
|
||||||
self, check_st_tmpl, hash_str, AnchoredKey, Key, MainPodInputs, NativeOperation,
|
self, check_st_tmpl, hash_str, AnchoredKey, Key, MainPodInputs, NativeOperation,
|
||||||
NativePredicate, OperationAux, OperationType, Params, PodId, PodProver, PodSigner, Predicate,
|
NativePredicate, OperationAux, OperationType, Params, PodId, PodProver, PodSigner, Predicate,
|
||||||
|
|
@ -17,8 +15,10 @@ use crate::middleware::{
|
||||||
|
|
||||||
mod custom;
|
mod custom;
|
||||||
mod operation;
|
mod operation;
|
||||||
|
mod serialization;
|
||||||
pub use custom::*;
|
pub use custom::*;
|
||||||
pub use operation::*;
|
pub use operation::*;
|
||||||
|
use serialization::*;
|
||||||
|
|
||||||
/// This type is just for presentation purposes.
|
/// This type is just for presentation purposes.
|
||||||
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
#[derive(Clone, Debug, Default, PartialEq, Eq)]
|
||||||
|
|
@ -66,8 +66,8 @@ 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)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
// #[serde(try_from = "SignedPodHelper", into = "SignedPodHelper")]
|
#[serde(try_from = "SignedPodHelper", into = "SignedPodHelper")]
|
||||||
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
|
||||||
|
|
@ -591,8 +591,8 @@ impl MainPodBuilder {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone, Serialize, Deserialize)]
|
||||||
// #[serde(try_from = "MainPodHelper", into = "MainPodHelper")]
|
#[serde(try_from = "MainPodHelper", into = "MainPodHelper")]
|
||||||
pub struct MainPod {
|
pub struct MainPod {
|
||||||
pub pod: Box<dyn middleware::Pod>,
|
pub pod: Box<dyn middleware::Pod>,
|
||||||
pub public_statements: Vec<Statement>,
|
pub public_statements: Vec<Statement>,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,5 @@
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
// use serde::{Deserialize, Serialize};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
frontend::SignedPod,
|
frontend::SignedPod,
|
||||||
middleware::{AnchoredKey, OperationAux, OperationType, Statement, Value},
|
middleware::{AnchoredKey, OperationAux, OperationType, Statement, Value},
|
||||||
|
|
|
||||||
|
|
@ -1,19 +1,19 @@
|
||||||
/*
|
use std::collections::HashMap;
|
||||||
use std::collections::{BTreeMap, HashMap};
|
|
||||||
|
|
||||||
use schemars::{JsonSchema, Schema};
|
use schemars::JsonSchema;
|
||||||
use serde::{Deserialize, Serialize, Serializer};
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::mock::{mainpod::MockMainPod, signedpod::MockSignedPod},
|
backends::plonky2::mock::{mainpod::MockMainPod, signedpod::MockSignedPod},
|
||||||
frontend::{containers::Dictionary, MainPod, SignedPod, Statement, TypedValue},
|
frontend::{MainPod, SignedPod, Statement},
|
||||||
middleware::PodId,
|
middleware::{containers::Dictionary, Key, PodId, Value},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
#[schemars(title = "SignedPod")]
|
#[schemars(title = "SignedPod")]
|
||||||
pub struct SignedPodHelper {
|
pub struct SignedPodHelper {
|
||||||
entries: HashMap<String, TypedValue>,
|
entries: HashMap<Key, Value>,
|
||||||
proof: String,
|
proof: String,
|
||||||
pod_class: String,
|
pod_class: String,
|
||||||
pod_type: String,
|
pod_type: String,
|
||||||
|
|
@ -30,10 +30,8 @@ impl TryFrom<SignedPodHelper> for SignedPod {
|
||||||
return Err(anyhow::anyhow!("pod_type is not Mock"));
|
return Err(anyhow::anyhow!("pod_type is not Mock"));
|
||||||
}
|
}
|
||||||
|
|
||||||
let dict = Dictionary::new(helper.entries.clone())?
|
let dict = Dictionary::new(helper.entries.clone())?.clone();
|
||||||
.middleware_dict()
|
let pod = MockSignedPod::new(PodId(dict.commitment()), helper.proof, dict.kvs().clone());
|
||||||
.clone();
|
|
||||||
let pod = MockSignedPod::deserialize(PodId(dict.commitment()), helper.proof, dict);
|
|
||||||
|
|
||||||
Ok(SignedPod {
|
Ok(SignedPod {
|
||||||
pod: Box::new(pod),
|
pod: Box::new(pod),
|
||||||
|
|
@ -55,6 +53,7 @@ impl From<SignedPod> for SignedPodHelper {
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, JsonSchema)]
|
#[derive(Serialize, Deserialize, JsonSchema)]
|
||||||
#[schemars(title = "MainPod")]
|
#[schemars(title = "MainPod")]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct MainPodHelper {
|
pub struct MainPodHelper {
|
||||||
public_statements: Vec<Statement>,
|
public_statements: Vec<Statement>,
|
||||||
proof: String,
|
proof: String,
|
||||||
|
|
@ -94,76 +93,29 @@ impl From<MainPod> for MainPodHelper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn serialize_i64<S>(value: &i64, serializer: S) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: serde::Serializer,
|
|
||||||
{
|
|
||||||
serializer.serialize_str(&value.to_string())
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn deserialize_i64<'de, D>(deserializer: D) -> Result<i64, D::Error>
|
|
||||||
where
|
|
||||||
D: serde::Deserializer<'de>,
|
|
||||||
{
|
|
||||||
String::deserialize(deserializer)?
|
|
||||||
.parse()
|
|
||||||
.map_err(serde::de::Error::custom)
|
|
||||||
}
|
|
||||||
|
|
||||||
// HashMap is not ordered, but we want our dictionaries to be ordered
|
|
||||||
// by key for serialization, so we turn HashMaps into BTreeMaps.
|
|
||||||
pub fn ordered_map<S, K: Ord + Serialize, V: Serialize>(
|
|
||||||
value: &HashMap<K, V>,
|
|
||||||
serializer: S,
|
|
||||||
) -> Result<S::Ok, S::Error>
|
|
||||||
where
|
|
||||||
S: Serializer,
|
|
||||||
{
|
|
||||||
let ordered: BTreeMap<_, _> = value.iter().collect();
|
|
||||||
ordered.serialize(serializer)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn transform_value_schema(schema: &mut Schema) {
|
|
||||||
let obj = schema.as_object_mut().unwrap();
|
|
||||||
|
|
||||||
// Get the oneOf array which contains our variant schemas
|
|
||||||
if let Some(one_of_container) = obj.get_mut("oneOf") {
|
|
||||||
if let Some(variants) = one_of_container.as_array_mut() {
|
|
||||||
// Add String variant (untagged)
|
|
||||||
variants.push(serde_json::json!({
|
|
||||||
"type": "string"
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Add Boolean variant (untagged)
|
|
||||||
variants.push(serde_json::json!({
|
|
||||||
"type": "boolean"
|
|
||||||
}));
|
|
||||||
|
|
||||||
// Add Array variant (untagged)
|
|
||||||
variants.push(serde_json::json!({
|
|
||||||
"type": "array",
|
|
||||||
"items": {
|
|
||||||
"$ref": "#/definitions/Value"
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use anyhow::Result;
|
use std::collections::HashSet;
|
||||||
use schemars::generate::SchemaSettings;
|
|
||||||
|
|
||||||
|
use anyhow::Result;
|
||||||
|
// Pretty assertions give nicer diffs between expected and actual values
|
||||||
|
use pretty_assertions::assert_eq;
|
||||||
|
use schemars::schema_for;
|
||||||
|
|
||||||
|
// use schemars::generate::SchemaSettings;
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::mock::{mainpod::MockProver, signedpod::MockSigner},
|
backends::plonky2::mock::{mainpod::MockProver, signedpod::MockSigner},
|
||||||
examples::{zu_kyc_pod_builder, zu_kyc_sign_pod_builders},
|
examples::{
|
||||||
frontend::{
|
eth_dos_pod_builder, eth_friend_signed_pod_builder, zu_kyc_pod_builder,
|
||||||
containers::{Array, Dictionary, Set},
|
zu_kyc_sign_pod_builders,
|
||||||
SignedPodBuilder,
|
},
|
||||||
|
frontend::SignedPodBuilder,
|
||||||
|
middleware::{
|
||||||
|
self,
|
||||||
|
containers::{Array, Set},
|
||||||
|
Params, TypedValue,
|
||||||
},
|
},
|
||||||
middleware::{self, Params},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -174,34 +126,32 @@ mod tests {
|
||||||
(TypedValue::Int(42), "{\"Int\":\"42\"}"),
|
(TypedValue::Int(42), "{\"Int\":\"42\"}"),
|
||||||
(TypedValue::Bool(true), "true"),
|
(TypedValue::Bool(true), "true"),
|
||||||
(
|
(
|
||||||
TypedValue::Array(
|
TypedValue::Array(Array::new(vec!["foo".into(), false.into()]).unwrap()),
|
||||||
Array::new(vec![
|
|
||||||
TypedValue::String("foo".to_string()),
|
|
||||||
TypedValue::Bool(false),
|
|
||||||
])
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
"[\"foo\",false]",
|
"[\"foo\",false]",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
TypedValue::Dictionary(
|
TypedValue::Dictionary(
|
||||||
Dictionary::new(HashMap::from([
|
Dictionary::new(HashMap::from([
|
||||||
("foo".to_string(), TypedValue::Int(123)),
|
// The set of valid keys is equal to the set of valid JSON keys
|
||||||
("bar".to_string(), TypedValue::String("baz".to_string())),
|
("foo".into(), 123.into()),
|
||||||
|
// Empty strings are valid JSON keys
|
||||||
|
(("".into()), "baz".into()),
|
||||||
|
// Keys can contain whitespace
|
||||||
|
((" hi".into()), false.into()),
|
||||||
|
// Keys can contain special characters
|
||||||
|
(("!@£$%^&&*()".into()), "".into()),
|
||||||
|
// Keys can contain _very_ special characters
|
||||||
|
(("\0".into()), "".into()),
|
||||||
|
// Keys can contain emojis
|
||||||
|
(("🥳".into()), "party time!".into()),
|
||||||
]))
|
]))
|
||||||
.unwrap(),
|
.unwrap(),
|
||||||
),
|
),
|
||||||
"{\"Dictionary\":{\"bar\":\"baz\",\"foo\":{\"Int\":\"123\"}}}",
|
"{\"Dictionary\":{\"\":\"baz\",\"\\u0000\":\"\",\" hi\":false,\"!@£$%^&&*()\":\"\",\"foo\":{\"Int\":\"123\"},\"🥳\":\"party time!\"}}",
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
TypedValue::Set(
|
TypedValue::Set(Set::new(HashSet::from(["foo".into(), "bar".into()])).unwrap()),
|
||||||
Set::new(vec![
|
"{\"Set\":[\"bar\",\"foo\"]}",
|
||||||
TypedValue::String("foo".to_string()),
|
|
||||||
TypedValue::String("bar".to_string()),
|
|
||||||
])
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
"{\"Set\":[\"foo\",\"bar\"]}",
|
|
||||||
),
|
),
|
||||||
];
|
];
|
||||||
|
|
||||||
|
|
@ -209,14 +159,17 @@ mod tests {
|
||||||
let serialized = serde_json::to_string(&value).unwrap();
|
let serialized = serde_json::to_string(&value).unwrap();
|
||||||
assert_eq!(serialized, expected);
|
assert_eq!(serialized, expected);
|
||||||
let deserialized: TypedValue = serde_json::from_str(&serialized).unwrap();
|
let deserialized: TypedValue = serde_json::from_str(&serialized).unwrap();
|
||||||
assert_eq!(value, deserialized);
|
assert_eq!(
|
||||||
let expected_deserialized: TypedValue = serde_json::from_str(&expected).unwrap();
|
value, deserialized,
|
||||||
|
"value {:#?} should equal deserialized {:#?}",
|
||||||
|
value, deserialized
|
||||||
|
);
|
||||||
|
let expected_deserialized: TypedValue = serde_json::from_str(expected).unwrap();
|
||||||
assert_eq!(value, expected_deserialized);
|
assert_eq!(value, expected_deserialized);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn build_signed_pod() -> Result<SignedPod> {
|
||||||
fn test_signed_pod_serialization() {
|
|
||||||
let mut signer = MockSigner { pk: "test".into() };
|
let mut signer = MockSigner { pk: "test".into() };
|
||||||
let mut builder = SignedPodBuilder::new(&Params::default());
|
let mut builder = SignedPodBuilder::new(&Params::default());
|
||||||
builder.insert("name", "test");
|
builder.insert("name", "test");
|
||||||
|
|
@ -224,44 +177,36 @@ mod tests {
|
||||||
builder.insert("very_large_int", 1152921504606846976);
|
builder.insert("very_large_int", 1152921504606846976);
|
||||||
builder.insert(
|
builder.insert(
|
||||||
"a_dict_containing_one_key",
|
"a_dict_containing_one_key",
|
||||||
TypedValue::Dictionary(
|
Dictionary::new(HashMap::from([
|
||||||
Dictionary::new(HashMap::from([
|
("foo".into(), 123.into()),
|
||||||
("foo".to_string(), TypedValue::Int(123)),
|
(
|
||||||
(
|
"an_array_containing_three_ints".into(),
|
||||||
"an_array_containing_three_ints".to_string(),
|
Array::new(vec![1.into(), 2.into(), 3.into()])
|
||||||
TypedValue::Array(
|
.unwrap()
|
||||||
Array::new(vec![
|
.into(),
|
||||||
TypedValue::Int(1),
|
),
|
||||||
TypedValue::Int(2),
|
(
|
||||||
TypedValue::Int(3),
|
"a_set_containing_two_strings".into(),
|
||||||
])
|
Set::new(HashSet::from([
|
||||||
.unwrap(),
|
Array::new(vec!["foo".into(), "bar".into()]).unwrap().into(),
|
||||||
),
|
"baz".into(),
|
||||||
),
|
]))
|
||||||
(
|
.unwrap()
|
||||||
"a_set_containing_two_strings".to_string(),
|
.into(),
|
||||||
TypedValue::Set(
|
),
|
||||||
Set::new(vec![
|
]))
|
||||||
TypedValue::Array(
|
.unwrap(),
|
||||||
Array::new(vec![
|
|
||||||
TypedValue::String("foo".to_string()),
|
|
||||||
TypedValue::String("bar".to_string()),
|
|
||||||
])
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
TypedValue::String("baz".to_string()),
|
|
||||||
])
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
]))
|
|
||||||
.unwrap(),
|
|
||||||
),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
let pod = builder.sign(&mut signer).unwrap();
|
let pod = builder.sign(&mut signer).unwrap();
|
||||||
|
Ok(pod)
|
||||||
|
}
|
||||||
|
|
||||||
let serialized = serde_json::to_string(&pod).unwrap();
|
#[test]
|
||||||
|
fn test_signed_pod_serialization() {
|
||||||
|
let pod = build_signed_pod().unwrap();
|
||||||
|
|
||||||
|
let serialized = serde_json::to_string_pretty(&pod).unwrap();
|
||||||
println!("serialized: {}", serialized);
|
println!("serialized: {}", serialized);
|
||||||
let deserialized: SignedPod = serde_json::from_str(&serialized).unwrap();
|
let deserialized: SignedPod = serde_json::from_str(&serialized).unwrap();
|
||||||
|
|
||||||
|
|
@ -270,14 +215,11 @@ mod tests {
|
||||||
assert_eq!(pod.id(), deserialized.id())
|
assert_eq!(pod.id(), deserialized.id())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn build_zukyc_pod() -> Result<MainPod> {
|
||||||
fn test_main_pod_serialization() -> Result<()> {
|
|
||||||
let params = middleware::Params::default();
|
let params = middleware::Params::default();
|
||||||
let sanctions_values = vec!["A343434340".into()];
|
|
||||||
let sanction_set = TypedValue::Set(Set::new(sanctions_values)?);
|
|
||||||
|
|
||||||
let (gov_id_builder, pay_stub_builder, sanction_list_builder) =
|
let (gov_id_builder, pay_stub_builder, sanction_list_builder) =
|
||||||
zu_kyc_sign_pod_builders(¶ms, &sanction_set);
|
zu_kyc_sign_pod_builders(¶ms);
|
||||||
let mut signer = MockSigner {
|
let mut signer = MockSigner {
|
||||||
pk: "ZooGov".into(),
|
pk: "ZooGov".into(),
|
||||||
};
|
};
|
||||||
|
|
@ -295,8 +237,13 @@ mod tests {
|
||||||
|
|
||||||
let mut prover = MockProver {};
|
let mut prover = MockProver {};
|
||||||
let kyc_pod = kyc_builder.prove(&mut prover, ¶ms).unwrap();
|
let kyc_pod = kyc_builder.prove(&mut prover, ¶ms).unwrap();
|
||||||
|
Ok(kyc_pod)
|
||||||
|
}
|
||||||
|
|
||||||
let serialized = serde_json::to_string(&kyc_pod).unwrap();
|
#[test]
|
||||||
|
fn test_main_pod_serialization() -> Result<()> {
|
||||||
|
let kyc_pod = build_zukyc_pod()?;
|
||||||
|
let serialized = serde_json::to_string_pretty(&kyc_pod).unwrap();
|
||||||
println!("serialized: {}", serialized);
|
println!("serialized: {}", serialized);
|
||||||
let deserialized: MainPod = serde_json::from_str(&serialized).unwrap();
|
let deserialized: MainPod = serde_json::from_str(&serialized).unwrap();
|
||||||
|
|
||||||
|
|
@ -307,17 +254,70 @@ mod tests {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
fn build_ethdos_pod() -> Result<MainPod> {
|
||||||
fn test_schema() {
|
let params = Params {
|
||||||
let generator = SchemaSettings::draft07().into_generator();
|
max_input_signed_pods: 3,
|
||||||
let mainpod_schema = generator.clone().into_root_schema_for::<MainPodHelper>();
|
max_input_main_pods: 3,
|
||||||
let signedpod_schema = generator.into_root_schema_for::<SignedPodHelper>();
|
max_statements: 31,
|
||||||
|
max_signed_pod_values: 8,
|
||||||
|
max_public_statements: 10,
|
||||||
|
max_statement_args: 6,
|
||||||
|
max_operation_args: 5,
|
||||||
|
max_custom_predicate_arity: 5,
|
||||||
|
max_custom_batch_size: 5,
|
||||||
|
max_custom_predicate_wildcards: 12,
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
println!("{}", serde_json::to_string_pretty(&mainpod_schema).unwrap());
|
let mut alice = MockSigner { pk: "Alice".into() };
|
||||||
println!(
|
let bob = MockSigner { pk: "Bob".into() };
|
||||||
"{}",
|
let mut charlie = MockSigner {
|
||||||
serde_json::to_string_pretty(&signedpod_schema).unwrap()
|
pk: "Charlie".into(),
|
||||||
);
|
};
|
||||||
|
|
||||||
|
// Alice attests that she is ETH friends with Charlie and Charlie
|
||||||
|
// attests that he is ETH friends with Bob.
|
||||||
|
let alice_attestation =
|
||||||
|
eth_friend_signed_pod_builder(¶ms, charlie.pubkey().into()).sign(&mut alice)?;
|
||||||
|
let charlie_attestation =
|
||||||
|
eth_friend_signed_pod_builder(¶ms, bob.pubkey().into()).sign(&mut charlie)?;
|
||||||
|
|
||||||
|
let mut prover = MockProver {};
|
||||||
|
let alice_bob_ethdos = eth_dos_pod_builder(
|
||||||
|
¶ms,
|
||||||
|
&alice_attestation,
|
||||||
|
&charlie_attestation,
|
||||||
|
&bob.pubkey().into(),
|
||||||
|
)?
|
||||||
|
.prove(&mut prover, ¶ms)?;
|
||||||
|
|
||||||
|
Ok(alice_bob_ethdos)
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
// This tests that we can generate JSON Schemas for the MainPod and
|
||||||
|
// SignedPod types, and that we can validate real Signed and Main Pods
|
||||||
|
// against the schemas.
|
||||||
|
fn test_schema() {
|
||||||
|
let mainpod_schema = schema_for!(MainPodHelper);
|
||||||
|
let signedpod_schema = schema_for!(SignedPodHelper);
|
||||||
|
|
||||||
|
let kyc_pod = build_zukyc_pod().unwrap();
|
||||||
|
let signed_pod = build_signed_pod().unwrap();
|
||||||
|
let ethdos_pod = build_ethdos_pod().unwrap();
|
||||||
|
let mainpod_schema_value = serde_json::to_value(&mainpod_schema).unwrap();
|
||||||
|
let signedpod_schema_value = serde_json::to_value(&signedpod_schema).unwrap();
|
||||||
|
|
||||||
|
let kyc_pod_value = serde_json::to_value(&kyc_pod).unwrap();
|
||||||
|
let mainpod_valid = jsonschema::validate(&mainpod_schema_value, &kyc_pod_value);
|
||||||
|
assert!(mainpod_valid.is_ok(), "{:#?}", mainpod_valid);
|
||||||
|
|
||||||
|
let signed_pod_value = serde_json::to_value(&signed_pod).unwrap();
|
||||||
|
let signedpod_valid = jsonschema::validate(&signedpod_schema_value, &signed_pod_value);
|
||||||
|
assert!(signedpod_valid.is_ok(), "{:#?}", signedpod_valid);
|
||||||
|
|
||||||
|
let ethdos_pod_value = serde_json::to_value(ðdos_pod).unwrap();
|
||||||
|
let ethdos_pod_valid = jsonschema::validate(&mainpod_schema_value, ðdos_pod_value);
|
||||||
|
assert!(ethdos_pod_valid.is_ok(), "{:#?}", ethdos_pod_valid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
|
|
||||||
|
|
@ -55,15 +55,11 @@ use plonky2::{
|
||||||
hash::poseidon::PoseidonHash,
|
hash::poseidon::PoseidonHash,
|
||||||
plonk::config::Hasher,
|
plonk::config::Hasher,
|
||||||
};
|
};
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
use crate::middleware::{
|
use super::serialization::*;
|
||||||
// serialization::{
|
use crate::middleware::{Params, ToFields};
|
||||||
// deserialize_hash_tuple, deserialize_value_tuple, serialize_hash_tuple,
|
|
||||||
// serialize_value_tuple,
|
|
||||||
// },
|
|
||||||
Params,
|
|
||||||
ToFields,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// 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;
|
||||||
|
|
@ -75,16 +71,15 @@ pub const EMPTY_VALUE: RawValue = RawValue([F::ZERO, F::ZERO, F::ZERO, F::ZERO])
|
||||||
pub const SELF_ID_HASH: Hash = Hash([F::ONE, F::ZERO, F::ZERO, F::ZERO]);
|
pub const SELF_ID_HASH: Hash = Hash([F::ONE, F::ZERO, F::ZERO, F::ZERO]);
|
||||||
pub const EMPTY_HASH: Hash = Hash([F::ZERO, F::ZERO, F::ZERO, F::ZERO]);
|
pub const EMPTY_HASH: Hash = Hash([F::ZERO, F::ZERO, F::ZERO, F::ZERO]);
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, Default, Hash, PartialEq, Eq, Serialize, Deserialize, JsonSchema)]
|
||||||
// #[schemars(rename = "RawValue")]
|
|
||||||
pub struct RawValue(
|
pub struct RawValue(
|
||||||
// #[serde(
|
#[serde(
|
||||||
// serialize_with = "serialize_value_tuple",
|
serialize_with = "serialize_value_tuple",
|
||||||
// deserialize_with = "deserialize_value_tuple"
|
deserialize_with = "deserialize_value_tuple"
|
||||||
// )]
|
)]
|
||||||
// We know that Serde will serialize and deserialize this as a string, so we can
|
// We know that Serde will serialize and deserialize this as a string, so we can
|
||||||
// use the JsonSchema to validate the format.
|
// use the JsonSchema to validate the format.
|
||||||
// #[schemars(with = "String", regex(pattern = r"^[0-9a-fA-F]{64}$"))]
|
#[schemars(with = "String", regex(pattern = r"^[0-9a-fA-F]{64}$"))]
|
||||||
pub [F; VALUE_SIZE],
|
pub [F; VALUE_SIZE],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
@ -152,13 +147,13 @@ impl fmt::Display for RawValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Default, Hash, Eq, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct Hash(
|
pub struct Hash(
|
||||||
// #[serde(
|
#[serde(
|
||||||
// serialize_with = "serialize_hash_tuple",
|
serialize_with = "serialize_hash_tuple",
|
||||||
// deserialize_with = "deserialize_hash_tuple"
|
deserialize_with = "deserialize_hash_tuple"
|
||||||
// )]
|
)]
|
||||||
// #[schemars(with = "String", regex(pattern = r"^[0-9a-fA-F]{64}$"))]
|
#[schemars(with = "String", regex(pattern = r"^[0-9a-fA-F]{64}$"))]
|
||||||
pub [F; HASH_SIZE],
|
pub [F; HASH_SIZE],
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,10 @@ use std::collections::{HashMap, HashSet};
|
||||||
/// This file implements the types defined at
|
/// This file implements the types defined at
|
||||||
/// https://0xparc.github.io/pod2/values.html#dictionary-array-set .
|
/// https://0xparc.github.io/pod2/values.html#dictionary-array-set .
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Deserializer, Serialize};
|
||||||
|
|
||||||
|
use super::serialization::{ordered_map, ordered_set};
|
||||||
#[cfg(feature = "backend_plonky2")]
|
#[cfg(feature = "backend_plonky2")]
|
||||||
use crate::backends::plonky2::primitives::merkletree::{MerkleProof, MerkleTree};
|
use crate::backends::plonky2::primitives::merkletree::{MerkleProof, MerkleTree};
|
||||||
use crate::{
|
use crate::{
|
||||||
|
|
@ -14,9 +17,12 @@ use crate::{
|
||||||
/// Dictionary: the user original keys and values are hashed to be used in the leaf.
|
/// Dictionary: the user original keys and values are hashed to be used in the leaf.
|
||||||
/// leaf.key=hash(original_key)
|
/// leaf.key=hash(original_key)
|
||||||
/// leaf.value=hash(original_value)
|
/// leaf.value=hash(original_value)
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
pub struct Dictionary {
|
pub struct Dictionary {
|
||||||
|
#[serde(skip)]
|
||||||
mt: MerkleTree,
|
mt: MerkleTree,
|
||||||
|
#[serde(serialize_with = "ordered_map")]
|
||||||
kvs: HashMap<Key, Value>,
|
kvs: HashMap<Key, Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -76,12 +82,36 @@ impl PartialEq for Dictionary {
|
||||||
}
|
}
|
||||||
impl Eq for Dictionary {}
|
impl Eq for Dictionary {}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Dictionary {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let kvs: HashMap<Key, Value> = HashMap::deserialize(deserializer)?;
|
||||||
|
Dictionary::new(kvs).map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JsonSchema for Dictionary {
|
||||||
|
fn schema_name() -> String {
|
||||||
|
"Dictionary".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
|
// Just use the schema of HashMap<Key, Value> since that's what we're actually serializing
|
||||||
|
<HashMap<Key, Value>>::json_schema(gen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Set: the value field of the leaf is unused, and the key contains the hash of the element.
|
/// Set: the value field of the leaf is unused, and the key contains the hash of the element.
|
||||||
/// leaf.key=hash(original_value)
|
/// leaf.key=hash(original_value)
|
||||||
/// leaf.value=0
|
/// leaf.value=0
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
pub struct Set {
|
pub struct Set {
|
||||||
|
#[serde(skip)]
|
||||||
mt: MerkleTree,
|
mt: MerkleTree,
|
||||||
|
#[serde(serialize_with = "ordered_set")]
|
||||||
set: HashSet<Value>,
|
set: HashSet<Value>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -134,12 +164,38 @@ impl PartialEq for Set {
|
||||||
}
|
}
|
||||||
impl Eq for Set {}
|
impl Eq for Set {}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Set {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
// Deserialize the set directly
|
||||||
|
let set: HashSet<Value> = HashSet::deserialize(deserializer)?;
|
||||||
|
|
||||||
|
// Create a new Set using the set field
|
||||||
|
Set::new(set).map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JsonSchema for Set {
|
||||||
|
fn schema_name() -> String {
|
||||||
|
"Set".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
|
// Just use the schema of HashSet<Value> since that's what we're actually serializing
|
||||||
|
<HashSet<Value>>::json_schema(gen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Array: the elements are placed at the value field of each leaf, and the key field is just the
|
/// Array: the elements are placed at the value field of each leaf, and the key field is just the
|
||||||
/// array index (integer).
|
/// array index (integer).
|
||||||
/// leaf.key=i
|
/// leaf.key=i
|
||||||
/// leaf.value=original_value
|
/// leaf.value=original_value
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize)]
|
||||||
|
#[serde(transparent)]
|
||||||
pub struct Array {
|
pub struct Array {
|
||||||
|
#[serde(skip)]
|
||||||
mt: MerkleTree,
|
mt: MerkleTree,
|
||||||
array: Vec<Value>,
|
array: Vec<Value>,
|
||||||
}
|
}
|
||||||
|
|
@ -190,3 +246,24 @@ impl PartialEq for Array {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
impl Eq for Array {}
|
impl Eq for Array {}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Array {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let array: Vec<Value> = Vec::deserialize(deserializer)?;
|
||||||
|
Array::new(array).map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JsonSchema for Array {
|
||||||
|
fn schema_name() -> String {
|
||||||
|
"Array".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
|
// Just use the schema of Vec<Value> since that's what we're actually serializing
|
||||||
|
<Vec<Value>>::json_schema(gen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,16 +2,14 @@ use std::{fmt, iter, sync::Arc};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// use schemars::JsonSchema;
|
use crate::middleware::{
|
||||||
|
hash_fields, Hash, Key, NativePredicate, Params, ToFields, Value, F, HASH_SIZE,
|
||||||
// use serde::{Deserialize, Serialize};
|
|
||||||
use crate::{
|
|
||||||
middleware::HASH_SIZE,
|
|
||||||
middleware::{hash_fields, Hash, Key, NativePredicate, Params, ToFields, Value, F},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct Wildcard {
|
pub struct Wildcard {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
|
|
@ -35,7 +33,8 @@ impl ToFields for Wildcard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(tag = "type", content = "value")]
|
||||||
pub enum KeyOrWildcard {
|
pub enum KeyOrWildcard {
|
||||||
Key(Key),
|
Key(Key),
|
||||||
Wildcard(Wildcard),
|
Wildcard(Wildcard),
|
||||||
|
|
@ -62,7 +61,8 @@ impl ToFields for KeyOrWildcard {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(tag = "type", content = "value")]
|
||||||
pub enum StatementTmplArg {
|
pub enum StatementTmplArg {
|
||||||
None,
|
None,
|
||||||
Literal(Value),
|
Literal(Value),
|
||||||
|
|
@ -126,7 +126,7 @@ impl fmt::Display for StatementTmplArg {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Statement Template for a Custom Predicate
|
/// Statement Template for a Custom Predicate
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct StatementTmpl {
|
pub struct StatementTmpl {
|
||||||
pub pred: Predicate,
|
pub pred: Predicate,
|
||||||
pub args: Vec<StatementTmplArg>,
|
pub args: Vec<StatementTmplArg>,
|
||||||
|
|
@ -178,7 +178,8 @@ impl ToFields for StatementTmpl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
/// NOTE: fields are not public (outside of crate) to enforce the struct instantiation through
|
/// NOTE: fields are not public (outside of crate) to enforce the struct instantiation through
|
||||||
/// the `::and/or` methods, which performs checks on the values.
|
/// the `::and/or` methods, which performs checks on the values.
|
||||||
pub struct CustomPredicate {
|
pub struct CustomPredicate {
|
||||||
|
|
@ -278,7 +279,7 @@ impl fmt::Display for CustomPredicate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct CustomPredicateBatch {
|
pub struct CustomPredicateBatch {
|
||||||
pub name: String,
|
pub name: String,
|
||||||
pub predicates: Vec<CustomPredicate>,
|
pub predicates: Vec<CustomPredicate>,
|
||||||
|
|
@ -315,7 +316,7 @@ impl CustomPredicateBatch {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct CustomPredicateRef {
|
pub struct CustomPredicateRef {
|
||||||
pub batch: Arc<CustomPredicateBatch>,
|
pub batch: Arc<CustomPredicateBatch>,
|
||||||
pub index: usize,
|
pub index: usize,
|
||||||
|
|
@ -330,8 +331,8 @@ impl CustomPredicateRef {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
// #[serde(tag = "type", content = "value")]
|
#[serde(tag = "type", content = "value")]
|
||||||
pub enum Predicate {
|
pub enum Predicate {
|
||||||
Native(NativePredicate),
|
Native(NativePredicate),
|
||||||
BatchSelf(usize),
|
BatchSelf(usize),
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,8 @@ use std::{
|
||||||
|
|
||||||
use anyhow::anyhow;
|
use anyhow::anyhow;
|
||||||
use containers::{Array, Dictionary, Set};
|
use containers::{Array, Dictionary, Set};
|
||||||
|
use schemars::JsonSchema;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
pub mod containers;
|
pub mod containers;
|
||||||
mod custom;
|
mod custom;
|
||||||
mod operation;
|
mod operation;
|
||||||
|
|
@ -22,8 +24,7 @@ pub use basetypes::*;
|
||||||
pub use custom::*;
|
pub use custom::*;
|
||||||
use dyn_clone::DynClone;
|
use dyn_clone::DynClone;
|
||||||
pub use operation::*;
|
pub use operation::*;
|
||||||
// use schemars::JsonSchema;
|
use serialization::*;
|
||||||
// use serde::{Deserialize, Serialize};
|
|
||||||
pub use statement::*;
|
pub use statement::*;
|
||||||
|
|
||||||
use crate::backends::plonky2::primitives::merkletree::MerkleProof;
|
use crate::backends::plonky2::primitives::merkletree::MerkleProof;
|
||||||
|
|
@ -31,7 +32,7 @@ use crate::backends::plonky2::primitives::merkletree::MerkleProof;
|
||||||
pub const SELF: PodId = PodId(SELF_ID_HASH);
|
pub const SELF: PodId = PodId(SELF_ID_HASH);
|
||||||
|
|
||||||
// TODO: Move all value-related types to to `value.rs`
|
// TODO: Move all value-related types to to `value.rs`
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug, Serialize, Deserialize, Eq, PartialEq)]
|
||||||
// TODO #[schemars(transform = serialization::transform_value_schema)]
|
// TODO #[schemars(transform = serialization::transform_value_schema)]
|
||||||
pub enum TypedValue {
|
pub enum TypedValue {
|
||||||
// Serde cares about the order of the enum variants, with untagged variants
|
// Serde cares about the order of the enum variants, with untagged variants
|
||||||
|
|
@ -49,21 +50,18 @@ pub enum TypedValue {
|
||||||
Set(Set),
|
Set(Set),
|
||||||
Dictionary(Dictionary),
|
Dictionary(Dictionary),
|
||||||
Int(
|
Int(
|
||||||
// TODO #[serde(serialize_with = "serialize_i64", deserialize_with = "deserialize_i64")]
|
#[serde(serialize_with = "serialize_i64", deserialize_with = "deserialize_i64")]
|
||||||
// #[schemars(with = "String", regex(pattern = r"^\d+$"))]
|
// #[schemars(with = "String", regex(pattern = r"^\d+$"))]
|
||||||
i64,
|
i64,
|
||||||
),
|
),
|
||||||
// Uses the serialization for middleware::Value:
|
// Uses the serialization for middleware::Value:
|
||||||
Raw(RawValue),
|
Raw(RawValue),
|
||||||
// UNTAGGED TYPES:
|
// UNTAGGED TYPES:
|
||||||
// #[serde(untagged)]
|
#[serde(untagged)]
|
||||||
// #[schemars(skip)]
|
|
||||||
Array(Array),
|
Array(Array),
|
||||||
// #[serde(untagged)]
|
#[serde(untagged)]
|
||||||
// #[schemars(skip)]
|
|
||||||
String(String),
|
String(String),
|
||||||
// #[serde(untagged)]
|
#[serde(untagged)]
|
||||||
// #[schemars(skip)]
|
|
||||||
Bool(bool),
|
Bool(bool),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -176,6 +174,106 @@ impl From<&TypedValue> for RawValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Schemars/JsonSchema can't handle Serde's "untagged" variants.
|
||||||
|
// Instead, we have to implement schema generation directly. It's not as
|
||||||
|
// complicated as it looks, though.
|
||||||
|
// We have to generate schemas for each of the variants, and then combine them
|
||||||
|
// into a single schema using the `anyOf` keyword.
|
||||||
|
// If we add a new variant, we will have to update this function.
|
||||||
|
impl JsonSchema for TypedValue {
|
||||||
|
fn schema_name() -> String {
|
||||||
|
"TypedValue".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
|
use schemars::schema::{InstanceType, Schema, SchemaObject, SingleOrVec};
|
||||||
|
|
||||||
|
let set_schema = schemars::schema::SchemaObject {
|
||||||
|
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Object))),
|
||||||
|
object: Some(Box::new(schemars::schema::ObjectValidation {
|
||||||
|
properties: [("Set".to_string(), gen.subschema_for::<Set>())]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
required: ["Set".to_string()].into_iter().collect(),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let dictionary_schema = schemars::schema::SchemaObject {
|
||||||
|
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Object))),
|
||||||
|
object: Some(Box::new(schemars::schema::ObjectValidation {
|
||||||
|
properties: [("Dictionary".to_string(), gen.subschema_for::<Dictionary>())]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
required: ["Dictionary".to_string()].into_iter().collect(),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// Int is serialized/deserialized as a tagged string
|
||||||
|
let int_schema = schemars::schema::SchemaObject {
|
||||||
|
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Object))),
|
||||||
|
object: Some(Box::new(schemars::schema::ObjectValidation {
|
||||||
|
properties: [(
|
||||||
|
"Int".to_string(),
|
||||||
|
Schema::Object(SchemaObject {
|
||||||
|
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::String))),
|
||||||
|
metadata: Some(Box::new(schemars::schema::Metadata {
|
||||||
|
description: Some("An i64 represented as a string.".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
}),
|
||||||
|
)]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
required: ["Int".to_string()].into_iter().collect(),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
let raw_schema = schemars::schema::SchemaObject {
|
||||||
|
instance_type: Some(SingleOrVec::Single(Box::new(InstanceType::Object))),
|
||||||
|
object: Some(Box::new(schemars::schema::ObjectValidation {
|
||||||
|
properties: [("Raw".to_string(), gen.subschema_for::<RawValue>())]
|
||||||
|
.into_iter()
|
||||||
|
.collect(),
|
||||||
|
required: ["Raw".to_string()].into_iter().collect(),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
};
|
||||||
|
|
||||||
|
// This is the part that Schemars can't generate automatically:
|
||||||
|
let untagged_array_schema = gen.subschema_for::<Array>();
|
||||||
|
let untagged_string_schema = gen.subschema_for::<String>();
|
||||||
|
let untagged_bool_schema = gen.subschema_for::<bool>();
|
||||||
|
|
||||||
|
Schema::Object(SchemaObject {
|
||||||
|
subschemas: Some(Box::new(schemars::schema::SubschemaValidation {
|
||||||
|
any_of: Some(vec![
|
||||||
|
Schema::Object(set_schema),
|
||||||
|
Schema::Object(dictionary_schema),
|
||||||
|
Schema::Object(int_schema),
|
||||||
|
Schema::Object(raw_schema),
|
||||||
|
untagged_array_schema,
|
||||||
|
untagged_string_schema,
|
||||||
|
untagged_bool_schema,
|
||||||
|
]),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
metadata: Some(Box::new(schemars::schema::Metadata {
|
||||||
|
description: Some("Represents various POD value types. Array, String, and Bool variants are represented untagged in JSON.".to_string()),
|
||||||
|
..Default::default()
|
||||||
|
})),
|
||||||
|
..Default::default()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct Value {
|
pub struct Value {
|
||||||
// The `TypedValue` is under `Arc` so that cloning a `Value` is cheap.
|
// The `TypedValue` is under `Arc` so that cloning a `Value` is cheap.
|
||||||
|
|
@ -183,6 +281,37 @@ pub struct Value {
|
||||||
raw: RawValue,
|
raw: RawValue,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Values are serialized as their TypedValue.
|
||||||
|
impl Serialize for Value {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
self.typed.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Value {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let typed = TypedValue::deserialize(deserializer)?;
|
||||||
|
Ok(Value::new(typed))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl JsonSchema for Value {
|
||||||
|
fn schema_name() -> String {
|
||||||
|
"Value".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
|
// Just use the schema of TypedValue since that's what we're actually serializing
|
||||||
|
<TypedValue>::json_schema(gen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl PartialEq for Value {
|
impl PartialEq for Value {
|
||||||
fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
self.raw == other.raw
|
self.raw == other.raw
|
||||||
|
|
@ -336,7 +465,44 @@ impl From<Key> for RawValue {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
|
// When serializing a Key, we serialize only the name field, and not the hash.
|
||||||
|
// We can't directly tell Serde to render the whole struct as a string, so we
|
||||||
|
// implement our own serialization. It's important that if we change the
|
||||||
|
// structure of the Key struct, we update this implementation.
|
||||||
|
impl Serialize for Key {
|
||||||
|
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
self.name.serialize(serializer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'de> Deserialize<'de> for Key {
|
||||||
|
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
let name = String::deserialize(deserializer)?;
|
||||||
|
Ok(Key::new(name))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// As per the above, we implement custom serialization for the Key type, and
|
||||||
|
// Schemars can't automatically generate a schema for it. Instead, we tell it
|
||||||
|
// to use the standard String schema.
|
||||||
|
impl JsonSchema for Key {
|
||||||
|
fn schema_name() -> String {
|
||||||
|
"Key".to_string()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
|
||||||
|
<String>::json_schema(gen)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct AnchoredKey {
|
pub struct AnchoredKey {
|
||||||
pub pod_id: PodId,
|
pub pod_id: PodId,
|
||||||
pub key: Key,
|
pub key: Key,
|
||||||
|
|
@ -364,7 +530,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash, Default, Serialize, Deserialize, JsonSchema)]
|
||||||
pub struct PodId(pub Hash);
|
pub struct PodId(pub Hash);
|
||||||
|
|
||||||
impl ToFields for PodId {
|
impl ToFields for PodId {
|
||||||
|
|
@ -394,7 +560,8 @@ impl fmt::Display for PodType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
|
#[serde(rename_all = "camelCase")]
|
||||||
pub struct Params {
|
pub struct Params {
|
||||||
pub max_input_signed_pods: usize,
|
pub max_input_signed_pods: usize,
|
||||||
pub max_input_main_pods: usize,
|
pub max_input_main_pods: usize,
|
||||||
|
|
|
||||||
|
|
@ -3,8 +3,8 @@ use std::{fmt, iter, sync::Arc};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use log::error;
|
use log::error;
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
|
use serde::{Deserialize, Serialize};
|
||||||
|
|
||||||
// use serde::{Deserialize, Serialize};
|
|
||||||
use crate::{
|
use crate::{
|
||||||
backends::plonky2::primitives::merkletree::MerkleProof,
|
backends::plonky2::primitives::merkletree::MerkleProof,
|
||||||
middleware::{
|
middleware::{
|
||||||
|
|
@ -14,7 +14,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum OperationType {
|
pub enum OperationType {
|
||||||
Native(NativeOperation),
|
Native(NativeOperation),
|
||||||
Custom(CustomPredicateRef),
|
Custom(CustomPredicateRef),
|
||||||
|
|
@ -54,7 +54,7 @@ impl ToFields for OperationType {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
|
#[derive(Clone, Copy, Debug, PartialEq, Eq, Serialize, Deserialize)]
|
||||||
pub enum NativeOperation {
|
pub enum NativeOperation {
|
||||||
None = 0,
|
None = 0,
|
||||||
NewEntry = 1,
|
NewEntry = 1,
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,9 @@
|
||||||
// TODO: Reenable
|
use std::collections::{HashMap, HashSet};
|
||||||
/*
|
|
||||||
use plonky2::field::types::Field;
|
|
||||||
use serde::Deserialize;
|
|
||||||
|
|
||||||
|
use plonky2::field::types::Field;
|
||||||
|
use serde::{ser::SerializeSeq, Deserialize, Serialize, Serializer};
|
||||||
|
|
||||||
|
use super::{Key, Value};
|
||||||
use crate::middleware::{F, HASH_SIZE, VALUE_SIZE};
|
use crate::middleware::{F, HASH_SIZE, VALUE_SIZE};
|
||||||
|
|
||||||
fn serialize_field_tuple<S, const N: usize>(
|
fn serialize_field_tuple<S, const N: usize>(
|
||||||
|
|
@ -69,4 +70,60 @@ where
|
||||||
{
|
{
|
||||||
deserialize_field_tuple::<D, VALUE_SIZE>(deserializer)
|
deserialize_field_tuple::<D, VALUE_SIZE>(deserializer)
|
||||||
}
|
}
|
||||||
*/
|
|
||||||
|
pub fn serialize_i64<S>(value: &i64, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: serde::Serializer,
|
||||||
|
{
|
||||||
|
serializer.serialize_str(&value.to_string())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn deserialize_i64<'de, D>(deserializer: D) -> Result<i64, D::Error>
|
||||||
|
where
|
||||||
|
D: serde::Deserializer<'de>,
|
||||||
|
{
|
||||||
|
String::deserialize(deserializer)?
|
||||||
|
.parse()
|
||||||
|
.map_err(serde::de::Error::custom)
|
||||||
|
}
|
||||||
|
|
||||||
|
// In order to serialize a Dictionary consistently, we want to order the
|
||||||
|
// key-value pairs by the key's name field. This has no effect on the hashes
|
||||||
|
// of the keys and therefore on the Merkle tree, but it makes the serialized
|
||||||
|
// output deterministic.
|
||||||
|
pub fn ordered_map<S, V: Serialize>(
|
||||||
|
value: &HashMap<Key, V>,
|
||||||
|
serializer: S,
|
||||||
|
) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
// Convert to Vec and sort by the key's name field
|
||||||
|
let mut pairs: Vec<_> = value.iter().collect();
|
||||||
|
pairs.sort_by(|(k1, _), (k2, _)| k1.name.cmp(&k2.name));
|
||||||
|
|
||||||
|
// Serialize as a map
|
||||||
|
use serde::ser::SerializeMap;
|
||||||
|
let mut map = serializer.serialize_map(Some(pairs.len()))?;
|
||||||
|
for (k, v) in pairs {
|
||||||
|
map.serialize_entry(k, v)?;
|
||||||
|
}
|
||||||
|
map.end()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets are serialized as sequences of elements, which are not ordered by
|
||||||
|
// default. We want to serialize them in a deterministic way, and we can
|
||||||
|
// achieve this by sorting the elements. This takes advantage of the fact that
|
||||||
|
// Value implements Ord.
|
||||||
|
pub fn ordered_set<S>(value: &HashSet<Value>, serializer: S) -> Result<S::Ok, S::Error>
|
||||||
|
where
|
||||||
|
S: Serializer,
|
||||||
|
{
|
||||||
|
let mut set = serializer.serialize_seq(Some(value.len()))?;
|
||||||
|
let mut sorted_values: Vec<&Value> = value.iter().collect();
|
||||||
|
sorted_values.sort();
|
||||||
|
for v in sorted_values {
|
||||||
|
set.serialize_element(v)?;
|
||||||
|
}
|
||||||
|
set.end()
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,8 @@ use std::{fmt, iter};
|
||||||
|
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use plonky2::field::types::Field;
|
use plonky2::field::types::Field;
|
||||||
// use schemars::JsonSchema;
|
use schemars::JsonSchema;
|
||||||
// use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use strum_macros::FromRepr;
|
use strum_macros::FromRepr;
|
||||||
|
|
||||||
use crate::middleware::{
|
use crate::middleware::{
|
||||||
|
|
@ -20,7 +20,7 @@ pub const STATEMENT_ARG_F_LEN: usize = 8;
|
||||||
pub const OPERATION_ARG_F_LEN: usize = 1;
|
pub const OPERATION_ARG_F_LEN: usize = 1;
|
||||||
pub const OPERATION_AUX_F_LEN: usize = 1;
|
pub const OPERATION_AUX_F_LEN: usize = 1;
|
||||||
|
|
||||||
#[derive(Clone, Copy, Debug, FromRepr, PartialEq, Eq, Hash)]
|
#[derive(Clone, Copy, Debug, FromRepr, PartialEq, Eq, Hash, Serialize, Deserialize, JsonSchema)]
|
||||||
pub enum NativePredicate {
|
pub enum NativePredicate {
|
||||||
None = 0,
|
None = 0,
|
||||||
ValueOf = 1,
|
ValueOf = 1,
|
||||||
|
|
@ -49,7 +49,7 @@ impl ToFields for NativePredicate {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
pub enum WildcardValue {
|
pub enum WildcardValue {
|
||||||
PodId(PodId),
|
PodId(PodId),
|
||||||
Key(Key),
|
Key(Key),
|
||||||
|
|
@ -83,7 +83,8 @@ impl ToFields for WildcardValue {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Type encapsulating statements with their associated arguments.
|
/// Type encapsulating statements with their associated arguments.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize, JsonSchema)]
|
||||||
|
#[serde(tag = "predicate", content = "args")]
|
||||||
pub enum Statement {
|
pub enum Statement {
|
||||||
None,
|
None,
|
||||||
ValueOf(AnchoredKey, Value),
|
ValueOf(AnchoredKey, Value),
|
||||||
|
|
@ -275,7 +276,7 @@ impl fmt::Display for Statement {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Statement argument type. Useful for statement decompositions.
|
/// Statement argument type. Useful for statement decompositions.
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq, Serialize, Deserialize)]
|
||||||
pub enum StatementArg {
|
pub enum StatementArg {
|
||||||
None,
|
None,
|
||||||
Literal(Value),
|
Literal(Value),
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue