Deep Cryptanalysis: Invalid Curve Attack and Elliptic Curve Cryptography in the Bitcoin Ecosystem Implemented on Google Colab

02.08.2026
Deep Cryptanalysis: Invalid Curve Attack and Elliptic Curve Cryptography in the Bitcoin Ecosystem Implemented on Google Colab

Abstract.  This paper presents a detailed cryptanalytic analysis of the Invalid Curve Attack (ICA) as applied to the secp256k1 elliptic curve used in Bitcoin. It examines the mathematical underpinnings of the vulnerability, which stem from the lack of a check for curve point membership in the addition and doubling formulas. Particular attention is given to a practical demonstration of the attack in the Google Colab environment using the SageMath library: it is shown how an attacker can recover a private key by selecting points on weak curves with smooth ordering, using the Pohlig–Hellman algorithm and the Chinese Remainder Theorem. Examples of secure implementations in various languages ​​are given, and real-world vulnerabilities (CVE-2023-39910) are discussed. The article is intended for specialists in the field of blockchain security and cryptography. This research paper presents a deep cryptanalytic analysis of the Invalid Curve Attack in the context of the Bitcoin ecosystem. It examines the mathematical basis of the vulnerability in elliptic curve algorithms (secp256k1), the consequences of the lack of point validation, and cryptographic protection methods.

1. Introduction to Mathematical Foundations secp256k1

The Bitcoin cryptocurrency uses the secp256k1 elliptic curve, which is described by the Weierstrass equation over a finite Galois field. The formula is:  y^2 = x^3 + ax + b (mod p). For the secp256k1 curve, the parameters are strictly defined:  a = 0 and  b = 7, which leads to the equation  y^2 = x^3 + 7 (mod p).

2. Mechanics of Invalid Curve Attack

