From 8fa6acb798a624276c818d23f1c954318e8f2ebf Mon Sep 17 00:00:00 2001 From: root Date: Sun, 21 Dec 2025 08:06:29 +0000 Subject: [PATCH] Add v2.1 trace payload + styled paper + verifier --- ..._DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md | 234 +++++++++++ ...ING_TRACE_WHITEPAPER_v2.1_STYLED.md.sha256 | 1 + README.md | 17 + ...16cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz | Bin 0 -> 82010 bytes ...-6f9d-4ffe-aec0-99792d383ca1.tar.gz.sha256 | 1 + iftrace.py | 362 ++++++++++++++++++ iftrace.py.sha256 | 1 + 7 files changed, 616 insertions(+) create mode 100644 IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md create mode 100644 IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md.sha256 create mode 100644 emo_trace_payload_016cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz create mode 100644 emo_trace_payload_016cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz.sha256 create mode 100644 iftrace.py create mode 100644 iftrace.py.sha256 diff --git a/IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md b/IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md new file mode 100644 index 0000000..30e163b --- /dev/null +++ b/IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md @@ -0,0 +1,234 @@ +# IF.EMOTION TRACE PROTOCOL v2.1: AUDITABLE DEBUGGING (WITHOUT WISHFUL THINKING) + +**Subject:** End-to-End Traceability, Completeness Witnessing, and PQ-Anchored Evidence Binding +**Protocol:** IF.TTT (Traceable, Transparent, Trustworthy) +**Version:** 2.1 (Methodology Hardening) +**Date:** 2025-12-21 +**Status:** AUDIT REQUIRED +**Citation:** `if://whitepaper/emotion/trace-protocol/v2.1` + +--- + +## 1) What This Protocol Actually Guarantees + +This system does not try to “prove the model is true.” That is not a meaningful claim for probabilistic generation. + +This system proves something narrower and more valuable: + +1) what the system received (as a commitment), +2) what the system did (trace event chain), +3) what the system returned (output hash), +4) what evidence it claims to have used (retrieval IDs + citation handles), +5) that the resulting artifacts are tamper-evident and portable for external review. + +If a claim cannot be bound to an artifact, it does not exist. + +--- + +## 2) The Trace ID Contract (Non-Negotiable) + +Every request to `/api/chat/completions` receives a Trace ID. This includes denials. + +**Surfaces:** + +- **Header:** `X-IF-Emotion-Trace: ` +- **Header:** `X-IF-Emotion-Trace-Sig: ` (app-level integrity) +- **User output:** final line `Trace: ` + +The Trace ID is the support ticket, the incident handle, and the audit join key. + +--- + +## 3) Completeness: REQ_SEEN Witness Ledger (And Its Real Boundary) + +Integrity alone is easy. Completeness is where systems lie. + +### What REQ_SEEN does (v2.1) + +REQ_SEEN records every request attempt that reaches the backend witness boundary as a privacy-preserving commitment: + +- `user_text_sha256`, `user_len`, decision/reason, and `leaf_hash` + +It writes: + +- Hour ledger: `/opt/if-emotion/data/req_seen/.jsonl` +- Signed Merkle head: `/opt/if-emotion/data/req_seen/heads/.json` + +### The boundary (explicit) + +REQ_SEEN completeness is only valid for requests that reach the backend process. Requests blocked before the backend are out of scope until the witness is moved to the edge proxy. + +This is not a weakness in wording. It is a hard boundary condition. + +--- + +## 4) Merkle Proofs: Roots Are Not Enough + +A signed Merkle root helps, but roots alone do not give efficient proofs. + +v2.1 adds inclusion proofs for REQ_SEEN: + +- A specific trace can be proven to exist in an hourly ledger with an O(log n) Merkle path. +- The proof is generated from the ledger and verified against the signed head. + +Verification tooling is provided via `iftrace.py` (see Section 10). + +--- + +## 5) Trace Events: Hash Chain + Immediate Head Attestation + +Trace events are stored as a hash chain in: + +- `/opt/if-emotion/data/trace_events.jsonl` + +Each event includes: + +- `prev_hash` pointer +- `event_hash` computed as `sha256(prev_hash || canonical_json(event_without_event_hash))` + +This detects deletion or modification of interior events. It does not prevent a malicious deployment from not emitting events. That is addressed as a limitation and a roadmap item (Section 11). + +The trace head is also attested in the signed completion record with an app-level Ed25519 signature so integrity can be verified immediately. + +--- + +## 6) Canonicalization: What We Hash Must Be Stable + +Cryptographic systems die by “almost the same bytes.” + +v2.1 mandates canonical JSON bytes for hashing/signing: + +- Primary: `canonicaljson.encode_canonical_json(obj)` +- Fallback: stable JSON serialization (`sort_keys`, fixed separators, UTF-8) + +If two environments hash different bytes for “the same object,” you have no protocol. + +--- + +## 7) Key Management (POC-Grade Today, Audit-Grade Tomorrow) + +### Current state + +- App Ed25519 signing key: + - Private: `/opt/if-emotion/data/trace_ed25519.key` (0600) + - Public: `/opt/if-emotion/data/trace_ed25519.pub` (shipped in bundles) + - Key ID: `ed25519-app-v1` + +The key is generated by libsodium-backed primitives and stored on disk with file permissions. This is acceptable for a POC, not for external certification. + +### Rotation and compromise (required discipline) + +- If the key is compromised: rotate immediately, bump `key_id`, and mark all traces from that time window as `trust_tier=degraded` unless independently anchored. +- Old signatures remain verifiable with the historic public keys; key history must be preserved. + +### Certification path + +- Move keys to HSM/TPM or threshold signing. +- Bind deploy attestations (image digest + config hash) to IF.TTT. + +--- + +## 8) Post-Quantum: What Is PQ Today (And What Isn’t) + +### What is PQ-anchored today + +Evidence bundles are PQ-hybrid signed when registered into IF.TTT. The IF.TTT registry record includes: + +- `pq_status: hybrid-fips204` +- `pq_algo: ML-DSA-87` + +This is the PQ anchoring layer. + +### What is not PQ today + +Hot-path app signatures (Ed25519) are not post-quantum. That is a conscious trade: + +- Ed25519 provides immediate integrity at low latency. +- PQ signing occurs at registration time in IF.TTT. + +The correct claim is “PQ-anchored at registry time,” not “PQ everywhere.” + +--- + +## 9) IF.story: Readability Without Evidence Drift + +IF.story is a deterministic narrative projection of `trace_events.jsonl`. + +It is not evidence. It is an index. + +Each IF.story line includes the `event_hash` anchor, and auditors should verify those anchors against the raw JSONL. + +--- + +## 10) Verifier Tooling (Independent Checks, Not Operator Vibes) + +The bundle is designed to be verified with a single command and then deep-audited selectively. + +Verifier: + +- `iftrace.py verify --expected-sha256 ` + +Merkle inclusion proof (REQ_SEEN): + +- `iftrace.py prove-inclusion --ledger --head --trace-id ` +- `iftrace.py verify-inclusion ` + +Checksum rules (important): + +- `sha256s.txt` intentionally excludes itself and `manifest.json` to avoid self-referential checksum traps. + +--- + +## 11) Threat Model and Limitations (Explicit) + +### A) Truncation and external anchoring + +Hash chains detect edits. They do not prevent truncation unless head hashes are anchored externally or independently cached. + +Current mitigation: + +- IF.TTT registration anchors the tarball hash into a separate chain. + +Remaining requirement for certification: + +- scheduled external anchoring of IF.TTT head hashes to a public append-only log. + +### B) Clock integrity + +Timestamps are derived from system clocks and are not trusted for cryptographic time. + +Ordering is guaranteed by hash chain indices and hash pointers, not by wall-clock truth. + +Certification path: + +- introduce time witnesses or external timestamping for head hashes. + +### C) Code integrity + +Hash chains detect post-hoc tampering. They do not prevent a modified binary from choosing not to record. + +Certification path: + +- signed deploy attestations (image digest + config hash) bound into IF.TTT +- optional remote attestation + +--- + +## 12) Reference Proof Run (v2.1) + +Trace ID: + +- `016cca78-6f9d-4ffe-aec0-99792d383ca1` + +Hosted tarball URL: + +- `https://git.infrafabric.io/danny/hosted/raw/branch/main/emo_trace_payload_016cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz` + +Tarball SHA256: + +- `7101ff9c38fc759a66157f6a6ab9c0936af547d0ec77a51b5d05db07069966c8` + +IF.TTT citation handle for the tarball (PQ hybrid signed): + +- `if://citation/c24fe95e-226c-4efc-ba22-5ddcc37ff7d2/v1` + diff --git a/IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md.sha256 b/IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md.sha256 new file mode 100644 index 0000000..496164d --- /dev/null +++ b/IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md.sha256 @@ -0,0 +1 @@ +e6a2c04eb550f980f1e03dc220961c55fc9b8da356d115cf6085cc7b85f7815b /root/tmp/hosted_repo_update/IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md diff --git a/README.md b/README.md index e75a657..01d25e7 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,20 @@ Static hosted artifacts used in InfraFabric reviews. - File: `IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.0_STYLED.md` - Notes: methodology v2.0, references trace tarball `emo_trace_payload_09aad3e1-f420-451e-a189-e86f68073dc0.tar.gz`. + +## emo-social trace payload (v2.1, inclusion proof + pubkey) + +- File: `emo_trace_payload_016cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz` +- SHA256: `7101ff9c38fc759a66157f6a6ab9c0936af547d0ec77a51b5d05db07069966c8` +- IF.TTT citation (PQ hybrid signed): `if://citation/c24fe95e-226c-4efc-ba22-5ddcc37ff7d2/v1` +- Notes: includes `payload/trace_ed25519.pub` + `payload/req_seen_inclusion_proof.json` + nested priors (`payload/ttt_children*.json`). + +## IF.emotion trace whitepaper (styled v2.1) + +- File: `IF_EMOTION_DEBUGGING_TRACE_WHITEPAPER_v2.1_STYLED.md` + +## Verifier tool + +- File: `iftrace.py` (run with a Python venv that has `canonicaljson` + `pynacl`) +- Verify tarball: `python iftrace.py verify emo_trace_payload_.tar.gz --expected-sha256 ` +- Prove inclusion: `python iftrace.py prove-inclusion --ledger req_seen_.jsonl --head req_seen_head_.json --trace-id ` diff --git a/emo_trace_payload_016cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz b/emo_trace_payload_016cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz new file mode 100644 index 0000000000000000000000000000000000000000..cbb3990a207b654b25997128fabba98e36396d62 GIT binary patch literal 82010 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

