#elliptic-curve #curve #elliptic #schnorr-signature #schnorr #k256

bin+lib secp

A flexible and secure secp256k1 elliptic curve math library with constant-time support and superb ergonomics

17 unstable releases (4 breaking)

0.4.1 Nov 1, 2024
0.3.0 Jul 6, 2024
0.2.3 Mar 16, 2024
0.2.0 Nov 25, 2023

#188 in Cryptography

Download history 196/week @ 2024-07-23 216/week @ 2024-07-30 313/week @ 2024-08-06 351/week @ 2024-08-13 454/week @ 2024-08-20 593/week @ 2024-08-27 349/week @ 2024-09-03 439/week @ 2024-09-10 808/week @ 2024-09-17 632/week @ 2024-09-24 760/week @ 2024-10-01 795/week @ 2024-10-08 1176/week @ 2024-10-15 1671/week @ 2024-10-22 980/week @ 2024-10-29 698/week @ 2024-11-05

4,683 downloads per month
Used in 3 crates

Unlicense

175KB
3K SLoC

secp

A flexible and secure secp256k1 elliptic curve math library, with constant-time support, and superb ergonomics.

secp takes full advantage of Rust's std::ops traits to make elliptic curve cryptography code easy to read, easy to write, succinct, readable, and secure.

Example

Here's an implementation of simple Schnorr signatures using the secp crate.

use secp::{MaybeScalar, Point, Scalar};
use sha2::{Digest, Sha256};

fn compute_challenge(nonce_point: &Point, pubkey: &Point, msg: &[u8]) -> MaybeScalar {
    let hash: [u8; 32] = Sha256::new()
        .chain_update(&nonce_point.serialize())
        .chain_update(&pubkey.serialize())
        .chain_update(msg)
        .finalize()
        .into();
    MaybeScalar::reduce_from(&hash)
}

fn random_scalar() -> Scalar {
    // In an actual implementation this would produce a scalar value
    // sampled from a CSPRNG.
    Scalar::two()
}

fn schnorr_sign(secret_key: Scalar, message: &[u8]) -> (Point, MaybeScalar) {
    let nonce = random_scalar();
    let nonce_point = nonce.base_point_mul();
    let pubkey = secret_key.base_point_mul();

    let e = compute_challenge(&nonce_point, &pubkey, message);
    let s = nonce + secret_key * e;
    (nonce_point, s)
}

fn schnorr_verify(public_key: Point, signature: (Point, MaybeScalar), message: &[u8]) -> bool {
    let (r, s) = signature;
    let e = compute_challenge(&r, &public_key, message);
    s.base_point_mul() == r + e * public_key
}

let secret_key: Scalar = "0123456789abcdef0123456789abcdef0123456789abcdef0123456789abcdef"
    .parse()
    .unwrap();
let public_key = secret_key.base_point_mul();

let message = b"I am the dragon!";

let signature = schnorr_sign(secret_key, message);
assert!(schnorr_verify(public_key, signature, message));

Choice of Backbone

This crate does not implement elliptic curve point math directly. Instead we depend on one of two reputable elliptic curve cryptography libraries:

One or the other can be used. By default, this crate prefers to rely on libsecp256k1, as this is the most vetted and publicly trusted implementation of secp256k1 curve math available anywhere. However, if you need a pure-rust implementation, you can install this crate without it, and use the pure-rust k256 crate instead.

cargo add secp --no-default-features --features k256

If both k256 and secp256k1 features are enabled, then we default to using libsecp256k1 bindings for the actual math, but still provide trait implementations to make this crate interoperable with k256.

Documentation

To see the API documentation, head on over to docs.rs.

CLI

This crate also offers a CLI tool for computing secp256k1 curve operations in your shell. Build it with make cli. A binary will be built at target/release/secp.

Usage:

-- Scalar operations --
  secp scalar gen                           Generate a random scalar.
  secp scalar add <scalar> [<scalar>...]    Sum two or more scalars.
  secp scalar mul <scalar> [<scalar>...]    Multiply two or more scalars.
  secp scalar inv <scalar>                  Multiplicative inverse of a scalar mod n.

-- Point operations --
  secp scalar gen                           Generate a random point.
  secp point add <point> [<point>...]       Sum two or more points.
  secp point mul <point> [<scalar>...]      Multiply a point by one or more scalars.

-- Formats --

Points are represented in 65-byte compressed hex format. Example:

  02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

Scalars are represented in 32-byte hex format. Example:

  e8c23ee3c98e040adea5dc92c5c381d6be93615f289ec2d505909657368a0c8f

Prepending a minus sign '-' in front of a point or scalar will negate it. Example:

  -02eeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeeee

-- Special values --

- The values '0', '1', or '-1' may be substituted for any scalar.
- The value 'G' may be substituted for any point to represent the secp256k1 base point.
- The value '0' may be substituted for any point to represent the additive identity point (infinity).

Example usage:

s1=`secp scalar gen`
s2=`secp scalar gen`
p1=`secp point mul G $s1`
p2=`secp point mul G $s2`
p3=`secp point add $p1 $p2`
p4=`secp point add $p1 -$p2`

Dependencies

~8.5MB
~111K SLoC