No Pod IDs (#394)
- middleware:
- Add `Statement::Intro`
- Add `SignedBy` native predicate and operation. The signature is auxiliary data to the operation
- Rename `PodSigner` to `Signer` with a new API (just for signing `RawValue`)
- Removed `NewEntry` operation. Use `ContainsFromEntries` instead
- Remove `KEY_SIGNER` and `KEY_TYPE` which are no longer used
- Merge `RecursivePod` and `Pod` traits
- Change the `Pod::deserialize_data` method to use `Self` instead of `Box<dyn Pod>`
- Extend `Pod` trait with these methods:
- `is_main`: when the pod is Main, in a (recursive) verification its vk will be checked to exist in the vd_set but not if it's intro pod
- `is_mock`: skip some verifications in the recursive mock MainPod verification
- `verifier_data_hash`
- `pod_id` renamed to `statements_hash`
- AnchoredKeys are now a pair of dictionary root and key
- Entry statements are now defined as Contains with literal arguments
- Operations that take Entries now use Contains statements with literal arguments
- frontend:
- Rename `SignedPod` to `SignedDict` (which now contains the dict, public key and signature, and can still `verify(self)`ed)
- The `SignedDict` keeps the method `get_statement` for convenience but now it returns a `Contains` statement that proves the existence of the key in the dict
- The `MainPodBuilder` automatically inserts a `Contains` statement when an operation is added that uses an entry as argument that was not yet "opened".
- Removed the `literal` methods from the `MainPodBuilder` that were loading literals to anchored keys: that was no longer needed after we introduced literal arguments
- backend
- Only verify inclusion of the verifying key into the vd_set if the pod is MainPod. A pod is not MainPod if the first statement is Intro.
- Reject intro pods that have non-intro statements
- Empty pod now returns an intro statement
- Don't insert a type statement automatically in MainPod and MockMainPod. We get rid of the type entry.
- Implement `SignedBy` operation, which uses the muxed table to store signature verifications
- Rename `PodId` to `statements_hash` or `sts_hash` for short. Now this is only used as a hash of the statements for the circuits public inputs.
- Refactor normalization of `self` statements:
- Before: replace values that contain `SELF` by the given pod_id
- After: place the verifying key hash into the Intro predicates
This commit is contained in:
parent
122f9c3cac
commit
0e2f7b756e
39 changed files with 2127 additions and 3064 deletions
|
|
@ -1,73 +1,30 @@
|
|||
use std::collections::HashMap;
|
||||
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
use super::Error;
|
||||
use crate::{
|
||||
frontend::{MainPod, SignedPod},
|
||||
middleware::{
|
||||
deserialize_pod, deserialize_signed_pod, Key, Params, PodId, Statement, VDSet, Value,
|
||||
},
|
||||
frontend::MainPod,
|
||||
middleware::{deserialize_pod, Hash, Params, Statement, VDSet},
|
||||
};
|
||||
|
||||
#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[schemars(rename = "SignedPod")]
|
||||
pub struct SerializedSignedPod {
|
||||
pod_type: (usize, String),
|
||||
id: PodId,
|
||||
entries: HashMap<Key, Value>,
|
||||
data: serde_json::Value,
|
||||
}
|
||||
|
||||
impl SerializedSignedPod {
|
||||
pub fn id(&self) -> PodId {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, JsonSchema, Debug, Clone, PartialEq)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
#[schemars(rename = "MainPod")]
|
||||
pub struct SerializedMainPod {
|
||||
params: Params,
|
||||
pod_type: (usize, String),
|
||||
id: PodId,
|
||||
id: Hash,
|
||||
vd_set: VDSet,
|
||||
public_statements: Vec<Statement>,
|
||||
data: serde_json::Value,
|
||||
}
|
||||
|
||||
impl SerializedMainPod {
|
||||
pub fn id(&self) -> PodId {
|
||||
pub fn id(&self) -> Hash {
|
||||
self.id
|
||||
}
|
||||
}
|
||||
|
||||
impl From<SignedPod> for SerializedSignedPod {
|
||||
fn from(pod: SignedPod) -> Self {
|
||||
let (pod_type, pod_type_name_str) = pod.pod.pod_type();
|
||||
let data = pod.pod.serialize_data();
|
||||
SerializedSignedPod {
|
||||
pod_type: (pod_type, pod_type_name_str.to_string()),
|
||||
id: pod.id(),
|
||||
entries: pod.kvs().clone(),
|
||||
data,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl TryFrom<SerializedSignedPod> for SignedPod {
|
||||
type Error = Error;
|
||||
|
||||
fn try_from(serialized: SerializedSignedPod) -> Result<Self, Self::Error> {
|
||||
let pod = deserialize_signed_pod(serialized.pod_type.0, serialized.id, serialized.data)?;
|
||||
let kvs = pod.kvs().into_iter().map(|(ak, v)| (ak.key, v)).collect();
|
||||
Ok(Self { pod, kvs })
|
||||
}
|
||||
}
|
||||
|
||||
impl From<MainPod> for SerializedMainPod {
|
||||
fn from(pod: MainPod) -> Self {
|
||||
let (pod_type, pod_type_name_str) = pod.pod.pod_type();
|
||||
|
|
@ -116,17 +73,17 @@ mod tests {
|
|||
mainpod::{rec_main_pod_circuit_data, Prover},
|
||||
mock::mainpod::MockProver,
|
||||
primitives::ec::schnorr::SecretKey,
|
||||
signedpod::Signer,
|
||||
signer::Signer,
|
||||
},
|
||||
examples::{
|
||||
attest_eth_friend, zu_kyc_pod_builder, zu_kyc_sign_pod_builders, EthDosHelper,
|
||||
attest_eth_friend, zu_kyc_pod_builder, zu_kyc_sign_dict_builders, EthDosHelper,
|
||||
MOCK_VD_SET,
|
||||
},
|
||||
frontend::{Result, SignedPodBuilder},
|
||||
frontend::{Result, SignedDict, SignedDictBuilder},
|
||||
middleware::{
|
||||
self,
|
||||
containers::{Array, Dictionary, Set},
|
||||
Params, TypedValue, DEFAULT_VD_LIST,
|
||||
Params, Signer as _, TypedValue, DEFAULT_VD_LIST,
|
||||
},
|
||||
};
|
||||
|
||||
|
|
@ -182,9 +139,9 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
fn signed_pod_builder() -> SignedPodBuilder {
|
||||
fn signed_dict_builder() -> SignedDictBuilder {
|
||||
let params = &Params::default();
|
||||
let mut builder = SignedPodBuilder::new(params);
|
||||
let mut builder = SignedDictBuilder::new(params);
|
||||
builder.insert("name", "test");
|
||||
builder.insert("age", 30);
|
||||
builder.insert("very_large_int", 1152921504606846976);
|
||||
|
|
@ -228,46 +185,29 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn test_signed_pod_serialization() {
|
||||
let builder = signed_pod_builder();
|
||||
fn test_signed_dict_serialization() {
|
||||
let builder = signed_dict_builder();
|
||||
let signer = Signer(SecretKey(1u32.into()));
|
||||
let pod = builder.sign(&signer).unwrap();
|
||||
let signed_dict = builder.sign(&signer).unwrap();
|
||||
|
||||
let serialized = serde_json::to_string_pretty(&pod).unwrap();
|
||||
let serialized = serde_json::to_string_pretty(&signed_dict).unwrap();
|
||||
println!("serialized: {}", serialized);
|
||||
let deserialized: SignedPod = serde_json::from_str(&serialized).unwrap();
|
||||
let deserialized: SignedDict = serde_json::from_str(&serialized).unwrap();
|
||||
println!(
|
||||
"deserialized: {}",
|
||||
serde_json::to_string_pretty(&deserialized).unwrap()
|
||||
);
|
||||
assert_eq!(pod.kvs, deserialized.kvs);
|
||||
assert_eq!(pod.verify().is_ok(), deserialized.verify().is_ok());
|
||||
assert_eq!(pod.id(), deserialized.id())
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mock_signed_pod_serialization() {
|
||||
let builder = signed_pod_builder();
|
||||
let signer = Signer(SecretKey(1u32.into()));
|
||||
let pod = builder.sign(&signer).unwrap();
|
||||
|
||||
let serialized = serde_json::to_string_pretty(&pod).unwrap();
|
||||
println!("serialized: {}", serialized);
|
||||
let deserialized: SignedPod = serde_json::from_str(&serialized).unwrap();
|
||||
println!(
|
||||
"deserialized: {}",
|
||||
serde_json::to_string_pretty(&deserialized).unwrap()
|
||||
);
|
||||
assert_eq!(pod.kvs, deserialized.kvs);
|
||||
assert_eq!(pod.verify().is_ok(), deserialized.verify().is_ok());
|
||||
assert_eq!(pod.id(), deserialized.id())
|
||||
assert_eq!(signed_dict.dict.kvs(), deserialized.dict.kvs());
|
||||
assert_eq!(signed_dict.public_key, deserialized.public_key);
|
||||
assert_eq!(signed_dict.signature, deserialized.signature);
|
||||
assert_eq!(signed_dict.verify().is_ok(), deserialized.verify().is_ok());
|
||||
}
|
||||
|
||||
fn build_mock_zukyc_pod() -> Result<MainPod> {
|
||||
let params = middleware::Params::default();
|
||||
let vd_set = &*MOCK_VD_SET;
|
||||
|
||||
let (gov_id_builder, pay_stub_builder) = zu_kyc_sign_pod_builders(¶ms);
|
||||
let (gov_id_builder, pay_stub_builder) = zu_kyc_sign_dict_builders(¶ms);
|
||||
let signer = Signer(SecretKey(1u32.into()));
|
||||
let gov_id_pod = gov_id_builder.sign(&signer).unwrap();
|
||||
let signer = Signer(SecretKey(2u32.into()));
|
||||
|
|
@ -283,18 +223,19 @@ mod tests {
|
|||
let params = middleware::Params {
|
||||
// Currently the circuit uses random access that only supports vectors of length 64.
|
||||
// With max_input_main_pods=3 we need random access to a vector of length 73.
|
||||
max_input_recursive_pods: 1,
|
||||
max_input_pods: 1,
|
||||
..Default::default()
|
||||
};
|
||||
let mut vds = DEFAULT_VD_LIST.clone();
|
||||
vds.push(rec_main_pod_circuit_data(¶ms).1.verifier_only.clone());
|
||||
let vd_set = VDSet::new(params.max_depth_mt_vds, &vds).unwrap();
|
||||
|
||||
let (gov_id_builder, pay_stub_builder) = zu_kyc_sign_pod_builders(¶ms);
|
||||
let (gov_id_builder, pay_stub_builder) = zu_kyc_sign_dict_builders(¶ms);
|
||||
let signer = Signer(SecretKey(1u32.into()));
|
||||
let gov_id_pod = gov_id_builder.sign(&signer)?;
|
||||
let signer = Signer(SecretKey(2u32.into()));
|
||||
let pay_stub_pod = pay_stub_builder.sign(&signer)?;
|
||||
let _signer = Signer(SecretKey(3u32.into()));
|
||||
let kyc_builder = zu_kyc_pod_builder(¶ms, &vd_set, &gov_id_pod, &pay_stub_pod)?;
|
||||
|
||||
let prover = Prover {};
|
||||
|
|
@ -311,7 +252,10 @@ mod tests {
|
|||
let deserialized: MainPod = serde_json::from_str(&serialized).unwrap();
|
||||
|
||||
assert_eq!(kyc_pod.public_statements, deserialized.public_statements);
|
||||
assert_eq!(kyc_pod.pod.id(), deserialized.pod.id());
|
||||
assert_eq!(
|
||||
kyc_pod.pod.statements_hash(),
|
||||
deserialized.pod.statements_hash()
|
||||
);
|
||||
assert_eq!(kyc_pod.pod.verify()?, deserialized.pod.verify()?);
|
||||
|
||||
Ok(())
|
||||
|
|
@ -324,7 +268,10 @@ mod tests {
|
|||
let deserialized: MainPod = serde_json::from_str(&serialized).unwrap();
|
||||
|
||||
assert_eq!(kyc_pod.public_statements, deserialized.public_statements);
|
||||
assert_eq!(kyc_pod.pod.id(), deserialized.pod.id());
|
||||
assert_eq!(
|
||||
kyc_pod.pod.statements_hash(),
|
||||
deserialized.pod.statements_hash()
|
||||
);
|
||||
assert_eq!(kyc_pod.pod.verify()?, deserialized.pod.verify()?);
|
||||
|
||||
Ok(())
|
||||
|
|
@ -348,7 +295,7 @@ mod tests {
|
|||
let alice_attestation = attest_eth_friend(¶ms, &alice, bob.public_key());
|
||||
let bob_attestation = attest_eth_friend(¶ms, &bob, charlie.public_key());
|
||||
|
||||
let helper = EthDosHelper::new(¶ms, vd_set, true, alice.public_key())?;
|
||||
let helper = EthDosHelper::new(¶ms, vd_set, alice.public_key())?;
|
||||
let prover = MockProver {};
|
||||
let dist_1 = helper.dist_1(&alice_attestation)?.prove(&prover)?;
|
||||
let dist_2 = helper
|
||||
|
|
@ -360,28 +307,28 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
// This tests that we can generate JSON Schemas for the MainPod and
|
||||
// SignedPod types, and that we can validate Signed and Main Pods
|
||||
// SignedDict types, and that we can validate Signed and Main Pods
|
||||
// against the schemas. Since both Mock and Plonky2 PODs have the same
|
||||
// public interface, we can assume that the schema works for both.
|
||||
fn test_schema() {
|
||||
let mainpod_schema = schema_for!(SerializedMainPod);
|
||||
let signedpod_schema = schema_for!(SerializedSignedPod);
|
||||
let signeddict_schema = schema_for!(SignedDict);
|
||||
|
||||
let kyc_pod = build_mock_zukyc_pod().unwrap();
|
||||
let signed_pod = signed_pod_builder()
|
||||
let signed_dict = signed_dict_builder()
|
||||
.sign(&Signer(SecretKey(1u32.into())))
|
||||
.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 signed_dict_schema_value = serde_json::to_value(&signeddict_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 signed_dict_value = serde_json::to_value(&signed_dict).unwrap();
|
||||
let signed_dict_valid = jsonschema::validate(&signed_dict_schema_value, &signed_dict_value);
|
||||
assert!(signed_dict_valid.is_ok(), "{:#?}", signed_dict_valid);
|
||||
|
||||
let ethdos_pod_value = serde_json::to_value(ðdos_pod).unwrap();
|
||||
let ethdos_pod_valid = jsonschema::validate(&mainpod_schema_value, ðdos_pod_value);
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue