Skip to main content
Every decision MeshQu evaluates is bound to a SHA-256 integrity hash: a single 64-character hex string computed over the verdict, the context, the policy snapshot, and the timestamp. Change any of those inputs and the hash changes. That is what makes a recorded decision tamper-evident — not impossible to alter, but impossible to alter undetectably.
Mental model: the integrity hash is a fingerprint of the whole decision. The Ed25519 signature is MeshQu attesting “this fingerprint is mine.” Verification recomputes the fingerprint and checks the signature — no trust in MeshQu’s database required.
This page covers the hashing and signing primitives — the L2 (hashed) and L3 (signed) layers of the Decision Assurance maturity model. For the full offline-verifiable contract — bundles, transparency anchoring, and the per-sub-claim taxonomy — see Verification Bundle and the Receipt Reference.

Canonical JSON

Two objects with the same content must produce the same hash, regardless of the order their keys happen to be in. MeshQu achieves this with a canonical JSON serialization that recursively sorts object keys before hashing.
The canonicalization profile is named meshqu-canonical/v0 and is frozen: alphabetic key ordering with arrays left in their original element order. Because hashes are part of the verification contract, the profile is versioned in the data, not changed silently.
RFC 8785 (JCS) alignment is a planned follow-up that would introduce a meshqu-canonical/v1 profile. Today, the live profile is meshqu-canonical/v0. Receipts always carry the profile they were canonicalized under, so a future profile never invalidates an existing receipt.

What canonical JSON does not accept

The serializer is strict on purpose. Inputs that cannot be represented deterministically are rejected rather than silently coerced — a silently-coerced value would produce a validly-signed hash over the wrong data.
When you submit fields or evidence for evaluation, use plain JSON-compatible types — strings, numbers, booleans, null, objects, and arrays. Wrapping a value in a Map, Set, or BigInt will fail canonicalization. For large numeric identifiers, use a string ("12345678901234567890"), not a numeric literal.

The integrity hash

Every evaluation result includes an integrity_hash. It is sha256(canonicalJson(payload)), where the payload binds:
On the wire, the receipt field is evaluated_rules_hash. Inside the hash payload the key is named policy_snapshot_hash for historical signature stability — the same value under a legacy key name. You verify against evaluated_rules_hash; the internal key name does not affect what you check.

Source artifact binding — proof without disclosure

If you bind a source document, only its hash is included in the integrity hash. The document’s type, filename, and byte_size are stored for convenience but are not part of the cryptographic proof. This lets you prove a specific document was the one evaluated — by re-hashing your copy and comparing — without MeshQu ever holding the document itself.
MeshQu hashes what you give it. If you submit a source_artifact.hash or evidence reference, MeshQu binds that hash into the receipt — it does not independently fetch and re-hash the underlying document. The honesty of the input is yours to guarantee.

Ed25519 signing

After computing the integrity hash, MeshQu signs it with an Ed25519 key. The signature proves a specific key holder attested to the hash — not merely that the hash is internally consistent. Anyone with the matching public key can verify a receipt; no shared secret is involved. Public keys are published — unauthenticated — at:
In production, signing is mandatory: unsigned receipts are only possible in non-production environments.
Receipt schema v1 and v2. v1 receipts sign the bare integrity-hash string. v2 receipts sign a canonical envelope that also binds signature_kid, signature_algorithm, policy_snapshot_digest, and timestamp — so tampering with the declared key or algorithm fails verification. v1 receipts continue to verify forever; there is no cut-over. A verifier never falls back across versions. See the Receipt Reference for the exact payloads.

Verifying a receipt

Recompute and compare:
Both checks run entirely client-side against bundled or published public keys — no live MeshQu API call is required. Receipts can be verified through:

Transparency anchoring (optional)

When enabled, a signed receipt can be anchored in a public, append-only transparency log (Sigstore Rekor). This provides an independent witness that the receipt existed at a particular time.
  • Anchoring runs asynchronously after the decision is committed — it never blocks recording.
  • If the log is unreachable, the receipt is still valid (signed but unanchored). transparency_anchor: null is a legitimate state.
  • The anchor is explicitly excluded from the integrity hash, because it is produced after signing.
MeshQu verifies Rekor’s signed entry timestamp offline against a pinned log key — proving the log signed this exact entry at this exact time. It does not perform a live lookup against a running Rekor witness today. “Anchored to a public transparency log, verifiable offline against a pinned log key” is the accurate claim.

Audit trail hash chain

Beyond per-decision receipts, MeshQu’s audit log is an append-only, hash-chained record. Each event includes the integrity hash of the previous event:
Modify, delete, or insert any event and every subsequent hash no longer reconstructs — the break is detectable and locatable. At the database layer, audit rows, recorded decisions, and policy snapshots are protected by immutability triggers that reject UPDATE and DELETE (the one permitted post-write mutation is stamping the asynchronous transparency anchor).

What MeshQu does and does not claim

The remaining trust requirement is signing-key custody and the authenticity of the out-of-band public-key channel. That contract is documented under Decision Assurance — trust roots.

See also