1use serde::{Deserialize, Serialize};
9
10pub type Address = [u8; 20];
11
12#[derive(Clone, Debug, Serialize, Deserialize)]
14#[serde(rename_all = "camelCase")]
15pub struct PaymentRequirements {
16 pub scheme: String,
17 pub network: String,
18 pub amount: String,
19 #[serde(with = "hex_address")]
20 pub asset: Address,
21 #[serde(with = "hex_address")]
22 pub pay_to: Address,
23 pub max_timeout_seconds: u64,
24 pub extra: ZkExtra,
25}
26
27#[derive(Clone, Debug, Serialize, Deserialize)]
29#[serde(rename_all = "camelCase")]
30pub struct ZkExtra {
31 pub proof_system: String,
32 pub circuit_id: String,
33 #[serde(with = "hex_address")]
34 pub verifier_address: Address,
35}
36
37#[derive(Clone, Debug, Serialize, Deserialize)]
39#[serde(rename_all = "camelCase")]
40pub struct PublicInputs {
41 pub amount: String,
42 #[serde(with = "hex_address")]
43 pub asset: Address,
44 #[serde(with = "hex_address")]
45 pub pay_to: Address,
46 #[serde(with = "hex_address")]
47 pub from: Address,
48 pub network: String,
49 #[serde(with = "hex_nonce")]
50 pub nonce: [u8; 32],
51 pub valid_after: u64,
52 pub valid_before: u64,
53 #[serde(with = "hex_bytes")]
55 pub public_key: Vec<u8>,
56}
57
58#[derive(Clone, Debug, Serialize, Deserialize)]
60#[serde(rename_all = "camelCase")]
61pub struct PaymentPayload {
62 pub x402_version: u8,
63 pub accepted: PaymentRequirements,
64 #[serde(with = "hex_bytes")]
65 pub proof: Vec<u8>,
66 pub public_inputs: PublicInputs,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub proof_system_extra: Option<serde_json::Value>,
69}
70
71#[derive(Clone, Debug, Serialize, Deserialize)]
73#[serde(rename_all = "camelCase")]
74pub struct VerifyResponse {
75 pub is_valid: bool,
76 #[serde(skip_serializing_if = "Option::is_none")]
77 pub invalid_reason: Option<String>,
78}
79
80#[derive(Clone, Debug, Serialize, Deserialize)]
82#[serde(rename_all = "camelCase")]
83pub struct SettleResponse {
84 pub success: bool,
85 #[serde(skip_serializing_if = "Option::is_none")]
86 pub tx_hash: Option<String>,
87 #[serde(skip_serializing_if = "Option::is_none")]
88 pub error: Option<String>,
89}
90
91pub trait ProofSystem {
96 type ProvingKey;
97 type VerifyingKey;
98
99 fn prove(
100 pk: &Self::ProvingKey,
101 witness: &Witness,
102 public_inputs: &PublicInputs,
103 ) -> Result<Vec<u8>, ProofSystemError>;
104
105 fn verify(
106 vk: &Self::VerifyingKey,
107 proof: &[u8],
108 public_inputs: &PublicInputs,
109 ) -> Result<bool, ProofSystemError>;
110}
111
112#[derive(Clone, Debug)]
114pub struct Witness {
115 pub secret_key: Vec<u8>,
116 pub nonce_scalar: Vec<u8>,
117}
118
119#[derive(Debug)]
120pub enum ProofSystemError {
121 InvalidParameters,
122 ProvingFailed(String),
123 VerificationFailed(String),
124 Encoding(String),
125}
126
127impl std::fmt::Display for ProofSystemError {
128 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
129 match self {
130 Self::InvalidParameters => write!(f, "invalid proof system parameters"),
131 Self::ProvingFailed(msg) => write!(f, "proving failed: {msg}"),
132 Self::VerificationFailed(msg) => write!(f, "verification failed: {msg}"),
133 Self::Encoding(msg) => write!(f, "encoding error: {msg}"),
134 }
135 }
136}
137
138impl std::error::Error for ProofSystemError {}
139
140pub trait VerifyingKeyRegistry {
144 type VerifyingKeyHandle;
145
146 fn lookup(
147 &self,
148 proof_system: &str,
149 circuit_id: &str,
150 ) -> Option<Self::VerifyingKeyHandle>;
151}
152
153#[async_trait::async_trait]
155pub trait Scheme {
156 fn scheme_name(&self) -> &str;
157
158 async fn verify(
159 &self,
160 req: &PaymentRequirements,
161 payload: &PaymentPayload,
162 ) -> Result<VerifyResponse, SchemeError>;
163
164 async fn settle(
165 &self,
166 req: &PaymentRequirements,
167 payload: &PaymentPayload,
168 ) -> Result<SettleResponse, SchemeError>;
169}
170
171#[derive(Debug)]
172pub enum SchemeError {
173 StructuralMismatch(String),
174 UnsupportedCircuit,
175 CryptographicVerificationFailed,
176 Expired,
177 ChainError(String),
178 Internal(String),
179}
180
181impl std::fmt::Display for SchemeError {
182 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
183 match self {
184 Self::StructuralMismatch(msg) => write!(f, "structural mismatch: {msg}"),
185 Self::UnsupportedCircuit => write!(f, "unsupported circuit"),
186 Self::CryptographicVerificationFailed => write!(f, "proof verification failed"),
187 Self::Expired => write!(f, "payment window expired or not yet valid"),
188 Self::ChainError(msg) => write!(f, "chain error: {msg}"),
189 Self::Internal(msg) => write!(f, "internal error: {msg}"),
190 }
191 }
192}
193
194impl std::error::Error for SchemeError {}
195
196mod hex_address {
198 use serde::{Deserialize, Deserializer, Serializer};
199
200 pub fn serialize<S>(bytes: &[u8; 20], serializer: S) -> Result<S::Ok, S::Error>
201 where
202 S: Serializer,
203 {
204 let hex_string = format!("0x{}", hex::encode(bytes));
205 serializer.serialize_str(&hex_string)
206 }
207
208 pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 20], D::Error>
209 where
210 D: Deserializer<'de>,
211 {
212 let s = String::deserialize(deserializer)?;
213 let s = s.strip_prefix("0x").unwrap_or(&s);
214 let bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
215 bytes.try_into().map_err(|_| {
216 serde::de::Error::custom("expected 20 bytes for address")
217 })
218 }
219}
220
221mod hex_nonce {
222 use serde::{Deserialize, Deserializer, Serializer};
223
224 pub fn serialize<S>(bytes: &[u8; 32], serializer: S) -> Result<S::Ok, S::Error>
225 where
226 S: Serializer,
227 {
228 let hex_string = format!("0x{}", hex::encode(bytes));
229 serializer.serialize_str(&hex_string)
230 }
231
232 pub fn deserialize<'de, D>(deserializer: D) -> Result<[u8; 32], D::Error>
233 where
234 D: Deserializer<'de>,
235 {
236 let s = String::deserialize(deserializer)?;
237 let s = s.strip_prefix("0x").unwrap_or(&s);
238 let bytes = hex::decode(s).map_err(serde::de::Error::custom)?;
239 bytes.try_into().map_err(|_| {
240 serde::de::Error::custom("expected 32 bytes for nonce")
241 })
242 }
243}
244
245mod hex_bytes {
246 use serde::{Deserialize, Deserializer, Serializer};
247
248 pub fn serialize<S>(bytes: &[u8], serializer: S) -> Result<S::Ok, S::Error>
249 where
250 S: Serializer,
251 {
252 let hex_string = format!("0x{}", hex::encode(bytes));
253 serializer.serialize_str(&hex_string)
254 }
255
256 pub fn deserialize<'de, D>(deserializer: D) -> Result<Vec<u8>, D::Error>
257 where
258 D: Deserializer<'de>,
259 {
260 let s = String::deserialize(deserializer)?;
261 let s = s.strip_prefix("0x").unwrap_or(&s);
262 hex::decode(s).map_err(serde::de::Error::custom)
263 }
264}