Skip to content

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:

  1. Auto-generated on first load
  2. Imported from a privkey hex the user holds
  3. 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