Skip to main content

cross_language_verify/
verify.rs

1//! Cross-language interop demo, Rust side.
2//!
3//! Reads a `LocalLedger` written by the Python script `mint.py` (see the
4//! `cross_language_verify/` README) and verifies:
5//!
6//! 1. The hash chain is intact end-to-end (`LocalLedger::open` replays and
7//!    verifies the chain on load — any tamper aborts).
8//! 2. The LCT minted from Python is present in the ledger.
9//! 3. An anchor proof for that LCT verifies under the Rust implementation.
10//!
11//! The point of the demo is not the LCT itself — it's that the on-disk
12//! format is the contract. Any language with a Web4 spec implementation
13//! can verify what any other language minted, with no shared runtime.
14//!
15//! Run from the `web4-core/` directory:
16//!
17//! ```sh
18//! cargo run --example cross_language_verify -- \
19//!     --ledger ./shared_ledger.jsonl \
20//!     --lct-sidecar ./shared_lct.json
21//! ```
22
23use std::env;
24use std::fs;
25use std::path::PathBuf;
26use std::process::ExitCode;
27
28use serde::Deserialize;
29use web4_core::{Ledger, LocalLedger};
30
31#[derive(Deserialize)]
32struct LctSidecar {
33    lct_id: String,
34    fingerprint: String,
35}
36
37fn parse_args() -> (PathBuf, PathBuf) {
38    let mut ledger = PathBuf::from("./shared_ledger.jsonl");
39    let mut sidecar = PathBuf::from("./shared_lct.json");
40    let mut args = env::args().skip(1);
41    while let Some(arg) = args.next() {
42        match arg.as_str() {
43            "--ledger" => {
44                ledger = args
45                    .next()
46                    .expect("--ledger requires a path argument")
47                    .into();
48            }
49            "--lct-sidecar" => {
50                sidecar = args
51                    .next()
52                    .expect("--lct-sidecar requires a path argument")
53                    .into();
54            }
55            "-h" | "--help" => {
56                eprintln!(
57                    "usage: cargo run --example cross_language_verify -- \
58                     [--ledger PATH] [--lct-sidecar PATH]"
59                );
60                std::process::exit(0);
61            }
62            other => {
63                eprintln!("unknown argument: {}", other);
64                std::process::exit(2);
65            }
66        }
67    }
68    (ledger, sidecar)
69}
70
71fn main() -> ExitCode {
72    let (ledger_path, sidecar_path) = parse_args();
73
74    println!("[rust] Reading sidecar at {}", sidecar_path.display());
75    let sidecar_text = match fs::read_to_string(&sidecar_path) {
76        Ok(s) => s,
77        Err(e) => {
78            eprintln!("[rust] Could not read sidecar {}: {}", sidecar_path.display(), e);
79            eprintln!("[rust] Did you run `python mint.py` first?");
80            return ExitCode::from(2);
81        }
82    };
83    let sidecar: LctSidecar = match serde_json::from_str(&sidecar_text) {
84        Ok(s) => s,
85        Err(e) => {
86            eprintln!("[rust] Sidecar parse error: {}", e);
87            return ExitCode::from(2);
88        }
89    };
90    println!("[rust]   lct_id      = {}", sidecar.lct_id);
91    println!("[rust]   fingerprint = {}", sidecar.fingerprint);
92
93    println!(
94        "[rust] Opening LocalLedger at {} (this replays + verifies the chain)",
95        ledger_path.display()
96    );
97    let ledger = match LocalLedger::open(&ledger_path) {
98        Ok(l) => l,
99        Err(e) => {
100            eprintln!("[rust] Ledger open failed: {}", e);
101            eprintln!("[rust] If this is a chain-integrity failure, the ledger was tampered.");
102            return ExitCode::from(3);
103        }
104    };
105    println!("[rust] Chain intact. {} entries replayed.", ledger.len());
106
107    let lct_uuid = match uuid::Uuid::parse_str(&sidecar.lct_id) {
108        Ok(u) => u,
109        Err(e) => {
110            eprintln!("[rust] Sidecar lct_id is not a UUID: {}", e);
111            return ExitCode::from(2);
112        }
113    };
114
115    let lookup = match ledger.lookup(lct_uuid) {
116        Ok(l) => l,
117        Err(e) => {
118            eprintln!("[rust] Ledger lookup failed: {}", e);
119            return ExitCode::from(3);
120        }
121    };
122    let lct = match lookup {
123        Some(lct) => lct,
124        None => {
125            eprintln!("[rust] LCT {} not present in ledger.", sidecar.lct_id);
126            return ExitCode::from(3);
127        }
128    };
129    println!("[rust] LCT present in ledger.");
130
131    if lct.fingerprint() != sidecar.fingerprint {
132        eprintln!(
133            "[rust] FINGERPRINT MISMATCH:\n  sidecar:  {}\n  on-chain: {}",
134            sidecar.fingerprint,
135            lct.fingerprint()
136        );
137        return ExitCode::from(3);
138    }
139    println!("[rust] Fingerprint matches sidecar.");
140
141    let proof = match ledger.anchor(lct.id) {
142        Ok(p) => p,
143        Err(e) => {
144            eprintln!("[rust] anchor() failed: {}", e);
145            return ExitCode::from(3);
146        }
147    };
148    let verified = match ledger.verify_proof(&proof) {
149        Ok(v) => v,
150        Err(e) => {
151            eprintln!("[rust] verify_proof error: {}", e);
152            return ExitCode::from(3);
153        }
154    };
155    if !verified {
156        eprintln!("[rust] Anchor proof DID NOT verify under the Rust implementation.");
157        return ExitCode::from(3);
158    }
159    println!("[rust] Anchor proof verifies under the Rust implementation. ✓");
160    println!();
161    println!("[rust] Cross-language verification succeeded.");
162    println!(
163        "[rust] Python wrote a hash-chained ledger; Rust read the same file, replayed the chain, \
164         looked up the LCT by id, matched its fingerprint, and verified the inclusion proof — \
165         with zero shared runtime. The on-disk format is the contract."
166    );
167    ExitCode::SUCCESS
168}