Bitcoin Privacy Track · free, drop-in, every 1st & 3rd Tuesday on Discord Next session →

/Programs/Privacy_Track_

Bitcoin privacy. Build it to learn it.

Bitcoin is public by default. In 12 hands-on sessions you learn how privacy breaks and how it's being fixed, by building Silent Payments, payjoins and your own node, then reading the real code with the people writing it.

1st & 3rd Tuesday 12 sessions · 90 min Discord · drop-in Free

Every 1st & 3rd Tuesday, 07:00 UTC. Add to Google Calendar

privacy-track/labs/silent-payments

Session 1 · the lab

Silent Payments

Build a BIP352 sender in plain Python, graded against the official test vectors

  • 01Send
  • 02Scan
  • 03Review Core
$ python3 run_vectors.py send · 28/28 passing ✓
Free and open source · try it now →

Start here

Where Bitcoin privacy leaks.

The protocol is rarely the problem. Most privacy failures happen in three places, and every one of them is software that open-source contributors can fix.

01 · YOUR WALLET

How you receive and hold

Reusing an address links every payment you get. Merging coins tells the world they're yours. Silent Payments and coin control fix this.

02 · THE TRANSACTION

How it's built

Analysts assume all inputs have one owner, spot your change, and recognise your wallet's fingerprint. Learn their rules, then break them with Payjoin and CoinJoin.

03 · THE NETWORK

How it's sent and synced

Light wallets tell servers your addresses, and broadcasts can reveal your IP. Run your own node and broadcast privately.

Season one

12 sessions, one at a time.

Each session stands alone, so you can drop in anywhere. Tap one to learn the idea, try it yourself, and see what we do live.

S01 Silent Payments I One address, no trail Month 1

The idea in plain words

Publishing one Bitcoin address for donations or invoices means anyone can look up every payment you ever got, and when you spent it. Silent Payments (BIP352) let you publish one reusable address, while every payment lands at a fresh, unlinkable address on-chain. No server and no notification transaction needed.

The analogy

Paint mixing. The sender mixes their secret colour (their input keys) with your public colour (your scan key). Only you can remake that exact mix from your side, so only you recognise the result.

Try it yourself

You leave with: Your own Silent Payments sender, passing the 28 official BIP352 test vectors.

  1. 1

    Build the sender: 5 small functions in send.py, graded against the official vectors. Race to 28/28.

  2. 2

    Look up a public donation address on mempool.space and see every payment it ever received. That's what address reuse gives away.

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    bitcoin/bitcoin#36338: a small fix to how a sender reads a P2PKH public key. What did the old code do, and what if sender and receiver disagree?

  2. 📜

    BIP352 "Motivation": does Silent Payments make the reuse problem go away, or just move it somewhere else?

  3. 🎯

    Proof of work: Finish the lab to 28/28, or test a Silent Payments wallet on signet and file one well-documented bug.

S02 Silent Payments II Finding your money Month 1

The idea in plain words

The catch with Silent Payments: to find payments, the receiver has to check every eligible transaction on the chain. There are three ways to do that, each with its own privacy trade-off: run your own full node, download small hints ("tweaks") from a server and finish the maths yourself, or hand a server your scan key so it does the work and sees your incoming payments.

The analogy

The post office. (1) You sort all the mail yourself. (2) The post office gives you a stamp for each letter and you test them at home. (3) You give the postman a key that opens only your letters: quick, but he can read them.

Try it yourself

You leave with: A working scanner, and a number for how long it takes to scan a day of Bitcoin.

  1. 1

    Build the scanner in receive.py. The grader catches the two classic bugs.

  2. 2

    Run scan_benchmark.py and compare laptops: how long would a year offline take to catch up?

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    bitcoin-core/secp256k1#1912: a light-client API for Silent Payments. Which of the three scanning models is it for?

  2. 📜

    Satoshi's whitepaper, section 10 "Privacy": "keeping public keys anonymous." How far did we drift?

  3. 🎯

    Proof of work: Run BlindBit Oracle on signet and write up the setup, or pick a still-open good first issue in rust-silentpayments or bdk-sp.

S03 Silent Payments III: Review Club Silent Payments land in Bitcoin Core Month 2

The idea in plain words

Bitcoin Core merged the core Silent Payments logic in 2026, and sending and receiving are still in review. You built the protocol in S1 and S2, so now you can read the real implementation and recognise every piece. This session runs as a Review Club: we build the PR beforehand, then read it together.

