ZecProof
Testnet

Documentation

How ZecProof works

A walkthrough written for anyone who needs to trust a receipt: what the product does, how the proof is built, and how you can check it yourself. No jargon, no marketing.

What it is

ZecProof lets you prove that one specific Zcash payment was made, without exposing the rest of your wallet. It does this with three pieces that each do one job:

  • An invoice commits to its own ID, your address, and the amount — before anyone pays. The commitment is a hash, so it cannot be changed later without being caught.
  • A receipt names the single transaction that settled the invoice. It contains everything a verifier needs to re-run the checks.
  • A verifier re-runs those checks against testnet. It needs no wallet, no keys, and sends none of your information anywhere.

Run it locally

The app opens in a clearly-labelled demo mode, so you can walk the whole loop without testnet funds. Once you want to check it against the live chain, the commands below cover you.

pnpm install
pnpm dev   # open http://localhost:3000
  • pnpm testRun the protocol suite, including the memo round-trip.
  • pnpm spikeProve the live testnet gRPC path works, both directions.
  • pnpm demo:receiptMint a receipt pointing at a real testnet transaction.

The core idea

Zcash keeps who-paid-whom private by encrypting payments. That privacy is the whole reason a proof is hard: the transaction ID is public, but the amounts inside it are hidden.

ZecProof works around this by moving the binding out of the transaction and into the memo. A shielded memo on Zcash can carry up to 512 bytes of text that only the sender and the receiver can read. The invoice ID travels inside that memo, so:

  • When the payment arrives, ZecProof can read the memo and see “this transaction names invoice XYZ”. The invoice ID and the amount are both required, which stops short or misdirected payments from reading as settled.
  • The receipt records the transaction ID, which is public. Verifying it needs nothing but the public chain — no viewing key, no wallet.

The five checks

The verifier runs five checks and reports each one separately — because a tool whose whole output is a trust statement has no business summarising away the parts that did not pass.

1

Well-formed

The receipt has every required field, in the zecproof/1 format. A truncated or malformed receipt stops here.

2

Unmodified

The SHA-256 digest is recomputed from the receipt's contents and still matches. Editing a single character breaks this check.

3

Commitment

The invoice ID, address and amount are re-hashed and compared with the commitment stored in the receipt.

4

Binding

The memo written into the payment names this exact invoice. A receipt re-pointed at another invoice fails.

5

Chain

The transaction really exists on testnet, at the block height the receipt claims, without needing any viewing key.

The verifier also separates inconclusive from failed: a node it cannot reach is reported as unknown, never as a forgery.

What a receipt does not prove

ZecProof is deliberately honest about its limits. The verifier does not re-decrypt the memo bytes on the chain. Doing that would need the payee's viewing key — and handing that to a verifier would disclose the whole account, the exact thing this tool exists to prevent.

So a receipt proves the transaction exists and is intact; it does not claim to re-read the encrypted memo independently. The screen says so, rather than implying more than it checked.

Architecture

Everything the interface does flows through one ZcashClient boundary. No screen imports a wallet library, so swapping the simulated wallet for a real one is a change in one file.

getReceivingAddress · buildPaymentRequest
sendPayment · listIncoming · probeTransaction
  • Browser — invoices, receipts and the demo live here. All data stays on the device.
  • Server — a small, hand-built lightwalletd client that performs the chain check. It runs server-side because the public node cannot be reached from a browser.

Configuration

  • LIGHTWALLETD_URL — the testnet node for the chain check. Defaults to https://testnet.zec.rocks.
  • NEXT_PUBLIC_ZCASH_BACKEND — set to webzjs to use the real in-browser wallet. Unset, the app runs the labelled demo.

Nothing else is configured, because nothing else leaves the device. Invoices and receipts live in local storage. There is no account, no server copy and no sync — a tool premised on disclosing one payment has no business keeping a record of every payment somewhere you cannot see.

Scope

  • Testnet only. No mainnet, no real funds.
  • Transaction-level disclosure. One receiving account.
  • Local persistence. No auth, no cloud database.
  • No bridging, no smart contracts.