1#[cfg(not(feature = "std"))]
7use alloc::{boxed::Box, string::String, vec, vec::Vec};
8
9use serde::ser::{SerializeMap, Serializer};
10use serde::{Deserialize, Serialize};
11
12pub const PROTOCOL_VERSION: i32 = 1;
13pub const MAX_DELEGATION_CHAIN_DEPTH: usize = 3;
14pub const CHALLENGE_WINDOW_SECONDS: i64 = 300;
15
16pub const ED25519_PUBLIC_KEY_SIZE: usize = 32;
17pub const ED25519_SIGNATURE_SIZE: usize = 64;
18pub const MLDSA65_PUBLIC_KEY_SIZE: usize = 1952;
19pub const MLDSA65_SIGNATURE_SIZE: usize = 3309;
20
21#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
26pub struct HybridPublicKey {
27 #[serde(with = "crate::canonical::base64_bytes")]
28 pub ed25519: Vec<u8>, #[serde(with = "crate::canonical::base64_bytes")]
30 pub ml_dsa_65: Vec<u8>, }
32
33#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
37pub struct HybridSignature {
38 #[serde(with = "crate::canonical::base64_bytes")]
39 pub ed25519: Vec<u8>, #[serde(with = "crate::canonical::base64_bytes")]
41 pub ml_dsa_65: Vec<u8>, }
43
44#[derive(Debug, Clone)]
46pub struct HybridPrivateKey {
47 pub ed25519: Vec<u8>, pub ml_dsa_65: Vec<u8>, }
50
51#[derive(Debug, Clone, Serialize, Deserialize)]
53pub struct Anchor {
54 #[serde(rename = "type")]
55 pub anchor_type: String,
56 pub provider: String,
57 pub reference: String,
58 pub verified_at: i64,
59}
60
61#[derive(Debug, Clone, Serialize, Deserialize)]
63pub struct HumanRoot {
64 pub id: String,
65 pub public_key: HybridPublicKey,
66 pub created_at: i64,
67 #[serde(skip_serializing_if = "Option::is_none")]
68 pub anchors: Option<Vec<Anchor>>,
69}
70
71#[derive(Debug, Clone, Serialize, Deserialize)]
73pub struct AgentIdentity {
74 pub id: String,
75 pub public_key: HybridPublicKey,
76 pub name: String,
77 pub agent_type: String,
78 pub created_at: i64,
79}
80
81#[derive(Debug, Clone, Serialize, Deserialize)]
87pub struct DelegationCert {
88 pub cert_id: String,
89 pub version: i32,
90 pub issuer_id: String,
91 pub issuer_pub_key: HybridPublicKey,
92 pub subject_id: String,
93 pub subject_pub_key: HybridPublicKey,
94 pub scope: Vec<String>,
95 #[serde(default)]
98 pub constraints: Vec<Constraint>,
99 pub issued_at: i64,
100 pub expires_at: i64,
101 pub signature: HybridSignature,
102}
103
104#[derive(Debug, Clone, Default, Deserialize)]
120pub struct Constraint {
121 #[serde(default)]
122 pub count: i64,
123 #[serde(default)]
124 pub currency: String,
125 #[serde(default)]
126 pub end: String,
127 #[serde(default)]
128 pub lat: f64,
129 #[serde(default)]
130 pub lon: f64,
131 #[serde(default)]
132 pub max_alt_m: f64,
133 #[serde(default)]
134 pub max_amount: f64,
135 #[serde(default)]
136 pub max_lat: f64,
137 #[serde(default)]
138 pub max_lon: f64,
139 #[serde(default)]
140 pub max_mps: f64,
141 #[serde(default)]
142 pub min_alt_m: f64,
143 #[serde(default)]
144 pub min_lat: f64,
145 #[serde(default)]
146 pub min_lon: f64,
147 #[serde(default)]
148 pub points: Vec<[f64; 2]>,
149 #[serde(default)]
150 pub radius_m: f64,
151 #[serde(default)]
152 pub start: String,
153 #[serde(default)]
154 pub tz: String,
155 #[serde(rename = "type")]
156 pub kind: String,
157 #[serde(default)]
158 pub window_s: i64,
159}
160
161impl Serialize for Constraint {
165 fn serialize<S: Serializer>(&self, serializer: S) -> Result<S::Ok, S::Error> {
166 let entries: Vec<(&'static str, FieldValue)> = match self.kind.as_str() {
170 "geo_circle" => vec![
171 ("lat", FieldValue::F64(self.lat)),
172 ("lon", FieldValue::F64(self.lon)),
173 ("radius_m", FieldValue::F64(self.radius_m)),
174 ("type", FieldValue::Str(self.kind.clone())),
175 ],
176 "geo_polygon" => vec![
177 ("points", FieldValue::Points(self.points.clone())),
178 ("type", FieldValue::Str(self.kind.clone())),
179 ],
180 "geo_bbox" => {
181 let mut v = vec![
182 ("max_lat", FieldValue::F64(self.max_lat)),
183 ("max_lon", FieldValue::F64(self.max_lon)),
184 ("min_lat", FieldValue::F64(self.min_lat)),
185 ("min_lon", FieldValue::F64(self.min_lon)),
186 ];
187 if self.min_alt_m != 0.0 || self.max_alt_m != 0.0 {
188 v.insert(0, ("max_alt_m", FieldValue::F64(self.max_alt_m)));
190 v.insert(3, ("min_alt_m", FieldValue::F64(self.min_alt_m)));
192 }
193 v.push(("type", FieldValue::Str(self.kind.clone())));
194 v
195 }
196 "time_window" => vec![
197 ("end", FieldValue::Str(self.end.clone())),
198 ("start", FieldValue::Str(self.start.clone())),
199 ("type", FieldValue::Str(self.kind.clone())),
200 ("tz", FieldValue::Str(self.tz.clone())),
201 ],
202 "max_speed_mps" => vec![
203 ("max_mps", FieldValue::F64(self.max_mps)),
204 ("type", FieldValue::Str(self.kind.clone())),
205 ],
206 "max_amount" => vec![
207 ("currency", FieldValue::Str(self.currency.clone())),
208 ("max_amount", FieldValue::F64(self.max_amount)),
209 ("type", FieldValue::Str(self.kind.clone())),
210 ],
211 "max_rate" => vec![
212 ("count", FieldValue::I64(self.count)),
213 ("type", FieldValue::Str(self.kind.clone())),
214 ("window_s", FieldValue::I64(self.window_s)),
215 ],
216 _ => vec![("type", FieldValue::Str(self.kind.clone()))],
218 };
219 let mut m = serializer.serialize_map(Some(entries.len()))?;
220 for (k, v) in entries {
221 match v {
222 FieldValue::F64(x) => m.serialize_entry(k, &x)?,
223 FieldValue::I64(x) => m.serialize_entry(k, &x)?,
224 FieldValue::Str(x) => m.serialize_entry(k, &x)?,
225 FieldValue::Points(x) => m.serialize_entry(k, &x)?,
226 }
227 }
228 m.end()
229 }
230}
231
232enum FieldValue {
235 F64(f64),
236 I64(i64),
237 Str(String),
238 Points(Vec<[f64; 2]>),
239}
240
241#[derive(Default)]
245pub struct VerifierContext<'a> {
246 pub current_lat: Option<f64>,
247 pub current_lon: Option<f64>,
248 pub current_alt_m: Option<f64>,
249 pub current_speed_mps: Option<f64>,
250 pub requested_amount: Option<f64>,
251 pub requested_currency: Option<String>,
252 pub invocations_in_window: Option<Box<dyn Fn(&str, i64) -> i64 + 'a>>,
254}
255
256#[derive(Debug, Clone, Serialize, Deserialize)]
264pub struct ProofBundle {
265 pub agent_id: String,
266 pub agent_pub_key: HybridPublicKey,
267 pub delegations: Vec<DelegationCert>,
268 #[serde(with = "crate::canonical::base64_bytes")]
269 pub challenge: Vec<u8>,
270 pub challenge_at: i64,
271 pub challenge_sig: HybridSignature,
272 #[serde(
273 default,
274 skip_serializing_if = "Vec::is_empty",
275 with = "crate::canonical::base64_bytes"
276 )]
277 pub session_context: Vec<u8>,
278 #[serde(
279 default,
280 skip_serializing_if = "Vec::is_empty",
281 with = "crate::canonical::base64_bytes"
282 )]
283 pub stream_id: Vec<u8>,
284 #[serde(default, skip_serializing_if = "is_zero_i64")]
285 pub stream_seq: i64,
286}
287
288fn is_zero_i64(v: &i64) -> bool {
289 *v == 0
290}
291
292#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
296#[serde(rename_all = "snake_case")]
297pub enum IdentityStatus {
298 VerifiedHuman,
299 AuthorizedAgent,
300 Expired,
301 Revoked,
302 ScopeDenied,
303 ConstraintDenied,
304 ConstraintUnverifiable,
305 ConstraintUnknown,
306 DelegationNotAuthorized,
307 Invalid,
308 Unauthorized,
309}
310
311impl IdentityStatus {
312 pub fn as_str(&self) -> &'static str {
313 match self {
314 Self::VerifiedHuman => "verified_human",
315 Self::AuthorizedAgent => "authorized_agent",
316 Self::Expired => "expired",
317 Self::Revoked => "revoked",
318 Self::ScopeDenied => "scope_denied",
319 Self::ConstraintDenied => "constraint_denied",
320 Self::ConstraintUnverifiable => "constraint_unverifiable",
321 Self::ConstraintUnknown => "constraint_unknown",
322 Self::DelegationNotAuthorized => "delegation_not_authorized",
323 Self::Invalid => "invalid",
324 Self::Unauthorized => "unauthorized",
325 }
326 }
327
328 pub fn from_wire(s: &str) -> Option<Self> {
331 Some(match s {
332 "verified_human" => Self::VerifiedHuman,
333 "authorized_agent" => Self::AuthorizedAgent,
334 "expired" => Self::Expired,
335 "revoked" => Self::Revoked,
336 "scope_denied" => Self::ScopeDenied,
337 "constraint_denied" => Self::ConstraintDenied,
338 "constraint_unverifiable" => Self::ConstraintUnverifiable,
339 "constraint_unknown" => Self::ConstraintUnknown,
340 "delegation_not_authorized" => Self::DelegationNotAuthorized,
341 "invalid" => Self::Invalid,
342 "unauthorized" => Self::Unauthorized,
343 _ => return None,
344 })
345 }
346}
347
348#[derive(Debug, Clone, Serialize, Deserialize)]
350pub struct VerifyResult {
351 pub valid: bool,
352 pub identity_status: IdentityStatus,
353 #[serde(skip_serializing_if = "String::is_empty", default)]
354 pub human_id: String,
355 #[serde(skip_serializing_if = "String::is_empty", default)]
356 pub agent_id: String,
357 #[serde(skip_serializing_if = "String::is_empty", default)]
358 pub agent_name: String,
359 #[serde(skip_serializing_if = "String::is_empty", default)]
360 pub agent_type: String,
361 #[serde(skip_serializing_if = "Vec::is_empty", default)]
362 pub granted_scope: Vec<String>,
363 #[serde(skip_serializing_if = "String::is_empty", default)]
364 pub error_reason: String,
365 #[serde(skip_serializing_if = "Option::is_none", default)]
370 pub anchor: Option<Anchor>,
371}
372
373#[derive(Debug, Clone, Serialize, Deserialize)]
375pub struct RevocationList {
376 pub issuer_id: String,
377 pub updated_at: i64,
378 pub revoked_certs: Vec<String>,
379 pub signature: HybridSignature,
380}
381
382#[derive(Debug, Clone, Serialize, Deserialize)]
384pub struct RevocationPush {
385 pub issuer_id: String,
386 pub seq_no: i64,
387 pub entries: Vec<String>,
388 pub pushed_at: i64,
389 pub signature: HybridSignature,
390}
391
392#[derive(Debug, Clone, Serialize, Deserialize)]
394pub struct WitnessEntry {
395 #[serde(with = "crate::canonical::base64_bytes")]
396 pub prev_hash: Vec<u8>,
397 #[serde(with = "crate::canonical::base64_bytes")]
398 pub entry_data: Vec<u8>,
399 pub timestamp: i64,
400 pub witness_id: String,
401 pub signature: HybridSignature,
402}
403
404#[derive(Debug, Clone, Serialize, Deserialize)]
408pub struct SessionToken {
409 pub version: i32,
410 pub session_id: String,
411 pub agent_id: String,
412 pub agent_pub_key: HybridPublicKey,
413 pub human_id: String,
414 pub granted_scope: Vec<String>,
415 pub issued_at: i64,
416 pub valid_until: i64,
417 #[serde(with = "crate::canonical::base64_bytes")]
418 pub chain_hash: Vec<u8>,
419 #[serde(with = "crate::canonical::base64_bytes")]
420 pub mac: Vec<u8>,
421}
422
423#[derive(Debug, Clone, Serialize, Deserialize)]
425pub struct TransactionReceipt {
426 pub version: i32,
427 pub transaction_id: String,
428 pub created_at: i64,
429 pub terms_schema_uri: String,
430 #[serde(with = "crate::canonical::base64_bytes")]
431 pub terms_canonical_json: Vec<u8>,
432 pub parties: Vec<ReceiptParty>,
433 pub party_signatures: Vec<ReceiptPartySignature>,
434}
435
436#[derive(Debug, Clone, Serialize, Deserialize)]
438pub struct ReceiptParty {
439 pub party_id: String,
440 pub role: String,
441 pub agent_id: String,
442 pub agent_pub_key: HybridPublicKey,
443 pub proof_bundle: ProofBundle,
444}
445
446#[derive(Debug, Clone, Serialize, Deserialize)]
448pub struct ReceiptPartySignature {
449 pub party_id: String,
450 pub signature: HybridSignature,
451}
452
453pub struct TransactionReceiptResult {
455 pub valid: bool,
456 pub error_reason: String,
457 pub party_results: Vec<VerifyResult>,
458}
459
460#[derive(Debug, Clone, Serialize, Deserialize)]
462pub struct KeyRotationStatement {
463 pub version: i32,
464 pub old_id: String,
465 pub old_pub_key: HybridPublicKey,
466 pub new_id: String,
467 pub new_pub_key: HybridPublicKey,
468 pub rotated_at: i64,
469 pub reason: String,
470 pub signature_old: HybridSignature,
471 pub signature_new: HybridSignature,
472}
473
474#[derive(Debug, Clone, Default)]
480pub struct StreamContext {
481 pub stream_id: Vec<u8>,
482 pub last_seen_seq: i64,
483}
484
485pub trait RevocationProvider {
493 fn is_revoked(&self, cert_id: &str) -> Result<bool, String>;
494}
495
496pub trait PolicyProvider {
502 fn evaluate_policy(
503 &self,
504 bundle: &ProofBundle,
505 context: &VerifierContext,
506 ) -> Result<bool, String>;
507}
508
509pub trait AuditProvider {
514 fn log_verification(&self, result: &VerifyResult, bundle: &ProofBundle);
515}
516
517pub trait ConstraintEvaluator {
526 fn evaluate(
527 &self,
528 constraint: &Constraint,
529 cert_id: &str,
530 context: &VerifierContext,
531 now: i64,
532 ) -> Result<(), String>;
533}
534
535pub trait AnchorResolver {
540 fn resolve_anchor(&self, human_id: &str) -> Result<Option<Anchor>, String>;
541}
542
543#[derive(Debug, Clone, Serialize, Deserialize)]
548pub struct PolicyVerdict {
549 pub version: i32,
550 pub verdict_id: String,
551 pub agent_id: String,
552 pub scope: String,
553 pub allow: bool,
554 #[serde(with = "crate::canonical::base64_bytes")]
555 pub context_hash: Vec<u8>, pub issued_at: i64,
557 pub valid_until: i64,
558 #[serde(with = "crate::canonical::base64_bytes")]
559 pub mac: Vec<u8>, }
561
562#[derive(Debug, Clone, Serialize, Deserialize)]
569pub struct VerificationReceipt {
570 pub version: i32,
571 pub verifier_id: String,
572 pub verifier_pub: HybridPublicKey,
573 #[serde(with = "crate::canonical::base64_bytes")]
574 pub bundle_hash: Vec<u8>, pub decision: String,
576 #[serde(skip_serializing_if = "String::is_empty", default)]
577 pub human_id: String,
578 #[serde(skip_serializing_if = "String::is_empty", default)]
579 pub agent_id: String,
580 #[serde(skip_serializing_if = "Vec::is_empty", default)]
581 pub granted_scope: Vec<String>,
582 #[serde(skip_serializing_if = "String::is_empty", default)]
583 pub error_reason: String,
584 pub verified_at: i64,
585 #[serde(with = "crate::canonical::base64_bytes")]
586 pub prev_hash: Vec<u8>, pub signature: HybridSignature,
588}
589
590pub struct VerifyOptions<'a> {
592 pub required_scope: String,
594 #[deprecated(since = "1.0.0-alpha.7", note = "use `revocation` (SPEC §17.1) instead")]
601 pub is_revoked: Option<Box<dyn Fn(&str) -> bool + 'a>>,
602 pub revocation: Option<Box<dyn RevocationProvider + 'a>>,
605 pub force_revocation_check: bool,
609 pub now: Option<i64>,
611 pub session_context: Vec<u8>,
613 pub stream: Option<StreamContext>,
615 pub context: VerifierContext<'a>,
619 pub policy: Option<Box<dyn PolicyProvider + 'a>>,
623 pub audit: Option<Box<dyn AuditProvider + 'a>>,
627 pub constraint_evaluators:
631 Option<alloc::collections::BTreeMap<String, Box<dyn ConstraintEvaluator + 'a>>>,
632 pub policy_verdict: Option<PolicyVerdict>,
637 pub policy_secret: Option<Vec<u8>>,
639 pub anchor_resolver: Option<Box<dyn AnchorResolver + 'a>>,
643}
644
645impl<'a> Default for VerifyOptions<'a> {
646 fn default() -> Self {
647 #[allow(deprecated)]
651 Self {
652 required_scope: String::new(),
653 is_revoked: None,
654 revocation: None,
655 force_revocation_check: false,
656 now: None,
657 session_context: Vec::new(),
658 stream: None,
659 context: VerifierContext::default(),
660 policy: None,
661 audit: None,
662 constraint_evaluators: None,
663 policy_verdict: None,
664 policy_secret: None,
665 anchor_resolver: None,
666 }
667 }
668}