The analogy

You've cooked the dish at home. Now you read the restaurant's recipe and spot where they did it differently, and why.

Try it yourself

You leave with: A Bitcoin Core branch built, the BIP352 unit tests run, and a written review of real code.

  1. 1

    Before the session: build Bitcoin Core and run test_bitcoin --run_test=bip352_tests.

  2. 2

    Map your send.py onto src/common/bip352.cpp. Where do a_sum, input_hash and t_k live?

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    #35301 (merged core logic), #35302 (sending) and #32966 (receiving).

  2. 📜

    Why did Silent Payments in Core take three years? What does the order of the work tell you about how Core handles cryptography?

  3. 🎯

    Proof of work: Keep a running review on one open Silent Payments PR through the season.

S04 Think like the adversary You are being watched Month 2

The idea in plain words

Chain analysis firms follow money with a handful of rules of thumb. All inputs in a transaction belong to one person. Reused addresses link payments. Round amounts are payments, not change. And every wallet leaves a fingerprint in small details like nLockTime, nSequence and output order. Learn the rules and you can see your own transactions the way they do.

The analogy

Handwriting analysis on envelopes. You never open the letter, but the handwriting, the stamp and the postmark tell you a lot.

Try it yourself

You leave with: The five chain-analysis heuristics, a threat model you can reuse, and the ability to name a wallet from raw hex.

  1. 1

    Run the chain-analysis lab: implement the heuristics on sample transactions.

  2. 2

    Play analyst on each other's signet transactions: find the change, guess the wallet, trace the money.

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    A transaction-building PR in BDK or rust-bitcoin: does it change what a transaction looks like on-chain?

  2. 📜

    Eric Hughes, A Cypherpunk's Manifesto (1993): "Privacy is the power to selectively reveal oneself to the world."

  3. 🎯

    Proof of work: Add a wallet to the shared fingerprint table, with evidence.

S05 Coin selection and change Coins have memories Month 3

The idea in plain words

Every coin (UTXO) in your wallet has a history. When your wallet picks coins to pay with, it chooses which past lives to reveal, and merging two coins tells the world they belong to the same person. Different selection algorithms trade fees against privacy. Labels are your self-defence.

The analogy

Paying with banknotes that remember where they've been. Hand over two at once and the shop learns both stories.

Try it yourself

You leave with: Labelled coins, and a healthy fear of careless merging.

  1. 1

    Label every coin in a signet wallet (Sparrow works well), freeze one, and force selections. Then merge two labelled identities and see the damage.

  2. 2

    Run the coin-selection lab: try to beat branch-and-bound on privacy without losing on fees.

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    BDK coin-selection PRs. A small merged fix like bdk_wallet#471 shows contributions like this are within reach.

  2. 📜

    Hal Finney on what privacy people should be able to expect.

  3. 🎯

    Proof of work: A BDK beginner issue, or a test report on an open coin-selection PR.

S06 Payjoin Paying together Month 3

The idea in plain words

The analyst's favourite rule is that all inputs belong to one owner. In a payjoin, the receiver adds one of their own coins to the payment, so that rule quietly becomes false. And because a payjoin looks like any other transaction, it weakens the rule for everyone, even people who never use it. BIP78 needs the receiver online; BIP77 (async payjoin) doesn't.

The analogy

Two people putting cash on the restaurant table. Nobody watching can tell who paid what.

Try it yourself

You leave with: A payjoin done in pairs, and a broken heuristic.

  1. 1

    Do a payjoin in pairs on regtest with the payjoin lab: one sends, one receives, then swap.

  2. 2

    Play analyst: trace each input back to its wallet and point at the lie the transaction tells.

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    Review one open rust-payjoin PR together.

  2. 📜

    Adam Back: privacy has to be default and boring to win.

  3. 🎯

    Proof of work: A still-open, unclaimed rust-payjoin good first issue. Docs count.

S07 Light clients and your own node Don't trust, verify, privately Month 4

The idea in plain words

A light wallet that uses someone else's server tells that server every address you own, your balance and your IP. Old bloom filters (BIP37) leaked; compact block filters (BIP157/158) flip the model so you download a small summary of each block and check it yourself. Utreexo makes a full node light enough for a laptop.

The analogy

Telling the librarian every book you want, versus taking the catalogue home and looking it up yourself.

