<?xml version="1.0" encoding="utf-8" standalone="yes"?><rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom">
    <channel>
        <title>Ethereum on Infinite Cyber Sec</title>
        <link>https://infinisec.io/tags/ethereum/</link>
        <description>Recent content in Ethereum on Infinite Cyber Sec</description>
        <generator>Hugo -- gohugo.io</generator>
        <language>en-us</language>
        <lastBuildDate>Thu, 25 Jun 2026 12:00:00 +0200</lastBuildDate><atom:link href="https://infinisec.io/tags/ethereum/index.xml" rel="self" type="application/rss+xml" /><item>
            <title>Chasing 3 ETH Into a Dead Testnet: Anatomy of an Unsolvable Bounty</title>
            <link>https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/</link>
            <pubDate>Thu, 25 Jun 2026 12:00:00 +0200</pubDate>
            <guid>https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/</guid>
            <description>&lt;img src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-2160-wall.png&#34; alt=&#34;Featured image of post Chasing 3 ETH Into a Dead Testnet: Anatomy of an Unsolvable Bounty&#34; /&gt;&lt;p align=&#34;center&#34;&gt;&lt;img src=&#34;teikhos-logo.png&#34; alt=&#34;TEIKHOS — proof-of-public-key bounty investigation&#34; width=&#34;760&#34;&gt;&lt;/p&gt;&#xA;&lt;h2 id=&#34;tldr&#34;&gt;TL;DR&#xA;&lt;/h2&gt;&lt;p&gt;In 2018 a developer named &lt;strong&gt;Johan Nygren&lt;/strong&gt; deployed a set of &amp;ldquo;proof-of-public-key&amp;rdquo; bounty contracts on Ethereum mainnet and funded them with real ETH. Submit the right public key and the contract pays you. Eight years later, three of them are still holding ~2 ETH, plus a fourth holding 1 ETH that is bricked.&lt;/p&gt;&#xA;&lt;p&gt;I spent a long time trying to claim them. The result is &lt;strong&gt;not&lt;/strong&gt; a key — it&amp;rsquo;s a proof, from about fifteen independent directions, that &lt;strong&gt;there is no findable key&lt;/strong&gt;. But the interesting part isn&amp;rsquo;t the verdict; it&amp;rsquo;s the hunt: resurrecting two decommissioned testnets, a Shodan banner-search that found a node the rest of the internet forgot, a full sweep of every place this man ever published code, and the on-chain forensics tying it all together. This post is that methodology, start to finish.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;four-contracts-3-eth-one-dead-end&#34;&gt;Four contracts, ~3 ETH, one dead end&#xA;&lt;/h2&gt;&lt;p&gt;Everything traces back to one deployer, &lt;code&gt;0x4c5D24A7&lt;/code&gt; (&amp;ldquo;bipedaljoe&amp;rdquo;), who created 18 contracts in a 16-day burst in early 2018 and then went silent. Four are the prizes:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Bounty&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Address&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Value&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Why it&amp;rsquo;s unrecoverable&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;A&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;0x17e5e091…&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;1.0 ETH&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;256-bit random key, never published&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;B&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;0xd7c6d542…&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.5 ETH&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;same, two-layer &amp;ldquo;symmetric&amp;rdquo; variant&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;C&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;0x973c2178…&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0.5 ETH&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;same, hash + commit-reveal (plus a real flaw — see below)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;bricked&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;0xaec7e8c2…&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;1.0 ETH&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;key is &lt;strong&gt;known&lt;/strong&gt;, but the contract has no payout opcode — pays nobody, ever&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;Bounty C today, still holding 0.5 ETH under a long tail of failed &lt;code&gt;authenticate()&lt;/code&gt; attempts:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Bounty C on Etherscan — 0.5 ETH, dozens of failed authenticate() calls&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;394px&#34; data-flex-grow=&#34;164&#34; height=&#34;900&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-etherscan-C.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-etherscan-C_hu_f46b75de74d1f71a.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-etherscan-C.png 1480w&#34; width=&#34;1480&#34;&gt;&#xA;&lt;em&gt;Bounty C (&lt;code&gt;0x973c2178&lt;/code&gt;) on Etherscan — funded, dormant, every solve attempt reverted.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;The fourth one is the saddest. Its key is actually known and verified on-chain — but the contract was compiled without a &lt;code&gt;CALLER&lt;/code&gt; opcode in its payout path, so even the correct solver gets nothing. One ETH, frozen by a typo.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;how-the-lock-works&#34;&gt;How the lock works&#xA;&lt;/h2&gt;&lt;p&gt;To claim, you submit the 64-byte public key &lt;code&gt;P&lt;/code&gt;. The contract stores a hardcoded &lt;code&gt;proof&lt;/code&gt;, and the proof is the key&amp;rsquo;s &lt;strong&gt;own signature, XORed with the key itself&lt;/strong&gt;:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;proof = signature(P) ⊕ mask(P)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;claim iff  ecrecover( keccak256(&amp;#34;\x19Ethereum Signed Message:\n64&amp;#34; ‖ P), v, proof ⊕ mask(P) ) == address(keccak256(P))&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;&lt;code&gt;P&lt;/code&gt; appears on &lt;em&gt;both&lt;/em&gt; sides — it is its own fixed point, &lt;code&gt;P = f(P)&lt;/code&gt;: the public key you must submit is folded into the very signature it has to produce.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;The proof is a one-time pad whose solution is a self-referential fixed point&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;415px&#34; data-flex-grow=&#34;173&#34; height=&#34;1040&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-xor-fixedpoint.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-xor-fixedpoint_hu_11698fb9894903f3.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-xor-fixedpoint_hu_7fc6e11b890f3bd9.png 1600w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-xor-fixedpoint.png 1800w&#34; width=&#34;1800&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Forward (knowing &lt;code&gt;P&lt;/code&gt;): trivial — sign, XOR, submit. Backward (knowing only the proof): no shortcut. XOR lives in a different algebra (GF(2)²⁵⁶) than the elliptic curve, so it never lifts into anything solvable. The cheapest real attack is a brute-force search for any &lt;code&gt;P&lt;/code&gt; that hashes to the same address: &lt;strong&gt;2¹⁶⁰ work&lt;/strong&gt; — ~4.6 × 10¹⁹ years with the entire Bitcoin network&amp;rsquo;s hashpower.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;The 2^160 wall and the three things that build it&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;415px&#34; data-flex-grow=&#34;173&#34; height=&#34;1040&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-2160-wall.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-2160-wall_hu_460b017213c615f1.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-2160-wall_hu_5a741df2af5e5199.png 1600w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-2160-wall.png 1800w&#34; width=&#34;1800&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;And you can&amp;rsquo;t reverse it, either. The message hash &lt;code&gt;e = keccak256(prefix ‖ P)&lt;/code&gt; sits &lt;em&gt;inside&lt;/em&gt; the equation and depends on &lt;code&gt;P&lt;/code&gt;, so every guess moves the target — the equation chases its own tail. That kills BSGS/meet-in-the-middle (no independent split), Pollard&amp;rsquo;s rho (no single iterated map), and Gröbner/algebraic inversion (that&amp;rsquo;s just keccak preimage resistance by another name). There is no fifth door.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Every road to reconstructing the key is a wall&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;349px&#34; data-flex-grow=&#34;145&#34; height=&#34;1320&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-reconstruction-wall.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-reconstruction-wall_hu_41bdfd96274ade6f.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-reconstruction-wall_hu_60f27382ab622be5.png 1600w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-reconstruction-wall.png 1920w&#34; width=&#34;1920&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;So if the math is a wall, the only physically possible path is a &lt;strong&gt;leak&lt;/strong&gt; — the key sitting in some log, repo, transaction, or post the author forgot about. The rest of this is the hunt for that leak.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;reading-two-dead-testnets&#34;&gt;Reading two dead testnets&#xA;&lt;/h2&gt;&lt;p&gt;The strongest lead: maybe Johan &lt;em&gt;tested&lt;/em&gt; the bounties on a testnet in 2018 and left a key in the calldata. That meant reading &lt;strong&gt;Ropsten&lt;/strong&gt; and &lt;strong&gt;Rinkeby&lt;/strong&gt; — both long decommissioned, with their public RPCs shut down in 2023.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Ropsten — self-hosted archive node.&lt;/strong&gt; I stood up an &lt;strong&gt;Erigon archive node&lt;/strong&gt; on my own server to get complete Ropsten history. Erigon&amp;rsquo;s snapshots ship as &lt;strong&gt;pure BitTorrent&lt;/strong&gt; (DHT + public trackers, no webseed), so this was a genuine sync — pulling and indexing segments, forcing early-segment availability. Once queryable, I scanned &lt;strong&gt;~9.3 million blocks&lt;/strong&gt; for all of Johan&amp;rsquo;s known addresses and pulled &lt;strong&gt;220 &lt;code&gt;authenticate&lt;/code&gt; calls&lt;/strong&gt; to test against the engine. &lt;strong&gt;Zero hits.&lt;/strong&gt; Ropsten: dead end, definitively.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Rinkeby — the hard one.&lt;/strong&gt; Rinkeby is &lt;strong&gt;Clique proof-of-authority&lt;/strong&gt;, which is &lt;em&gt;excluded&lt;/em&gt; from every snapshot/era1/torrent system — so a local sync had nothing to sync &lt;em&gt;from&lt;/em&gt;. Before the breakthrough, I exhausted the entire registered world looking for any surviving endpoint:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;~80 RPC endpoints&lt;/strong&gt; across every historical provider (Infura, Alchemy, Ankr, Cloudflare gateway, and ~70 more) — all dead.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Source-code search for hardcoded live RPCs&lt;/strong&gt; across &lt;strong&gt;GitHub&lt;/strong&gt; (~60 endpoints in old configs/&lt;code&gt;.env&lt;/code&gt; files, all dead), &lt;strong&gt;GitLab&lt;/strong&gt; (free-tier global code search disabled — 403), and &lt;strong&gt;Bitbucket&lt;/strong&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Data indexers&lt;/strong&gt; — Covalent/GoldRush and Bitquery (confirmed they&amp;rsquo;d dropped Rinkeby), Crystal Intelligence (mainnet-only), and &lt;strong&gt;Google BigQuery&lt;/strong&gt; across 11 EVM chains (which is what flagged one address, &lt;code&gt;0x2513CF99&lt;/code&gt;, as Rinkeby-only — the thread that justified the whole hunt).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Censys&lt;/strong&gt; — free tier blocks the search API entirely.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Every registered path was dead. Which forced the reframe that finally worked.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;the-shodan-reframe--finding-a-node-nobody-remembers&#34;&gt;The Shodan reframe — finding a node nobody remembers&#xA;&lt;/h2&gt;&lt;p&gt;Stop asking &lt;em&gt;&amp;ldquo;who still serves Rinkeby?&amp;rdquo;&lt;/em&gt; and ask &lt;em&gt;&amp;ldquo;who accidentally left a Rinkeby node exposed and running?&amp;rdquo;&lt;/em&gt; &lt;strong&gt;Shodan&lt;/strong&gt; indexes the JSON-RPC banner of every exposed &lt;code&gt;:8545&lt;/code&gt; host on the internet — including its &lt;code&gt;eth_chainId&lt;/code&gt; response. So:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;shodan search:  &amp;#34;Chain Id: 0x4&amp;#34;   →   a single exact match (host redacted)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;I then probed &lt;strong&gt;3,979&lt;/strong&gt; candidate Geth/&lt;code&gt;:8545&lt;/code&gt; hosts Shodan knew of to confirm that match was unique for &lt;code&gt;eth_chainId == 0x4&lt;/code&gt;. It was. And it was real:&lt;/p&gt;&#xA;&lt;div class=&#34;highlight&#34;&gt;&lt;div class=&#34;chroma&#34;&gt;&#xA;&lt;table class=&#34;lntable&#34;&gt;&lt;tr&gt;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code&gt;&lt;span class=&#34;lnt&#34;&gt;1&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;2&#xA;&lt;/span&gt;&lt;span class=&#34;lnt&#34;&gt;3&#xA;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&#xA;&lt;td class=&#34;lntd&#34;&gt;&#xA;&lt;pre tabindex=&#34;0&#34; class=&#34;chroma&#34;&gt;&lt;code class=&#34;language-fallback&#34; data-lang=&#34;fallback&#34;&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;chainId 0x4 · net_version 4 · Geth/v1.8.27-stable&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;genesis extraData → &amp;#34;Respect my authoritah ~E.Cartman&amp;#34;   (the iconic Rinkeby genesis)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;span class=&#34;line&#34;&gt;&lt;span class=&#34;cl&#34;&gt;block bodies: genesis → 5,435,344   (covers all of 2018)&#xA;&lt;/span&gt;&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;&lt;/td&gt;&lt;/tr&gt;&lt;/table&gt;&#xA;&lt;/div&gt;&#xA;&lt;/div&gt;&lt;p&gt;A live, queryable Rinkeby archive node on &lt;strong&gt;no provider list anywhere&lt;/strong&gt; — a relic someone forgot to switch off. This was the genuine technical achievement of the project, and the method generalizes: &lt;em&gt;to read a dead chain, don&amp;rsquo;t look for infrastructure that preserved it — look for a node that never stopped.&lt;/em&gt; (I redact the host here so this writeup doesn&amp;rsquo;t point at a stranger&amp;rsquo;s misconfigured box.)&lt;/p&gt;&#xA;&lt;p&gt;Here is the actual Shodan record for that host — the &lt;code&gt;:8545&lt;/code&gt; service banner advertising &lt;code&gt;Geth v1.8.27&lt;/code&gt; and, decisively, &lt;code&gt;Chain Id: 0x4&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;The live Shodan host record — port 8545, Geth v1.8.27, Chain Id 0x4 (Rinkeby). IP and SSH key redacted.&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;260px&#34; data-flex-grow=&#34;108&#34; height=&#34;920&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-shodan.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-shodan_hu_fdee73696749fbfc.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-shodan.png 1000w&#34; width=&#34;1000&#34;&gt;&#xA;&lt;em&gt;Shodan&amp;rsquo;s banner for the exposed node — &lt;code&gt;Geth/v1.8.27-stable&lt;/code&gt;, &lt;code&gt;Chain Id: 0x4&lt;/code&gt;. The IP and SSH key are redacted here.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;OSINT method: a Shodan banner search resurrects a forgotten archive node&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;443px&#34; data-flex-grow=&#34;184&#34; height=&#34;1040&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-osint-shodan.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-osint-shodan_hu_698a2c1f52a0fa53.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-osint-shodan_hu_7aed2f476d569b7a.png 1600w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-osint-shodan.png 1920w&#34; width=&#34;1920&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;The scanner.&lt;/strong&gt; The node had no tx index, no &lt;code&gt;debug&lt;/code&gt;/&lt;code&gt;trace&lt;/code&gt;, and only head state — but full block bodies, which is all you need to read historical calldata. So I wrote &lt;code&gt;rinkeby_scan.py&lt;/code&gt;:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Parallel batched JSON-RPC&lt;/strong&gt; (&lt;code&gt;eth_getBlockByNumber&lt;/code&gt; with full transactions), resumable per-range checkpoints, and a recovery loop that waits out node blips instead of dying (it was a single fragile box).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Two detectors per transaction:&lt;/strong&gt; the &lt;code&gt;authenticate&lt;/code&gt; selector &lt;code&gt;0xee0d605c&lt;/code&gt; (extract the 64-byte public key → live-test against A/B/C), and any &lt;strong&gt;mainnet proof value&lt;/strong&gt; showing up in calldata (a &amp;ldquo;twin-hunt&amp;rdquo; for a Rinkeby copy of A/B/C).&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;A bug I caught:&lt;/strong&gt; the first extractor read the ABI &lt;em&gt;offset/length&lt;/em&gt; words instead of the key bytes (&lt;code&gt;bytes&lt;/code&gt; args are &lt;code&gt;selector‖offset‖length‖data&lt;/code&gt;) — fixed and re-ran every hit.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;I scanned the full 2018 window and then the whole chain. &lt;strong&gt;0 mainnet twins, 0 solving public keys.&lt;/strong&gt;&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;The red herring.&lt;/strong&gt; What the scan &lt;em&gt;did&lt;/em&gt; surface was a cluster of real TeikhosBounty activity — resolved by CREATE-address arithmetic: a hobbyist (&lt;code&gt;0x6daa5ca5…&lt;/code&gt;) had deployed &lt;strong&gt;34 of the 41&lt;/strong&gt; testnet bounty contracts and self-claimed a dozen (one with an off-curve junk &amp;ldquo;key&amp;rdquo;). And &lt;code&gt;0x2513CF99&lt;/code&gt; — the address that sent me to Rinkeby in the first place — is exactly &lt;code&gt;CREATE(0x6daa5ca5, nonce 85)&lt;/code&gt;: that hobbyist&amp;rsquo;s Rinkeby SHA3-512 helper, confirmed by bounty C&amp;rsquo;s own source comments. Johan&amp;rsquo;s mainnet deployer had &lt;strong&gt;never transacted on Rinkeby&lt;/strong&gt; (nonce 0). The node was a triumph; the lead was a ghost.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;the-bulk-census--bigquery-etherscan-and-the-deployment-map&#34;&gt;The bulk census — BigQuery, Etherscan, and the deployment map&#xA;&lt;/h2&gt;&lt;p&gt;Two tools did the heavy on-chain forensics without running a full mainnet node:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Etherscan&lt;/strong&gt; gave verified source for all 18 deployed contracts, their ABIs, the internal-transaction graph, and the deployer cluster (&lt;code&gt;0x4c5d24a7&lt;/code&gt; / &lt;code&gt;0x125d657d&lt;/code&gt; / &lt;code&gt;0x4f6816a7&lt;/code&gt; / &lt;code&gt;0x80028f80&lt;/code&gt;). It also confirmed the bricked contract on a live transaction.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Google BigQuery&lt;/strong&gt; (&lt;code&gt;bigquery-public-data.crypto_ethereum&lt;/code&gt;, via Application Default Credentials) ran the census: every contract the deployer ever touched, transaction counts, the full deployment timeline, and the one solver transaction at block &lt;strong&gt;14,513,678&lt;/strong&gt;. For census questions this is faster and more reliable than a node. The same approach, run across six chains (ETH/ETC/BTC/LTC/DOGE/BCH), covered the cross-chain angle.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;That census draws the whole operation. The only contracts Johan ever solved himself are the &lt;strong&gt;tutorials&lt;/strong&gt;; the four he never touched again are exactly A, B, C, and the bricked one:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;On-chain deployment map: tutorials he answered, vaults he never did&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;415px&#34; data-flex-grow=&#34;173&#34; height=&#34;1040&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-deployment-map.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-deployment-map_hu_cffa181be926cf90.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-deployment-map_hu_95933d9d40a4dc65.png 1600w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-deployment-map.png 1800w&#34; width=&#34;1800&#34;&gt;&#xA;&lt;em&gt;All 18 contracts from one deployer in 16 days — the tutorials he answered himself, the vaults he never did, and the silent twins.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;the-source-hunt--finding-the-original-code-he-wrote&#34;&gt;The source hunt — finding the original code he wrote&#xA;&lt;/h2&gt;&lt;p&gt;If the key ever leaked, the likeliest place was the author&amp;rsquo;s own published code. So I swept every host he ever used, in full git history.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;GitHub&lt;/strong&gt; (&lt;code&gt;resilience-me&lt;/code&gt;): 51 repos and &lt;strong&gt;139 gists&lt;/strong&gt;, back to 2014. Crucially, the keygen source was found &lt;strong&gt;only via gist enumeration&lt;/strong&gt; (&lt;code&gt;api.github.com/users/&amp;lt;handle&amp;gt;/gists&lt;/code&gt;), not in any repo: &lt;strong&gt;&lt;code&gt;g_6.sol&lt;/code&gt;&lt;/strong&gt; — a fully-worked C-type demo that publishes the public key, message hash, &lt;em&gt;signature&lt;/em&gt;, proof, and address (I verified it end-to-end against the engine) — and &lt;strong&gt;&lt;code&gt;all_30.txt&lt;/code&gt;&lt;/strong&gt;, the actual key-generation script.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Dependency-date pinning:&lt;/strong&gt; &lt;code&gt;all_30.txt&lt;/code&gt; uses &lt;code&gt;eth-crypto@0.2.0&lt;/code&gt; → &lt;code&gt;eth-lib@0.2.7&lt;/code&gt;. Fetching that exact version from unpkg pinned the keygen precisely: &lt;code&gt;Account.create()&lt;/code&gt; = &lt;code&gt;keccak256&lt;/code&gt; of four &lt;code&gt;crypto.randomBytes(32)&lt;/code&gt; draws — a 256-bit OpenSSL CSPRNG key with RFC-6979 nonces. The author&amp;rsquo;s own generator rules out a weak seed.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;GitLab&lt;/strong&gt; (&lt;code&gt;bipedaljoe&lt;/code&gt;): 33 repos, mirrors and experiments — no extra deployments.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Bitbucket&lt;/strong&gt; (&lt;code&gt;bipedaljoe&lt;/code&gt;): 14 repos visible via the API; the web profile 404s; the &lt;code&gt;teikhos&lt;/code&gt; and &lt;code&gt;bitpeople&lt;/code&gt; workspaces had been &lt;strong&gt;deleted&lt;/strong&gt;.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;&lt;code&gt;priv.prv&lt;/code&gt;&lt;/strong&gt; — a tantalizing filename — traces to his &lt;code&gt;Vanityreum&lt;/code&gt; repo: it&amp;rsquo;s the &lt;code&gt;.gitignore&lt;/code&gt;&amp;rsquo;d &lt;em&gt;output&lt;/em&gt; of a vanity-address generator built on &lt;code&gt;os.urandom&lt;/code&gt;, never committed. No key file exists on any disk, repo, or leak.&lt;/li&gt;&#xA;&lt;li&gt;&lt;strong&gt;Archive recovery:&lt;/strong&gt; &lt;strong&gt;Software Heritage&lt;/strong&gt; had preserved &lt;strong&gt;40 &lt;code&gt;resilience-me&lt;/code&gt; origins&lt;/strong&gt; — enough to confirm the keygen and contract provenance independent of live GitHub, ruling out post-hoc edits. The &lt;strong&gt;Wayback Machine&lt;/strong&gt; held &lt;strong&gt;0 captures&lt;/strong&gt; of the deleted Bitbucket workspaces. That development history is gone — but it doesn&amp;rsquo;t matter, because the deployed bytecode and the npm dependency chain are fully verified on their own.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Johan Nygren’s published gists — where the original keygen and demo code actually lived&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;338px&#34; data-flex-grow=&#34;140&#34; height=&#34;1050&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-gists.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-gists_hu_4993a78a116f6342.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-gists.png 1480w&#34; width=&#34;1480&#34;&gt;&#xA;&lt;em&gt;The gists (&lt;code&gt;resilience-me&lt;/code&gt;) — &lt;code&gt;g_6.sol&lt;/code&gt; and &lt;code&gt;all_30.txt&lt;/code&gt; live here, not in any repo.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;the-authors-own-words--the-forum-posts&#34;&gt;The author&amp;rsquo;s own words — the forum posts&#xA;&lt;/h2&gt;&lt;p&gt;The last surface was his prose, read straight off the chains and threads where he published it.&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;Steemit / Hive&lt;/strong&gt; (&lt;code&gt;johan-nygren&lt;/code&gt;, &lt;code&gt;teikhos&lt;/code&gt; tag), pulled via the Steem blockchain API (&lt;code&gt;condenser_api.get_discussions_by_blog&lt;/code&gt;, paged back to early 2018) rather than the web frontend. He published the whole design diary there — 29 posts in the bounty window — including the announcement of the bounty itself, in his own words. His framing is explicit: &lt;em&gt;&amp;ldquo;approximate perfect security&amp;rdquo;&lt;/em&gt;, and — settling the weak-RNG question — &lt;em&gt;&amp;ldquo;truly random keys.&amp;rdquo;&lt;/em&gt; He even flags the commit-reveal time-window (the C-type flaw) in the announcement itself.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Johan Nygren’s 2018 Steem/Hive post announcing the Teikhos bounty&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;213px&#34; data-flex-grow=&#34;88&#34; height=&#34;1350&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-steemit.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-steemit_hu_ab5131dad9b55426.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-steemit.png 1200w&#34; width=&#34;1200&#34;&gt;&#xA;&lt;em&gt;The 2018 announcement on the Steem blockchain (&lt;code&gt;@johan-nygren&lt;/code&gt;) — the scheme, the &lt;code&gt;proof = publicKey xor …&lt;/code&gt; format, and links to the live bounty contracts.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;&lt;strong&gt;EIP-935&lt;/strong&gt;, the 2018 GitHub thread where he proposed the scheme. An Ethereum developer (&lt;code&gt;@3esmit&lt;/code&gt;) reviewed it and reached the exact conclusion I did eight years later: it&amp;rsquo;s &lt;em&gt;&amp;ldquo;just one more hashing on top of address private key bruteforce&amp;rdquo;&lt;/em&gt; — the 2¹⁶⁰ wall, on the public record since 2018.&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;EIP-935: an Ethereum dev independently calls it a 2^160 wall in 2018&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;338px&#34; data-flex-grow=&#34;140&#34; height=&#34;1050&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-eip935.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-eip935_hu_85b10aae6a6da555.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-eip935.png 1480w&#34; width=&#34;1480&#34;&gt;&#xA;&lt;em&gt;EIP-935 — &lt;code&gt;@3esmit&lt;/code&gt; characterizing the security as one hash on top of address-bruteforce, with Johan (&lt;code&gt;resilience-me&lt;/code&gt;) replying.&lt;/em&gt;&lt;/p&gt;&#xA;&lt;p&gt;Here is every surface swept, with its yield:&lt;/p&gt;&#xA;&lt;table&gt;&#xA;&#x9;&lt;thead&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Host / source&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Handle&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;What it gave&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;th&gt;Key-relevant?&lt;/th&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/thead&gt;&#xA;&#x9;&lt;tbody&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Etherscan&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;—&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;verified source for all 18 contracts, deployer cluster, bricked-contract proof&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;ground truth&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Google BigQuery&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;—&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;mainnet + cross-chain census, the 2022 solver tx&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;census, no key&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Ropsten Erigon archive&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;—&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;9.3M blocks, 220 &lt;code&gt;authenticate&lt;/code&gt; calls&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0 hits&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Rinkeby node (Shodan)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;—&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;only surviving Rinkeby archive; full 2018 calldata&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0 twins, 0 keys&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;GitHub&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;resilience-me&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;51 repos + 139 gists; &lt;code&gt;g_6.sol&lt;/code&gt;, &lt;code&gt;all_30.txt&lt;/code&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;source &amp;amp; keygen, no key&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;npm / unpkg&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;(dependency)&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;eth-crypto@0.2.0&lt;/code&gt; → &lt;code&gt;eth-lib@0.2.7&lt;/code&gt; keygen&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;entropy proof&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;GitLab&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;bipedaljoe&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;33 repos, mirrors&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;handle linkage&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Bitbucket&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;bipedaljoe&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;14 repos (API only); teikhos/bitpeople &lt;strong&gt;deleted&lt;/strong&gt;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;unrecoverable&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Steemit&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;johan-nygren&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&amp;ldquo;approximate perfect security&amp;rdquo;, &amp;ldquo;truly random keys&amp;rdquo;&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;author intent&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;EIP-935&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;—&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;&lt;code&gt;@3esmit&lt;/code&gt;: 2¹⁶⁰ wall, in 2018&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;third-party confirmation&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Software Heritage&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;resilience-me&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;40 preserved origins&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;provenance&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&#x9;&#x9;&lt;tr&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;Wayback Machine&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;bipedaljoe&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;0 captures of deleted repos&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&#x9;&#x9;&lt;td&gt;unrecoverable&lt;/td&gt;&#xA;&#x9;&#x9;&#x9;&lt;/tr&gt;&#xA;&#x9;&lt;/tbody&gt;&#xA;&lt;/table&gt;&#xA;&lt;p&gt;And the cryptographic battery that ran in parallel — every attack draining to zero:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Every attack and candidate set, all draining to zero solves&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;415px&#34; data-flex-grow=&#34;173&#34; height=&#34;1040&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-attack-funnel.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-attack-funnel_hu_2047aa2d3b404bfe.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-attack-funnel_hu_278dc0d877d9d8be.png 1600w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-attack-funnel.png 1800w&#34; width=&#34;1800&#34;&gt;&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;the-one-that-was-solved--and-the-flaw-hiding-in-it&#34;&gt;The one that &lt;em&gt;was&lt;/em&gt; solved — and the flaw hiding in it&#xA;&lt;/h2&gt;&lt;p&gt;One sibling contract — a 0.5 ETH &lt;strong&gt;demo&lt;/strong&gt; — was drained back in 2022. Here it is, balance zero:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;The demo contract, drained to 0 ETH&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;284px&#34; data-flex-grow=&#34;118&#34; height=&#34;1250&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-demo-drained.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-demo-drained_hu_3f7c3e8159fbc305.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/shot-demo-drained.png 1480w&#34; width=&#34;1480&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;It was solvable for one reason: its answer key was &lt;strong&gt;published off-chain&lt;/strong&gt;. And &lt;em&gt;how&lt;/em&gt; it drained exposes a genuine, previously-unreported flaw in the C-type contract — so I checked whether that flaw could be turned against the &lt;em&gt;live&lt;/em&gt; 0.5 ETH bounty. (Spoiler: no, and the &amp;ldquo;why not&amp;rdquo; is the interesting part.)&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;The flaw.&lt;/strong&gt; C picks its winner in &lt;code&gt;reveal()&lt;/code&gt; as whoever committed the &lt;em&gt;earliest&lt;/em&gt; signature that recovers to their own address over &lt;code&gt;isSolved.msgHash&lt;/code&gt; — &lt;strong&gt;not&lt;/strong&gt; whoever submitted the solving key in &lt;code&gt;authenticate()&lt;/code&gt;. And &lt;code&gt;isSolved.msgHash&lt;/code&gt; is written to public storage the instant a solve lands. So if two parties both know the key, the one who &lt;em&gt;committed first&lt;/em&gt; wins, regardless of who did the work. On the demo, exactly that happened: address &lt;code&gt;0x83e4b2a5&lt;/code&gt; (earlier committer) walked off with the ETH while &lt;code&gt;0x9c739dfa&lt;/code&gt; — the address that actually called &lt;code&gt;authenticate()&lt;/code&gt; with the valid key — got nothing.&lt;/p&gt;&#xA;&lt;p&gt;&lt;strong&gt;Can it touch the live bounty C?&lt;/strong&gt; I ran six independent adversarial analyses across every attack class — reward-path reachability, the commit-race, ecrecover edge cases (zero-address tricks, malleability), the external SHA3-512 helper, and state-machine griefing. Unanimous: &lt;strong&gt;no.&lt;/strong&gt; Every path that moves the 0.5 ETH out — &lt;code&gt;reveal()&lt;/code&gt;, &lt;code&gt;reward()&lt;/code&gt;, the &lt;code&gt;selfdestruct&lt;/code&gt; — is gated on &lt;code&gt;isSolved.timestamp != 0&lt;/code&gt;, written in exactly one place: inside &lt;code&gt;authenticate()&lt;/code&gt;, inside the &lt;code&gt;if&lt;/code&gt; that only fires when &lt;code&gt;ecrecover&lt;/code&gt; matches &lt;code&gt;address(keccak256(P))&lt;/code&gt;. That&amp;rsquo;s the 2¹⁶⁰ wall again. No valid key → no solve → the contract is frozen in its Commit state forever, and the front-running flaw never becomes reachable. It&amp;rsquo;s a &lt;strong&gt;steal-from-a-future-solver&lt;/strong&gt; bug, not a &lt;strong&gt;claim-without-a-key&lt;/strong&gt; bug — and since C can never be solved, there&amp;rsquo;s no future solver to steal from. Real flaw, permanently dormant. (One subtlety: you can&amp;rsquo;t &amp;ldquo;commit garbage now and fix it later&amp;rdquo; — &lt;code&gt;reveal()&lt;/code&gt; reads the signature stored at commit time and then deletes it, so a winning attacker must already know the key before the commit window closes. On the live bounty that window never opens.)&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;proof-it-was-deliberate-not-a-mistake&#34;&gt;Proof it was deliberate, not a mistake&#xA;&lt;/h2&gt;&lt;p&gt;A natural last hope is that the author was sloppy — a weak RNG, a reused nonce, a wrong key in the XOR. His own git history kills that idea. Cloning the C bounty&amp;rsquo;s gist surfaced &lt;strong&gt;six&lt;/strong&gt; distinct proof iterations he cycled through. Testing every key I hold against all six draws a perfectly clean line:&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Six proof iterations in the author’s git history: demos solved, bounties never&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;384px&#34; data-flex-grow=&#34;160&#34; height=&#34;1200&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-proof-iterations.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-proof-iterations_hu_bf83c7421724c6f7.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-proof-iterations_hu_9cd236e43eab75bf.png 1600w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-proof-iterations.png 1920w&#34; width=&#34;1920&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;Three are demos he solved himself — keys public, I have them. Three were never solved and no key exists anywhere, including &lt;code&gt;7b5f8ddd…&lt;/code&gt;, the exact proof sitting in the live bounty C. The same hand drew both kinds and treated them oppositely: &lt;strong&gt;every demo got a published answer; no real bounty ever did.&lt;/strong&gt; That&amp;rsquo;s not negligence — it&amp;rsquo;s intent.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;four-investigators-one-wall&#34;&gt;Four investigators, one wall&#xA;&lt;/h2&gt;&lt;p&gt;By the end I wasn&amp;rsquo;t the only one who&amp;rsquo;d tried. Comparing notes, four independent efforts — mine, two other AI systems run cold, and a public bounty-hunter (&lt;code&gt;@rebel0x0&lt;/code&gt;) still racing for the same money in 2026 — converged on the same verdict with different toolkits. The hunter, the one with the most to gain, solved only the published demo and reported &amp;ldquo;0 hits&amp;rdquo; on the real bounties after recovering 1,600+ sender pubkeys and testing 20,000+ candidates.&lt;/p&gt;&#xA;&lt;p&gt;&lt;img alt=&#34;Four independent investigations, four toolkits, one identical result&#34; class=&#34;gallery-image&#34; data-flex-basis=&#34;411px&#34; data-flex-grow=&#34;171&#34; height=&#34;1120&#34; loading=&#34;lazy&#34; sizes=&#34;(max-width: 767px) calc(100vw - 30px), (max-width: 1023px) 700px, (max-width: 1279px) 950px, 1232px&#34; src=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-four-way-convergence.png&#34; srcset=&#34;https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-four-way-convergence_hu_a117535a229eaced.png 800w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-four-way-convergence_hu_40d8d436068455ed.png 1600w, https://infinisec.io/p/chasing-3-eth-into-a-dead-testnet-anatomy-of-an-unsolvable-bounty/fig-four-way-convergence.png 1920w&#34; width=&#34;1920&#34;&gt;&lt;/p&gt;&#xA;&lt;p&gt;When independent searches with different tools all return zero, the convergence stops being four failures and becomes the proof: there is no shortcut, no reconstruction, and no leak — because there is nothing to find.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;verdict&#34;&gt;Verdict&#xA;&lt;/h2&gt;&lt;p&gt;The ~3 ETH cannot be claimed by anyone. Three bounties are sealed by sound cryptography; the fourth by the author&amp;rsquo;s own bug. This was never a failure to find a key — it&amp;rsquo;s a proof, from every direction I could devise, that there is no key to find.&lt;/p&gt;&#xA;&lt;p&gt;What the hunt produced instead:&lt;/p&gt;&#xA;&lt;ul&gt;&#xA;&lt;li&gt;A &lt;strong&gt;from-scratch, validated reimplementation&lt;/strong&gt; of the whole cryptosystem, anchored to a real on-chain solve.&lt;/li&gt;&#xA;&lt;li&gt;A &lt;strong&gt;reusable method for reading a dead chain&lt;/strong&gt;: Shodan banner-search to resurrect a forgotten archive node, BigQuery census in place of a full node, dependency-date pinning, gist enumeration, CREATE-address arithmetic, and archival recovery via Software Heritage.&lt;/li&gt;&#xA;&lt;li&gt;An &lt;strong&gt;on-chain proof&lt;/strong&gt;, for about $0.05, that the fourth bounty is bricked.&lt;/li&gt;&#xA;&lt;li&gt;A &lt;strong&gt;responsible disclosure&lt;/strong&gt; of a real, live commit-reveal flaw (below).&lt;/li&gt;&#xA;&lt;/ul&gt;&#xA;&lt;p&gt;Sometimes the deliverable of a treasure hunt isn&amp;rsquo;t the treasure — it&amp;rsquo;s the toolkit you built to reach it, and a proof, beyond doubt, that no one else can reach it either.&lt;/p&gt;&#xA;&lt;hr&gt;&#xA;&lt;h2 id=&#34;responsible-disclosure--the-c-type-commit-reveal-flaw&#34;&gt;Responsible disclosure — the C-type commit-reveal flaw&#xA;&lt;/h2&gt;&lt;p&gt;For completeness: the C-type &lt;code&gt;TeikhosBounty&lt;/code&gt; contract binds its reward to the &lt;em&gt;earliest committer who can produce a self-signature over the solution&amp;rsquo;s message hash&lt;/em&gt;, rather than to the account that submits the solving key. Because &lt;code&gt;isSolved.msgHash&lt;/code&gt; becomes public the moment a solve lands, any party who already knows the solution key can win the reward out from under the legitimate solver by having committed earlier. This was demonstrated in the wild on the demo contract &lt;code&gt;0x735ba26f&lt;/code&gt; (winner ≠ solver). It does &lt;strong&gt;not&lt;/strong&gt; affect the funds in the live A/B/C bounties, which can never be solved and are therefore never exposed to it. The fix, for anyone building a similar scheme: commit to &lt;code&gt;keccak256(publicKey, msg.sender)&lt;/code&gt; rather than a bare signature, and bind the payout to the &lt;code&gt;authenticate()&lt;/code&gt; caller — not to a separate, front-runnable reveal.&lt;/p&gt;&#xA;&lt;p&gt;The contract author, Johan Nygren, remains publicly reachable, and all data used here is public — no private keys, private messages, or non-public systems were accessed. Every source was a public API or banner: Etherscan, GitHub, Google BigQuery (ADC), Shodan, Software Heritage, the Steem and Ethereum chains themselves.&lt;/p&gt;&#xA;</description>
        </item></channel>
</rss>
