<!-- Generated raw Markdown for /concepts/privacy; product pin 638fa1e9ca7face19a442cef43754f0d627c7705. -->

This is the canonical privacy page of this site: the single place that states
SubEtha's privacy claim in full, with every caveat attached. Every other page
that touches privacy links here rather than restating the claim. The
normative sources are the product repository's
[README "Privacy" section](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/README.md)
and
[`docs/OVERVIEW.md` §4](https://github.com/peaceandwhisky/SubEtha/blob/638fa1e9ca7face19a442cef43754f0d627c7705/docs/OVERVIEW.md)
at the pinned commit.

## The claim, with its caveats

<PrivacyCaveats />

## Why the burn and the mint don't link

The mechanism behind the claim, from the pinned sources:

- The burn address is derived as
  `burnAddress = truncate160(Poseidon("burn", recipientFr, secret))` with
  `recipientFr = SHA256(chainId ‖ recipient ‖ tweak)`. The `secret` and
  `tweak` exist only on the deriving side; the `secret` never appears
  on-chain, and it is what breaks the link.
- On-chain, the burn is recorded as an event of the same shape as an ordinary
  transfer: `IndexedTransfer(payer → burnAddress)`. The burn address is an
  opaque hash; an observer who does not know the secret cannot work back to
  the treasury from it. Derivation inputs change per payment, so burn
  addresses do not link to each other either.
- The mint-time ZK proof's public signals are
  `[transferRoot, recipient(hash), totalValue]` — **which burn was spent is a
  private witness**. The verifier call's calldata carries the receiver
  information used to check the recipient hash, but nothing that points at a
  burn.

## The payer–provider correspondence model, precisely

What is hidden is a **correspondence**, against a specific observer:

- **Hidden from on-chain observers:** which payer's burn funded which
  provider's mint. No payer → treasury transfer ever exists on-chain.
- **Hidden from the payer:** the provider's real payout destination. The 402
  carries only the one-time burn address; the payer is never shown the
  treasury.
- **Not hidden from the facilitator.** The facilitator derives every burn
  address and processes every payment, so it sees the full correspondence at
  all times. The claim is about the public ledger, not about the parties
  operating the flow. The same goes for the provider, which knows who called
  its API.

## What the system does not hide

None of the following is concealed, and no page on this site may imply
otherwise:

- **Amounts.** The burn is an ordinary-looking transfer; values are
  transparent on-chain. Anyone can see how much a given address burned.
- **The payer's own activity.** `IndexedTransfer(payer → burnAddress)` names
  the payer. An observer sees that this payer burned this amount at this
  time — what it cannot see is *to whom* that payment corresponds.
- **The treasury at mint time.** The treasury address appears in the mint
  calldata and as the mint destination. Hidden is the correspondence to any
  burn, not the recipient's existence or its revenue address.
- **Timing.** Burns and mints are timestamped public events; with few
  payments in flight, timing and amount coincidences narrow the guesswork
  (caveats 3 and 4 above).
- **The HTTP layer.** SubEtha changes nothing about HTTP: the provider sees
  the payer's requests exactly as any web server sees its clients (network
  address, headers, timing). Transport-level concealment is out of scope and
  not claimed.

## Scope of the claim

The unlinkability property is independent of the gasless choice — permit mode
versus self-transfer neither weakens nor strengthens it. It is also
conditional on volume: with few payments the anonymity set is small and the
claim is correspondingly weak. This is a structural property of a
low-traffic PoC, stated here once and linked from everywhere else.

Who must trust whom — including the facilitator's privileged position — is
[Trust & Limits](/trust/); the settlement machinery referenced above is
[Accepted vs finalized](/concepts/accepted-vs-finalized/).
