0:00
/

Neural Bitcoin Small Class Number Attack

We trained a neural network to attack bitcoin. It works
Quick Intro
LeetArxiv shows programmers how to turn PhD-level math papers into C and Python code.

Stop reading papers. Start coding them. Engineers who use LeetArxiv for their professional growth can use this template email to ask their employers to expense a subscription.

Here’s the Polymarket bet on touching Satoshi’s wallet..
Here is 12 months of Perplexity Pro on us.
Here’s 20 dollars to send money abroad.
Here are some free gpu credits from Runpod:)

1.0 Satoshi Chose a Bizarre Prime Number

We coded Hacking Dormant Bitcoin Wallets in C and saw how Satoshi’s wallet is protected by an elliptic curve modulo the prime number below (Certicom, 2010)1:

p = 115792089237316195423570985008687907853269984665640564039457584007908834671663

or in hexadecimal:

p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F

We then coded the GLV Endomorphism paper and saw that bitcoin’s prime number is special. It splits well over the set of imaginary numbers.

For anyone who missed it, we saw how Eisenstein integers permit super fast arithmetic on curves like Bitcoin.

Finding a cube root of unity using Eisenstein integers

Finally, we saw in the Gaussian Integers paper that the bitcoin prime has a special property: it has a class number of 1.

In a nutshell, class number of 1 means we can uniquely factorize integers over the set of real numbers and over the set of complex numbers.

We saw that there are only 9 special imaginary numbers that have a class number of 1 and Bitcoin’s prime works great with -3, one of the smallest lol.

2.0 Small Class Number Attack on Bitcoin

If Trump didn’t defund math programs then I’d be getting a PhD in index calculus techniques. Now I identify as an internet math autist while I figure out how I’ll afford grad school lol.

In the Small Class number Attack on Bitcoin we ‘attempt’ to use a neural network to find non-linear relationships between private and public keys.

It’s inspired by the Xedni Calculus Attack in Python. However, we fit a neural network over our public keys instead of fitting an elliptic curve.

Super silly to admit but we were trying to answer the question ‘How would Joseph Silverman improve the Xedni Calculus Attack he invented in the early 2000s if he had access to a H100 and a transformer’

These are the steps involved:

  1. Take a bitcoin wallet’s public key and ‘tokenize’ it by finding its prime factorization over the set of real and complex numbers.

    • The secp prime has a class number of 1 so we know this factorization is unique.

    • Splitting over real and complex primes permits us train on 32 bit floats since the numbers are small.

  2. Find discrete logarithms modulo the bitcoin prime, just like we did here.

  3. Use a neural network to relate the discrete logarithms of the prime factorization of the public key to the secret key.

    You can think of this as part 2 of the logarithmic pollard-rho for elliptic curves we did here:

2.1 Attack Preparation

We prepare for the attack by:

  1. Rewriting the bitcoin prime as a complex prime over the set of Eisenstein integers.

  2. Sieving to find relations between the regular integer form and Eisenstein integer form of the bitcoin prime.

  3. Using linear algebra to find logarithms like we did in our index calculus series.

2.1.1 Finding the Complex Form of the Bitcoin Prime

As we did before, we need to rewrite our integer prime p as an Eisenstein prime p'. We covered the process in detail here and found these T and V values:

T = 367917413016453100223835821029139468249
V = 303414439467246543595250775667605759171

such that the norm of the complex prime number involving T and V (T+V√-3) equals the bitcoin prime:

Complex prime (p'): (367917413016453100223835821029139468249 + 303414439467246543595250775667605759171√-3)

Norm = 115792089237316195423570985008687907853269984665640564039457584007908834671663 

where the norm of an Eisenstein integer is computed as:

Norm calculation for Eisenstein integers

We further find cube roots of unity (ω) modulo p, just like we did in the GLV paper:

Root of unity0: 60197513588986302554485582024885075108884032450952339817679072026166228089408

Root of unity1: 55594575648329892869085402983802832744385952214688224221778511981742606582254

2.1.2 Sieving to Find Relations

Now we need to relate our bitcoin’s regular form to its complex number form using the relationship observed here:

cV-dT = V(c+dω) mod p`

where ω is one of the three possible cube roots of unity modulo p.

Collecting lots of relations permits us perform linear algebra to understand the mathematical relationship between our complex form and integer form.

2.1.2.1 Naive Bruteforce Relation Collecting

First, we tried to collect relations using the naive method from our past index calculus in the Pell number field.

It took 10 hours to collect 1000 relations yet we need a million of them lol!

2.1.2.2 Complex Number Sieve Relation Collecting

Factoring takes the most time in the naive approach. We can use a complex number sieve to identify the best candidates for big integer factorization.

Lucky us, our complex numbers are of the form:

c_1V-c_2T

So the strategy in the Gaussian integers paper works great!

Sieving can be summarized as:

  1. Fix c1 and init an empty array of c2 values.

  2. Calculate the product of c1, V and inverse of T modulo the current factor base prime, call this variable arrayIndex.

  3. Add the logarithm of factorBasePrime at every congruent arrayIndex.

  4. After sieving, the indices of the c2 array with the largest values are the best factorization candidates.

Pseudocode resembles this:

arrayIndex =  (C1 * V * TInverse) % (factorBasePrime ^ largestExponent)
array[arrayIndex] += 1000* naturalLog(factorBasePrime)

Our sieve has the parameters:

int factorBaseBitLength = 27;
int c1 = 95000;
int c2 = 100000;

We estimate the expected natural log we desire as ln(c_1V-c_2T) and when an array value difference is about 19,000 then we have a smooth number over our factor base.

c2: 18198, 69816 98426: 28610 temp1: -3660913272961480835377261263636554845726131 (Bad Candidate)

c2: 19441, 75690 98426: 22736 temp1: -4118234617340932038955489189175775204759638 (Bad Candidate)

c2: 20376, 79915 98426: 18511 temp1: -4462237398511315687664775681838020607572453 (Good
 Candidate)

For each candidate c1,c2 pair we factor over both the regular integers and Eisenstein integers and save this for the next step.

  • Before: It took 10 hours to collect 1000 relations.

    • It would have taken 41 days to collect 100,000 relations.

  • Now: It takes 20 seconds to collect 1000 relations with our sieve lol.

    • We’ll have 100,000 relations in half an hour.

Going from 41 days to 20 seconds is wild IMO!

As expected, we collected ~300,000 relations after 30 minutes of sieving

2.1.2 Linear Algebra Step using Neural Networks

Our Practical Index Calculus for Programmers series and Semaev’s Summation Polynomial Index Calculus for Elliptic Curves, all featured a linear system similar to this one taken from (Howell, 1998)2:

Example linear system we need to solve for our logarithms.

However, this approach only works when our system has solutions. We don’t know if our matrix system can be solved.

Will a neural network permit us overcome the ‘can’t find our null space’ problem in both RREF and Hermite Normal Form?

Here are the changes we propose:

  1. No explicit factor base.

    • Instead, we pass a prime factorization to our network and let it figure out a factor base.

  2. Logarithm weights are floats. (I spent December 2025 trying to make floats work. It was futile)

    • Not integers like in typical index calculus.

  3. 1st Feb update.

    • Logarithm weights are integers over the finite field modulo p-1 / 42, where p is the field characteristic (the bigger prime).

      • So we’re working modulo:

        - 13441
        - 205115282021455665897114700593932402728804164701536103180137503955397371 
      • For the most bizarre reason, the larger prime above also permits Eisenstein integer style tokenization.

    • We avoid backprop entirely in favor of hand-wavy weight tuning in the style of ‘Noam Shazeer’.

2.1.3 Network Architecture, Inputs, Training and Outputs

2.1.3.1 Inputs

Our tokenized input resembles this in Python:

Complete input token class in Python

We follow the exact steps from the Gaussian integers paper to generate input data and ‘tokenize’ the dataset:

  1. Take the x-coordinate of the desired public key.

  2. Find its rational reconstruction (A/B).

  3. For the numerator and denominator, find each one’s corresponding Eisenstein integer in the form V(c+dw).

  4. Factor (c+dw) into smaller eisenstein primes.

2.1.3.2 Network Layer

The entire network is one big integer layer. Idk how to backprop over a finite field (i don’t think it’s possible tbh) so I did what I know.

We borrow the integer lattice covered when we coded (Boneh & Venkatesan, 1996)3.

Solving this lattice provides a solution to the Hidden Number Problem. Taken from page 6 of (Boneh & Venkatesan, 1996).

Each unique dataset item is a column of the integer lattice. Training is the weird part.

  1. First, we perform gaussian elimination over a finite field like we did here.

  2. We split the large ‘trained’ matrix into submatrices and perform LLL reduction like we did in this paper.

  3. We repeat these steps and use the gaussian heuristic as our primary loss function ie (I’m praying the matrix determinant approaches zero)

  • I have no idea why this works.

  • I stumbled upon it by trial and error.

  • It took me 4 months to figure out the loss function.

  • I can’t find an algo for it so it’s just me hand-tuning my integer weights (and lattice parameters) on nights and weekends after coming home from my day job.

2.1.3.3 Output and Testing

After training, we append our targets as a column of our weight matrix. I borrowed this from the Special Number Field Sieve for Discrete Logarithms paper we coded.

Then we LLL reduce the trained matrix with the appended target column.

The network correctly predicts the first 5 to 10 bits of a 135-bit private key

Voila! The network correctly predicts the first 3 to four bits of the private key.

atp I’m just running on intuition. I absolutely don’t know why this works.

I left out a lot of technical details:

  1. The network works in the 135-bit private key range. I generated a train/test dataset for the bitcoin puzzles.

    • It doesn’t work on keys outside the training range.

    • I tried training on a 140 bit dataset. It isn’t working. I surmise I need more data

  2. Output accuracy is hand-wavy. When it works, I get upto 10 bits of the private key’s Most significant bits. When it fails, it guesses a private key in the 237-bit range.

  3. Acquiring data is my primary bottleneck. I need to solve lots of discrete logarithms and my resources limit me to collecting ~1200 relations / hour.

  4. The train dataset is ~10,000 public keys. The test is ~1,000 public keys. It’s expensive to solve discrete logs on Runpod. I think it will scale once I figure out how to collect relations faster with my ‘broke PhD student budget’

If you found this interesting and would like to get involved HMU.

If you have access to CPU (not GPU) cores then lmk.

Bitcoin 135 puzzle wallet

The bitcoin 135 wallet is worth a million dollars atm. If you’d like to sponsor this project and get a share then subscribe as a founding member.

References

1

Certicom Research. (2010). SEC 2: Recommended Elliptic Curve Domain Parameters. Link.

2

Howell, S,. J,. (1998). The Index Calculus Algorithm for Discrete Logarithms. Clemson University Masters Thesis.

3

Boneh, D., & Venkatesan, R. (1996). Hardness of Computing the Most Significant Bits of Secret Keys in Diffie-Hellman and Related Schemes. In: Koblitz, N. (eds) Advances in Cryptology — CRYPTO ’96. CRYPTO 1996. Lecture Notes in Computer Science, vol 1109. Springer, Berlin, Heidelberg. https://doi.org/10.1007/3-540-68697-5_11

Discussion about this video

User's avatar

Ready for more?