Try it yourself

You leave with: Your own node syncing, with your wallet pointed at it.

  1. 1

    Build and run Floresta and connect a wallet to your own node. First to sync wins sats.

  2. 2

    Run the compact block filters lab: build a simplified BIP158 filter and measure false positives.

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    A Floresta or Kyoto PR. Floresta has welcoming maintainers and a real good-first-issue culture.

  2. 📜

    "Don't trust, verify": what does it actually ask of us?

  3. 🎯

    Proof of work: A still-open Floresta good first issue, or turn tonight's setup pain into a docs PR.

S08 The network sees you Tor, BIP324, private broadcast, ASmap Month 4

The idea in plain words

Even a perfect transaction can be traced back to your IP address by whoever hears it first. Bitcoin Core now has three defences: BIP324 encrypts traffic between nodes so your ISP can't read it; -privatebroadcast (Core 31) sends your transactions out over short-lived Tor or I2P connections; and -asmap spreads your peers across networks so no single operator surrounds you.

The analogy

Never send all your messengers out through the same gate.

Try it yourself

You leave with: Your node's traffic inspected, your broadcasts made private, and a map of your network exposure.

  1. 1

    Wiretap yourself with the network lab: compare plaintext and BIP324 traffic in Wireshark.

  2. 2

    Turn on -privatebroadcast, send a signet transaction and watch getprivatebroadcastinfo. Then compare peer diversity with -asmap=1.

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    A peer-observer PR, or a private-broadcast follow-up in Core such as #34533.

  2. 📜

    Timothy May, The Crypto Anarchist Manifesto (1988). Is the network layer Bitcoin's soft underbelly?

  3. 🎯

    Proof of work: A peer-observer beginner issue, or publish your AS-diversity check as a guide.

S09 CoinJoin and OpenSwap Breaking the trail Month 5

The idea in plain words

Following the money works because money leaves one trail. A CoinJoin mixes many people's coins into equal outputs so nobody can tell which output is whose. A swap trades coin histories with a stranger, and on-chain it looks like two boring, unrelated payments. Fidelity bonds stop one person pretending to be many.

The analogy

CoinJoin: identical envelopes shaken in a box. Swaps: trading gift cards with a stranger.

Try it yourself

You leave with: A real CoinJoin dissected, a post-mix checklist, and an atomic swap on regtest.

  1. 1

    Autopsy a historical CoinJoin: count its anonymity set, then find the post-mix mistakes that un-mixed people's coins.

  2. 2

    Run openswap on regtest in pairs and complete a swap. Then try to prove a swap happened at all.

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    JoinMarket (a deep good-first-issue list) or openswap (a young repo where reviews really matter).

  2. 📜

    Debate: is using a mixer a moral act, a neutral act, or a red flag? Steelman all three.

  3. 🎯

    Proof of work: A JoinMarket beginner issue, or write tonight's openswap walkthrough as docs.

S10 Lightning privacy Lightning doesn't fix this Month 5

The idea in plain words

Lightning hides payment amounts from the chain, but it leaks elsewhere: channels are public coins, balances can be probed, invoices link identities, and your node's public key is a fingerprint. BOLT12 offers and blinded paths are the fixes in progress.

The analogy

A relay race where every runner sees who handed them the baton, unless the route is sealed.

Try it yourself

You leave with: A probed channel, a traced hop, and a blinded path that beat both.

  1. 1

    Spin up a 3-node regtest network with Polar.

  2. 2

    Pay a BOLT11 invoice and list what each hop learned. Then pay a BOLT12 offer with a blinded path and compare.

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    An LDK, ldk-node or Core Lightning PR about offers or blinded paths.

  2. 📜

    Debate: does layer 2 inherit layer 1's sins?

  3. 🎯

    Proof of work: An LDK or Core Lightning docs or test issue on offers or blinded paths.

S11 Ecash: Cashu and Fedimint Blind signatures, community custody Month 6

The idea in plain words

A mint knows it issued 1,000 sats and later redeemed 1,000 sats, but it can't tell they were the same person. That's blind signatures, invented by David Chaum. Cashu uses a single mint; Fedimint spreads trust across a federation of guardians. The trade: excellent privacy from the mint, in exchange for giving up self-custody.

The analogy

Signing a sealed envelope through carbon paper. Your signature is on what's inside, but you never saw it.

