Risks
This page catalogs every assumption load-bearing for safety: what could fail, what mitigates it today, and what does not. We rank by category, not by severity — different users have different threat models, and a small caveat for one (browser-storage wallet UX) is a deal-breaker for another (custodial-grade operations).
Risk overview
| CATEGORY | RISK | SEVERITY (per our reading) |
|---|---|---|
| Cryptographic | Trusted setup of the mixer ceremony | △ Bounded — soundness rests on ≥ 1 of 2,227 contributors honest |
| Protocol | Indexer-validated, not Bitcoin-consensus-enforced | △ Material — same trust model as Runes/Ordinals; well-understood |
| Issuer | Confidential supply trust at etch time | △ Mitigated — attestation flow defaults on |
| Audit | No third-party audit; "experimental software, no warranty" | △ Material — only the spec + the code itself |
| Wallet | Browser-storage in-page privkey | △ Material — clearing localStorage = loss |
| Privacy | Address-graph and asset-graph leaks | ◇ Known scope limit — Tacit does not claim to close these |
| Anonymity set | Practical privacy depends on pool volume | △ Scales with usage |
| Recovery | Atomic-intent recipient UTXOs need worker fallback within 24h | △ Edge case — only this one envelope shape |
| Network | Esplora-endpoint dependency for chain data | ☑ Mitigated — tip-divergence watchdog across two providers |
| Operations | First-CXFER-after-withdraw discipline | △ User responsibility |
The rest of this page expands each.
Cryptographic: trusted-setup soundness
Groth16 requires a per-circuit trusted setup. If every contributor colluded and retained their secret randomness, they could forge proofs against the pool's verifying key. Soundness requires ≥ 1 honest contributor who destroyed their Toxic Waste. The ceremony itself (Polygon Hermez pot14 for Phase 1, 2,227 community contributions + Bitcoin block 948,824 (mempool) beacon for Phase 2) is documented on the Mixer page.
| WHAT IT BUYS | WHAT IT DOES NOT BUY |
|---|---|
| ☑ Privacy holds even if every contributor colluded | ☒ Cannot prove every contributor was honest |
| ☑ Public-randomness beacon closes the late-Sybil window | ☒ Beacon's MiMC iterations are a defense-in-depth, not a proof |
| ☑ Contributor identities + Bitcoin-block-hash commitments are openly observable | ☒ Identities being public does not prove honesty |
| ☑ Anyone can re-run the chain-walk verification offline | ☒ Once finalized, the ceremony is immutable |
A fully compromised ceremony breaks soundness (forged withdrawals against the pool's vk), not privacy (deposits and withdraws still cannot be linked). Anyone who can identify even one participant in the attestation log they trust to have destroyed their share can rely on the ceremony's soundness — the construction degrades only if all 2,227 colluded.
Protocol: indexer-validated, not consensus-enforced
Tacit is a meta-protocol. Bitcoin consensus does not enforce its rules. Miners do not validate envelopes; they only see ordinary Taproot transactions. Token validity is what every conforming indexer agrees it is.
This is the same trust model as Ordinals, BRC-20, and Runes — in production for years. It is not, however, the same as Bitcoin native security.
| MITIGATION | WHAT IT PROVIDES |
|---|---|
| MIT-licensed normative specification | Anyone can re-implement the indexer |
| Content-addressed dApp (IPFS CID pinning) | Two browsers running the same CID reach the same verdict |
| Spec-conformance test suite (per-opcode envelope encoding, indexer determinism, mixer flows) | Cross-implementation parity is testable |
WORKER_BASE = '' disables worker entirely |
The dApp still validates from chain alone |
Until the spec has been independently re-implemented and audited, a bug in the reference implementation could become a de-facto rule. This is a maturity concern; every metaprotocol on Bitcoin (Runes included) went through the same phase.
Issuer: confidential-supply trust at etch time
A CETCH commits to its initial supply via a Pedersen commitment. Observers know the supply is some integer in [0, 2⁶⁴) and nothing more — the commitment hides the value. The issuer announcing a specific supply is making a claim that cannot be verified cryptographically unless they publish the (supply, blinding) opening.
| MITIGATION | LIMITATION |
|---|---|
dApp publishes (supply, blinding) to IPFS by default at etch time |
Requires honest one-time publish; not enforced cryptographically |
| Asset metadata blob includes attestation field; verifier checks the commitment opens to the announced value | Pinned to IPFS by content hash, so on-chain reference is to content, not server — but IPFS pinning itself is operational |
| Issuers can opt out for "centralized stablecoin trust model" use case | Opt-out is per asset; observable via the attestation field's presence |
| Supply attestation is provably permanent for non-mintable assets attested at etch | Only matters if the issuer never opts out and the IPFS pin persists |
For non-mintable assets attested at etch, supply is provably and permanently public. For mintable assets, the same attestation must be re-published for each subsequent T_MINT envelope. For assets with mint_authority = 0x00…00 (non-mintable) but no attestation, supply is permanently unverifiable.
Audit: none, "experimental software, no warranty"
Tacit ships explicitly without an audit. The repo README, the dApp's mainnet banner, and the SPEC all repeat the same disclaimer: experimental software, no warranty, do not put amounts at risk that you cannot afford to lose.
| WHAT EXISTS | WHAT DOES NOT |
|---|---|
| ~133 test files in repo, including 108 mixer-specific tests and cross-impl test vectors | No third-party security audit |
| Spec-conformance suite | No formal verification of the validator |
Runtime Known Answer Test (KAT) (runStartupKAT()) for crypto primitives |
No external review of the trusted-setup ceremony |
| Beacon-pinning of the Phase 2 ceremony to a confirmed Bitcoin block | No independent reproduction of the ceremony bundle |
The code is MIT-licensed and re-implementable from the spec — see the z0r0z entity profile for the author's other open-source work. That does not substitute for an audit. Treat Tacit as it bills itself: experimental.
Wallet: in-browser privkey storage
Tacit's privkey is generated in the browser and stored in localStorage. There are three derivation paths:
- Auto-generated on first load
- Imported from a privkey hex the user holds
- Locally bound to an external wallet's address when the user connects Xverse / UniSat / Leather
| RISK | DETAIL |
|---|---|
| Clearing localStorage = loss of access | Without a backup of the privkey, every Tacit asset controlled by it is permanently inaccessible |
| Per-browser-profile identity | A Tacit identity is bound to one browser profile on one device. Switching browsers/devices yields a different identity |
| Locally-bound is not cryptographic derivation | Connecting the same Xverse wallet in a different browser does not re-derive the same Tacit identity |
| Hardware wallets do not work for protocol-level signing | Kernel Signatures, taproot script-path signatures, and Hash-based Message Authentication Code (HMAC) blinding are all in-browser only |
| Mainnet UX gates value-creating ops behind an export-and-acknowledge step | Mitigates the worst case but does not eliminate it |
The dApp ships the mainnet export-and-acknowledge gate explicitly for this reason. Hardware-wallet support for protocol-level signing paths is listed as a future enhancement in the spec.
Treat the Tacit privkey export with the same discipline as a seed phrase.
Privacy: what Tacit hides and what it does not
Tacit's privacy scope is precise.
| WHAT IS HIDDEN | WHAT IS NOT HIDDEN |
|---|---|
| ☑ Amounts of every CXFER, T_AXFER, T_MINT, T_BURN change | ☒ Sender's Bitcoin address |
| ☑ Initial supply at CETCH (subject to attestation) | ☒ Recipient's Bitcoin address |
| ☑ Mixer deposit-to-withdraw linkage (Groth16) | ☒ Asset ID being moved (asset_id is plaintext in every envelope) |
| ☑ Sum of balances across a chosen UTXO set (via range disclosure) | ☒ The fact that an envelope exists (the script-path spend is publicly tagged "TACIT") |
☑ Mixer notes (secret, ν) (browser-local, never network-transmitted) |
☒ Mixer pool denomination (public; defines the pool) |
The address-graph leak is the substrate-level constraint — every Bitcoin-substrate protocol leaks this, because Bitcoin addresses are public. BIP-352 Silent Payments (receiver privacy) is on the project roadmap and compatible with Tacit's wallet model. The asset-graph leak is a v1 simplification — Liquid hides asset_id via Asset Surjection Proofs; Tacit v1 does not.
Use cases requiring address-graph privacy (not just amount privacy) need additional tooling beyond Tacit alone.
Anonymity set: practical privacy versus structural privacy
Mixer cryptographic unlinkability is unconditional. Mixer practical unlinkability depends on the size of the anonymity set — the number of currently-unspent leaves in the pool at withdraw time.
| ANONYMITY SET | DAPP CLASSIFICATION | INTERPRETATION |
|---|---|---|
| < 5 | △ Very small | Withdraw correlates strongly with one of a small set of deposits |
| 5–29 | △ Casual privacy only | Statistical mixing, but enumeration is plausible |
| 30–99 | ◇ Healthy / well-mixed | Acceptable for most threat models |
| 100+ | ☑ Strong | dApp threshold for the strong-privacy banner |
The dApp surfaces the live anonymity-set count on the withdraw screen. A pool that has seen 40 deposits in a year is structurally sound — every check verifies, conservation holds — but withdrawing from it does not provide meaningful privacy. This is on the user, not on the protocol.
Recovery: the atomic-intent edge case
Tacit's claim — "your privkey plus the chain is enough" — has exactly one exception. Atomic-intent recipient UTXOs (SPEC §5.7.6) use a uniform-random blinding so browse-and-take can publish a cleartext amount on-chain without leaking via a baby-step-giant-step attack on the commitment.
| RECOVERY PATH | WHO IT WORKS FOR | TIME WINDOW |
|---|---|---|
| Privkey + chain alone | Every other Tacit operation's outputs | Unconditional |
| Privkey + local cache | Atomic-intent recipient UTXOs on the same browser profile | Unconditional |
| Privkey + worker's fulfilment record | Atomic-intent recipient UTXOs on a fresh device | 24 hours after fulfilment |
Outside the 24-hour worker window, an atomic-intent recipient who lost their local cache and never re-broadcast a related share-link is the one combination that cannot recover from privkey alone. The dApp warns about this; the share-link UX is the practical mitigation.
Network: Esplora dependency
The dApp fetches chain data from mempool.space (and blockstream.info as a parallel cross-check). Both are public APIs run by third parties. A long-term outage or a coordinated tamper of both would degrade Tacit usability.
| DEFENSE | WHAT IT PROVIDES |
|---|---|
| Tip-divergence watchdog across the two providers | Tampering with one surfaces as an in-app banner |
WORKER_BASE = '' mode |
Disables the convenience worker, the dApp still works |
| Self-hosting Esplora | Eliminates the third-party dependency for users who want it |
This is operational, not cryptographic. The protocol's safety is not at risk; only liveness is.
Operations: post-withdraw first-CXFER discipline
The mixer's "shielded on two axes" property (linkage + ambient amount) depends on the recipient performing a CXFER on the withdrawn UTXO before any other spend that would reveal it. Until then, the withdrawn UTXO's amount is exactly the pool's denomination — publicly known.
| BEHAVIOR | OUTCOME |
|---|---|
| Recipient CXFERs the withdrawn UTXO into a hidden-amount split as their first spend | Trail becomes amount-opaque from that point forward |
| Recipient spends the withdrawn UTXO directly to a transparent destination | Reveals the exact pool denomination at the recipient — defeats the ambient-amount shield |
The dApp UX nudges toward the first pattern. Discipline is on the user.
What we have not verified
The following are claims from the project's own materials that we have not independently verified:
| CLAIM | STATUS |
|---|---|
| The 2,227-contributor ceremony's transcript is valid and beacon-pinned | Read claim; did not re-run verification |
The NUMS H generator derivation is correct against the published cross-impl vectors |
Read claim; did not run the test suite |
The withdraw.circom constraints match the SPEC §3.8 description byte-for-byte |
Read circuit description; did not compile locally |
| The dApp's IPFS-pinned CID corresponds to the repo HEAD we cloned | Did not perform CID computation |
| The 108-test mixer suite passes | Did not run |
The 57K-line tacit.js has no malicious code injected at any point in its history |
Read claim; relied on repo provenance + MIT license |
These are not red flags. They are research scope limits — to make any of them confidence-grade claims requires re-running the project's tooling locally, which is a separate exercise from the spec + code reading this analysis is built on. A reader who wants to operate on Tacit with assets they cannot afford to lose should do this exercise themselves or wait for a third-party audit.
Trade-offs versus alternatives
| ALTERNATIVE | WHEN TACIT IS BETTER | WHEN TACIT IS WORSE |
|---|---|---|
| Liquid Confidential Transactions | Need Bitcoin proper, not a federated sidechain | Need lower-cost transfers; Liquid's per-tx cost is much lower |
| RGB / Taproot Assets | Need recovery from privkey + chain alone; do not want off-chain proof distribution | Need Lightning-native transfer (Taproot Assets) or already accept proof-chain UX (RGB) |
| Tornado Cash (Ethereum) | Want to mix tokens on Bitcoin proper, with ambient-amount shield around the mixer | Want native ETH mixing without wrapping; want a larger established anonymity set |
| Runes / BRC-20 / Ordinals | Need amount confidentiality | Need lowest-cost transfers; do not need amount confidentiality |
| CoinJoin (Wasabi/Whirlpool/JoinMarket) | Want token-graph confidentiality plus mixer | Want native BTC mixing only |
Tacit is not strictly better than any alternative for every use case. Each row above describes a specific trade-off; the choice depends on which property is load-bearing for the user.
References
- Tacit protocol specification — SPEC.md (z0r0z/tacit, MIT) — §5.6 disclosures, §5.7.6 atomic-intent UTXOs, §8 supply attestation
- Tacit mixer specification — MIXER.md — Phase 2 ceremony, anonymity-set thresholds
- Bitcoin Improvement Proposal 352 (Silent Payments) — BIP-352 — referenced as the receiver-privacy roadmap item
- Elements Project — Asset Surjection Proofs (Liquid asset-id hiding, the technique Tacit V1 does not implement) — elementsproject.org
- mempool.space Esplora API — mempool.space/docs/api
- blockstream.info Esplora API — github.com/Blockstream/esplora
- DNZN — z0r0z entity profile, Project Overview, Protocol, Mechanisms, Mixer, Operations