Skip to main content

pamoja_audit/
lib.rs

1#![cfg_attr(not(test), no_std)]
2
3//! Tamper-evident audit logs for the pamoja SDK.
4//!
5//! The health and cold-chain deployments this SDK targets need more than authentic
6//! readings; they need an authentic *record* of them. A vaccine fridge's
7//! temperature history is only useful as evidence if no one can quietly edit out an
8//! excursion, drop an inconvenient reading, or reorder the log after the fact. This
9//! crate provides that record by chaining signed entries together:
10//!
11//! - [`AuditLog`] - appends entries, each signed with a
12//!   [`DeviceIdentity`](pamoja_security::DeviceIdentity) and linked by hash to the
13//!   entry before it.
14//! - [`Entry`] - one record: its payload, its index, the previous entry's digest,
15//!   and the signature, with a byte form for durable storage.
16//! - [`Verifier`] and [`verify_chain`] - replay a stored log and confirm, against the
17//!   device's [`PublicIdentity`](pamoja_security::PublicIdentity), that every entry
18//!   is in sequence, correctly chained, and authentically signed.
19//!
20//! Because each entry commits to the previous one with a SHA-256 hash and an ed25519
21//! signature, altering a payload, reordering entries, inserting a forgery, or
22//! dropping a record all break verification at the point of tampering. The crate is
23//! `no_std` and synchronous, so the same log can be written on a microcontroller and
24//! audited on a server.
25//!
26//! # Examples
27//!
28//! ```
29//! use pamoja_audit::{verify_chain, AuditLog, Entry};
30//! use pamoja_security::DeviceIdentity;
31//!
32//! let device = DeviceIdentity::from_seed(&[9u8; 32]);
33//! let public = device.public();
34//!
35//! // Record two readings, persisting each entry's bytes as you would to an SD card.
36//! let mut log = AuditLog::new(device);
37//! let mut stored: Vec<Vec<u8>> = Vec::new();
38//! for reading in [b"4.6C".as_slice(), b"4.9C".as_slice()] {
39//!     stored.push(log.append(reading).to_bytes());
40//! }
41//!
42//! // An auditor rebuilds the chain from storage and verifies it.
43//! let entries: Vec<Entry> = stored
44//!     .iter()
45//!     .map(|bytes| Entry::from_bytes(bytes))
46//!     .collect::<pamoja_core::Result<_>>()
47//!     .unwrap();
48//! assert!(verify_chain(&public, &entries).is_ok());
49//! ```
50
51extern crate alloc;
52
53mod entry;
54mod log;
55
56pub use entry::Entry;
57pub use log::{verify_chain, AuditLog, Verifier};