Curvy (Curvy v0.3.0) View Source
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.0"}
]
end
Usage
1. Key generation
Create random ECDSA keypairs.
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.
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.
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.
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.
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.
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.
iex> s1 = Curvy.get_shared_secret(key1, key2)
iex> s2 = Curvy.get_shared_secret(key2, key1)
iex> s1 == s2
true
Link to this section Summary
Functions
Creates a new random ESCDA keypair.
Computes an ECDH shared secret from the first given key's private key and the second's public key.
Recovers the public key from the signature and signed message.
Signs the message with the given private key.
Verifies the signature against the given message and public key.
Link to this section Functions
Specs
generate_key() :: Curvy.Key.t()
Creates a new random ESCDA keypair.
Specs
recover_key(Curvy.Signature.t() | binary(), binary(), keyword()) :: Curvy.Key.t() | :error
Recovers the public key from the signature and signed message.
Returns an ECDSA Keypair
struct, without the privkey value.
If recovering fom a DER encoded signature, the Recovery ID
returned from Curvy.sign(msg, key, recovery: true)
must be passed as an
option. If recovering from a compact signature the recovery ID is already
encoded in the signature.
Accepted options
:encoding
- Optionally decode the given signature as:base64
or:hex
.:hash
- Digest algorithm to hash the message with. Default is:sha256
.:recovery_id
- The signatureRecovery ID
.
Specs
sign(binary(), Curvy.Key.t() | binary(), keyword()) :: binary()
Signs the message with the given private key.
Returns a DER encoded or compact signature binary.
Accepted options
:hash
- Digest algorithm to hash the message with. Default is:sha256
.:normalize
- Normalize the signature by enforcing low-S. Default istrue
.:compact
- Return a compact 65 byte signature. Default isfalse
.:encoding
- Optionally encode the returned signature as:base64
or:hex
.:recovery
- Return the signature in a tuple paired with a recovery ID. Default isfalse
.:k
- Optionally provide a signing secretK
value, as a 256 bit integer or binary.
Specs
verify( Curvy.Signature.t() | binary(), binary(), Curvy.Key.t() | binary(), keyword() ) :: boolean() | :error
Verifies the signature against the given message and public key.
Returns a boolean.
Accepted options
:encoding
- Optionally decode the given signature as:base64
or:hex
.:hash
- Digest algorithm to hash the message with. Default is:sha256
.