Demo: tampering with signed evidence makes offline verification fail
Signed EVE evidence can be verified independently and offline, in Python, Node, or the browser, without trusting the EVE server. This demo produces a signed evidence record, verifies it, mutates one field of the signed artifact, and shows offline verification reject the altered copy.
Synthetic fixtures. No production credentials.
Readiness
- Signed decision evidence: SUPPORTED.
- Independent offline verification (Python / Node / browser): SUPPORTED.
- jcs-1 canonicalization with Python/TypeScript/browser byte parity for the supported value domain: SUPPORTED.
Setup
Produce a real signed record from a governed decision (embedded facade):
# demo_evidence_tampering.py — synthetic fixtures only
import copy
from core.eve_sdk import EVE, verify_evidence
IDENT = {"tenant_id": "acme", "principal_id": "agent-1", "session_id": "sess-1"}
eve = EVE(policy="lending_v1", mode="embedded")
decision = eve.govern_tool_call(
tool="loan_approval",
arguments={"amount": 500000},
context={**IDENT, "credit_score": 480, "debt_to_income": 0.9},
)
envelope = decision.certificate # signed evidence envelope
Code
# 1) Verify the authentic envelope offline -> valid.
good = verify_evidence("decision", envelope, expected_tenant="acme")
assert good["valid"] and good["signature"] == "ed25519-valid"
print("authentic:", good["valid"], good["signature"])
# 2) Tamper: flip the recorded action from BLOCK to ALLOW, leave the signature intact.
tampered = copy.deepcopy(envelope)
tampered["action"] = "ALLOW" # mutate a signed field
# 3) Verify the tampered envelope offline -> rejected (content hash no longer matches).
bad = verify_evidence("decision", tampered, expected_tenant="acme")
assert bad["valid"] is False, "tampered evidence must fail verification"
print("tampered:", bad["valid"], bad.get("reason"))
TypeScript / browser offline verification is at parity and rejects the same tamper:
import { verifyEvidence } from "@eve/coreguard"; // ESM, Node >= 18
const good = verifyEvidence(envelope, { publicKeyPem });
// good.valid === true, good.signature === "ed25519-valid"
const bad = verifyEvidence({ ...envelope, action: "ALLOW" }, { publicKeyPem });
// bad.valid === false
Expected decision / result
| Artifact | Offline verification |
|---|---|
| authentic signed envelope | valid (ed25519-valid) |
| envelope with one mutated field | invalid (content-hash mismatch) |
Expected evidence
// authentic
{"valid": true, "signature": "ed25519-valid", "canon": "jcs-1"}
// tampered
{"valid": false, "reason": "content_hash_mismatch"}
Verification command
python demo_evidence_tampering.py
# authentic: True ed25519-valid
# tampered: False content_hash_mismatch
Verification requires only the Ed25519 public key — no EVE server, no secrets.
Zero-side-effect assertion
No tool is invoked and no state is written: the demo signs, verifies, deep-copies, mutates the copy in memory, and verifies again. The original envelope is unchanged; only the local copy was altered.
Cleanup
del tampered # in-memory only; nothing persisted
No files or network calls.
Limitations
- Verification proves the evidence is authentic and unaltered; it does not attest the correctness of the underlying decision.
- Independent (asymmetric) verification requires the Ed25519 public key. An HMAC-SHA256 fallback is symmetric and not independently verifiable.
- jcs-1 is a constrained RFC 8785 profile: it does not serialize non-integer floats / NaN / Infinity (fail-closed). Signed governance artifacts use the supported domain (rates carried as integer permille).