View Source Eddy (Eddy v1.0.0)

Curvy

License

Meet Eddy! A steady little Ed25519 library for Elixir. Ed25519 is an elliptic curve that can be used in signature schemes and ECDH shared secrets.

highlights

Highlights

  • Pure Elixir implementation of Ed25519 (no external dependencies)
  • Secure generation of EdDSA key pairs
  • Ed25519 signature schemes
  • X25519 (ECDH) shared secrets
  • Build your own crypto - customisable hash algo

instalation

Instalation

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

def deps do
  [
    {:eddy, "~> 1.0.0"}
  ]
end

quick-start

Quick start

1-key-generation

1. Key generation

Generate new EdDSA keypairs.

iex> privkey = Eddy.generate_key()
%Eddy.PrivKey{}

iex> pubkey = Eddy.get_pubkey(privkey)
%Eddy.PubKey{}

2-sign-messages

2. Sign messages

Sign messages with a private key.

iex> sig = Eddy.sign("test", privkey)
%Eddy.Sig{}

3-verify-messages

3. Verify messages

Verify a signature against the message and a public key.

iex> Eddy.verify(sig, "test", pubkey)
true

iex> Eddy.verify(sig, "test", wrong_pubkey)
false

4-x25519-shared-secrets

4. X25519 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 = Eddy.get_shared_secret(priv_a, pubkey_b)
iex> s2 = Eddy.get_shared_secret(priv_b, pubkey_a)
iex> s1 == s2
true

custom-hash-function

Custom hash function

As per the rfc8032 spec, by default Eddy uses the sha512 hash function internally. Optionally, a custom hash function can be configured in your application's config/config.exs.

The custom hash function must return 64 bytes.

import Config

# The hash function will be invoked as `:crypto.hash(:sha3_512, payload)`
config :eddy, hash_fn: {:crypto, :hash, [:sha3_512], []}

# The hash function will be invoked as `B3.hash(payload, length: 64)`
config :eddy, hash_fn: {B3, :hash, [], [[length: 64]]}

Link to this section Summary

Types

Binary encoding format.

Private Key.

Public Key.

Signature.

Functions

Generates a new random private key.

Takes a private key and returns the corresponding public key.

Computes an ECDH shared secret from the given private and public keys.

Returns the Ed25519 elliptic curve parameters.

Signs the message with the given private key.

Verifies the signature against the given message and public key. Returns a boolean or error tuple.

Link to this section Types

@type encoding() :: :raw | :base16 | :base64 | :hex

Binary encoding format.

Eddy can encoding keys and signatures in raw, base16 or base64 encodings. Hex is as base16, but with lower case letters.

@type privkey() :: Eddy.PrivKey.t() | binary()

Private Key.

Are represented as PrivKey structs or 32 byte binaries.

@type pubkey() :: Eddy.PubKey.t() | binary()

Public Key.

Are represented as PubKey structs or 32 byte binaries.

@type sig() :: Eddy.Sig.t() | binary()

Signature.

Are represented as Sig structs or 64 byte binaries.

Link to this section Functions

Link to this function

generate_key(opts \\ [])

View Source
@spec generate_key(keyword()) :: privkey()

Generates a new random private key.

The private key can optionally be returned as a raw or encoded binary.

options

Options

  • :encoding - Optionally encode with a binary encoding/0.

examples

Examples

iex> privkey = Eddy.generate_key()
%Eddy.PrivKey{}

iex> privkey = Eddy.generate_key(encoding: :raw)
<<182, 7, 194, 105, 23, 114, 238, 195, 188, 101, 41, 99, 155, 2, 174, 52, 187,
235, 72, 4, 221, 189, 111, 49, 33, 240, 224, 53, 161, 77, 253, 50>>

iex> privkey = Eddy.generate_key(encoding: :hex)
"3056ade0bc0215aa21db1dfddd3ea6786a4127b28efddb7e9b6af9845b8ef57a"
Link to this function

get_pubkey(privkey, opts \\ [])

View Source
@spec get_pubkey(
  privkey(),
  keyword()
) :: pubkey()

Takes a private key and returns the corresponding public key.

Acceps a private key struct or raw binary. The public key can optionally be returned as a raw or encoded binary.

options

Options

  • :encoding - Optionally encode with a binary encoding/0.

examples

Examples

iex> pubkey = Eddy.get_pubkey(privkey)
%Eddy.PubKey{}

iex> pubkey = Eddy.get_pubkey(privkey, encoding: :hex)
"9dcfaa3dca4a02da72c500885dd6824a7c9abb76b88f9e3f10378f33c56d2465"
Link to this function

get_shared_secret(privkey, pubkey, opts \\ [])

View Source
@spec get_shared_secret(privkey(), pubkey(), keyword()) :: binary()

Computes an ECDH shared secret from the given private and public keys.

Acceps both keys as structs or raw binaries. Returns a 32 byte raw binary which can optionally be encoded.

options

Options

  • :encoding - Optionally encode with a binary encoding/0.

examples

Examples

iex> secret = Eddy.get_shared_secret(privkey, pubkey)
<<109, 226, 95, 89, 0, 39, 15, 239, 181, 187, 28, 242, 106, 214, 8, 227, 116,
66, 47, 52, 133, 10, 111, 113, 107, 173, 191, 203, 207, 135, 18, 114>>

iex> secret = Eddy.get_shared_secret(privkey, pubkey, encoding: :hex)
"6de25f5900270fefb5bb1cf26ad608e374422f34850a6f716badbfcbcf871272"
@spec params() :: map()

Returns the Ed25519 elliptic curve parameters.

Link to this function

sign(message, privkey, opts \\ [])

View Source
@spec sign(binary(), privkey(), keyword()) :: sig()

Signs the message with the given private key.

Acceps a private key struct or raw binary. The signature can optionally be returned as a raw or encoded binary.

options

Options

  • :encoding - Optionally encode with a binary encoding/0.

examples

Examples

iex> sig = Eddy.sign("test", privkey)
%Eddy.Sig{}

iex> sig = Eddy.sign("test", privkey, encoding: :base64)
"uS5X1ek6+aHAYGMEMWLF5+O9W8rxK6HDHHI2QOoBOReVaAsf5sFSI3Dqvms4LUtecW/ILAOaWS1L737ye6dkBg=="
Link to this function

verify(sig, message, pubkey, opts \\ [])

View Source
@spec verify(sig(), binary(), pubkey(), keyword()) :: boolean() | {:error, term()}

Verifies the signature against the given message and public key. Returns a boolean or error tuple.

Acceps a public key struct or raw binary. The signature can optionally be decoded from a raw or encoded binary.

options

Options

  • :encoding - Optionally decode from a binary encoding/0.

examples

Examples

iex> Eddy.verify(sig, "test", pubkey)
true

iex> sig = "uS5X1ek6+aHAYGMEMWLF5+O9W8rxK6HDHHI2QOoBOReVaAsf5sFSI3Dqvms4LUtecW/ILAOaWS1L737ye6dkBg=="
iex> Eddy.verify(sig, "test", pubkey, encoding: :base64)
true