pod2/src/lang/grammar.pest
Eduard S. 0e2f7b756e
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
2025-08-27 13:19:40 +02:00

114 lines
4 KiB
Text

// Grammar for the "Podlang" language. Used for describing POD2 Custom
// Predicates and Proof Requests.
// Silent rules (`_`) are automatically handled by Pest between other rules.
// WHITESPACE matches one or more spaces, tabs, or newlines.
WHITESPACE = _{ (" " | "\t" | NEWLINE)+ }
// COMMENT matches '//' followed by any characters until the end of the line.
// Also silent.
COMMENT = _{ "//" ~ (!NEWLINE ~ ANY)* }
// Define rules for identifiers (predicate names, variable names without '?')
// Must start with alpha or _, followed by alpha, numeric, or _
identifier = @{ !("private") ~ (ASCII_ALPHA | "_") ~ (ASCII_ALPHANUMERIC | "_")* }
private_kw = { "private:" }
// Define wildcard names (start with '?')
wildcard = @{ "?" ~ identifier }
arg_section = {
public_arg_list ~ ("," ~ private_kw ~ private_arg_list)?
}
public_arg_list = { identifier ~ ("," ~ identifier)* }
private_arg_list = { identifier ~ ("," ~ identifier)* }
document = { SOI ~ (use_statement | custom_predicate_def | request_def)* ~ EOI }
use_statement = { "use" ~ use_predicate_list ~ "from" ~ batch_ref }
use_predicate_list = { import_name ~ ("," ~ import_name)* }
import_name = { identifier | "_" }
batch_ref = { hash_hex }
request_def = { "REQUEST" ~ "(" ~ statement_list? ~ ")" }
// Define conjunction type explicitly
conjunction_type = { "AND" | "OR" }
custom_predicate_def = {
identifier
~ "(" ~ arg_section ~ ")"
~ "="
~ conjunction_type
~ "(" ~ statement_list ~ ")"
}
statement_list = { statement+ }
statement_arg = { anchored_key | wildcard | literal_value }
statement_arg_list = { statement_arg ~ ("," ~ statement_arg)* }
statement = { identifier ~ "(" ~ statement_arg_list? ~ ")" }
// Anchored Key: ?Var["key_literal"]
anchored_key = { wildcard ~ "[" ~ literal_string ~ "]" }
// Literal Values (ordered to avoid ambiguity, e.g., string before int)
literal_value = {
literal_public_key |
literal_secret_key |
literal_dict |
literal_set |
literal_array |
literal_bool |
literal_raw |
literal_string |
literal_int
}
// Primitive literal types
literal_int = @{ "-"? ~ ASCII_DIGIT+ }
literal_bool = @{ "true" | "false" }
// hash_hex: 0x followed by exactly 32 PAIRS of hex digits (64 hex characters)
// representing a 32-byte value in big-endian order
hash_hex = @{ "0x" ~ (ASCII_HEX_DIGIT ~ ASCII_HEX_DIGIT){32} }
literal_raw = { "Raw" ~ "(" ~ hash_hex ~ ")" }
// String literal parsing based on https://pest.rs/book/examples/json.html
literal_string = ${ "\"" ~ inner ~ "\"" } // Compound atomic string rule
inner = @{ char* } // Atomic rule for the raw inner content
char = { // Rule for a single logical character (unescaped or escaped)
!("\"" | "\\") ~ ANY // Any char except quote or backslash
| "\\" ~ ("\"" | "\\" | "/" | "b" | "f" | "n" | "r" | "t") // Simple escape sequences
| "\\" ~ ("u" ~ ASCII_HEX_DIGIT{4}) // Unicode escape sequence
}
// PublicKey(...)
base58_char = { '1'..'9' | 'A'..'H' | 'J'..'N' | 'P'..'Z' | 'a'..'k' | 'm'..'z' }
base58_string = @{ base58_char+ }
literal_public_key = { "PublicKey" ~ "(" ~ base58_string ~ ")" }
// SecretKey(...)
base64_char = { 'a'..'z' | 'A'..'Z' | '0'..'9' | "+" | "/" | "=" }
base64_string = @{ base64_char+ }
literal_secret_key = { "SecretKey" ~ "(" ~ base64_string ~ ")" }
// Container Literals (recursive definition using literal_value)
literal_array = { "[" ~ (literal_value ~ ("," ~ literal_value)*)? ~ "]" }
literal_set = { "#[" ~ (literal_value ~ ("," ~ literal_value)*)? ~ "]" }
literal_dict = { "{" ~ (dict_pair ~ ("," ~ dict_pair)*)? ~ "}" }
dict_pair = { literal_string ~ ":" ~ literal_value }
// --- Rules for testing full input matching ---
test_identifier = { SOI ~ identifier ~ EOI }
test_wildcard = { SOI ~ wildcard ~ EOI }
test_literal_int = { SOI ~ literal_int ~ EOI }
test_hash_hex = { SOI ~ hash_hex ~ EOI }
test_literal_raw = { SOI ~ literal_raw ~ EOI }
test_literal_value = { SOI ~ literal_value ~ EOI }
test_statement = { SOI ~ statement ~ EOI }
test_custom_predicate_def = { SOI ~ custom_predicate_def ~ EOI }