The attack exploits the peculiarities of the formulas for adding and doubling points on an elliptic curve. The algebraic calculations for these operations use the coordinates of the points and the parameter  a, but the parameter  b is not involved. If the cryptographic library does not check whether the input point belongs to the original curve, an attacker can pass a point belonging to a different curve (where  b' ≠ 7).

3. Cryptanalytic laws and key extraction

The attacker deliberately selects a “weak” curve whose order (the number of points) factorizes into small prime factors (a smooth order). When communicating with the server (for example, in the ECDH protocol), the server multiplies its private key by the transmitted malicious point. Using the Pohlig-Hellman algorithm, the attacker solves the discrete logarithm problem in small subgroups and then applies the Chinese Remainder Theorem (CRT) to fully recover the private key.

4. Historical examples

Archived incident:  Vulnerability CVE-2023-39910 in the libbitcoin library (Polycurve Extraction Attack). The library did not perform a full mathematical check to ensure that a point belonged to the secp256k1 curve. This allowed attackers to transmit “spurious” points and piecemeal recover the wallet’s private key, leading to theft of funds.

5. Examples of protective implementations (Checking for ownership)

Python (Pure Mathematics)

def is_valid_point(x, y, p):
    # Для secp256k1: y^2 = x^3 + 7 mod p
    return (y**2 % p) == ((x**3 + 7) % p)

SageMath

p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
K = GF(p)
E = EllipticCurve(K, [0, 7])
# Безопасная проверка: в SageMath P in E вернет True/False
def validate(P):
    return P in E

Magma

F := FiniteField(p);
E := EllipticCurve([F!0, F!7]);
// Проверка точки
isValid := P in E;

PARI/GP

E = ellinit([0,7]*Mod(1,p));
\ Проверка, лежит ли точка на кривой
isoncurve(P) = ellisoncurve(E, P);

1. Invalid Curve Attacks in libraries (e.g., CVE-2023-39910 in libbitcoin)

The security of most modern blockchain platforms, including Bitcoin, is based on the strength of the elliptic curve discrete logarithm problem (ECDLP). The  secp256k1 curve  ( y² = x³ + 7 (mod p) ) is the de facto standard for generating keys and signatures. However, even with a flawless mathematical foundation, implementations of cryptographic protocols can contain bugs that lead to catastrophic consequences. One such bug is the lack of verification that an input point actually belongs to a given curve, giving rise to a class of attacks known as  Invalid Curve Attacks . Despite being well-known, this vulnerability periodically surfaces in real libraries (for example, CVE-2023-39910 in libbitcoin).

The goal of this paper is not only to describe in detail the mathematical mechanics of the attack but also to provide the reader with reproducible code for Google Colab, clearly demonstrating each stage of the hack. This approach allows for a deep understanding of the nature of the vulnerability and the development of intuition for preventing it.

2. Mathematical foundations secp256k1

The elliptic curve  secp256k1  is defined over a prime field  𝔽 p , where

p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F

The equation of the curve is  y² ≡ x³ + 7 (mod p) , i.e. the parameters  a = 0 ,  b = 7. The group of points of the curve has prime order  n  (equal to the number of points), which makes it cryptographically secure.

The basic operations—point addition and doubling—use formulas that involve  x, y ,  and the parameter  a , but   not  b . This is the root of the problem: if a point doesn’t lie on the original curve (i.e., doesn’t satisfy the equation with the correct b ), the formulas will still produce a result that corresponds to some other curve with the same  a but a different  b’ . An attacker can choose  b’ , so that the order of the resulting curve is smooth (factorizable into small prime factors).

3. Mechanics of Invalid Curve Attack

3.1. The absence of the parameter  b  in addition formulas

Let two points  P = (x₁, y₁)  and  Q = (x₂, y₂) be given . Formulas for the sum  R = P + Q :

  • If  P ≠ Q :  λ = (y₂ − y₁) / (x₂ − x₁) ,  x₃ = λ² − x₁ − x₂ ,  y₃ = λ·(x₁ − x₃) − y₁ .
  • If  P = Q  (doubling):  λ = (3x₁² + a) / (2y₁) .

None of the formulas contain  b . Therefore, the result of the operations is correct for any curve of the form  y² = x³ + a x + b’,  provided that the points belong to this curve. The attacker can choose an arbitrary point  P and calculate b’ = y² − x³ − a x  for it  , obtaining “his” curve.

3.2 Weak Curve Selection and Smooth Ordering

The attacker seeks a curve  E’  with the same parameter  a but a different  b’ such that its order  n’  is  smooth  —it factorizes into small prime factors  n’ = ∏ q_i^{e_i} , where  q_i  are small (e.g., 2, 3, 5, 7, …). Then the discrete logarithm problem in  E’  can be solved modulo each  q_i  using the Pohlig–Hellman algorithm, which is computationally efficient.

3.3 The Pohlig–Hellman Algorithm and the Chinese Remainder Theorem (CRT)

Let the server (victim) have a private key  s . In an ECDH exchange, the server receives a point  P  from the attacker, computes  Q = s P  , and returns  Q . If  P  belongs to a weak curve  E’  with a smooth order, then  Q  also lies on  E’ . The attacker solves  Q = s P  with respect to  s  in the group  E’ . Since the order of  P  (denoted  m ) is a divisor  of n’  and therefore smooth, the discrete logarithm is quickly found. As a result, the attacker obtains  s mod m . Repeating the operation with different points whose orders are pairwise coprime numbers, he accumulates a system of comparisons and, using the CRT,   completely reconstructs s ​​.

4. Hands-on demonstration in Google Colab

To reproduce the attack, we use the Google Colab environment with the  SageMath library installed , which provides powerful tools for working with elliptic curves and discrete logarithms. The code below can be copied into Colab cells and executed sequentially.

4.1. Installation and configuration

# Установка SageMath в Colab
!pip install sage==10.3

After installation, import the required modules and set the secp256k1 curve parameters.

from sage.all import *

# Параметры secp256k1
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
a = 0
b = 7
K = GF(p)
E = EllipticCurve(K, [a, b])
n = E.order()  # порядок (большое простое)
# Генераторная точка G (из стандарта)
Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
G = E(Gx, Gy)

# Секретный ключ (жертвы)
s = randint(1, n-1)
print("Приватный ключ (не должен быть известен атакующему):", s)

4.2. Weak curve generation and point selection

An attacker might try to choose the parameter  b’  such that the order of the curve  E’  is smooth. In Sage, this is done by trying small  b’s  and checking the order factorization. However, in reality, finding a suitable curve for a 256-bit field is computationally difficult, but known weak curves exist. For demonstration purposes, we can take a known weak curve of small order, for example,  b’ = 6 , whose order contains small factors. To simplify the example, we will choose a curve with an order that has a small prime factor and find a point of this order.

# Выбираем b' для атаки
b_prime = 6
E_prime = EllipticCurve(K, [a, b_prime])
order_prime = E_prime.order()
print("Порядок слабой кривой:", factor(order_prime))

# Ищем точку малого порядка (например, порядка 2)
P = E_prime.lift_x(0)  # находим точку с x=0, если она есть
if P == E_prime(0):
    print("Точка с x=0 не найдена, ищем другую")
    # Просто берём генератор и умножаем на порядок/2, чтобы получить точку порядка 2
    gen = E_prime.gens()[0]
    P = gen * (order_prime // 2)  # порядок P = 2 (если 2 делит order_prime)
print("Точка P:", P)
print("Порядок P:", P.order())

4.3. Conducting the attack (obtaining the remainder modulo order P)

The victim (server) receives a point  P  and computes  Q = s P . The attacker intercepts  Q  and solves the discrete logarithm  Q = k P  on the weak curve, obtaining  k ≡ s (mod m) , where  m = ord(P) .

# Жертва вычисляет Q
Q = s * P
print("Q = s*P:", Q)

# Атакующий решает дискретный логарифм на слабой кривой
k = discrete_log(Q, P, operation='+')
print("Найденный остаток k = s mod m:", k)
print("Проверка: s mod m =", s % P.order())

4.4 Collection of multiple residues and CRT application

To recover the full key, we need to obtain comparisons across several relatively prime moduli. For example, we’ll find points of order 3, 5, 7, and so on. In the code below, we automate the search for points with small prime orders on the same weak curve (or on several).

# Ищем точки с порядками 3,5,7 на E_prime (если такие есть)
small_primes = [3, 5, 7]
residues = []
moduli = []

for q in small_primes:
    # Ищем точку порядка q (если q делит order_prime)
    if order_prime % q == 0:
        # Берём генератор и умножаем на order_prime // q
        gen = E_prime.gens()[0]
        Pq = gen * (order_prime // q)
        if Pq.order() == q:
            # Жертва вычисляет Qq = s*Pq
            Qq = s * Pq
            # Атакующий решает логарифм
            kq = discrete_log(Qq, Pq, operation='+')
            residues.append(kq)
            moduli.append(q)
            print(f"Порядок {q}: остаток {kq}")
        else:
            print(f"Не удалось найти точку порядка {q}")
    else:
        print(f"Порядок слабой кривой не кратен {q}")

# Китайская теорема об остатках
s_recovered = CRT_list(residues, moduli)
print("Восстановленный ключ (по модулю произведения):", s_recovered)
print("Реальный ключ:", s)
# Проверяем, что восстановленный ключ совпадает с реальным по модулю произведения
M = prod(moduli)
print("Совпадение:", s % M == s_recovered)

For full recovery, the product of the moduli must exceed  n  (the order of the original curve). In practice, the attacker uses a set of points with smooth orders whose product is sufficiently large.

4.5. Protection: checking whether a point belongs to a curve

The simplest and most effective defense is to always check that the resulting point satisfies the equation of the original curve. In code, this looks like this:

def is_valid_point(x, y):
    return (y^2 - (x^3 + a*x + b)) % p == 0

# Пример проверки
P_valid = E(1, 2)  # подставьте реальные координаты
if is_valid_point(P_valid[0], P_valid[1]):
    print("Точка корректна, можно выполнять умножение")
else:
    print("Точка не принадлежит кривой, отклоняем!")

If such a check is built into the library, the attack becomes impossible.

5. Real-life incidents (CVE-2023-39910)

Archived incident: The CVE-2023-39910  vulnerability   in the libbitcoin library (Polycurve Extraction Attack) was discovered in 2023. The library did not check whether a point belonged to the secp256k1 curve, allowing attackers to pass “spurious” points and piecemeal recover the private key. This could have resulted in thefts of tens of millions of dollars. The issue was fixed by adding a check  ec_validate.

6. Recommendations for protection

  • Always check the validity of a point  before any scalar operations. This should include the curve equation and, possibly, membership in the correct subgroup (if the order is composite).
  • Use proven cryptographic libraries  (e.g. OpenSSL, libsecp256k1) that already contain protection against Invalid Curve.
  • When implementing your own protocols,  do not rely on “implicit trust” in input data.
  • Periodically audit your code  for missing validation.

Appendix: Complete code for Google Colab (single block)

Below is the complete code that can be copied into a single Colab cell and executed.

# Установка SageMath (если ещё не установлен)
!pip install sage==10.3

from sage.all import *

# Параметры secp256k1
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
a = 0
b = 7
K = GF(p)
E = EllipticCurve(K, [a, b])
n = E.order()

Gx = 0x79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798
Gy = 0x483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8
G = E(Gx, Gy)

# Секретный ключ жертвы
s = randint(1, n-1)
print("Приватный ключ s =", s)

# ---- Атака ----
# Выбираем слабую кривую с b' = 6 (для демонстрации)
b_prime = 6
E_prime = EllipticCurve(K, [a, b_prime])
order_prime = E_prime.order()
print("Порядок E':", factor(order_prime))

# Собираем точки малых порядков
small_primes = [2, 3, 5, 7, 11, 13]  # можно добавить больше
residues = []
moduli = []

for q in small_primes:
    if order_prime % q == 0:
        gen = E_prime.gens()[0]
        Pq = gen * (order_prime // q)
        if Pq.order() == q:
            Qq = s * Pq
            kq = discrete_log(Qq, Pq, operation='+')
            residues.append(kq)
            moduli.append(q)
            print(f"Порядок {q}: остаток {kq}")
        else:
            # Пробуем найти другую точку порядка q
            # Можно перебрать все точки, но для демонстрации пропустим
            print(f"Не удалось найти точку порядка {q}")
    else:
        print(f"Порядок E' не кратен {q}, пропускаем")

if residues:
    M = prod(moduli)
    s_recovered = CRT_list(residues, moduli)
    print("\nВосстановленный ключ по модулю M =", M, ":", s_recovered)
    print("Реальный ключ s =", s)
    print("Совпадает с s mod M:", s % M == s_recovered)
else:
    print("Не удалось найти ни одной точки малого порядка.")

# Проверка валидности точки (защита)
def is_valid_point(x, y):
    return (y^2 - (x^3 + a*x + b)) % p == 0

# Тест на валидной точке
test_x = Gx
test_y = Gy
print("Точка G валидна?", is_valid_point(test_x, test_y))  # True
# Тест на точке с другой кривой
P_attack = E_prime.gens()[0]
print("Точка с b'=6 валидна на secp256k1?", is_valid_point(P_attack[0], P_attack[1]))  # False

Conclusion

The invalid curve attack is a prime example of how neglecting mathematical validation of input data can undermine the security of asymmetric cryptography. Strict equation verification  y^2 = x^3 + 7 (mod p) before any scalar multiplications is a mandatory security standard for blockchain networks.

The invalid curve attack is a classic example of how a subtle mathematical detail (the missing parameter  b  in the addition formulas) can, if implemented carelessly, lead to complete compromise of a private key. We demonstrated the attack mechanism both theoretically and using reproducible code in Google Colab, allowing any researcher to gain a deeper understanding of the vulnerability. It is critical to implement point verification at all stages of elliptic curve protocols.

In the future, we plan to extend the analysis to cases where curves with composite order are used (e.g., in some cryptocurrencies) and explore countermeasures based on isogenies and twists.

List of references

  1. DJ Bernstein, T. Lange. “SafeCurves: choosing safe curves for elliptic-curve cryptography.”
  2. NP Smart. “The Hessian form of an elliptic curve”.
  3. M. Joye, S. M. Yen. “The Montgomery powering ladder.”
  4. CVE-2023-39910:  https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2023-39910
  5. Bitcoin Wiki: secp256k1.