S0JgfDQcz={Lg{r{AnXC)H1g1! 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 literal 0 HcmV?d00001 diff --git a/emo_trace_payload_016cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz.sha256 b/emo_trace_payload_016cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz.sha256 new file mode 100644 index 0000000..fed60e8 --- /dev/null +++ b/emo_trace_payload_016cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz.sha256 @@ -0,0 +1 @@ +7101ff9c38fc759a66157f6a6ab9c0936af547d0ec77a51b5d05db07069966c8 /root/tmp/hosted_repo_update/emo_trace_payload_016cca78-6f9d-4ffe-aec0-99792d383ca1.tar.gz diff --git a/iftrace.py b/iftrace.py new file mode 100644 index 0000000..6a1d5f3 --- /dev/null +++ b/iftrace.py @@ -0,0 +1,362 @@ +#!/usr/bin/env python3 +""" +IF.emotion trace bundle verifier + Merkle inclusion proof tool. + +Run with the venv: + /root/tmp/iftrace_venv/bin/python /root/tmp/iftrace.py ... +""" + +from __future__ import annotations + +import argparse +import hashlib +import io +import json +import os +import tarfile +import tempfile +from dataclasses import dataclass +from pathlib import Path +from typing import Any, Iterable + +from canonicaljson import encode_canonical_json +from nacl.signing import VerifyKey +from nacl.encoding import HexEncoder + + +def sha256_bytes(data: bytes) -> str: + return hashlib.sha256(data or b"").hexdigest() + + +def sha256_file(path: Path) -> str: + h = hashlib.sha256() + with path.open("rb") as f: + for chunk in iter(lambda: f.read(1024 * 1024), b""): + h.update(chunk) + return h.hexdigest() + + +def canonical_json_bytes(obj: Any) -> bytes: + return encode_canonical_json(obj) + + +def merkle_root_hex(leaves_hex: list[str]) -> str: + if not leaves_hex: + return sha256_bytes(b"") + level: list[bytes] = [bytes.fromhex(h) for h in leaves_hex if isinstance(h, str) and len(h) == 64] + if not level: + return sha256_bytes(b"") + while len(level) > 1: + if len(level) % 2 == 1: + level.append(level[-1]) + nxt: list[bytes] = [] + for i in range(0, len(level), 2): + nxt.append(hashlib.sha256(level[i] + level[i + 1]).digest()) + level = nxt + return level[0].hex() + + +def merkle_inclusion_proof(leaves_hex: list[str], index: int) -> dict: + if index < 0 or index >= len(leaves_hex): + raise ValueError("index out of range") + level: list[bytes] = [bytes.fromhex(h) for h in leaves_hex] + proof: list[dict] = [] + idx = index + while len(level) > 1: + if len(level) % 2 == 1: + level.append(level[-1]) + sibling_idx = idx ^ 1 + sibling = level[sibling_idx] + side = "left" if sibling_idx < idx else "right" + proof.append({"sibling": sibling.hex(), "side": side}) + nxt: list[bytes] = [] + for i in range(0, len(level), 2): + nxt.append(hashlib.sha256(level[i] + level[i + 1]).digest()) + level = nxt + idx //= 2 + root = level[0].hex() + return {"index": index, "root": root, "path": proof} + + +def merkle_verify_proof(leaf_hex: str, proof: dict) -> bool: + try: + cur = bytes.fromhex(leaf_hex) + for step in proof.get("path", []): + sib = bytes.fromhex(step["sibling"]) + if step["side"] == "left": + cur = hashlib.sha256(sib + cur).digest() + else: + cur = hashlib.sha256(cur + sib).digest() + return cur.hex() == proof.get("root") + except Exception: + return False + + +def read_json(path: Path) -> Any: + return json.loads(path.read_text(encoding="utf-8", errors="strict")) + + +def verify_ed25519_hex(*, pub_hex: str, msg: bytes, sig_hex: str) -> None: + vk = VerifyKey(pub_hex, encoder=HexEncoder) + vk.verify(msg, bytes.fromhex(sig_hex)) + + +@dataclass(frozen=True) +class VerifyResult: + ok: bool + notes: list[str] + + +def verify_trace_events(events_path: Path) -> VerifyResult: + notes: list[str] = [] + prev_hash = "0" * 64 + expected_idx = 0 + lines = events_path.read_text(encoding="utf-8", errors="ignore").splitlines() + for line in lines: + if not line.strip(): + continue + obj = json.loads(line) + ev = obj.get("event") or {} + idx = int(ev.get("idx", -1)) + if idx != expected_idx: + return VerifyResult(False, notes + [f"trace_events: idx mismatch (got {idx}, expected {expected_idx})"]) + if str(ev.get("prev_hash") or "") != prev_hash: + return VerifyResult(False, notes + ["trace_events: prev_hash mismatch"]) + stored_hash = str(ev.get("event_hash") or "") + payload = dict(ev) + payload.pop("event_hash", None) + recomputed = sha256_bytes(prev_hash.encode("utf-8") + canonical_json_bytes(payload)) + if recomputed != stored_hash: + return VerifyResult(False, notes + ["trace_events: event_hash mismatch (recomputed != stored)"]) + prev_hash = stored_hash + expected_idx += 1 + notes.append(f"trace_events: ok (events={expected_idx}, head_hash={prev_hash[:16]}…)") + return VerifyResult(True, notes) + + +def verify_req_seen(ledger_path: Path, head_path: Path) -> VerifyResult: + notes: list[str] = [] + head = read_json(head_path) + pub_hex = str(head.get("signer_ed25519") or "").strip() + sig_hex = str(head.get("sig_ed25519") or "").strip() + if not pub_hex or not sig_hex: + return VerifyResult(False, ["req_seen: missing signer_ed25519 or sig_ed25519 in head"]) + # Recreate the message that was signed (the head core before adding sig/key_id/signer). + head_core = { + "schema": head.get("schema"), + "hour_utc": head.get("hour_utc"), + "updated_utc": head.get("updated_utc"), + "count": head.get("count"), + "merkle_root": head.get("merkle_root"), + "last_leaf_hash": head.get("last_leaf_hash"), + } + verify_ed25519_hex(pub_hex=pub_hex, msg=canonical_json_bytes(head_core), sig_hex=sig_hex) + notes.append("req_seen_head: Ed25519 signature OK") + + leaves: list[str] = [] + lines = ledger_path.read_text(encoding="utf-8", errors="ignore").splitlines() + for line in lines: + if not line.strip(): + continue + entry = json.loads(line) + leaf = str(entry.get("leaf_hash") or "").strip() + entry_core = dict(entry) + entry_core.pop("leaf_hash", None) + recomputed_leaf = sha256_bytes(canonical_json_bytes(entry_core)) + if recomputed_leaf != leaf: + return VerifyResult(False, notes + ["req_seen: leaf_hash mismatch"]) + leaves.append(leaf) + + root = merkle_root_hex(leaves) + if root != str(head.get("merkle_root") or ""): + return VerifyResult(False, notes + ["req_seen: merkle_root mismatch"]) + if int(head.get("count") or 0) != len(leaves): + return VerifyResult(False, notes + ["req_seen: count mismatch"]) + notes.append(f"req_seen: ok (count={len(leaves)}, merkle_root={root[:16]}…)") + return VerifyResult(True, notes) + + +def verify_story(story_path: Path, events_path: Path) -> VerifyResult: + notes: list[str] = [] + # Collect all event hashes from ground truth. + hashes: set[str] = set() + for line in events_path.read_text(encoding="utf-8", errors="ignore").splitlines(): + if not line.strip(): + continue + ev = (json.loads(line).get("event") or {}) + h = str(ev.get("event_hash") or "").strip() + if len(h) == 64: + hashes.add(h) + # Ensure every story line that mentions event_hash=... points to a real event. + for line in story_path.read_text(encoding="utf-8", errors="ignore").splitlines(): + if "event_hash=" not in line: + continue + h = line.split("event_hash=", 1)[1].strip().split()[0] + if h and h not in hashes: + return VerifyResult(False, [f"if_story: unknown event_hash referenced: {h}"]) + notes.append("if_story: ok (all referenced event_hash values exist)") + return VerifyResult(True, notes) + + +def verify_manifest(payload_dir: Path) -> VerifyResult: + notes: list[str] = [] + manifest_path = payload_dir / "manifest.json" + sha_list_path = payload_dir / "sha256s.txt" + if not manifest_path.exists() or not sha_list_path.exists(): + return VerifyResult(False, ["manifest: missing manifest.json or sha256s.txt"]) + + manifest = read_json(manifest_path) + files = manifest.get("files") or [] + manifest_map = {f["path"]: f["sha256"] for f in files if isinstance(f, dict) and "path" in f and "sha256" in f} + + sha_map: dict[str, str] = {} + for line in sha_list_path.read_text(encoding="utf-8", errors="ignore").splitlines(): + parts = line.strip().split() + if len(parts) >= 2: + sha_map[parts[1]] = parts[0] + + # sha256s.txt is a checksum file; it must not be self-referential. + sha_map.pop("sha256s.txt", None) + # manifest.json is the root index; do not make it self-referential in sha256s. + sha_map.pop("manifest.json", None) + + for name, sha in sha_map.items(): + p = payload_dir / name + if not p.exists(): + return VerifyResult(False, [f"manifest: sha256s references missing file: {name}"]) + got = sha256_file(p) + if got != sha: + return VerifyResult(False, [f"manifest: sha256 mismatch for {name}"]) + if name != "manifest.json": + if manifest_map.get(name) != sha: + return VerifyResult(False, [f"manifest: manifest.json mismatch for {name}"]) + + notes.append(f"manifest: ok (files={len(sha_map)})") + return VerifyResult(True, notes) + + +def extract_tarball(tar_path: Path) -> Path: + tmp = Path(tempfile.mkdtemp(prefix="iftrace_")) + with tarfile.open(tar_path, "r:gz") as tf: + tf.extractall(tmp) # trusted local artifact + return tmp + + +def cmd_verify(args: argparse.Namespace) -> int: + tar_path = Path(args.tar).resolve() + expected_sha = (args.expected_sha256 or "").strip().lower() + got_sha = sha256_file(tar_path) + if expected_sha and got_sha != expected_sha: + print(f"FAIL tar_sha256 expected={expected_sha} got={got_sha}") + return 2 + print(f"OK tar_sha256 {got_sha}") + + root = extract_tarball(tar_path) + payload_dir = root / "payload" + if not payload_dir.exists(): + print("FAIL: tarball missing payload/ directory") + return 2 + + checks: list[VerifyResult] = [] + checks.append(verify_manifest(payload_dir)) + + events_path = payload_dir / "trace_events.jsonl" + if events_path.exists(): + checks.append(verify_trace_events(events_path)) + + story_path = payload_dir / "if_story.md" + if story_path.exists() and events_path.exists(): + checks.append(verify_story(story_path, events_path)) + + # REQ_SEEN verification if present + head_files = sorted(payload_dir.glob("req_seen_head_*.json")) + ledger_files = sorted(payload_dir.glob("req_seen_*.jsonl")) + if head_files and ledger_files: + checks.append(verify_req_seen(ledger_files[0], head_files[0])) + + ok = True + for res in checks: + for n in res.notes: + print(n) + ok = ok and res.ok + + if not ok: + print("FAIL verify") + return 2 + print("OK verify") + return 0 + + +def cmd_prove_inclusion(args: argparse.Namespace) -> int: + ledger = Path(args.ledger).resolve() + head = Path(args.head).resolve() + trace_id = (args.trace_id or "").strip() + leaf_hash = (args.leaf_hash or "").strip().lower() + + leaves: list[str] = [] + idx_by_trace: dict[str, int] = {} + lines = ledger.read_text(encoding="utf-8", errors="ignore").splitlines() + for i, line in enumerate(lines): + if not line.strip(): + continue + entry = json.loads(line) + lh = str(entry.get("leaf_hash") or "").strip() + leaves.append(lh) + tid = str(entry.get("trace_id") or "").strip() + if tid and tid not in idx_by_trace: + idx_by_trace[tid] = len(leaves) - 1 + + if trace_id: + if trace_id not in idx_by_trace: + raise SystemExit("trace_id not found in ledger") + index = idx_by_trace[trace_id] + leaf_hash = leaves[index] + else: + if not leaf_hash: + raise SystemExit("provide --trace-id or --leaf-hash") + if leaf_hash not in leaves: + raise SystemExit("leaf_hash not found in ledger") + index = leaves.index(leaf_hash) + + proof = merkle_inclusion_proof(leaves, index) + proof["leaf_hash"] = leaf_hash + proof["hour_utc"] = read_json(head).get("hour_utc") + print(json.dumps(proof, indent=2, sort_keys=True)) + return 0 + + +def cmd_verify_inclusion(args: argparse.Namespace) -> int: + proof = read_json(Path(args.proof).resolve()) + leaf = str(proof.get("leaf_hash") or "").strip() + ok = merkle_verify_proof(leaf, proof) + print("OK" if ok else "FAIL") + return 0 if ok else 2 + + +def main() -> int: + ap = argparse.ArgumentParser(prog="iftrace") + sub = ap.add_subparsers(dest="cmd", required=True) + + v = sub.add_parser("verify", help="Verify a trace payload tarball (manifest, hashes, chains, signatures)") + v.add_argument("tar", help="Path to emo_trace_payload_.tar.gz") + v.add_argument("--expected-sha256", default="", help="Expected tarball SHA256 (optional)") + v.set_defaults(func=cmd_verify) + + p = sub.add_parser("prove-inclusion", help="Generate a Merkle inclusion proof for a REQ_SEEN ledger leaf") + p.add_argument("--ledger", required=True, help="Path to req_seen_.jsonl") + p.add_argument("--head", required=True, help="Path to req_seen_head_.json") + g = p.add_mutually_exclusive_group(required=True) + g.add_argument("--trace-id", default="", help="Trace ID to prove inclusion for") + g.add_argument("--leaf-hash", default="", help="Leaf hash to prove inclusion for") + p.set_defaults(func=cmd_prove_inclusion) + + pv = sub.add_parser("verify-inclusion", help="Verify a Merkle inclusion proof JSON") + pv.add_argument("proof", help="Path to proof JSON") + pv.set_defaults(func=cmd_verify_inclusion) + + args = ap.parse_args() + return int(args.func(args)) + + +if __name__ == "__main__": + raise SystemExit(main()) diff --git a/iftrace.py.sha256 b/iftrace.py.sha256 new file mode 100644 index 0000000..6a08853 --- /dev/null +++ b/iftrace.py.sha256 @@ -0,0 +1 @@ +7b4587a12218b37abaafe56adb3a7071e84bbc6bfe9ee9442236e476c6533f9c /root/tmp/hosted_repo_update/iftrace.py