approval_digest: binding what you reviewed to what you sign
A hardware signer is only as honest as the link between the screen you read and the bytes the device puts a signature on. approval_digest is the contract that makes that link non-forgeable.
A trusted display is necessary but not sufficient. If the firmware can
display screen A and sign payload B, the display is worth nothing.
nSealr closes that gap with one specific contract:
approval_digest.
The contract
approval_digest is a deterministic hash over the exact canonical
material the user reviewed: signer pubkey, event kind, created_at,
the full unmodified content, the complete tag list (including detail
pages for long fields), the request id, and the review context.
The local approval action — pressing a physical button, completing an on-card acknowledgement — is bound to that digest. The signer refuses to emit a signature whose underlying serialization does not reproduce the same digest. Any drift between “what was shown” and “what gets signed” fails closed.
# companion, when verifying a signed response:
$ nsealr verify --request req.json --response resp.json
✓ event id matches BIP-340 signature
✓ approval_digest matches reviewed material
If the second line fails, the response is rejected even if the BIP-340 signature is mathematically valid. No display, no signature.
What it specifically prevents
- Host-side template swap. A compromised client cannot show you
benign metadata then sneak a different
kindor different tags into the bytes the device signs — the digest would not match. - Unicode look-alikes inside content. Long content goes through the
review-detail-page contract; the digest covers the same canonical
bytes the user sees, with explicit
Unicode fallbackfor codepoints the display cannot render. - Replay across contexts. The digest includes the request id and review context, so an approval gesture for request A cannot authorize signing request B.
Why it lives in the shared specs and not in each firmware
Every signer solution that claims trusted review uses the same
approval-digest-v0 contract from
nSealr/specs. Raspberry/Pi
QR vault, ESP32 QR vault, ESP32 USB/NIP-46 signer, and (for displayful
hardware) the custom wallet line — they share the contract, so swapping
the hardware does not silently downgrade the safety story.
Display-less solutions are an exception: a smartcard cannot bind a
review it cannot show. The smartcard line therefore depends on the
external-review-acknowledgement-v0 contract instead — an explicit
external reviewer takes responsibility for binding what was reviewed to
the APDU that gets sent.
Status today
The approval_digest contract is implemented on:
- Raspberry/Pi stateless QR vault,
- ESP32 stateless QR vault (host-core review flow),
- ESP32 USB/NIP-46 signer (disabled-signing development firmware).
It is partial on smartcard (acknowledgement plumbing under development) and planned on the custom hardware-wallet line. See the feature matrix per solution for the exact target/current status.
The point of writing this down: when someone asks “what does the
hardware actually guarantee?” the answer is not “we promise” — the
answer is a contract_id you can read, vectors you can run, and a
digest the device refuses to lie about.