Try it yourself

You leave with: Ecash minted, sent and redeemed on a test mint, and a clear picture of the trade-off.

  1. 1

    Mint ecash on a test mint, send it in a chat message, and redeem it.

  2. 2

    Play the mint operator: what do your logs actually show?

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    A cdk or Fedimint PR touching privacy or the wallet.

  2. 📜

    David Chaum, "Security without Identification" (1985), the paper that started it.

  3. 🎯

    Proof of work: A cdk or Fedimint docs or test issue, or an ecash guide in your local language.

S12 Contribution sprint Ship it Month 6

The idea in plain words

The season ends with a sprint. We pick from a board of issues checked that morning, pair up and ship. Before anything goes upstream, someone else reviews it against the PR checklist, because maintainers' time is precious and our reputation is what opens doors for the next cohort.

The analogy

A barn raising: everyone builds at once, and what goes up is real.

Try it yourself

You leave with: Something real submitted upstream: code, a test report, or a review that passed the checklist.

  1. 1

    Pick an issue from the board (rust-payjoin, Floresta, Kyoto, BDK, peer-observer, JoinMarket, openswap, cdk), pair up and ship it live.

  2. 2

    Review someone else's draft against the PR checklist before it goes upstream.

In the session

Every session reads a real open PR and argues about a primary text.

  1. PR

    Each other's drafts, against the checklist.

  2. 📜

    Hughes' closing lines, read after the sprint: "Cypherpunks write code."

  3. 🎯

    Proof of work: Vote on Season Two topics. Strong contributors: ask about the Review Club and fellowships.

The 90 minutes

A hangout, not a lecture.

For privacy-minded, cypherpunk Bitcoiners. Test networks only, pseudonyms welcome, cameras optional. Every session has the same six beats.

10 min🩸 Cold open

A true surveillance story that sets the stakes.

15 min🕳 Rabbit hole

The concept in plain language, with one analogy.

30 min🛠 Hands-on

Everyone builds or runs it on their own machine.

20 min🔍 Review circle

Read a live PR together. What does it change? How would we test it?

10 min📜 Cypherpunk corner

Read a short primary text aloud, then argue about it.

5 min🎯 Proof of work

Claim one concrete next step: a lab, a test report, a doc fix.

Try it now

Labs you can run tonight.

The Python labs need only Python 3.8+, no installs, and work offline. Each one tells you exactly which step is wrong.

# get the labs
$ git clone https://github.com/code-orange-dev/curriculum
$ cd curriculum/privacy-track/labs/silent-payments
$ python3 run_vectors.py send

  ✓   1 Simple send: two inputs
  ✓   7 Single recipient: taproot only inputs with even y-values
  ✗   8 Single recipient: taproot only with mixed even/odd y-values
        Exercise 2: a_sum is wrong (did you negate odd-y taproot keys?)

21/28 vectors passing
Silent Payments ↗S1–S2A BIP352 sender and scanner, graded against the 28 official test vectors, plus a scanning benchmark
Chain analysis ↗S4The core heuristics (common inputs, change detection, clustering) on sample transactions
Coin selection ↗S5Four selection algorithms, scored on fees versus privacy
Payjoin ↗S6An async payjoin on regtest, then catch the common-input heuristic lying (needs Docker and Rust)
Compact block filters ↗S7A simplified BIP158 filter: Golomb-Rice coding, matching, false positives
Network privacy ↗S8BIP324 in Wireshark, private broadcast and ASmap peer diversity (needs Bitcoin Core 31 and Tor)

Beyond the sessions

From curious to contributor.

Enter at any rung, with no pressure to climb. People who keep coming back and ship proof of work get invited into the Privacy Review Club and the fellowship pathway.

  1. EngageBuild a repo, read the code, join its chat.
  2. TestBuild someone's PR, run it, report exactly what you saw.
  3. FixDocs, error messages, small clarity fixes.
  4. CoverAdd tests. Maintainers love them.
  5. ReviewExplain a PR, find an edge case.
  6. BuildFix a real bug and see it through review.
  7. LeadHost a session, mentor newcomers.

Before anything goes upstream it passes our PR checklist. The privacy world is small, and maintainers' trust is what opens doors.

Open source

Privacy isn't something you wait for. It's something you ship.

The whole track is on GitHub under CC0: every session, lab, reading list and the glossary. Fork it, translate it, run it in your city.