Contract Analysis
DISCLAIMER // NFA // DYOR
This analysis is based on observations of the contract behavior. We are not smart contract security experts. This document aims to explain what the contract appears to do based on the code. It should not be considered a comprehensive security audit or financial advice. Always verify critical information independently and consult with blockchain security professionals for important decisions.
⊙ generated by robots | curated by humans
Analysis Date: 2026-06-02
Metadata
Primary Contract
| PROPERTY | VALUE |
|---|---|
| Contract Name | TacitBridgeMixer |
| Contract Address | 0x82eb1246...90cC37 (etherscan) |
| Network | Ethereum Mainnet |
| Contract Type | Standalone, immutable (no proxy, no admin) |
| Deployment Date | 2026-06-01 20:11:23 UTC |
| Deployment Block | 25224831 (etherscan) |
| Contract Creator | 0x42e7b9e9...55483c (etherscan) |
| Creation TX | 0x71db7809...62cfd6 (tx) |
| Compiler Version | Solidity v0.8.34+commit.80d5c536 (optimizer on, viaIR, EVM prague) |
| Total Functions | 26 external/public (3 state-changing, 1 receive, 23 view) |
| External Contract Dependencies | 4 (Bitcoin relay, SP1 pool-root verifier, SP1 gateway, Groth16 verifier) |
| Upgrade Mechanism | ☒ None — Not Upgradable (all configuration is immutable) |
| Verification Status | ☑ Verified (Exact Match) on Etherscan |
| Audit Status | ☒ None — upstream Tacit ships as experimental software, no warranty |
Related Addresses
| TYPE | ADDRESS | NOTES |
|---|---|---|
| Bitcoin header relay | 0x36358295...8Ca6D0 (etherscan) |
HEADER_RELAY. Verified BitcoinLightRelay. Permissionless tip advance; one-time deployer-seeded genesis checkpoint |
| SP1 pool-root verifier | 0x42Ab3d9d...2a3CCb (etherscan) |
The bound poolVerifier for all 8 pools. Verified SP1PoolRootVerifier. No admin |
| SP1 verifier gateway | 0x397A5f7f...48dA9B (etherscan) |
Succinct's canonical mainnet SP1VerifierGateway, deployed 2024. Verifies the SP1 state proof |
| Groth16 burn verifier | 0x031b22ba...7Ab2ca (etherscan) |
BURN_VERIFIER. ☒ Unverified bytecode (1,752 bytes) — bn254 pairing verifier |
| Contract creator | 0x42e7b9e9...55483c (etherscan) |
Deployed the relay, SP1 pool-root verifier, and Groth16 burn verifier above (the gateway is Succinct's). Distinct from z0r0z's canonical zFi deployer 0x1C0Aa8cC...855A20 (etherscan) |
| Bound Tacit asset | 0x3cba71e1...126f34 (tacitscan) |
ASSET_ID — the Tacit-side asset this mixer bridges. Not TAC (f0bbe868...94762b (tacitscan)) |
Executive Summary
TacitBridgeMixer is the Ethereum end of a two-way bridge between native ETH and the Tacit confidential-token meta-protocol on Bitcoin. It locks ETH on Ethereum and lets the depositor mint a matching confidential balance on Bitcoin; later, a burn of that balance on Bitcoin releases the locked ETH back out on Ethereum. It is also a mixer in the Tornado sense — deposits go into fixed-denomination pools and withdrawals are unlinked from them by a zk-SNARK — but the unlinking proof here is verified against state that originates on Bitcoin, not Ethereum.
The contract advertises itself as "fully trustless … No trusted roles," and the bytecode supports the first half of that claim literally: it has no privileged roles, no fee mechanism, and no upgrade path. Every parameter — the relay, the verifiers, the eight denominations, the asset id — is fixed at construction and cannot change. What the contract cannot remove is its dependence on four external contracts and two off-chain cryptographic systems. The contract relocates trust rather than removing it: from a privileged key to (a) the soundness of a Succinct SP1 state proof and its off-chain guest program, (b) a Groth16 burn circuit whose on-chain verifier is unverified bytecode, (c) a Bitcoin light client whose genesis checkpoint was seeded once by the deployer, and (d) the Trusted Setup ceremonies behind both SNARKs.
The intended audience is a Tacit user who wants to move value between Bitcoin-side confidential assets and Ethereum ETH without a custodian or a federation. The withdrawal path stacks six independent checks — Bitcoin proof-of-work inclusion, Tacit envelope validity, an SP1-accepted burn claim, a Groth16 knowledge proof, a domain-bound bindHash, and an aggregate balance cap — so defeating it appears to require breaking one of those primitives rather than stealing a key. The main risks are the unaudited, freshly-deployed status (the contract is one day old as of analysis), the unverified Groth16 verifier, the off-chain SP1 guest program that no on-chain reader can inspect, and a thin anonymity set (all current activity is the deployer's own end-to-end test).
Architecture
graph TD
User([User / Depositor])
Recip([Withdrawal recipient])
subgraph ETH["Ethereum"]
MIX["TacitBridgeMixer<br/>0x82eb1246...90cC37<br/>(holds ETH, Poseidon deposit trees)"]
RELAY["BitcoinLightRelay<br/>0x36358295...8Ca6D0<br/>(heaviest-chain header store)"]
SP1V["SP1PoolRootVerifier<br/>0x42Ab3d9d...2a3CCb<br/>(acceptedBurns registry)"]
GW["Succinct SP1VerifierGateway<br/>0x397A5f7f...48dA9B"]
G16["Groth16 burn verifier<br/>0x031b22ba...7Ab2ca<br/>(unverified)"]
end
subgraph BTC["Bitcoin"]
TACIT["Tacit confidential asset<br/>(Taproot envelopes)"]
end
User -->|"deposit ETH<br/>(commitment, denom)"| MIX
MIX -.->|"leaf appears, user mints<br/>on Bitcoin"| TACIT
TACIT -.->|"T_BRIDGE_BURN (0x61)<br/>Taproot reveal"| BTCBURN[["burn tx on Bitcoin"]]
User -->|"withdrawFromBurn(rawBtcTx, headers, proof)"| MIX
MIX -->|"verifyBlock (PoW + tip)"| RELAY
MIX -->|"isAcceptedBurn(claimId)"| SP1V
MIX -->|"verifyProof (bn254 pairing)"| G16
MIX -->|"ETH denom"| Recip
Relayer([anyone]) -->|"advanceTip(headers)"| RELAY
Prover([anyone]) -->|"proveStateTransition(SP1 proof)"| SP1V
SP1V -->|"verifyProof"| GW
SP1V -->|"getRootAccumulator"| MIX
BTCBURN -.->|"proven by SP1 guest"| SP1V
System Overview
The bridge has two directions and one shared escrow balance.
Into Tacit (deposit / batchDeposit). A user sends ETH equal to one of eight fixed denominations and supplies a 32-byte commitment (a Poseidon Hash of their secret note). The contract appends the commitment as a leaf in a per-denomination incremental Merkle Tree (depth 20, up to 1,048,576 leaves), records the new root, and increments totalBalance. Off-chain, the Tacit dApp watches for this leaf and lets the depositor mint the equivalent confidential asset on Bitcoin.
Out of Tacit (withdrawFromBurn). To redeem ETH, the user first burns their confidential balance on Bitcoin with a T_BRIDGE_BURN envelope (opcode 0x61), then submits the raw Bitcoin transaction plus a header chain to withdrawFromBurn. The contract verifies the burn is in Bitcoin's canonical chain via the relay, that the SP1 prover has accepted the exact burn claim, and that a Groth16 proof of note knowledge is valid, then releases the denomination to the recipient encoded in the burn envelope.
- Escrowed ETH is released only against a stacked Bitcoin-origin proof — no signer can move funds.
- The contract holds no admin, pause, fee, or upgrade capability. Once deployed, behavior is fixed.
- Producing the SP1 proof and running the relay are off-chain jobs anyone can perform; both must stay advanced for withdrawals to process, which is a liveness dependency rather than a custody one.
Design Patterns Used
- Fixed-denomination mixer: pools are keyed by
keccak256(ASSET_ID, denomination); withdrawals are denomination-pure, which keeps each pool's anonymity set fungible. Mirrors Tornado Cash's pool design. - Incremental Merkle tree with cached
filledSubtreesand precomputedzeros[]: O(20) hashing per deposit, no full-tree storage. Poseidon Hash is used as the tree hash because it is cheap inside the withdrawal SNARK. - Bitcoin Simplified Payment Verification (SPV) on Ethereum: a hand-rolled light client (
BitcoinLightRelay) plus in-contract transaction parsing, txid recomputation, and Merkle inclusion — the contract reads Bitcoin without trusting any oracle. - Proof-carrying state bridge: the authoritative "which burns are valid" decision is delegated to an SP1 zero-knowledge proof of the Bitcoin-side pool state, recorded in
acceptedBurns. The mixer never reconstructs Tacit semantics itself. - Transient reentrancy lock: inherits Solady's
ReentrancyGuardTransient(EIP-1153 transient storage), guardingdeposit,batchDeposit, andwithdrawFromBurn.
Access Control
Roles & Permissions
There is no privileged role on this contract. No constructor argument assigns an owner, operator, or pauser, and no function checks msg.sender against a stored address. The table below reflects that everything is either open to anyone or driven by external contracts, whose risk surface is covered in the Potential Risks assessment.
| ROLE | ASSIGNED BY | REVOKABLE | CALL COUNT |
|---|---|---|---|
| User (depositor / withdrawer) | Permissionless — anyone | N/A | Unlimited |
| Relayer / SP1 prover | Permissionless — anyone (acts on external relay + verifier) | N/A | Unlimited |
| Admin / Owner | ☒ Does not exist | — | — |
Permission Matrix
| FUNCTION | OWNER | USER | ANYONE |
|---|---|---|---|
deposit |
— (no owner) | ☑ | ☑ |
batchDeposit |
— | ☑ | ☑ |
withdrawFromBurn |
— | ☑ | ☑ |
| view functions | — | ☑ | ☑ |
| pause / upgrade / set-fee / rescue | ☒ no such function exists | ☒ | ☒ |
Time Locks & Delays
| ACTION | TIME LOCK | CAN CANCEL | PURPOSE |
|---|---|---|---|
| Withdrawal after burn | Bitcoin confirmations (CONFIRMATION_DEPTH = 6) before the relay accepts the block |
No | ◇ Finality — the burn block must be buried under 6 headers chaining to the relay tip |
| Deposit | None — immediate | No | ◇ Funds escrow on the same transaction |
Economic Model
The contract custodies native ETH and releases it only along the withdrawal path. Neither deposits nor withdrawals take a fee, and there is no protocol treasury.
Funding Sources & Sinks
- Inflow:
deposit/batchDepositrequiremsg.valueto exactly equal the denomination(s). Any mismatch reverts (InvalidDenomination). Thereceive()function reverts, so ETH cannot enter except through a deposit. - Outflow:
withdrawFromBurnsends exactlyp.denominationto the recipient via SoladyforceSafeTransferETH. There is no other path out: no sweep or owner-withdrawal function.
Economic Invariants
- Aggregate solvency gate: withdrawals check
totalBalance >= p.denominationand decrementtotalBalanceon each release. Because total redeemable value is capped at total deposits, the contract cannot pay out more ETH than was put in — even though pools are otherwise fungible (a burn in any denomination can be redeemed as long as aggregate backing exists). - Double-spend prevention: each pool tracks
burnNullifiers; a nullifier can be consumed once. A replayed burn revertsNullifierAlreadySpent. - Denomination set — eight fixed values, in wei:
| INDEX | WEI | ETH | TACIT UNITS (8-DEC) |
|---|---|---|---|
| 0 | 10,000,000,000,000 | 0.00001 | 1,000 |
| 1 | 100,000,000,000,000 | 0.0001 | 10,000 |
| 2 | 1,000,000,000,000,000 | 0.001 | 100,000 |
| 3 | 10,000,000,000,000,000 | 0.01 | 1,000,000 |
| 4 | 100,000,000,000,000,000 | 0.1 | 10,000,000 |
| 5 | 1,000,000,000,000,000,000 | 1 | 100,000,000 |
| 6 | 10,000,000,000,000,000,000 | 10 | 1,000,000,000 |
| 7 | 100,000,000,000,000,000,000 | 100 | 10,000,000,000 |
UNIT_SCALE = 10^10 converts between ETH's 18 decimals and Tacit's 8 decimals (TACIT_DECIMALS = 8). The constructor enforces every denomination is a whole multiple of UNIT_SCALE, so each maps to an exact integer number of Tacit units.
Observed Balance
As of analysis date totalBalance is 90,000,000,000,000 wei (0.00009 ETH), matching the contract's on-chain ETH balance. This is the residue of the deployer's own round-trip tests (see Summary of Observations).
Summary of Observations
TacitBridgeMixer is an immutable escrow that connects Ethereum ETH to Bitcoin-side Tacit confidential assets, with mixer-style unlinkability layered on top. The deposit side is self-contained: lock ETH, append a Poseidon commitment to a fixed-denomination tree. The withdrawal side carries the bulk of the logic and the trust assumptions. A single withdrawFromBurn call parses a raw Bitcoin transaction in Solidity, recomputes its txid, proves it is buried in Bitcoin's heaviest chain through the relay, extracts a Taproot script-path envelope, reconstructs a domain-separated bindHash over chainid and the contract's own address, confirms the SP1 prover has accepted the exact burn claim, and finally checks a Groth16 proof of note knowledge — all before a single wei moves.
On money: the contract holds only what was deposited, charges nothing, and gates every payout on an aggregate totalBalance that can never let withdrawals exceed deposits. There is no admin path to the funds. We traced a real withdrawal (tx 0x45f7ccbc...4491d9) end to end: it called the relay's verifyBlock, the SP1 verifier's isAcceptedBurn, then the Groth16 verifier's verifyProof (which executed genuine bn254 ecadd/ecmul/ecpairing precompiles and returned true), and released 0.001 ETH. The withdrawal path executed successfully in the one withdrawal we traced.
On concerns: the contract is one day old, unaudited, and its current anonymity set is a single user — the deployer, who performed two deposits and two withdrawals. The Groth16 burn verifier it depends on is unverified bytecode, so a reader cannot confirm on-chain which circuit it enforces. The SP1 guest program that decides which Bitcoin burns are valid lives off-chain; the contract pins only its verification-key hash (PROGRAM_VKEY), not its source. The Bitcoin relay's safety rests on a one-time genesis checkpoint set by the deployer and on Bitcoin not experiencing a deep reorg across a difficulty retarget (explicitly out of scope in the relay's own comments). And the whole withdrawal flow inherits the trusted-setup assumptions of two separate SNARK systems. These are the trust assumptions the design depends on, beyond the "no trusted roles" claim. See the Potential Risks assessment for the summarized findings.
References
| RESOURCE | NOTES |
|---|---|
| TacitBridgeMixer source (Etherscan) | Verified Solidity source; primary input to this analysis |
| TacitBridgeMixer.sol @ z0r0z/tacit | Upstream source at the analyzed commit |
| Tacit Project Overview | DNZN research on the Bitcoin-side meta-protocol this bridge connects to |
| Tacit — Research Timeline | Where this analysis is catalogued among DNZN's Tacit research (protocol, mechanisms, mixer, operations, risks) |
| Tacit — The Shielded Mixer | The Bitcoin-side Groth16 mixer; same primitive family as this bridge's withdrawal proof |
| Succinct SP1 documentation | The SP1 zkVM and on-chain verifier gateway used to prove Bitcoin pool state |
| Tornado Cash design | Reference for the fixed-denomination Poseidon-tree mixer pattern |
Change Log
| DATE | AUTHOR | NOTES |
|---|---|---|
| 2026-06-02 | Artificial. | Generated by robots. Gas: 130 tok |
| 2026-07-03 | Denizen. | Reviewed, edited, and curated by humans. |