This content originally appeared on DEV Community and was authored by 0xMouiz
Intro
Elliptic curve cryptography (ECC) powers the security of Bitcoin, Ethereum, and countless secure systems.
One of the most famous curves, secp256k1, is the backbone of Bitcoin addresses and Ethereum keys.
While libraries like secp256k1 and ecdsa abstract away the math, building it yourself is a great way to understand how elliptic curves and ECDSA signatures work.
In this post, we’ll walk through my minimal Python implementation of secp256k1 — covering:
- The math behind the curve
- Point addition, doubling, and scalar multiplication
- Private/public key generation
- ECDSA signing and verification with Keccak-256
1. What is secp256k1?
secp256k1 is a Koblitz curve defined over a finite field. Its equation is:
y² ≡ x³ + 7 (mod p)
Where:
- p is a large prime
- a=0, b=7
- G is the generator point
- n is the order of the curve
- It’s used in Bitcoin, Ethereum, and other blockchain systems because it offers strong security and fast computation.
2. Implementing the Curve
We start with a Point class for elliptic curve points, supporting:
- Addition (P+Q)
- Doubling (2P)
- Scalar multiplication (kP)
class Point:
def __add__(self, other):
if self.is_at_infinity():
return other
if other.is_at_infinity():
return self
if self == other:
return self.double()
if self.x == other.x and (self.y + other.y) % self.curve.p == 0:
return Point(None, None, self.curve) # point at infinity
s = ((other.y - self.y) * pow(other.x - self.x, -1, self.curve.p)) % self.curve.p
x_r = (s**2 - self.x - other.x) % self.curve.p
y_r = (s * (self.x - x_r) - self.y) % self.curve.p
return Point(x_r, y_r, self.curve)
The Curve class enforces the curve equation and provides helper methods like _tangent_slope _for doubling.
3. secp256k1 Parameters
We define the constants exactly as per the official specification:
p = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F
a = 0
b = 7
Gx = 0x79BE66...
Gy = 0x483ADA...
n = 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141
h = 1
curve = Curve(a, b, p, n, h, Gx, Gy, "secp256k1")
4. Key Generation
Private key: random integer in [1,n−1]
Public key: priv × G
5. ECDSA Signing
We use Keccak-256 for hashing (Ethereum’s choice) and the standard ECDSA formula:
def sign(msg, private_key):
z = int.from_bytes(keccak256(msg), "big")
while True:
k = secrets.randbelow(curve.n)
R = k * curve.G
r = R.x % curve.n
s = (modinv(k, curve.n) * (z + r * private_key)) % curve.n
if r != 0 and s != 0:
return (r, s)
6. ECDSA Verification
The verifier computes:
u1 = z × w
u2 = r × w
P = u1 × G + u2 × Q
Valid if Px mod n = r
7. Demo Run
python3 main.py
Example output:
[+] Private key: 0x1393b6573adf24c61b73561768d9ea4ba1670dcc77554f25938cbca621ed7645
[+] Public key: 0475ca8eaf8393...
[+] Signature: (2313066..., 8090080...)
[+] Signature valid? True
8. Why This Matters
This code is not for production — it’s educational.
It shows exactly how:
- Bitcoin addresses are derived
- Ethereum signs transactions
- ECDSA math works without relying on “magic” library calls
9. Full Source Code
https://github.com/0xMouiz/python-secp256k1
This content originally appeared on DEV Community and was authored by 0xMouiz