Module crrl::secp256k1

source ·
Expand description

secp256k1 curve implementation.

This module implements generic group operations on the secp256k1 elliptic curve, a short Weierstraß curve with equation y^2 = x^3 + 7. This curve is standardized in SEC 2.

The curve has prime order. “Scalars” are integers modulo that prime order, and are implemented by the Scalar structure. This structure supports the usual arithmetic operators (+, -, *, /, and the compound assignments +=, -=, *= and /=).

A point on the curve is represented by the Point structure. The additive arithmetic operators can be applied on Point instances (+, -, +=, -=); multiplications by an integer (u64 type) or by a scalar (Scalar type) are also supported with the * and *= operators. Point doublings can be performed with the double() function (which is somewhat faster than general addition), and additional optimizations are obtained in the context of multiple successive doublings by calling the xdouble() function. All these operations are implemented with fully constant-time code and are complete, i.e. they work with all points, even when adding a point with itself or when operations involve the curve point-at-infinity (the neutral element for the curve as a group).

Scalars can be encoded over 32 bytes, using unsigned little-endian convention) and decoded back. Encoding is always canonical, and decoding always verifies that the value is indeed in the canonical range. Take care that many standards related to secp256k1 tend to use big-endian for encoding scalars (and often use a variable-length encoding, e.g. an ASN.1 INTEGER).

Points can be encoded in compressed (33 bytes) or uncompressed (65 bytes) formats. These formats internally use big-endian. The nominal encoding of the point-at-infinity is a single byte of value 0x00; the encode_compressed() and encode_uncompressed() functions cannot produce that specific encoding (since they produce fixed-length outputs), and instead yield a sequence of 33 or 65 zeros in that case. Point decoding accepts compressed and uncompressed formats, and also the one-byte encoding of the point-at-infinity, but they do not accept a sequence of 33 or 65 zeros as a valid input. Thus, point decoding is stricly standards-conforming. All decoding operations enforce canonicality of encoding, and verify that the point is indeed on the curve.

The PrivateKey structure represents a private key for the ECDSA signature algorithm; it is basically a wrapper around a private scalar value. The PrivateKey::encode() and PrivateKey::decode() functions encode a private key to exactly 32 bytes, and decode it back, this time using unsigned big-endian, as per SEC 1 encoding rules (which represents private keys with the ASN.1 OCTET STRING type). The PrivateKey::from_seed() allows generating a private key from a source seed, which is presumed to have been obtained from a cryptographically secure random source.

The PublicKey structure represents a public key for the ECDSA signature algorithm; it is a wrapper around a Point. It has its own decode(), encode_compressed() and encode_uncompressed() which only wrap around the corresponding Point functions, except that decode() explicitly rejects the point-at-infinity: an ECDSA public key is never the identity point.

ECDSA signatures are generated with PrivateKey::sign_hash(), and verified with PublicKey::verify_hash(). The signature process is deterministic, using the SHA-256 function, following the description in RFC 6979. The caller is provides the pre-hashed message (normally, this hashing uses SHA-256, but the functions accept hash values of any length). In this implementation, the ECDSA signatures follow the non-ASN.1 format: the two r and s halves of the signature are encoded in unsigned big-endian format and concatenated, in that order. When generating a signature, exactly 32 bytes are used for each of r and s, so the signature has length 64 bytes exactly. When verifying a signature, any input size is accepted provided that it is even (so that it is unambiguous where r stops and s starts), and that the two r and s values are still in the proper range (i.e. lower than the curve order).

Structs

  • A point on the short Weierstraß curve secp256k1.
  • A secp256k1 private key simply wraps around a scalar.
  • A secp256k1 public key simply wraps around a curve point.

Type Definitions

  • Integers modulo the curve order n (a 256-bit prime).