Documentation
Selective disclosure
Private by default, proven by choice. A holder proves one shielded balance to a party they choose — an auditor, a counterparty — revealing nothing else.
Why it matters
A shielded pool that can only hide is a dark pool, and a regulated-chain sponsor cannot build on that. Gloam is private by default and provable on demand: the holder, and only the holder, chooses to prove a specific fact to a specific party. That is the difference between privacy and opacity — and the answer to the dark-pool objection.
What a disclosure proves
A disclosure is a portable token that lets a verifier confirm:
- the discloser knows the secret that binds a commitment to a specific
amountandasset, and - that commitment is a live note in the pool.
Together: this holder owns this balance in the Gloam vault. It reveals nothing about who they are, does not expose the note secret (so it can never be used to spend), and says nothing about any of their other notes.
How it works
It reuses the shield circuit — no new trusted setup. The shield proof already proves commitment == Poseidon(secret, amount, asset) with the secret private. A disclosure is that proof plus the public commitment. The verifier checks the proof, then confirms membership on-chain with pool.commitmentSeen(commitment). Because the commitment is already a public tree leaf, a disclosure leaks nothing new beyond the amount and asset the holder chose to reveal.
Create a disclosure
In the app, open /app/disclose, pick a note, and copy the token. Programmatically, generate the shield proof for the note you want to reveal and package it:
import { artifactProver } from "@gloamtrade/sdk";
// prove the note you choose to reveal (same input as a shield)
const prover = artifactProver({ wasm: "shield.wasm", zkey: "shield_final.zkey" });
const { proof, publicSignals } = await prover({
commitment: note.commitmentField.toString(),
amount: note.amountWei.toString(),
asset: assetField.toString(),
secret: note.secretField.toString(),
});
// publicSignals === [commitment, amount, asset]
const disclosure = { v: 1, chainId, pool, commitment: publicSignals[0],
amount: publicSignals[1], asset: publicSignals[2], proof };Verify a disclosure
Anyone can verify at /verify — no wallet, no account. The proof is checked locally with snarkjs and the note is looked up directly on Robinhood Chain. Verification is two independent checks:
import { groth16 } from "snarkjs";
// 1) the proof (ownership + amount/asset binding)
const vkey = await (await fetch("/circuits/shield_vkey.json")).json();
const proofOk = await groth16.verify(vkey, [d.commitment, d.amount, d.asset], d.proof);
// 2) membership: the commitment is a live note in the pool
const live = await pool.read.commitmentSeen([toBytes32(d.commitment)]);
const verified = proofOk && live;Guarantees
- Unspendable. The disclosure carries a proof, not the secret, so it can never move the funds.
- Scoped. It reveals exactly one note. Other holdings, the wallet, and the history stay private.
- Trustless to verify. The recipient checks the math and the chain themselves; they do not trust the holder or Gloam.
Roadmap: viewing keys for continuous read access to a designated auditor, and range disclosures ("I hold at least X") without revealing the exact amount.