Skip to main content

zk_protocol/
lib.rs

1/// General protocol for ZK attestation between agents
2/// This library provides common types and serialization helpers
3/// that any agent can use without depending on other agents' code.
4
5use serde::{Deserialize, Serialize};
6use serde_json::Value;
7
8/// Request to the attester service to generate a ZK proof
9#[derive(Serialize, Deserialize, Debug, Clone)]
10pub struct AttestRequest {
11    pub program_id: String,
12    /// Input data as raw bytes (bincode-serialized)
13    /// Will be passed to the zkVM program via stdin as a single buffer entry.
14    /// For programs that call io::read() multiple times, use `stdin_items` instead.
15    pub input_bytes: Vec<u8>,
16    /// Multiple stdin buffer entries (each pushed separately).
17    /// When present, each entry maps to one sp1_zkvm::io::read() call.
18    /// Takes precedence over `input_bytes` when non-empty.
19    #[serde(default)]
20    pub stdin_items: Vec<Vec<u8>>,
21    /// Expected output for verification (optional, format defined by agent)
22    pub claimed_output: Option<Value>,
23    /// Whether to verify the proof locally before returning
24    #[serde(default = "default_verify")]
25    pub verify_locally: bool,
26    /// Optional external transaction ID (payment processor binding).
27    /// When present, the attester auto-saves the proof keyed by this ID
28    /// so the payment processor can pull it directly — bypassing the LLM.
29    #[serde(default, skip_serializing_if = "Option::is_none")]
30    pub external_id: Option<String>,
31    /// Intent commitment: SHA-256(proof_hash || "||" || external_id).
32    /// Stored alongside the proof for retrieval by the payment processor.
33    #[serde(default, skip_serializing_if = "Option::is_none")]
34    pub intent_commitment: Option<String>,
35    /// Fields verified in the proof (e.g. ["amount", "quantity", "product_id"]).
36    #[serde(default, skip_serializing_if = "Option::is_none")]
37    pub verified_fields: Option<Vec<String>>,
38}
39
40fn default_verify() -> bool {
41    true
42}
43
44/// Response from the attester service
45#[derive(Serialize, Deserialize, Debug, Clone)]
46pub struct AttestResponse {
47    /// Hex-encoded Groth16 proof for on-chain verification
48    pub proof: String,
49    /// Public values committed by the zkVM program (hex-encoded)
50    pub public_values: String,
51    /// VK hash for on-chain verifier (bytes32)
52    pub vk_hash: String,
53    /// Output from the zkVM program
54    pub verified_output: Value,
55    /// Echo back the external_id if one was provided in the request.
56    #[serde(default, skip_serializing_if = "Option::is_none")]
57    pub external_id: Option<String>,
58}
59
60/// Response from POST /register-elf
61#[derive(Serialize, Deserialize, Debug, Clone)]
62pub struct RegisterResponse {
63    /// Content-addressable program ID (e.g. "sha256:<hex>")
64    pub program_id: String,
65    /// Version number (defaults to 1)
66    #[serde(default = "default_version")]
67    pub version: i32,
68    /// ISO-8601 timestamp
69    pub registered_at: String,
70}
71
72fn default_version() -> i32 {
73    1
74}
75
76/// Response from an agent's pricing/booking endpoint
77#[derive(Serialize, Deserialize, Debug, Clone)]
78pub struct AgentResponse {
79    /// Agent-specific response data (price, booking ID, etc.)
80    #[serde(flatten)]
81    pub data: Value,
82    /// Program ID for ZK verification
83    pub program_id: String,
84    /// ELF hash of the zkVM program
85    pub elf_hash: String,
86}
87
88/// Helper to serialize any serde-compatible type to bincode bytes
89pub fn serialize_input<T: Serialize>(input: &T) -> Result<Vec<u8>, bincode::Error> {
90    bincode::serialize(input)
91}
92
93/// Helper to deserialize bincode bytes to any serde-compatible type
94pub fn deserialize_output<T: for<'de> Deserialize<'de>>(bytes: &[u8]) -> Result<T, bincode::Error> {
95    bincode::deserialize(bytes)
96}
97
98/// Convert bincode bytes to JSON array format for HTTP transport
99pub fn bytes_to_json_array(bytes: &[u8]) -> Value {
100    Value::Array(bytes.iter().map(|b| Value::Number((*b).into())).collect())
101}
102
103/// Extract bytes from JSON array format
104pub fn json_array_to_bytes(value: &Value) -> Option<Vec<u8>> {
105    if let Value::Array(arr) = value {
106        Some(arr.iter().filter_map(|v| v.as_u64().map(|n| n as u8)).collect())
107    } else {
108        None
109    }
110}