Skip to content

julia

From Curve to Signature: A Hands-on Guide to ECDSA

ECDSA operates on elliptic curve groups over finite fields.
In the most common form, the curve is defined by the Weierstrass equation:\(E(\mathbb{F}_p):\; y^2 \equiv x^3 + ax + b \pmod p,\) where \(a, b\) are curve parameters and \(p\) is a prime defining the field \(\mathbb{F}_p\). In production systems, the curve is fixed by cryptographers β€” for example, secp256k1 in Ethereum β€” but nothing prevents you from experimenting with your own, especially for learning, prototyping, or testing with small primes.

Generate a toy Weierstrass curve

This example searches for a curve over primes \(\pi \in (97,103)\), with parameters \(a \in (10,15)\), \(b \in (2,7)\). It selects the first candidate that is non-singular, whose group of points has prime order, and that admits a generator spanning the group.

using TinyCrypto

curve = Weierstrass(97:103, 10:15, 2:7)
Weierstrass{𝔽₉₇}: yΒ² = xΒ³ + 10x + 3 | 𝔾(0,10), q = 101, h = 1, #E = 101
Here, \(q\) is the order of the generator \(\mathbb{G} (0𝔽₉₇,10𝔽₉₇)\), \(h\) the cofactor, and \(\#E = q \cdot h\) the total number of points on the curve.

Sign a Message (ECDSA)
priv, pub = genkey(curve)             # Generate private/public key pair
msg = "hello ethereum"                # The message to sign
signature = sign(curve, priv, msg)    # β†’ (r, s, v)

The result is a NamedTuple:

(r = ..., s = ..., v = ...)

Here, \((r,s)\) are the ECDSA signature scalars, and \(v\) is the recovery identifier β€” letting you reconstruct the signer’s public key from the signature and message alone. This is exactly how Ethereum transactions prove authenticity without revealing the private key.

Verify the Signature
is_valid = verify(curve, pub, signature, msg)
@assert is_valid

Verification checks that the signature \((r,s)\) was produced with the private key corresponding to the public key pub, on the exact message msg. If the check passes, you know the message is authentic and unaltered β€” the essence of digital signatures in action.

Recover the Public Key (like Ethereum)
recovered = ecrecover(curve, msg, signature)
@assert pub == recovered

ECDSA with recovery adds a small extra bit \(v\) to the signature, making it possible to reconstruct the signer’s public key directly from (msg, signature). This is how Ethereum avoids shipping full public keys inside every transaction: the network can derive them on the fly, saving space while still proving who signed what.

Summary

TinyCrypto.jl makes it easy to:

  • Define toy elliptic curves over small prime fields
  • Generate key pairs and sign messages with ECDSA
  • Verify signatures to ensure authenticity and integrity
  • Recover public keys from signatures (Γ  la Ethereum)

Perfect for learning, prototyping, or experimenting with elliptic curve cryptography β€” without the overhead of production-grade libraries.

πŸ”— Source code on GitHub