# Curvy


![Build Status](

Signatures and Bitcoin flavoured crypto written in pure Elixir. Curvy is an implementation of `secp256k1`, an elliptic curve that can be used in signature schemes, asymmetric encryption and ECDH shared secrets.

## Highlights

* Pure Elixir implementation of `secp256k1` - no external dependencies
* Fast ECDSA cryptography using Jacobian Point mathematics
* Supports deterministic ECDSA signatures as per [RFC 6979](
* Securely generate random ECDSA keypairs
* Compute ECDH shared secrets

## Installation

The package can be installed by adding `curvy` to your list of dependencies in `mix.exs`.

def deps do
    {:curvy, "~> 0.3"}

## Usage

For further examples, refer to the [full documentation](

### 1. Key generation

Create random ECDSA keypairs.

iex> key = Curvy.generate_key()
  crv: :secp256k1,
  point: %Curvy.Point{},
  private_key: <<>>

ECDSA Keypairs can by converted to public and private key binaries.

iex> Curvy.Key.to_privkey(key)

iex> Curvy.Key.to_pubkey(key)

iex> Curvy.Key.to_pubkey(key, compressed: false)

### 2. Sign messages

Sign arbitrary messages with a private key. Signatures are deterministic as per [RFC 6979](

iex> sig = Curvy.sign("hello", key)

iex> sig = Curvy.sign("hello", compact: true)

iex> sig = Curvy.sign("hello", compact: true, encoding: :base64)

### 3. Verify signatures

Verify a signature against the message and a public key.

iex> sig = Curvy.verify(sig, "hello", key)

iex> sig = Curvy.verify(sig, "hello", wrongkey)

# Returns :error if the signature cannot be decoded
iex> sig = Curvy.verify("notasig", "hello", key)

### 4. Recover the public key from a signature

It's possible to recover the public key from a compact signature when given
with the signed message.

iex> sig = Curvy.sign("hello", key, compact: true)
iex> recovered = Curvy.recover_key(sig, "hello")
iex> recovered.point == key.point

The same can be done with DER encoded signatures if the recovery ID is known.

iex> {sig, recovery_id} = Curvy.sign("hello", key, recovery: true)
iex> recovered = Curvy.recover_key(sig, "hello", recovery_id: recovery_id)
iex> recovered.point == key.point

### 5. ECDH shared secrets

ECDH shared secrets are computed by multiplying a public key with a private
key. The operation yields the same result in both directions.

iex> s1 = Curvy.get_shared_secret(key1, key2)
iex> s2 = Curvy.get_shared_secret(key2, key1)
iex> s1 == s2

For more examples, refer to the [full documentation](

## Disclaimer

The are many warnings that you should never try to implement well-known (and known to be secure) crypto algorithms yourself. Well guess what, that's exactly what I've done here. I am **not** a cryptographer nor a mathmetician. Proceed at your own risk. If you're after the most performant and battle tested Bitcoin library, use the [`libsecp256k1`]( NIF bindings.

This library offers a simpler and smaller interface for common functionality. Being writting purely in Elixir without any dependencies, it is a lighter-weight option without the compilation complexities NIF bindings may bring.

I am grateful to the authors of the following open source libraries I have referred to extensively in creating this library:

* [noble-secp256k1]( - JS
* [starbank-ecdsa]( - Elixir
* [bsv]( - JS

## License

Curvy is open source and released under the [Apache-2 License](

© Copyright 2021 [Chronos Labs Ltd](