1pub mod credentials;
12pub mod did;
13pub mod mandates;
14pub mod verification;
15
16pub use credentials::{
17 CredentialSubject, Proof, ProofPurpose, VerifiableCredential, VerificationMethod,
18};
19pub use did::{DidDocument, DidManager, DidResolver, ServiceEndpoint};
20pub use mandates::{
21 CartItem, CartMandate, IntentMandate, Mandate, MandateStatus, MandateType, PaymentMandate,
22 PaymentMethod, Permission,
23};
24pub use verification::{
25 ConsensusVerification, VerificationResult, VerificationWorkflow, VerifierNode,
26};
27
28use chrono::{DateTime, Utc};
29use serde::{Deserialize, Serialize};
30use std::collections::HashMap;
31use thiserror::Error;
32
33pub const AP2_VERSION: &str = "1.0.0";
35
36#[derive(Debug, Error)]
38pub enum Ap2Error {
39 #[error("Invalid credential: {0}")]
40 InvalidCredential(String),
41
42 #[error("Signature verification failed: {0}")]
43 SignatureVerificationFailed(String),
44
45 #[error("DID resolution failed: {0}")]
46 DidResolutionFailed(String),
47
48 #[error("Mandate validation failed: {0}")]
49 MandateValidationFailed(String),
50
51 #[error("Consensus verification failed: {0}")]
52 ConsensusVerificationFailed(String),
53
54 #[error("Expired credential or mandate")]
55 Expired,
56
57 #[error("Insufficient authorization: {0}")]
58 InsufficientAuthorization(String),
59
60 #[error("Serialization error: {0}")]
61 SerializationError(String),
62
63 #[error("Cryptographic error: {0}")]
64 CryptographicError(String),
65}
66
67pub type Result<T> = std::result::Result<T, Ap2Error>;
68
69pub const VC_CONTEXT: &str = "https://www.w3.org/2018/credentials/v1";
71pub const AP2_CONTEXT: &str = "https://ap2.protocol/v1";
72
73#[derive(Debug, Clone, Serialize, Deserialize, PartialEq)]
75pub struct AgentIdentity {
76 pub did: String,
77 pub public_key: Vec<u8>,
78 pub metadata: HashMap<String, String>,
79}
80
81impl AgentIdentity {
82 pub fn new(did: String, public_key: Vec<u8>) -> Self {
83 Self {
84 did,
85 public_key,
86 metadata: HashMap::new(),
87 }
88 }
89
90 pub fn with_metadata(mut self, key: String, value: String) -> Self {
91 self.metadata.insert(key, value);
92 self
93 }
94}
95
96#[derive(Debug, Clone, Serialize, Deserialize)]
98pub struct PaymentAuthorization {
99 pub intent_mandate: VerifiableCredential,
100 pub cart_mandate: VerifiableCredential,
101 pub payment_mandate: VerifiableCredential,
102 pub authorization_chain: Vec<VerifiableCredential>,
103 pub timestamp: DateTime<Utc>,
104}
105
106impl PaymentAuthorization {
107 pub fn new(
108 intent_mandate: VerifiableCredential,
109 cart_mandate: VerifiableCredential,
110 payment_mandate: VerifiableCredential,
111 ) -> Self {
112 Self {
113 intent_mandate: intent_mandate.clone(),
114 cart_mandate: cart_mandate.clone(),
115 payment_mandate: payment_mandate.clone(),
116 authorization_chain: vec![intent_mandate, cart_mandate, payment_mandate],
117 timestamp: Utc::now(),
118 }
119 }
120
121 pub fn verify_chain(&self, did_resolver: &DidResolver) -> Result<bool> {
123 for credential in &self.authorization_chain {
124 if !credential.verify(did_resolver)? {
125 return Ok(false);
126 }
127 }
128 Ok(true)
129 }
130
131 pub fn is_valid(&self) -> bool {
133 let now = Utc::now();
134 self.authorization_chain
135 .iter()
136 .all(|vc| vc.expiration_date.map_or(true, |exp| exp > now))
137 }
138}
139
140#[derive(Debug)]
142pub struct Ap2Protocol {
143 did_manager: DidManager,
144 did_resolver: DidResolver,
145 verification_workflow: VerificationWorkflow,
146}
147
148impl Ap2Protocol {
149 pub fn new() -> Self {
150 Self {
151 did_manager: DidManager::new(),
152 did_resolver: DidResolver::new(),
153 verification_workflow: VerificationWorkflow::new(),
154 }
155 }
156
157 pub fn register_agent(&mut self, agent_id: &str, public_key: Vec<u8>) -> Result<AgentIdentity> {
159 let did = self.did_manager.create_did(agent_id, public_key.clone())?;
160 Ok(AgentIdentity::new(did, public_key))
161 }
162
163 pub fn create_intent_mandate(
165 &self,
166 issuer: &AgentIdentity,
167 subject_agent: &str,
168 intent_description: &str,
169 private_key: &[u8],
170 ) -> Result<VerifiableCredential> {
171 let mandate = IntentMandate::new(
172 issuer.did.clone(),
173 subject_agent.to_string(),
174 intent_description.to_string(),
175 );
176
177 let subject = CredentialSubject {
178 id: subject_agent.to_string(),
179 claims: serde_json::to_value(mandate)
180 .map_err(|e| Ap2Error::SerializationError(e.to_string()))?,
181 };
182
183 VerifiableCredential::new(issuer.did.clone(), subject, private_key)
184 }
185
186 pub fn create_cart_mandate(
188 &self,
189 issuer: &AgentIdentity,
190 items: Vec<CartItem>,
191 total_amount: u64,
192 currency: &str,
193 private_key: &[u8],
194 ) -> Result<VerifiableCredential> {
195 let mandate = CartMandate::new(issuer.did.clone(), items, total_amount, currency.to_string());
196
197 let subject = CredentialSubject {
198 id: issuer.did.clone(),
199 claims: serde_json::to_value(mandate)
200 .map_err(|e| Ap2Error::SerializationError(e.to_string()))?,
201 };
202
203 VerifiableCredential::new(issuer.did.clone(), subject, private_key)
204 }
205
206 pub fn create_payment_mandate(
208 &self,
209 issuer: &AgentIdentity,
210 recipient: &str,
211 amount: u64,
212 currency: &str,
213 payment_method: &str,
214 private_key: &[u8],
215 ) -> Result<VerifiableCredential> {
216 let mandate = PaymentMandate::new(
217 issuer.did.clone(),
218 recipient.to_string(),
219 amount,
220 currency.to_string(),
221 payment_method.to_string(),
222 );
223
224 let subject = CredentialSubject {
225 id: recipient.to_string(),
226 claims: serde_json::to_value(mandate)
227 .map_err(|e| Ap2Error::SerializationError(e.to_string()))?,
228 };
229
230 VerifiableCredential::new(issuer.did.clone(), subject, private_key)
231 }
232
233 pub async fn verify_payment_authorization(
235 &self,
236 authorization: &PaymentAuthorization,
237 verifier_nodes: Vec<VerifierNode>,
238 ) -> Result<VerificationResult> {
239 if !authorization.verify_chain(&self.did_resolver)? {
241 return Err(Ap2Error::ConsensusVerificationFailed(
242 "Credential chain verification failed".to_string(),
243 ));
244 }
245
246 self.verification_workflow
248 .verify_with_consensus(
249 &authorization.payment_mandate,
250 verifier_nodes,
251 &self.did_resolver,
252 )
253 .await
254 }
255
256 pub fn resolve_did(&self, did: &str) -> Result<DidDocument> {
258 self.did_resolver.resolve(did)
259 }
260
261 pub fn did_resolver(&self) -> &DidResolver {
263 &self.did_resolver
264 }
265
266 pub fn did_manager(&self) -> &DidManager {
268 &self.did_manager
269 }
270}
271
272impl Default for Ap2Protocol {
273 fn default() -> Self {
274 Self::new()
275 }
276}
277
278#[cfg(test)]
279mod tests {
280 use super::*;
281
282 #[test]
283 fn test_agent_identity_creation() {
284 let public_key = vec![1, 2, 3, 4];
285 let identity = AgentIdentity::new("did:example:123".to_string(), public_key.clone());
286
287 assert_eq!(identity.did, "did:example:123");
288 assert_eq!(identity.public_key, public_key);
289 }
290
291 #[test]
292 fn test_ap2_protocol_initialization() {
293 let protocol = Ap2Protocol::new();
294 assert!(protocol.did_resolver.resolve("test").is_err());
295 }
296
297 #[test]
298 fn test_payment_authorization_validity() {
299 let protocol = Ap2Protocol::new();
301
302 assert!(protocol.did_resolver.resolve("did:example:test").is_err());
304 }
305}