0:00
/
0:00

Computation of Discrete Logarithms in Prime Fields (Gaussian Integers Method used to break Sun Microsystems in 1991)

Coding the 1991 paper, Computation of Discrete Logarithms in Prime Fields by LaMacchia & Odlyzko for a Bitcoin Attack using Eisenstein Integers
Quick Intro
LeetArxiv is a successor to Papers With Code after the latter shutdown.
Here’s the Polymarket bet on touching Satoshi's wallet..

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.

Abstract for the 1991 paper Computation of Discrete Logarithms in Prime Fields (LaMacchia & Odlyzko, 1991)
Here is 12 months of Perplexity Pro on us.
Here’s 20 dollars to send money abroad.
Here are some free gpu credits :)
Quick Summary
This paper introduces a fast sub-exponential algorithm for solving discrete logarithms over the set of complex numbers of type -2: the ring of Gaussian integers.

As usual, here’s the Python Google Colab link and here’s the GitHub with both C and Python.

*Jump to Section 3.0 for the bitcoin content.

1.0 Paper Introduction

The 1991 paper Computation of Discrete Logarithms in Prime Fields (LaMacchia & Odlyzko, 1991)1 demonstrates the ‘Gaussian Integers’ approach to collecting relations for an index calculus-style attack on discrete logarithms.

Gaussian integers illustration. Taken from Libretexts

Gaussian integers are imaginary numbers from high school math.

We assume familiarity with index calculus techniques. This is part of our series on Practical Index Calculus for Computer Programmers.

Part 1: Discrete Logarithms and the Index Calculus Solution.

Part 2: Solving Pell Equations with Index Calculus and Algebraic Numbers.

Part 3: Solving Index Calculus Equations over Integers and Finite Fields.

Part 4.1 : Pollard Kangaroo when Index Calculus Fails.

Part 4.2 : Pohlig-Hellman Attack.

Part 5 : Smart Attack on Anomalous Curves.

Part 6: Hacking Dormant Bitcoin Wallets in C.

2.0 Sieving Algorithms

The authors introduce two sieving algorithms, the linear sieve and the gaussian integer sieve.

They demonstrate the linear sieve’s limitations and introduce the gaussian sieve in its place.

2.1 Linear Sieve

Linear Sieve taken from page 7 of (LaMacchia & Odlyzko, 1991)

The authors propose searching for relations of the form above.

We demonstrate relation collection in this Google Colab notebook.

Linear sieve in Python

Two challenges are apparent:

  1. The factor base is rather large since we have primes besides all (H+c) terms.

  2. Lots of equations are needed to solve the system.

  3. After finding g, we still need to find the logarithm of the original primitive root in terms of our collected weights.

We are informed the linear sieve challenges are not serious. Taken from page 8 of (LaMacchia & Odlyzko, 1991)

However, as mentioned by the authors, these deficiencies are not serious and finding (H+c) terms that factor through our list of primes is optimal. This prevents additional new equations.

2.2 Gaussian Integer Sieve

Gaussian integers are complex numbers with integer coefficients and they are closed under both addition and multiplication (Cryptohack, 2021)2.

We recommend (William, 2020)3 and (Conrad, 2020)4 for friendly introductions to Gaussian integers.

The (LaMacchia & Odlyzko, 1991) paper focuses on the problem below:

Target discrete logarithm taken from Equation 7 of (LaMacchia & Odlyzko, 1991)

where p is a 192-bit prime number:

p = 5213619424271520371687014113170182341777563603680354416779

2.2.1 Important Definitions

Here are some important definitions from algebraic number theory (Tao, 2020)5 that will help us through the coding guide:

  • Unit - a number u is called a unit if u divides 1, that is, there exists a number v such that uv = 1.

  • Irreducible number - a number p is irreducible if it is not zero or a unit, and p cannot be written as the product of smaller thing. (It’s a generalized version of a prime number)

  • Unique Factorization Domain (UFD) - a number system where every number, except 0 and a unit, can be written as a product of irreducible prime numbers.

  • Class number of 1 - a ring of integers that permits a unique factorization domain. (Weisstein, 2025)6

  • Heegner numbers - imaginary quadratic fields with unique factorization (have class number 1). (OEIS, A003173)7

    • There are only 9 Heegner numbers: -1, -2, -3, -7, -11, -19, -43, -67, -163.

    • Note that Heegner numbers are all negative.

  • Quadratic residue - we say that an integer m is a quadratic residue (QR) modulo n if there exists an integer x for which x2 ≡ m mod (n).

    • If it has a square root mod n then it’s QR.

    • A number is QR if its legendre symbol mod p is 1.

2.2.2 Finding a Number Field

*Italicized words are from the definitions in Section 2.2.1
Finding a suitable number field. Taken from Section 5 of (LaMacchia & Odlyzko, 1991)

