Norcaster · Trust center
Trace verification algorithm
The checks the offline verifier performs, in order, and what each one does and does not prove. This is the same text the verifier ships with.
Terminology
Tamper-evident is the right word: the ledger is designed so that post-hoc edits break hash links or external anchors. It makes changes detectable; it does not make them impossible.
Chain construction
- Each tenant has a SHA-256 hash chain (
org_trace_chain_entries). - Entry hash:
SHA256(prev_hash + "\n" + canonical_json(payload))with sorted JSON keys. - Genesis entry uses
prev_hash = 64 × "0". - Runs sealed after cutover receive a
run_sealentry linked to the prior head.
Merkle segments
Anchoring batches entries into segments. Segment Merkle root is computed over entry hashes (binary SHA-256 tree, duplicate last leaf if odd).
External anchoring
Segment roots are published to Sigstore Rekor (primary) and optionally OpenTimestamps. Rekor provides a public, independently queryable inclusion record.
Offline verification steps (norcaster-verify)
- Bundle parse — parse the proof JSON (no field validation beyond JSON well-formedness).
- Local chain proof — Confirm
chain_proof.validandentry_hashpresent. - Merkle path — Recompute root from
merkle_proof+entry_hash; compare toanchor.segment_merkle_root. - Rekor —
GETtherekor_url(or--rekor-urloverride); parse entry body; confirm embedded digest equalssegment_merkle_root. For signed bundles, also confirm the entry embeds the same public key asanchor_signerand the same signature bytes asanchor.anchor_signature(Rekor validated that signature on ingestion). - Entry signature (bundle_version ≥ 2) — verify
signature.signatureas ES256 (ECDSA P-256, DER) overSHA256("norcaster-trace-entry-v1\n" + chain_id + "\n" + chain_position + "\n" + entry_hash)withsignature.public_key_pem; confirmsignature.key_id == sha256(public_key_pem)[:16]. Reported asverified,invalid, orunsigned— an absent signature is never a pass. - Root signature — verify
anchor.anchor_signatureover the segment root withanchor_signer.public_key_pem. Norcaster signs the raw root digest (what Rekor requires); Node can only verify ECDSA over a message it hashes itself, so this step uses the root's preimage recovered from the Merkle path and is reportedskipped_single_leafwhen the segment has one entry (step 4's key check still applies).
No Norcaster credentials or API access is required for steps 1–3, 5 and 6. Step 4 uses only the public Rekor transparency log.
What a signature proves (and its limit)
The key is specific to one tenant and its public half is committed to the chain (a signing_key_activated entry) and to Rekor. In the current release Norcaster holds the private key, encrypted at rest: a valid signature proves the entry was signed with the key Norcaster holds for that tenant. It rules out forgery by any other party and makes rewrites detectable before anchoring; it does not remove Norcaster from the trust base until customer-held keys ship.
Trust boundaries
| You trust | You get |
|---|---|
| Bundle file + Rekor public log | Segment was committed to Rekor with matching Merkle root, by the tenant key when signed |
| Bundle file alone (v2) | Entry signature verifies under the tenant public key the bundle carries; the key's on-chain activation is named so it can be checked against the ledger and its anchor |
| Norcaster hourly integrity job | Tenant-wide chain continuity (dashboard status) |
| Norcaster API at download time | Bundle was assembled from live DB state |
For maximum independence, archive proof bundles and verify with this CLI after download.