Start free

Trust levels

A receipt carries a trust level that the verifier re-derives from the signatures it can check. L0 means the operator authorized it; L1 means an authorized human also approved it with their own key.

A trust level is a claim about who stood behind an action, backed by real signatures. There are two levels today, L0 and L1. Both are recorded in the receipt as trust_level, but neither is taken on faith. The verifier re-computes the level from the Ed25519 signatures it can check, and rejects any receipt that claims more than its signatures support.

L0 and L1

Each level maps to a set of signatures that pass. L0 carries one Ed25519 signature from the operator; L1 carries that operator signature plus a second Ed25519 signature from a human approver. Both are real cryptographic signatures over the action’s canonical bytes — not flags, not database rows.

LevelSignaturesWhat it proves
L0Operator Ed25519The operator authorized this action under a known policy — the policy matched and produced a decision.
L1Operator Ed25519 + approver Ed25519Everything L0 proves, and additionally that an authorized human approved it by signing with their own key.

An L0 receipt carries a single signature entry, keyed as the operator:

receipt.json
"signatures": [  { "algorithm": "Ed25519", "key_id": "operator",    "public_key": "ed25519:uP3…b1", "signature": "3a9f…04af" }]

An L1 receipt carries a second entry, keyed as the approver. The key_id distinguishes them, and each has its own public_key:

receipt.json
"signatures": [  { "algorithm": "Ed25519", "key_id": "operator",    "public_key": "ed25519:uP3…b1", "signature": "3a9f…04af" },  { "algorithm": "Ed25519", "key_id": "approver",    "public_key": "ed25519:k7Q…9d", "signature": "be12…77c1" }]
What a level proves — and what it doesn't

A trust level records authorization. L1 proves a specific person approved the action with a device-held key — it identifies who approved, not whether the approval was the right call.

Re-derived on verify

The trust_level stored in the receipt is a claim. The verifier never trusts it directly. As the last gate in the verify order, it re-derives the level from which signatures actually verified, then compares that to the embedded value.

  • The operator signature verifies, and no approver signature is present, the derived level is L0.
  • Both the operator signature and an approver signature verify, the derived level is L1.
  • The derived level is less than the embedded level — a receipt stamped L1 whose approver signature is missing or invalid — verification fails with trust_mismatch.

So a receipt can never inflate its own trust. Stamping "trust_level": "L1" on an action that only carries an operator signature does not produce an L1 receipt; it produces an invalid one:

json
{  "valid": false,  "state": "trust_mismatch",  "embedded_trust_level": "L1",  "derived_trust_level": "L0"}

Because the level is re-derived from signatures, and the check runs in the browser verifier exactly as it runs on a server, anyone can confirm the claim offline. There is nothing to take on trust from HESO itself.

The co-signature

L1 exists because of a second signature: the approver co-signature— the approver’s own signature on the same action. When an action is routed to a human, the approver signs an approval token over the same canonical action bytes the operator signed, using a key held on their own device.

  • The approver’s private key never leaves their device.
  • Only their public fingerprint is shared, recorded in the receipt as the approver’s public key.
  • Because both signatures cover the same canonical bytes, the co-signature binds the human’s decision to this exact action — not a different one.

The approver’s decision and identity are recorded alongside the signature. For the full routing flow — the approval token, the device-held key, and the approver record — see Human approval.

No cloud signing key

The approver signs with their ownkey, and that is the whole point. The HESO cloud holds no signing key — not the operator’s, not any approver’s. It cannot mint an L0 or an L1 on your behalf, because it has nothing to sign with.

The cloud cannot forge a trust level

HESO’s control plane stores and serves receipts, but it never signs them. There is no server-side signing key, so the cloud — or anyone who breaches it — cannot fake an L1 receipt naming an approver who did not actually approve. An L1 can only come from an approver’s own device-held key, and any receipt that claims L1 without that signature fails with trust_mismatch.

This is the core trust property. The cloud carries receipts, but it is not a trusted party: every claim it forwards can be re-checked against the signatures, by you, with no HESO infrastructure in the loop.

No higher levels yet

There is no L2 or L3 in this version. The levels stop at L1 on purpose — a higher grade would need to mean something concrete and checkable, and the pieces for that are not built yet. Rather than ship a level that hints at more assurance than the signatures can back, HESO ships only the two it can prove.

If you need a higher bar today, encode it in policy: route more lanes to approval, require specific approvers, or tighten the conditions that gate an action. The trust level still re-derives honestly from whatever signatures result.