We search the set of Heegner numbers to find the smallest quadratic residue of class number 1 modulo our prime using the fmpz_jacobi function.

*Jacobi symbol is a generalized version of the legendre symbol.
Finding a suitable number field in C using FLINT

We also need to find S, the square root of the heegner number field.

*Finding S by square root only applies to Gaussian integers. Section 3.0 demonstrates finding S for Eisenstein integers.

In Python, this resembles:

Python search for a number field and S over the Gaussian integers

We find these number field parameters:

Heegner Number (r): -2
Heegner Root (S): 674628418031497608859095525797188659682765178381388426867

2.2.3 Finding V and T

Next we find T and V such that T2 ≡ rV2 mod p such that:

Properties of T and V, where r = 2. Taken from Section 5 of (LaMacchia & Odlyzko, 1991)

We search for T and V in the continued fraction convergents of (S / p) using Euclid’s algorithm (Gautam, 2016)8:

*Remember, this paper’s from 1986 so the approach is outdated lol
Euclid’s algorithm and continued fraction expansion of a rational. Taken from page 7 of (Gautam, 2016)

In Python the code, including the starting coefficients of the continued fraction:

Using the continued fraction expansion to find T and V

You can verify the exapnsion with this online continued fraction calculator and the input:

4538991006240022762827918587372993682094798425298965989912/5213619424271520371687014113170182341777563603680354416779
*if you get an unexpected character error then remove the spaces around the division symbol‘/’

Now we search through the numerator and denominator pairs for T and V and observe two things:

  1. The first time fails. We need to use the other root (p - S).

  2. Our desired values occur in the denominator:

Our desired T and V values occur in the denominator of the second root

There’s a shortcut to solving this called Cornacchia’s algorithm (Praxix, 2012)9:

Cornacchia’s algorithm in Python. The C version doesn’t show how ‘shortcuty’ it is compared to the CF expansion

We obtain T and V:

T: 22760185083691921160273336139
V: 48454067936694480117959482723

2.2.4 Finding Smooth Numbers

First, we set a smoothness bound as we did before in the Pell Index Calculus paper:

Pomerance bound was covered in Pell paper

In our case, our small factor base is prime numbers upto 237 and the large prime factor base from (Lenstra & Manasse, 1994)10 upto 55 bits:

Bound0:  37 bits
Bound1:  55 bits

Alternatively, you can use prime counting function to determine the size of the factor base:

Prime counting function estimates arounf 5 billion primes upto 2 ^ 37

Then we use the medium prime trick (LaMacchia & Odlyzko, 1991) to find smooth relations close to the square root of p.

Annotated description of the medium prime trick. Taken from Section 7 of (LaMacchia & Odlyzko, 1991)

So we collect relations of the form:

  • XF_YF → Full relation factors completely over factor base.

  • XF_YP → 1 large prime (in Y) outside factor base.

  • XP_YF → 1 large prime (in X)

  • XP_YP → 2 large primes (one in X, one in Y)

2.2.5 Gaussian Integer Factorization Trick

Finally, we use the factorization trick in Equation 7.12 to make our medium-sized primes even smaller:

Breaking a medium-sized prime into smaller primes over regular integers and gaussian integers. Taken from equation 7.12 of (LaMacchia & Odlyzko, 1991)

The authors use contined fractions to find small integer solutions (Elkies, 2011)11 to the equation:

*r here is the medium prime, not the heegner number field
Searching for c and d in this linear diophantine

This paper is from 1991 so they overexplained Gaussian Lattice Reduction in Dimension 2 (Hoffstein et al., 2015)12.

Sample T and V values

Let’s walk through the paper’s example for 20261929 where T and V are shown above:

