README.md

# Curvy

![Curvy](https://github.com/libitx/curvy/raw/master/media/poster.png)

![Hex.pm](https://img.shields.io/hexpm/v/curvy?color=informational)
![License](https://img.shields.io/github/license/libitx/curvy?color=informational)
![Build Status](https://img.shields.io/github/workflow/status/libitx/curvy/Elixir%20CI)

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](https://tools.ietf.org/html/rfc6979)
* 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`.

```elixir
def deps do
  [
    {:curvy, "~> 0.2"}
  ]
end
```

## Usage

For further examples, refer to the [full documentation](https://hexdocs.pm/curvy).

### 1. Key generation

Create random ECDSA keypairs.

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

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

```elixir
iex> Curvy.Key.to_privkey(key)
<<privkey::binery-size(32)>>

iex> Curvy.Key.to_pubkey(key)
<<privkey::binary-size(33)>>

iex> Curvy.Key.to_pubkey(key, compressed: false)
<<privkey::binary-size(65)>>
```

### 2. Sign messages

Sign arbitrary messages with a private key. Signatures are deterministic as per [RFC 6979](https://tools.ietf.org/html/rfc6979).

```elixir
iex> sig = Curvy.sign("hello", key)
<<sig::binary-size(71)>>

iex> sig = Curvy.sign("hello", compact: true)
<<sig::binary-size(65)>>

iex> sig = Curvy.sign("hello", compact: true, encoding: :base64)
"IEnXUDXZ3aghwXaq1zu9ax2zJj7N+O4gGREmWBmrldwrIb9B7QuicjwPrrv3ocPpxYO7uCxcw+DR/FcHR9b/YjM="
```

### 3. Verify signatures

Verify a signature against the message and a public key.

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

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

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

### 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.

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

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

```elixir
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
true
```

### 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.

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



For more examples, refer to the [full documentation](https://hexdocs.pm/curvy).

## 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`](https://hex.pm/packages/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](https://github.com/paulmillr/noble-secp256k1) - JS
* [starbank-ecdsa](https://github.com/starkbank/ecdsa-elixir) - Elixir
* [bsv](https://github.com/moneybutton/bsv) - JS

## License

Txpost is open source and released under the [Apache-2 License](https://github.com/libitx/curvy/blob/master/LICENSE).

© Copyright 2021 [Chronos Labs Ltd](https://www.chronoslabs.net).