deviant/scripts/build_zeroconf_fud_html.py
walerikus 518a3ce174 chore: initial project baseline — full Deviant codebase under version control
Brings the whole project into git (previously only the on-ramp feature and
a few parallel files were tracked). Includes: wallet core (src/), CashScript
contracts/, the Capacitor shell (shells/), scripts/, tests, and the docs
corpus (wiki/, snapshots/, Parameters/, Archive/, KnowledgeBase text).

Excluded via .gitignore: node_modules/, dist/, .env (secrets), testnet WIF
key files (.chipnet-*.json, devWallets.ts), KnowledgeBase/RAW media (~9.6 GB),
transcripts/ (session logs), and machine-local config (.claude/*.local,
*.lock). Secret-scanned before commit — no credentials in the tree.

Note: src/swapMath.ts, src/swapBuilder.ts, contracts/OpenMintToken.cash are
legacy (OP_RETURN era) but still imported; committed as-is, flagged for a
separate removal once de-referenced.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-13 20:38:07 +02:00

155 lines
14 KiB
Python

#!/usr/bin/env python3
"""Build the SHORT corpus-styled HTML for the zero-conf / double-spend-FUD note,
reusing the Block Size Wars <head> (= Vol.13 stylesheet) so it matches the corpus.
Key ideas only — a companion note, not the full DRAFT (RAW/...DRAFT.md keeps the
long version). Re-runnable; refuses to clobber a hand-expanded destination.
"""
from pathlib import Path
ROOT = Path(__file__).resolve().parents[1]
SRC = ROOT / "KnowledgeBase/03_historical_and_political_economic/blocksize-war_FOR-sophisticated-readers-and-historical-analysts.html"
# SUPERSEDED (2026-06-09): this standalone note is now folded into the Block Size
# Wars document as the "0-conf · The double-spend FUD" section. The standalone
# build is retired to Archive/ to avoid two drifting copies; the canonical source
# of the long-form argument is RAW/zero-conf-and-the-double-spend-fud_DRAFT.md.
DST = ROOT.parent / "Archive/zero-conf-double-spend-fud_FOR-sophisticated-readers-and-security-analysts.html" # D:/Dev/Archive (outside the repo)
if DST.exists():
raise SystemExit(f"REFUSING TO OVERWRITE existing {DST.name} — delete deliberately to regenerate.")
lines = SRC.read_text(encoding="utf-8").split("\n")
head = "\n".join(lines[0:842]).replace( # up to and incl. </head>
"<title>DEVIANT · The Block Size Wars</title>",
"<title>DEVIANT · Zero-Conf and the Double-Spend FUD</title>",
)
body = r"""<body>
<div class="frame">
<header class="master">
<div class="deviant-brand">Deviant</div>
<div class="vol-label">Companion note · the block-size conflict</div>
<span class="vol-tag">0-conf</span>
<h1>Zero-Conf and the <span class="accent">Double-Spend FUD.</span></h1>
<div class="subtitle">The attack, the defense Satoshi already wrote, and the narrative that erased the difference.</div>
<div class="descriptive">How a real, conditional, already-mitigated 2012 result was stripped of its conditions and its remedy, then recited as a timeless verdict against the one chain that implemented the remedy.</div>
<div class="meta">
<span><strong>For:</strong> Sophisticated readers and security analysts</span>
<span><strong>Date:</strong> June 2026</span>
<span><strong>Status:</strong> Companion note (full version: RAW/zero-conf-and-the-double-spend-fud_DRAFT.md)</span>
</div>
</header>
<p class="lede">The claim "Bitcoin 0-confirmation is unsafe" is true of a <em>naive</em> merchant, false of a <em>defended</em> one, and the difference was described by Satoshi in 2010. The peer-reviewed paper everyone cites is honest within its scope and even proposes the defense. What fails verification is not the measurement — it is the generalization built on top of it. The suspicion was warranted; its correct object is the narrative, not the science.</p>
<div class="callout">
<div class="callout-label">The comparison the title hides &mdash; same attack, different node</div>
<p>The 2012 paper is titled for the <em>attack</em>, but its data is a <em>comparison</em>: double-spend success is a function of the merchant's connectivity and defense, not of "0-conf" as such. Restoring that framing:</p>
<table style="width:100%; max-width:740px; border-collapse:collapse; font-size:13px; line-height:1.45; margin:10px 0 6px; font-family:'JetBrains Mono', ui-monospace, monospace;">
<thead>
<tr style="text-align:left; border-bottom:2px solid rgba(0,0,0,.45);">
<th style="padding:7px 9px; font-weight:700;">Node posture</th>
<th style="padding:7px 9px; font-weight:700;">Attacker effort to win</th>
<th style="padding:7px 9px; font-weight:700;">Outcome</th>
<th style="padding:7px 9px; font-weight:700;">Source</th>
</tr>
</thead>
<tbody>
<tr style="border-bottom:1px solid rgba(0,0,0,.12);">
<td style="padding:7px 9px;">Naive &middot; low connectivity (&approx;8 peers) &middot; no listening</td>
<td style="padding:7px 9px;">1 relay</td>
<td style="padding:7px 9px;"><strong>Succeeds</strong> (&approx;100%)</td>
<td style="padding:7px 9px;">KAC &sect;4.4</td>
</tr>
<tr style="border-bottom:1px solid rgba(0,0,0,.12);">
<td style="padding:7px 9px;">Well-connected (&approx;125 peers) &middot; no listening</td>
<td style="padding:7px 9px;">1 relay &rarr; coin-flip; needs &ge;2 relays</td>
<td style="padding:7px 9px;">Harder; only with a relay fleet</td>
<td style="padding:7px 9px;">KAC &sect;4.4</td>
</tr>
<tr style="border-bottom:1px solid rgba(0,0,0,.12);">
<td style="padding:7px 9px;">Well-connected <strong>payment processor</strong> &middot; listening + observers</td>
<td style="padding:7px 9px;">&mdash;</td>
<td style="padding:7px 9px;"><strong>Detected &rarr; fails</strong> (normal case)</td>
<td style="padding:7px 9px;">Satoshi 2010; KAC &sect;5</td>
</tr>
<tr>
<td style="padding:7px 9px;">BCH vendor with <strong>DSProof</strong> &middot; listening automated for all</td>
<td style="padding:7px 9px;">&mdash;</td>
<td style="padding:7px 9px;"><strong>Detected &rarr; fails</strong> (normal case)</td>
<td style="padding:7px 9px;">DSProof</td>
</tr>
</tbody>
</table>
<p style="margin-top:8px;">The deciding variable is <strong>connectivity + active listening</strong>, not "0-conf." Residual across the defended rows: a Sybil/eclipse attacker &mdash; a far higher bar, never "impossible." Read this way, the paper says what it measured: <em>naive merchants lose; listening ones win.</em></p>
</div>
<section>
<div class="section-head"><div class="section-num">I</div><h2>The attack and its defense were both Satoshi's, in 2010.</h2></div>
<p>Two years before the 2012 paper, in the <em>"Bitcoin snack machine"</em> thread, Satoshi described the race and its answer: a payment processor connected to many nodes that broadcasts a transaction and simultaneously listens for a conflicting one.</p>
<div class="primary-quote">
The payment processor has connections with many nodes. When it gets a transaction, it blasts it out, and at the same time monitors the network for double-spends&hellip; A double-spent transaction wouldn't get very far without one of the listeners hearing it.
<span class="attribution">&mdash; Satoshi Nakamoto, 17 Jul 2010</span>
</div>
<p>The structure is a trap for the attacker: to win the mining race he must propagate the double-spend <em>widely</em> &mdash; which is exactly what many listeners <em>hear</em>. He cannot both flood it (to win) and hide it (to evade). Satoshi also fixed the ceiling, in his own words, and it must be quoted unsoftened: when challenged that this was &ldquo;still not impermeable,&rdquo; he replied <strong>&ldquo;I didn't say impermeable, I said good-enough. The loss in practice would be far lower than with credit cards.&rdquo;</strong> Risk-reduction, not impossibility.</p>
</section>
<section>
<div class="section-head"><div class="section-num">II</div><h2>Why "first-seen" doesn't, by itself, save a naive vendor.</h2></div>
<p>First-seen is <em>local to each node</em> &mdash; there is no global &ldquo;first.&rdquo; The attacker engineers a split-brain: send the payment only to the vendor (whose mempool now holds it and who releases goods) while flooding the conflicting transaction to the <em>miners</em>, who hold it first and confirm it. Both sides obey first-seen; their &ldquo;firsts&rdquo; simply disagree, and <strong>the miner, not the vendor, breaks the tie.</strong> At block level only one of the two ever confirms &mdash; the fraud is entirely off-ledger; the merchant is left holding the losing transaction. The chain never double-spends.</p>
</section>
<section>
<div class="section-head"><div class="section-num">III</div><h2>The 2012 paper: honest within scope; the fix is BCH's DSProof.</h2></div>
<p>Karame&ndash;Androulaki&ndash;Capkun (CCS 2012) ran ~500 real attempts against their <em>own, undefended</em> vendor nodes and measured 90&ndash;100% success. That result is real &mdash; and so is its conditional conclusion: <em>&ldquo;unless effective detection techniques are integrated&hellip; vendors should not accept fast payments.&rdquo;</em> Its &sect;5 proposes the detection: a listening period and observers. <strong>That is Satoshi's 2010 defense, restated.</strong> Bitcoin Cash's <em>double-spend proof</em> (DSProof) is the same defense automated at the protocol layer: any node seeing two conflicting transactions floods a cryptographic alert, so every vendor is warned without running a processor. One idea, three stages &mdash; Satoshi (2010) &rarr; KAC (2012) &rarr; DSProof.</p>
<div class="callout">
<div class="callout-label">The attacker's real requirement</div>
<p>Not a full node. But not a one-line script either: KAC's own data shows reliability scales with a <em>coordinated relay fleet</em> (1 helper &approx; coin-flip against a well-connected vendor; 2 helpers &approx; guaranteed). The attack is capability-gated, and a listening vendor / DSProof defeats the basic form in the normal case. The genuine residual is a Sybil/eclipse attacker &mdash; a far higher bar, never &ldquo;impossible.&rdquo;</p>
</div>
</section>
<section>
<div class="section-head"><div class="section-num">IV</div><h2>RBF is the trivial attack &mdash; and it is BTC-only.</h2></div>
<p>The famous real-world 0-conf theft &mdash; Peter Todd against Coinbase, 2016, first try &mdash; was <em>not</em> the 2012 race. It used <strong>Replace-By-Fee</strong>: send a low-fee payment, then replace it with a higher-fee one to yourself. No topology, no race &mdash; just bump the fee. RBF is a 2016 BTC protocol feature that <strong>Bitcoin Cash explicitly rejected.</strong> So the dramatic, repeatable real-world fraud is RBF-based, on a chain BCH is not. Pointing at it to indict BCH 0-conf is RBF fraud cited against a chain without RBF.</p>
</section>
<section>
<div class="section-head"><div class="section-num">V</div><h2>The settlement model, and the word that must not be rounded up.</h2></div>
<p>0-conf / no hashpower &rarr; defeated in practice (first-seen, no RBF, DSProof) &mdash; <em>good-enough</em>. Confirmed / no hashpower &rarr; defeated. Confirmed / majority hashpower (a reorg) &rarr; <strong>irrational at scale, economically gated, priced &mdash; not impossible</strong> (Satoshi's own &sect;6/&sect;11 conditional; it has happened on cheap-hashpower chains, never on BTC). BCH's gate is real but <em>lower than BTC's</em> &mdash; it shares SHA-256 and runs at a fraction of BTC's hashrate, so the fleet that defends it could attack it; historically it has defended, because its major holders are aligned stakeholders. Security is the <strong>economic gate, not miner loyalty</strong>. Design rule: <strong>scale confirmations to value.</strong></p>
<div class="callout warn">
<div class="callout-label">The BCH May-2019 reorg was not a double-spend</div>
<p>It was two incumbent pools <em>coordinating</em> to reverse an opportunist's grab of anyone-can-spend SegWit-recovery coins &mdash; capability used defensively, not a profit double-spend and not an external 51% capture. It proves the capability exists; it is not an example of the attack.</p>
</div>
</section>
<section>
<div class="section-head"><div class="section-num">VI</div><h2>The FUD, stated precisely.</h2></div>
<p>In one line, needing no claim of intent: <strong>sound analysis, a one-sided title, and a predictable impression effect on a public that reads titles, not papers.</strong> Each of the three is independently checkable &mdash; read the title, read &sect;4&ndash;5, look at how it is cited. Intent is the one thing that cannot be proven and the one thing the case does not need.</p>
<p>Assembled, the disqualification of &ldquo;Bitcoin as cash&rdquo; reads as context-stripping, not fabrication: (1) a <em>conditional</em> result is flattened into a <em>categorical</em> one; (2) the paper's own remedy and its 2010 Satoshi provenance are dropped; (3) the trivial <em>RBF</em> attack is merged with the hard <em>race</em> attack and aimed at the chain that rejected RBF; (4) RBF's adoption then ends 0-conf on BTC, making &ldquo;Bitcoin isn't for payments&rdquo; self-fulfilling on the chain that adopted it &mdash; while the chain that kept first-seen and added DSProof is told its payments are unsafe using the other chain's evidence.</p>
<div class="pullquote rust">
The corpus does not call any paper fraudulent. It restores the conditions, the remedy, and the chain distinction that were removed &mdash; and the verdict collapses on its own. These narratives do not survive in a neutral information environment; they propagate in a captured one. This case is a checkable specimen of that mechanism: every erased caveat sits in the primary sources. Verify, don't trust.
</div>
</section>
<section>
<div class="section-head"><div class="section-num">Sources</div><h2>Primary sources.</h2></div>
<ul style="font-size:14.5px; line-height:1.7; margin:12px 0 22px 24px; max-width:760px;">
<li>Satoshi Nakamoto, <em>&ldquo;Bitcoin snack machine (fast transaction problem),&rdquo;</em> bitcointalk, 17 Jul 2010 22:29:13 UTC &mdash; <strong>verified verbatim</strong>: satoshi.nakamotoinstitute.org/posts/bitcointalk/233/</li>
<li>Karame, Androulaki, Capkun, <em>Double-spending fast payments in Bitcoin,</em> ACM CCS 2012 (&sect;4.4 experiments, &sect;5 countermeasures). Extended: <em>Misbehavior in Bitcoin,</em> ACM TISSEC 2015.</li>
<li>Peter Todd double-spends Coinbase via RBF (2016); Cointelegraph, <em>&ldquo;Real Bitcoin Double Spends Are Hard.&rdquo;</em></li>
<li>BCH 2019 reorg: Bravenewcoin (<em>reorg or 51%?</em>), read.cash (<em>The year 2019 in Bitcoin Cash</em>), 2019-05-15 upgrade spec.</li>
<li>Internal: empirical chipnet test (<code>scripts/chipnet-doublespend-test.mjs</code>), <code>wiki/onchain-game-settlement-threat-model.md</code>, snapshot 0135.</li>
</ul>
</section>
<footer>
<div>Companion note &middot; Zero-Conf and the Double-Spend FUD &middot; June 2026</div>
<div class="note">The whitepaper is short. The forum posts are archived. The chains are observable. The comparison is direct. Nothing here depends on trust.</div>
</footer>
</div>
</body>
</html>"""
DST.write_text(head + "\n" + body, encoding="utf-8")
print(f"wrote {DST.relative_to(ROOT)} ({len((head + body)):,} chars, {(head + body).count(chr(10)) + 1} lines)")