[AVAILABLE], demonstrated in this session with the Parmana server confirmed stopped throughout the verify step, commit
651497a.Goal
Prove the independent-verification claim literally: take a trust record as plain JSON, verify it with nothing but Parmana’s public key, while Parmana itself is not running.Prerequisites
- Parmana’s public key file,
keys/default.public.pem(already committed for local dev). You do not need the private key,default.private.pem, for any step in this guide. - A trust record to verify, saved as JSON. Get one from Quickstart, or reuse
any
ExecutionTrustRecordyou already have on disk. - Read Execution trust records first, this guide verifies exactly the hash and signature that page describes.
Steps
1. Get a trust record and save it, then stop the server
2. Verify it with VerificationCrypto, offline
VerificationCrypto (@parmana/crypto) takes a plain ExecutionTrustRecord object and a
FileKeyProvider reading only local PEM files, no network call, no database, no running
Runtime:
FileKeyProvider.getPublicKey() only checks for <keyId>.public.pem
(packages/crypto/src/providers/key/FileKeyProvider.ts:118-133), it never reads or checks
for the private key. Verifying a record you received from someone else never needs, and
never has access to, the key that signed it.
Verify
Real output, this session, server confirmed stopped (see step 1):true. Change one nested
field, executions[0].evidence.parameters.amount, in the saved JSON, and rerun the exact
same script against the tampered file:
verifySignature() also fails because it
verifies the signature against the current (now-mutated) content, not a cached original,
the mutation invalidates both checks independently, matching what the hash and signature
actually cover.
Troubleshoot
Public key not found: default.VerificationCryptoresolves keys viaPARMANA_KEY_DIR(or./keysif unset), confirmkeys/default.public.pemexists at that path relative to where you run the script.- Verification fails on a record you’re sure is untampered. Confirm you copied the JSON exactly as returned, re-serializing through a tool that reorders keys or reformats timestamps can change byte-level content even though the JSON is semantically identical, canonical serialization is order-sensitive by design.
- You need this in Python, not TypeScript. The Python SDK’s
client.verification.verify()callsPOST /verifyover HTTP, it requires a running server, there is currently no offline/local verification path in the Python SDK, only in@parmana/crypto.
Next
Detect tampering
The same tamper-then-verify pattern, applied to the authorization envelope instead.
Execution trust records
Exactly what’s inside the hash this guide recomputed.