Skip to Content

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