Implementing curve agnostic Elliptic Curve Signatures from scratch in Rust

If Bob wants to talk to Alice over an insecure channel, can he guarantee the messages come from her? The answer is yes, one method for achieving this is the Elliptic Curve Digital Signature Algorithm (ECDSA). In the modern day, ECDSA is used in a variety of applications to ensure the integrity of messages passed over insecure channels, including Bitcoin, and Ethereum. This is a post on building a rust implementation of ECDSA over finite fields of order p, where the underlying curve is an arbitrary specified elliptic curve. Very little high level maths is assumed, and the content should be fairly accessible to people with little prior maths knowledge. It is not a rigorous treatment of elliptic curves in general, and the code provided is not guaranteed to be cryptographically secure.

We will cover 3 sections, finite fields, elliptic curves, and finally ECDSA. Each section inherits from the previous, the objects’ implementations are provided and explained in situ with their maths.

Finite Fields

Before we can go on, understanding the rest of this blog hinges on “fields”, these are a set of objects where you can do basic operations like adding, subtracting, multiplying, and dividing, and these operations behave in the way you expect.

Fields in general

A Field is a set of “elements” that are endowed with two associated “relations” (+,)(+, \bullet) these operations act as one would expect (addition and multiplication on the real numbers).

These operations also follow a couple of “nice” rules

Fields mod p

The specific type of field that we will consider here will be Fp\F_p, where pp is a prime number, the set of numbers we consider is {0,1,2,,p1}\{0,1,2, \ldots\,, p-1\}, and (+,)(+, \bullet) work like normal addition but “wrap around” at pp. This keeps all our numbers inside our set. A clock gives is a good way to imagine this. On a 12-hour clock:

This is similar to how mod p works, but instead of wrapping around after 12, we wrap around after p , which is any prime number (e.g., 5, 7, 11). We will go over inverses in Fp\F_p later, when we implement an inverse_modp function.