1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
//! # hash-attestation
//!
//! **Sign and verify Kinetic Gain Protocol Suite documents** using ed25519
//! signatures over the same canonical-hash convention every other Suite
//! repo already uses (`sha256:<hex>` over sorted-keys, no-whitespace JSON).
//!
//! ## The missing layer
//!
//! Right now a consumer fetches an AEO doc (or agent-card, or decision-card)
//! over HTTPS and trusts that the bytes came from the published origin. That
//! works for typo-grade tampering but breaks the moment a CDN is misconfigured
//! or an MITM lands. This crate adds a detached-signature layer: vendors sign
//! the canonical hash with an ed25519 private key, publish the public key at a
//! well-known URL, and consumers verify the [`Attestation`] before they trust
//! the doc.
//!
//! ## At-a-glance
//!
//! ```
//! use hash_attestation::{Attestation, Attestor, canonical_hash};
//! use ed25519_dalek::SigningKey;
//! use rand_core::OsRng;
//!
//! let key = SigningKey::generate(&mut OsRng);
//! let attestor = Attestor::new(key.clone(), "https://acme.example/keys/aeo".to_string());
//!
//! let body = serde_json::json!({
//! "aeo_version": "0.1",
//! "entity": { "id": "https://acme.example/#org", "name": "Acme" }
//! });
//!
//! let signed: Attestation = attestor.sign(&body).unwrap();
//! assert!(signed.verify(&key.verifying_key(), &body).is_ok());
//! ```
//!
//! ## What's in the box
//!
//! - [`canonical_hash`] — `sha256:<hex>` over canonical JSON. Same convention
//! as `procurement-decision-api` + `aeo-validator-service`.
//! - [`Attestor`] — wraps a `SigningKey` with the key URL so calls always
//! produce a self-describing [`Attestation`].
//! - [`Attestation`] — serde-serialisable signature record. Drop it next to
//! the source doc as `<doc>.sig.json`, or include it inline.
//! - [`Verifier`] — convenience for verifying with a list of trusted keys.
//!
//! ## Composes with
//!
//! - **[aeo-validator-service](https://github.com/mizcausevic-dev/aeo-validator-service)**
//! — verifies the attestation alongside its drift check; mismatches surface
//! as a top-level `Attestation::Tampered` issue.
//! - **[procurement-decision-api](https://github.com/mizcausevic-dev/procurement-decision-api)**
//! — every published Decision Card can be paired with a signature so policy
//! bundles can prove provenance.
//! - **[aeo-crawler](https://github.com/mizcausevic-dev/aeo-crawler)** — emits
//! the canonical hash for every fetched doc, ready for offline verification.
/// Optional audit-stream-py producer. Gated behind the `audit-stream`
/// Cargo feature so the core crypto crate stays sync and HTTP-free.
pub use Attestation;
pub use Attestor;
pub use AttestationError;
pub use canonical_hash;
// Verifier holds a small set of trusted keys.
pub use Verifier;