Use it
Get started
Go to tacit.finance/tac and sign in with your Ethereum wallet. Signing in creates your Tacit key. The same wallet always creates the same key, so you can sign in again on any device.
- Shield. Pick an amount of TAC and press Shield. If you have no ETH, you sign once and the leader sends it in for a small fee in TAC. If you hold ETH, you sign and send one transaction yourself, with no fee. Your TAC then shows as private TAC on the Tacit chain. For now, each shield has a limit, which the page shows.
- Send. Enter a
tacit1…address, aname.weior an0x…address, and an amount. You see “Sent” within seconds. The payment settles on Ethereum about a minute later. A payment to a tacit1 address or a name stays private. A payment to an 0x address arrives as ordinary public TAC, but no one can see who sent it. - Get paid. Open the Receive tab. Share your tacit1 address, or a pay link such as
tacit.finance/to/yourname/25. You can also show a code to scan. It turns to “Paid” when the money arrives. - Withdraw. Move TAC out to your wallet as public TAC, into the DeFi pool to swap, farm or borrow privately, or to Bitcoin.
People can pay your tacit1 address on the chain once you have opened your Tacit wallet. If you already have private TAC in the DeFi pool, you can move it onto the chain from the same page.
Use it
Fees
Each action costs a small fee in TAC. The page shows it before you press. Most of the fee pays the leader for Ethereum gas, so it goes up and down with gas prices. A small part stays in the chain’s pool.
| Action | Stays in the pool | Pays for gas |
|---|---|---|
| Send | 0.002 TAC | The leader’s fee |
| Shield | A small margin, now 0.02% | The leader’s fee, plus sending it in if you signed once |
| Withdraw | 0.1%, at least 0.002 TAC | The leader’s fee |
Your private balance is counted in shares of this pool. The part of each fee that stays in the pool makes every share worth a little more. So when other people pay, what you hold grows slightly. A share never loses value in TAC.
Use it
What is public
The chain hides what happens inside it. What crosses its edges is public, as the picture at the top shows.
| Public | Hidden | |
|---|---|---|
| Shield | Your Ethereum address and the amount | Who holds it afterwards |
| Send | That a block landed, and how many notes it made | Who paid whom, and how much |
| Withdraw | The amount and the address it goes to | Who it came from |
| Balances | The total on the chain | What anyone holds |
Because the edges are public, a withdrawal of exactly the amount you shielded can be linked to it. Wait a while between the two, and use different amounts.
Use it
If something goes wrong
No single party can freeze your money. Here is what happens in each case.
- The leader stops. If no block lands for 10 minutes, anyone may land the next one.
- Your payment is left out. Press “Post it to Ethereum yourself” in the app. Blocks must include it within an hour. A posted payment shows on Ethereum which notes it spends and creates, but not the amounts.
- A shield never goes in. After 7 days, press “Take back” in the app. The TAC goes back to your wallet, or into the DeFi pool as private TAC.
- You lose your device. Sign in with the same wallet somewhere else. You get the same key, and the app finds your notes again from the data on Ethereum.
How it works
A payment’s path
- Your deviceProves the payment. Your keys and amounts stay here.
- LeaderChecks the proof and adds it to the next block.You see “Sent”
- ProverProves the whole block at once, on a GPU.
- EthereumChecks the block’s proof and stores its data.You see “Settled”
Your device makes a zero-knowledge proof. The proof shows that you own the notes you are spending and that the amounts add up, without revealing either. It uses Halo2, the same circuit as the Bitcoin shielded pool.
The leader checks the proof and adds the payment to the next block. A prover then runs the block program in SP1. The program checks every payment proof in the block in one step and produces a single Groth16 proof for the whole block. The TacitBlocks contract checks that proof on Ethereum and records the block.
Checking a block’s proof costs the same on Ethereum whether the block holds one payment or thirty. The payments in a block share that cost, which keeps fees low.
How it works
Notes and shares
Your balance is made of notes. A note is a sealed record of an amount and its owner. The chain stores only the seal, called a commitment, so no one can read the amount or the owner from it.
To spend notes, your wallet publishes their nullifiers. A nullifier is a tag that only the owner can compute. It marks a note as spent, so the note can’t be spent twice, but it doesn’t reveal which note it was.
A payment spends up to two notes and creates up to three new ones: one for the person you pay, one for your change, and one for the leader’s fee.
Each new note comes with an encrypted memo of 1,152 bytes. Your wallet finds your notes by trying to open the memos with your key. The memos use ML-KEM-768 together with secp256k1, so even a future quantum computer couldn’t read one recorded today.
Notes count shares of the pool. One share is worth (pool + 1) / (shares + 1) TAC. The extra 1 on each side is a virtual TAC that no note holds, so no single deposit can set the price. Shielding buys shares at this rate. Withdrawing sells them back, less the fee.
How it works
Blocks and leaders
A leader collects payments and lands blocks on Ethereum. The TacitSeats contract decides who leads. It has no owner.
Anyone can take a seat by locking 1,000 TAC. If you leave, you get the TAC back 7 days later.
Time is split into slots of 50 Ethereum blocks, about 10 minutes each. In each slot, one seat leads. While no one holds a seat, the bootstrap leader leads.
Every payment includes a fee note for its leader, which pays the gas to land the block. Provers are paid in points.
Two rules keep the chain moving. If no block lands for 10 minutes, anyone may land one. And anything posted to the forced queue on Ethereum must be in a block within an hour.
To lead, run the node and leader from tacit-leader ↗ and call announce(url). To prove blocks with your GPU, see tacit.finance/prove.
How it works
What you trust
| For | You rely on | Not on |
|---|---|---|
| Your funds | The proofs and the contract’s code | The leader or the provers |
| Staying live | Any leader, or anyone after 10 minutes | Any single leader |
| Your data | Ethereum, which stores every block’s notes, memos and nullifiers | Any indexer. Anyone can rebuild the chain’s state. |
| Your privacy | Your own device, which makes every proof | The leader or the provers |
The contract has no owner, no upgrade key and no pause. Improvements come as a new chain. Each person moves their own notes to it and keeps their privacy on the way.
A block’s prover can see which nullifiers and new notes belong to the same payment within that block. It can’t see keys, amounts or owners.
The proofs use pairings, like most zk-rollups on Ethereum. The memos are already safe against quantum computers.
How it works
Build on it
The leader’s API is public and needs no key.
curl https://tacit-chain-leader.onrender.com/state # height, roots, pool and shares
curl https://tacit-chain-leader.onrender.com/fee # what a payment costs now| Route | Returns |
|---|---|
GET /state | Height, note root, counts, the forced queue, pool and shares |
GET /fee | The fee, the shield’s sending fee and limit, and the leader’s chain address |
GET /notes?from=N&limit=M | New notes and their memos, to scan |
GET /path/N | A note’s Merkle path |
GET /spent/0x… | Whether a nullifier is spent |
POST /spend | Takes a proved payment. Follow it at /receipt/ID. |
POST /forced | The bytes to post with TacitBlocks.force |
In JavaScript, dapp/tacit-chain-client.js is the app’s complete chain wallet. Amounts are in units of 10−8 TAC.
import { makeChainClient } from './dapp/tacit-chain-client.js';
import { tacitChain } from './dapp/tacit-chain-config.js';
import { makeHalo2System } from './dapp/btc-pool-halo2-prover.js';
// rpcCall(method, params): an Ethereum JSON-RPC call. priv: the Tacit key
const system = makeHalo2System({ wasm, params, vk, pinnedVkHash });
const c = makeChainClient({ cfg: tacitChain(), rpcCall, priv, system: () => system });
await c.ready();
await c.scan(); // find your notes
await c.worth(); // your balance, in units
await c.pay(chainAddress, units); // proved here, sent to the leader
await c.withdraw('0x…', units);| Contract | Address |
|---|---|
| TacitBlocks | 0x00000000000a9147ffd8d41d152d730ca5f84e6c |
| TacitSeats | 0x00000000001f703eae70de3b528213e4802790fb |
| TAC | 0xA1313eb9f3A445606D9583bcAc3ebeB56a858279 |
| SP1 verifier | 0xb69f2584CBcFf99a58C4e7002E8b89Af54a6f4e2 |
| Block program key | 0x00610fb0fa1b5d800e548c3cdcdf98ceb4288828be1cec1fb81e39004bad6ed6 |