/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.
Every 1st & 3rd Tuesday, 07:00 UTC. Add to Google Calendar
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 ✓
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.
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.
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.
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
Build the sender: 5 small functions in send.py, graded against the official vectors. Race to 28/28.
- 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.
- 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?
- 📜
BIP352 "Motivation": does Silent Payments make the reuse problem go away, or just move it somewhere else?
- 🎯
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
Build the scanner in receive.py. The grader catches the two classic bugs.
- 2
Run
scan_benchmark.pyand 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.
- PR
bitcoin-core/secp256k1#1912: a light-client API for Silent Payments. Which of the three scanning models is it for?
- 📜
Satoshi's whitepaper, section 10 "Privacy": "keeping public keys anonymous." How far did we drift?
- 🎯
Proof of work: Run BlindBit Oracle on signet and write up the setup, or pick a still-open
good first issuein 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
Before the session: build Bitcoin Core and run
test_bitcoin --run_test=bip352_tests. - 2
Map your
send.pyontosrc/common/bip352.cpp. Where doa_sum,input_hashandt_klive?
In the session
Every session reads a real open PR and argues about a primary text.
- PR
- 📜
Why did Silent Payments in Core take three years? What does the order of the work tell you about how Core handles cryptography?
- 🎯
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
Run the chain-analysis lab: implement the heuristics on sample transactions.
- 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.
- PR
A transaction-building PR in BDK or rust-bitcoin: does it change what a transaction looks like on-chain?
- 📜
Eric Hughes, A Cypherpunk's Manifesto (1993): "Privacy is the power to selectively reveal oneself to the world."
- 🎯
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
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
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.
- PR
BDK coin-selection PRs. A small merged fix like bdk_wallet#471 shows contributions like this are within reach.
- 📜
Hal Finney on what privacy people should be able to expect.
- 🎯
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
Do a payjoin in pairs on regtest with the payjoin lab: one sends, one receives, then swap.
- 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.
- PR
Review one open rust-payjoin PR together.
- 📜
Adam Back: privacy has to be default and boring to win.
- 🎯
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
Build and run Floresta and connect a wallet to your own node. First to sync wins sats.
- 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.
- PR
A Floresta or Kyoto PR. Floresta has welcoming maintainers and a real good-first-issue culture.
- 📜
"Don't trust, verify": what does it actually ask of us?
- 🎯
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
Wiretap yourself with the network lab: compare plaintext and BIP324 traffic in Wireshark.
- 2
Turn on
-privatebroadcast, send a signet transaction and watchgetprivatebroadcastinfo. Then compare peer diversity with-asmap=1.
In the session
Every session reads a real open PR and argues about a primary text.
- PR
A peer-observer PR, or a private-broadcast follow-up in Core such as #34533.
- 📜
Timothy May, The Crypto Anarchist Manifesto (1988). Is the network layer Bitcoin's soft underbelly?
- 🎯
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
Autopsy a historical CoinJoin: count its anonymity set, then find the post-mix mistakes that un-mixed people's coins.
- 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.
- PR
JoinMarket (a deep good-first-issue list) or openswap (a young repo where reviews really matter).
- 📜
Debate: is using a mixer a moral act, a neutral act, or a red flag? Steelman all three.
- 🎯
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
Spin up a 3-node regtest network with Polar.
- 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.
- PR
An LDK, ldk-node or Core Lightning PR about offers or blinded paths.
- 📜
Debate: does layer 2 inherit layer 1's sins?
- 🎯
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
Mint ecash on a test mint, send it in a chat message, and redeem it.
- 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.
- PR
- 📜
David Chaum, "Security without Identification" (1985), the paper that started it.
- 🎯
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
Pick an issue from the board (rust-payjoin, Floresta, Kyoto, BDK, peer-observer, JoinMarket, openswap, cdk), pair up and ship it live.
- 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.
- PR
Each other's drafts, against the checklist.
- 📜
Hughes' closing lines, read after the sprint: "Cypherpunks write code."
- 🎯
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.
A true surveillance story that sets the stakes.
The concept in plain language, with one analogy.
Everyone builds or runs it on their own machine.
Read a live PR together. What does it change? How would we test it?
Read a short primary text aloud, then argue about it.
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–S2 | A BIP352 sender and scanner, graded against the 28 official test vectors, plus a scanning benchmark |
| Chain analysis ↗ | S4 | The core heuristics (common inputs, change detection, clustering) on sample transactions |
| Coin selection ↗ | S5 | Four selection algorithms, scored on fees versus privacy |
| Payjoin ↗ | S6 | An async payjoin on regtest, then catch the common-input heuristic lying (needs Docker and Rust) |
| Compact block filters ↗ | S7 | A simplified BIP158 filter: Golomb-Rice coding, matching, false positives |
| Network privacy ↗ | S8 | BIP324 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.
- EngageBuild a repo, read the code, join its chat.
- TestBuild someone's PR, run it, report exactly what you saw.
- FixDocs, error messages, small clarity fixes.
- CoverAdd tests. Maintainers love them.
- ReviewExplain a PR, find an edge case.
- BuildFix a real bug and see it through review.
- 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.