Homogeneous sol is first basis vector and xgcd result is second basis vector
  1. We need two basis vectors for reduction and easily find:

    • Kernel basis (set c to T and d to V)

    • Extended gcd basis (use the extended gcd to find a particular solution):

      Particular sol:-59673551245166860509291709922547017,
       -127038787049622592945843517621047980
      
      Homogeneous sol:22760185083691921160273336139, 48454067936694480117959482723
  2. Next we write a brief Gaussian lattice reduction function:

    Gaussian lattice reduction algorithm taken from page 437 of (Hoffstein et al., 2015)
    • Here’s a gist example in FLINT. We get the shortest solution:

      (3683, 2244)
    • If you’re confused then you can follow by hand:

      Gaussian lattice reduction example taken from page 438 of (Hoffstein et al., 2015)
  3. Now check if (cV-dT)/r factors into small primes.

    • If it doesn’t then we test other linear combinations v = (x0,y0) + k*(T,V)

    • If it does then we have a nice denominator. Our search yields a vector and 191717 (an 18 bit number) in its factorization:

      *Remember 20261929 is a 24 bit number. We saved 6 bits!
      Vector(c,d): (692011, 3827045)
      
      Factors: 2 ^ 1, 17 ^ 1, 53 ^ 1, 157 ^ 1, 3067 ^ 1, 18553 ^ 1, 22189 ^ 1, 191717 ^ 1, 38609 ^ 1,
  4. Now we factor the numerator over complex numbers using the relationship from page 9 and steps from (Alpertron, 2025)13:

    cV-dT = V(c+ds) mod p`.
    • Step 1: Find the prime factorization of the norm of c+ds

      (c,d): (692011, 3827045) 
      heegnerNumberField (s): -2
      Norm: 29771426088171
      Norm factors: 3 ^ 3, 163 ^ 1, 89083 ^ 1, 75937 ^ 1
      
    • Step 2: Find the legendre symbol for each prime in the norm factorization where

      legendre  0: p ramifies
       - p appear as squareRoot p with exponent divided by 2
      
      legendre -1: p inert, so p is a prime in complex field
       - p appears in prime factorization unchanged
      
      
      legendre  1: p splits as (a+b√d)(a-b√d), find a,b like in Section 2.2.3
      
    • Then factorize.

In Python, this method of finding smaller primes resembles:

Finding smaller primes using the Gaussian integer trick : cV-dT

For the sake of completion, our factor base is entirely integers. Observe that equation 7.12 holds over the integers:

Eq 7.12 in Python

We are done with the paper!

3.0 Bitcoin Modifications

I recommend skimming the definitions in Section 2.2.1 if you jumped here

Bitcoin’s field characteristic prime number is given in the offical SEC whitepaper (Certicom, 2010)14:

p = 115792089237316195423570985008687907853269984665640564039457584007908834671663

The largest factor of p-1 is a 236 bit prime and this is important for index calculus:

(p-1) factors = 2 * 3 * 7 * 13441 * 205115282021455665897114700593932402728804164701536103180137503955397371

However, the smallest Heegner number (definition in Section 2.2.1) for the bitcoin prime is -3.

3.1 Ring of Eisenstein Integers

*We defined all these foreign words earlier in Section 2.

The UFD with Heegner number (-3) is defined over the ring of Eisenstein integers (Weisstein, 2025)15.

We follow (Lemvig, 2024)16 to modify the algorithms introduced in Section 2.0

  • Change 1: Integer Form

    • The Eisenstein integers are complex numbers of the form a+bw where a and b are normal integers and w is a cube root of unity (Weisstein, 2025):

      Imaginary part of Eisenstein integers
  • Change 2: Norm Calculation

    • The norm changes to:

      Norm calculation for Eisenstein integers
    • Units are elements of norm 1 and the Eisenstein ring has 6 units:

      Units among Eisenstein integers
  • Change 3: S, T and V Parameters

    • p must be a number where legendre (-3/p) = 1.

      • This means -3 must be a quadratic residue modulo p.

    • p` takes the form:

      p’ is a complex number over the set of Eisenstein integers
    • We find T and V such that :

      Finding T and V
      • We use the modified version of Cornacchia’s algorithm from Section 2.2.3 (Woba, 2024)17

        • Let U = 2T - V and sub into T2−TV+V2

        • Solving via Cornacchia’s algorithm U2+3V2 = 4p gives us T and V.

    • S is a non-trivial cubic root of unity modulo p found by solving:

      How to find S
    • If your root of unity fails to solve for T and V, then use the other one. Here’s a C script that finds T, V and S for different primes.

  • Change 4: Prime Factorization Algorithm

    • As we saw in Section 2.2.5, we first compute the norm and its prime factorization.

    • For each prime:

      Handling different prime cases
  • Change 5: Finding a primitive root modulo T+Vw

    • We find a prime primitive root modulo p, test if it splits -3, then find a T,V representation. Here’s a sample C script.

3.2 Worked Example

We work with the prime number 20959 with Heegner number 3 and these parameters:

Integer Prime: 20959
Integer Prime-1: 20958
Integer Primitive Root: 97
Norm factors:
(2 ^ 1)(3 ^ 1)(7 ^ 1)(499 ^ 1)
Heegner Number: -3
RootOfUnity (S): 1631
T: 167
V: 77
Complex prime: (167 + 77√-3) Norm = 20959
Complex PrimitiveRoot: (11 + 3√-3) Norm = 97

For bitcoin:

Integer Prime: 115792089237316195423570985008687907853269984665640564039457584007908834671663

Integer Prime-1: 115792089237316195423570985008687907853269984665640564039457584007908834671662

Integer Primitive Root: 691

Norm factors:
(2 ^ 1)(3 ^ 1)(7 ^ 1)(13441 ^ 1)(205115282021455665897114700593932402728804164701536103180137503955397371 ^ 1)

Heegner Number: -3

