Security
Normative threat model
This page is a summary. The authoritative copy lives in the spec repo.
The threat model every orangecheck protocol shares is on Ecosystem security. This page covers the attestation-specific layer on top.
Report channelLink to this section
Email security@ochk.io. Do not open a public issue for a bug that affects
verifiers. See
SECURITY.md (opens in a new tab)
for the full reporting terms.
What a valid attestation provesLink to this section
A verifier that resolves an attestation against live chain state can rely on three facts:
- Address control. The signer held the private key for the address when they signed. BIP-322 signature over the canonical message.
- Sats bonded. The address held
sats_bondedsats unspent when the verifier resolved the chain, re-derived from current UTXOs, never taken from the envelope. - Days unspent. The bonded coin has been confirmed for at least
days_unspentdays, also re-derived live.
And one self-asserted fact:
- Handle ownership. A claim like
github:aliceornostr:npub1…is the address holder's claim. The attestation does not prove it; a verifier may check it out of band.
What an attestation does NOT proveLink to this section
- Personhood or uniqueness. One person can hold many addresses, and many addresses can collude. OC Attest raises the cost of sybils; it does not make them impossible.
- Reputation. Sats × time is an economic signal, not a moral one.
- Future control. Custody of the key can change after the signature, by theft, sale or a wallet change. Treat an attestation as a point in time.
- Chain finality. The holder can spend the coin the moment the attestation is published. Re-resolve chain state on every check, and never cache a result longer than your tolerance for sybil entry.
AdversariesLink to this section
| Adversary | What they can do | What stops them |
|---|---|---|
| Anonymous sybil farmer | Produce many synthetic identities cheaply | The bond cost scales per identity |
| Spammer with one wallet | Sign many messages from one address | One address is one attestation; the bond does not multiply |
| Stolen-key opportunist | Sign attestations with a compromised key | The rightful holder publishes a fresh attestation from a new address |
| Compromised hosted verifier | attest.ochk.io answers ok: true falsely | Run the checks yourself with the published packages (Self-hosting the verifier); chain state is open to all |
| Chain-watching deanonymizer | Cluster addresses by spending behaviour | Out of scope: the attestation publishes the address |
| Block-reorg griefer | Bond with a transaction that is later reorged out | Verifiers require a confirmation depth |
OC Attest is not built to defend against coercion (a holder forced to sign once can be forced again), a compromised publishing platform stripping or replacing unsigned metadata (re-fetch from at least two relays), or a patient adversary who bonds for years to look like a long-term holder (cost rises with bond × time; size your gate for it).
What a verifier must doLink to this section
- Re-derive sats and days from current chain state. Do not trust
sats_bondedordays_unspentin the envelope. - Check the BIP-322 signature against the exact canonical message bytes. See Canonical message.
- Check the audience when your gate scopes proofs to one origin, and drop attestations issued for a different site.
- Require a confirmation depth before counting
days_unspent. Six is the default in@orangecheck/sdk(BOND_MIN_CONFIRMATIONS); high-stakes gates should require more. - Apply your freshness window. The signature has no expiry of its own.
- Take the subject from the signed message. Relay tags and the envelope's
address,identities,issued_atandexpires_atare not signed. An attestation answers a query only if its canonical message states the id, address or identity asked for. - Hold one bond to one identity per protocol. If the address also binds a
different identity on the same protocol, refuse with
stake_shared.
The exact algorithm is on Verification.
PrivacyLink to this section
Every attestation is public: it reveals the address, the bonded coin and any claimed handles. There is no zero-knowledge mode. Use a different address per context to keep gates from seeing each other's attestations; on-chain analysis can still cluster them.