Examples
Basic receipt verification
The most common use case — verify a receipt file using anchor-based trust:
use atl_core::prelude::*;
use std::fs;
fn main() -> AtlResult<()> {
// Load receipt from .atl file
let receipt_json = fs::read_to_string("document.pdf.atl")?;
let receipt = Receipt::from_json(&receipt_json)?;
// Verify using external anchors (no key required)
let verifier = ReceiptVerifier::anchor_only();
let result = verifier.verify(&receipt);
if result.is_valid() {
println!("Receipt verified!");
println!("Entry ID: {}", receipt.entry.id);
println!("Payload hash: {}", receipt.entry.payload_hash);
println!("Metadata hash: {}", receipt.entry.metadata_hash);
println!("Checkpoint timestamp (ns): {}", receipt.proof.checkpoint.timestamp);
if result.has_valid_anchor() {
println!("Trust established via external anchor");
}
} else {
println!("Verification failed:");
for error in &result.errors {
println!(" - {:?}", error);
}
}
Ok(())
}Verification with public key
If you have the Log Operator’s public key, add signature verification as an integrity check:
use atl_core::prelude::*;
fn verify_with_key(receipt_json: &str, public_key: &[u8; 32]) -> AtlResult<()> {
let receipt = Receipt::from_json(receipt_json)?;
// Create checkpoint verifier from public key
let checkpoint_verifier = CheckpointVerifier::from_bytes(public_key)?;
// Verify with signature check
let verifier = ReceiptVerifier::with_key(checkpoint_verifier);
let result = verifier.verify(&receipt);
if result.is_valid() {
println!("Receipt verified!");
// Signature is an integrity check, not trust
if result.signature_status.is_verified() {
println!("Signature valid (integrity check passed)");
}
// Trust comes from anchors
if result.has_valid_anchor() {
println!("Receipt is trustworthy (anchor verified)");
}
}
Ok(())
}Check receipt tier
Determine receipt completeness level:
use atl_core::prelude::*;
fn check_tier(receipt_json: &str) -> AtlResult<()> {
let receipt = Receipt::from_json(receipt_json)?;
match receipt.tier() {
ReceiptTier::Full => {
println!("Full receipt - all proofs and anchors present");
}
ReceiptTier::Tsa => {
println!("TSA receipt - RFC 3161 anchor present, Bitcoin OTS missing");
}
ReceiptTier::Lite => {
println!("Lite receipt - insufficient anchors for higher tiers");
}
}
Ok(())
}Verify data hash
Verify that a file matches the hash in the receipt:
use atl_core::prelude::*;
use sha2::{Sha256, Digest};
use std::fs;
fn verify_file_matches_receipt(
file_path: &str,
receipt_path: &str,
) -> AtlResult<bool> {
// Load and hash the file
let file_data = fs::read(file_path)?;
let mut hasher = Sha256::new();
hasher.update(&file_data);
let file_hash = hex::encode(hasher.finalize());
let file_hash_prefixed = format!("sha256:{file_hash}");
// Load receipt
let receipt_json = fs::read_to_string(receipt_path)?;
let receipt = Receipt::from_json(&receipt_json)?;
// Compare hashes
let matches = file_hash_prefixed == receipt.entry.payload_hash;
if matches {
println!("File hash matches receipt");
} else {
println!("Hash mismatch!");
println!(" File: {}", file_hash_prefixed);
println!(" Receipt: {}", receipt.entry.payload_hash);
}
Ok(matches)
}Cross-receipt verification
Verify that two receipts come from the same log instance with consistent history:
use atl_core::prelude::*;
fn verify_same_log(receipt_a_json: &str, receipt_b_json: &str) -> AtlResult<()> {
let receipt_a = Receipt::from_json(receipt_a_json)?;
let receipt_b = Receipt::from_json(receipt_b_json)?;
let result = verify_cross_receipts(&receipt_a, &receipt_b);
if result.is_valid() {
println!("Both receipts from same log instance");
println!("History is consistent (append-only verified)");
println!(
"Receipt A at index {}, Receipt B at index {}",
result.receipt_a_index, result.receipt_b_index
);
} else {
println!("Cross-receipt verification failed:");
for error in &result.errors {
println!(" - {}", error);
}
}
Ok(())
}Merkle tree operations
Low-level Merkle tree operations:
use atl_core::{compute_root, generate_inclusion_proof, verify_inclusion, AtlResult, Hash};
fn merkle_examples() -> AtlResult<()> {
// Two leaves (already hashed values)
let leaves: Vec<Hash> = vec![[0u8; 32], [1u8; 32]];
let root = compute_root(&leaves);
// Provide storage callback for proof generation (level 0 = leaves)
let get_node = |level: u32, index: u64| -> Option<Hash> {
if level == 0 {
leaves.get(index as usize).copied()
} else {
None
}
};
let proof = generate_inclusion_proof(0, leaves.len() as u64, get_node)?;
let is_included = verify_inclusion(&leaves[0], &proof, &root)?;
println!("Included: {is_included}");
Ok(())
}JCS canonicalization
Create deterministic JSON for hashing:
use atl_core::prelude::*;
use serde_json::json;
fn jcs_example() {
let data = json!({
"name": "test",
"value": 42,
"nested": {
"z": 1,
"a": 2
}
});
// Canonicalize (keys sorted, no whitespace)
let canonical = canonicalize(&data);
println!("Canonical: {}", canonical);
// Output: {"name":"test","nested":{"a":2,"z":1},"value":42}
// Canonicalize and hash in one step
let hash = canonicalize_and_hash(&data);
println!("Hash: {}", hex::encode(hash));
}Handle verification errors
Comprehensive error handling:
use atl_core::prelude::*;
fn handle_errors(receipt_json: &str) {
match Receipt::from_json(receipt_json) {
Ok(receipt) => {
let verifier = ReceiptVerifier::anchor_only();
let result = verifier.verify(&receipt);
if !result.is_valid() {
for error in &result.errors {
match error {
VerificationError::InclusionProofFailed { .. } => {
eprintln!("Inclusion proof failed");
}
VerificationError::SignatureFailed => {
eprintln!("Checkpoint signature failed (Require mode)");
}
VerificationError::NoTrustAnchor => {
eprintln!("No trust anchor (no valid external anchors)");
}
_ => {
eprintln!("Error: {:?}", error);
}
}
}
}
}
Err(AtlError::InvalidReceipt(msg)) => eprintln!("Failed to parse receipt: {msg}"),
Err(AtlError::UnsupportedReceiptVersion(version)) => {
eprintln!("Unsupported receipt version: {version}");
}
Err(e) => {
eprintln!("Error: {:?}", e);
}
}
}Last updated on