RootOfUnity (S): 55594575648329892869085402983802832744385952214688224221778511981742606582254
T: 367917413016453100223835821029139468249
V: 303414439467246543595250775667605759171

Complex prime: (367917413016453100223835821029139468249 + 303414439467246543595250775667605759171√-3) 

Norm = 115792089237316195423570985008687907853269984665640564039457584007908834671663

Complex PrimitiveRoot: (19 + 30√-3) Norm = 691

We are ready to go!

Bonus content

I encountered the most bizarre thing. In Section 3.0, we saw the bitcoin field characteristic prime has a 236 bit prime factor:

205115282021455665897114700593932402728804164701536103180137503955397371

Using these T, V and S values:

RootOfUnity (S): 55594575648329892869085402983802832744385952214688224221778511981742606582254
T: 367917413016453100223835821029139468249
V: 303414439467246543595250775667605759171

we find the c, d (from Section 2.2.5) values:

C: -5563461929641081618017608186510193177419
D: 1878996444240933906989529462134320462276

This is where it gets sooo strange: cV-dT/r factors into a thing with 15 bits:

cV - dT = -2379350193711653076113482045115753289395500225200194993664095394545358693634373

M = (cV - dT)/r = -11600063

Factorization of M: {647: 1, 17929: 1, -1: 1}

The numerator has a 95 bit prime:

39831306940520651376621602713

We went from 236 bits to 95 and 15 bits. IMO this should be statistically impossible.

So we can rewrite the largest prime factor (r) as:

r = (cV - dT)/ M 
r = (3 * 53 * 127 * 622793 * 96590783 * 10405113293 * 126147778933237103171 * 39831306940520651376621602713) /(11600063) mod p

or

This is the final cell in our colab notebook.

Bonus content
*Trump defunded my math PhD and now I identify as an internet math autist. Could one or two of you subscribe and help me pay December’s rent while I figure things out.

Become a paying subscriber

4.0 Further reading

Here are other chapters from our attempt at accessing Satoshi’s wallet.

Available Chapters
  • Chapter 1 : A Programmer’s Introduction to Elliptic Curves.

  • Chapter 2 : What Every Programmer Needs To Know About Conic Sections (To Attack Bitcoin)

  • Chapter 3 : The Discrete Logarithm Problem and the Index Calculus Solution.

  • Chapter 4: Smart Attack on Elliptic Curves.

  • Chapter 5: The US Government Hid a Mathematical Backdoor in another Elliptic Curve.

  • Chapter 6: Hacking Dormant Bitcoin Wallets in C coding guide.

  • Chapter 7: Pollard’s Rho and Kangaroo Collision Searching.

  • Chapter 7: If you’re smart why are you poor? Elliptic Curve Edition.

Subscribe for more applied math articles.

References

1

LaMacchia, B. A., & Odlyzko, A. M. (1991). Computation of discrete logarithms in prime fields. Designs, Codes, and Cryptography, *1*(1), 46–62. PDF.

2

Cryptohack, Jack. (2021). Finite Groups, Gaussian Integers & TetCTF 2021. Link.

3

William, A. (2020). The Arithmetic of the Gaussian Integers. UBC Math 444 Assignment. PDF.

4

Conrad, K,. (2020). Gaussian Integers. University of Connecticut. PDF.

5

Tao, Y. (2020). Prime Factorizations Part II - Gaussian Integers. UCLA Circles. PDF.

6

Weisstein, E. (2025). Class Number. MathWorld--A Wolfram Resource. Link.

7

OEIS A003173. Heegner Numbers. Link.

8

Gautam, G. (2016). Continued Fractions. Ithaca High School Senior Math Seminar. PDF.

9

Praxis, P. (2012). Cornacchia’s Algorithm. Link.

10

Lenstra, A & Manasse, M. (1994). Factoring with Two Large Primes. Mathematics of Computation, Vol. 63, No. 208 (Oct., 1994), pp. 785-798. American Mathematical Society.

11

Elkies, N,. (2011). [Answer] Which Diophantine equations can be solved using continued fractions?. Link.

12

Hoffstein, J., Pipher J., & Silverman, J. (2015). An Introduction to Mathematical Cryptography. Springer New York, Undergraduate Texts in Mathematics. PDF. DOI.

13

Alpertron, N. (2025). Gaussian integer factorization calculator. Link.

14

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

15

Weisstein, E. (2025). Eisenstein Integer. From MathWorld--A Wolfram Resource. Link.

16

Lemvig, R,. (2024). A Tour of the Eisenstein Integers. GitHub. PDF.

17

Woba, M.D. (2024). Representation of an Integer by a Quadratic Form through the Cornacchia Algorithm. Applied Mathematics, 15, 614-629. https://doi.org/10.4236/am.2024.159037

Discussion about this video

User's avatar

Ready for more?