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:
Eduard S. 2025-08-27 13:19:40 +02:00 committed by GitHub
parent 122f9c3cac
commit 0e2f7b756e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
39 changed files with 2127 additions and 3064 deletions

View file

@ -32,9 +32,8 @@ mod tests {
backends::plonky2::primitives::ec::schnorr::SecretKey,
lang::error::ProcessorError,
middleware::{
hash_str, CustomPredicate, CustomPredicateBatch, CustomPredicateRef, Key,
NativePredicate, Params, PodId, PodType, Predicate, RawValue, StatementTmpl,
StatementTmplArg, Value, Wildcard, KEY_SIGNER, KEY_TYPE, SELF,
CustomPredicate, CustomPredicateBatch, CustomPredicateRef, Key, NativePredicate,
Params, Predicate, RawValue, StatementTmpl, StatementTmplArg, Value, Wildcard,
},
};
@ -107,7 +106,7 @@ mod tests {
fn test_e2e_simple_request() -> Result<(), LangError> {
let input = r#"
REQUEST(
Equal(?ConstPod["my_val"], 0x0000000000000000000000000000000000000000000000000000000000000001)
Equal(?ConstPod["my_val"], Raw(0x0000000000000000000000000000000000000000000000000000000000000001))
Lt(?GovPod["dob"], ?ConstPod["my_val"])
)
"#;
@ -482,10 +481,8 @@ mod tests {
#[test]
fn test_e2e_ethdos_predicates() -> Result<(), LangError> {
let params = Params {
max_input_signed_pods: 3,
max_input_recursive_pods: 3,
max_input_pods: 3,
max_statements: 31,
max_signed_pod_values: 8,
max_public_statements: 10,
max_statement_args: 6,
max_operation_args: 5,
@ -496,10 +493,9 @@ mod tests {
};
let input = r#"
eth_friend(src, dst, private: attestation_pod) = AND(
Equal(?attestation_pod["_type"], 1)
Equal(?attestation_pod["_signer"], ?src)
Equal(?attestation_pod["attestation"], ?dst)
eth_friend(src, dst, private: attestation_dict) = AND(
SignedBy(?attestation_dict, ?src)
Equal(?attestation_dict["attestation"], ?dst)
)
eth_dos_distance_base(src, dst, distance) = AND(
@ -536,23 +532,13 @@ mod tests {
// eth_friend (Index 0)
let expected_friend_stmts = vec![
StatementTmpl {
pred: Predicate::Native(NativePredicate::Equal),
args: vec![
sta_ak(("attestation_pod", 2), "_type"), // Pub(0-1), Priv(2)
sta_lit(PodType::Signed),
],
pred: Predicate::Native(NativePredicate::SignedBy),
args: vec![sta_wc_lit("attestation_dict", 2), sta_wc_lit("src", 0)],
},
StatementTmpl {
pred: Predicate::Native(NativePredicate::Equal),
args: vec![
sta_ak(("attestation_pod", 2), "_signer"),
sta_wc_lit("src", 0), // Pub arg 0
],
},
StatementTmpl {
pred: Predicate::Native(NativePredicate::Equal),
args: vec![
sta_ak(("attestation_pod", 2), "attestation"),
sta_ak(("attestation_dict", 2), "attestation"),
sta_wc_lit("dst", 1), // Pub arg 1
],
},
@ -563,7 +549,7 @@ mod tests {
true, // AND
expected_friend_stmts,
2, // public_args_len: src, dst
names(&["src", "dst", "attestation_pod"]),
names(&["src", "dst", "attestation_dict"]),
)?;
// eth_dos_distance_base (Index 1)
@ -853,7 +839,6 @@ mod tests {
#[test]
fn test_e2e_literals() -> Result<(), LangError> {
let pk = crate::backends::plonky2::primitives::ec::curve::Point::generator();
let pod_id = PodId(hash_str("test"));
let raw = RawValue::from(1);
let string = "hello";
let int = 123;
@ -864,17 +849,14 @@ mod tests {
r#"
REQUEST(
Equal(?A["pk"], {})
Equal(?B["pod_id"], {})
Equal(?C["raw"], {})
Equal(?D["string"], {})
Equal(?E["int"], {})
Equal(?F["bool"], {})
Equal(?G["sk"], {})
Equal(?H["self"], SELF)
Equal(?B["raw"], {})
Equal(?C["string"], {})
Equal(?D["int"], {})
Equal(?E["bool"], {})
Equal(?F["sk"], {})
)
"#,
Value::from(pk).to_podlang_string(),
Value::from(pod_id).to_podlang_string(),
Value::from(raw).to_podlang_string(),
Value::from(string).to_podlang_string(),
Value::from(int).to_podlang_string(),
@ -884,7 +866,6 @@ mod tests {
/*
REQUEST(
Equal(?A["pk"], PublicKey(3t9fNuU194n7mSJPRdeaJRMqw6ZQCUddzvECWNe1k2b1rdBezXpJxF))
Equal(?B["pod_id"], 0x735b31d3aad0f5b66002ffe1dc7d2eaa0ee9c59c09b641e8261530c5f3a02f29)
Equal(?C["raw"], Raw(0x0000000000000000000000000000000000000000000000000000000000000001))
Equal(?D["string"], "hello")
Equal(?E["int"], 123)
@ -905,31 +886,23 @@ mod tests {
},
StatementTmpl {
pred: Predicate::Native(NativePredicate::Equal),
args: vec![sta_ak(("B", 1), "pod_id"), sta_lit(Value::from(pod_id))],
args: vec![sta_ak(("B", 1), "raw"), sta_lit(Value::from(raw))],
},
StatementTmpl {
pred: Predicate::Native(NativePredicate::Equal),
args: vec![sta_ak(("C", 2), "raw"), sta_lit(Value::from(raw))],
args: vec![sta_ak(("C", 2), "string"), sta_lit(Value::from(string))],
},
StatementTmpl {
pred: Predicate::Native(NativePredicate::Equal),
args: vec![sta_ak(("D", 3), "string"), sta_lit(Value::from(string))],
args: vec![sta_ak(("D", 3), "int"), sta_lit(Value::from(int))],
},
StatementTmpl {
pred: Predicate::Native(NativePredicate::Equal),
args: vec![sta_ak(("E", 4), "int"), sta_lit(Value::from(int))],
args: vec![sta_ak(("E", 4), "bool"), sta_lit(Value::from(bool))],
},
StatementTmpl {
pred: Predicate::Native(NativePredicate::Equal),
args: vec![sta_ak(("F", 5), "bool"), sta_lit(Value::from(bool))],
},
StatementTmpl {
pred: Predicate::Native(NativePredicate::Equal),
args: vec![sta_ak(("G", 6), "sk"), sta_lit(Value::from(sk))],
},
StatementTmpl {
pred: Predicate::Native(NativePredicate::Equal),
args: vec![sta_ak(("H", 7), "self"), sta_lit(Value::from(SELF))],
args: vec![sta_ak(("F", 5), "sk"), sta_lit(Value::from(sk))],
},
];
@ -972,21 +945,13 @@ mod tests {
let params = Params::default();
let available_batches = &[];
let input = format!(
r#"
identity_verified(username, private: identity_pod) = AND(
Equal(?identity_pod["{key_type}"], {signed_pod_type})
Equal(?identity_pod["{key_signer}"], {identity_server_pk})
Equal(?identity_pod["username"], ?username)
Equal(?identity_pod["user_public_key"], ?user_public_key)
let input = r#"
identity_verified(username, private: identity_dict) = AND(
Equal(?identity_dict["username"], ?username)
Equal(?identity_dict["user_public_key"], ?user_public_key)
)
"#,
key_type = KEY_TYPE,
signed_pod_type = PodType::Signed as u32,
key_signer = KEY_SIGNER,
identity_server_pk =
"0x0000000000000000000000000000000000000000000000000000000000000000"
);
"#
.to_string();
let result = parse(&input, &params, available_batches);