exth_crypto v0.1.6 ExthCrypto.Signature

A variety of functions for calculating cryptographic signatures.

Right now these all rely on the libsecp256k1 library, and thus only performs signatures on this Elliptic Curve, but I don’t see any reason why we couldn’t switch to standard libraries if they provide similar functionality.

Link to this section Summary

Functions

Given a private key, returns a public key

Recovers a public key from a given signature for a given digest

Computes an ECDSA signature of the given (already digested) data

Verifies a that a given signature for a given digest is valid against a public key

Link to this section Types

Link to this type recovery_id()
recovery_id() :: integer()
Link to this type signature()
signature() :: binary()

Link to this section Functions

Link to this function get_public_key(private_key)
get_public_key(ExthCrypto.Key.private_key()) ::
  {:ok, ExthCrypto.Key.public_key()} | {:error, String.t()}

Given a private key, returns a public key.

Examples

iex> ExthCrypto.Signature.get_public_key(ExthCrypto.Test.private_key)
{:ok, <<4, 54, 241, 224, 126, 85, 135, 69, 213, 129, 115, 3, 41, 161, 217, 87, 215,
       159, 64, 17, 167, 128, 113, 172, 232, 46, 34, 145, 136, 72, 160, 207, 161,
       171, 255, 26, 163, 160, 158, 227, 196, 92, 62, 119, 84, 156, 99, 224, 155,
       120, 250, 153, 134, 180, 218, 177, 186, 200, 199, 106, 97, 103, 50, 215, 114>>}

iex> ExthCrypto.Signature.get_public_key(<<1>>)
{:error, "Private key size not 32 bytes"}
Link to this function recover(digest, signature, recovery_id)
recover(binary(), signature(), recovery_id()) ::
  {:ok, ExthCrypto.Key.public_key()} | {:error, String.t()}

Recovers a public key from a given signature for a given digest.

Note, the key is returned in DER format (with a leading 0x04 to indicate that it’s an octet-string).

Examples

iex> msg = ExthCrypto.Math.nonce(32)
iex> {signature, _r, _s, recovery_id} = ExthCrypto.Signature.sign_digest(msg, ExthCrypto.Test.private_key(:key_a))
iex> ExthCrypto.Signature.recover(msg, signature, recovery_id)
{:ok, <<4, 54, 241, 224, 126, 85, 135, 69, 213, 129, 115, 3, 41, 161, 217, 87, 215,
        159, 64, 17, 167, 128, 113, 172, 232, 46, 34, 145, 136, 72, 160, 207, 161,
        171, 255, 26, 163, 160, 158, 227, 196, 92, 62, 119, 84, 156, 99, 224, 155,
        120, 250, 153, 134, 180, 218, 177, 186, 200, 199, 106, 97, 103, 50, 215, 114>>}

iex> {signature, _r, _s, recovery_id} = ExthCrypto.Signature.sign_digest(msg = ExthCrypto.Math.nonce(32), ExthCrypto.Test.private_key(:key_a))
iex> ExthCrypto.Signature.recover(msg, signature, recovery_id)
{:ok, <<4, 54, 241, 224, 126, 85, 135, 69, 213, 129, 115, 3, 41, 161, 217, 87, 215,
        159, 64, 17, 167, 128, 113, 172, 232, 46, 34, 145, 136, 72, 160, 207, 161,
        171, 255, 26, 163, 160, 158, 227, 196, 92, 62, 119, 84, 156, 99, 224, 155,
        120, 250, 153, 134, 180, 218, 177, 186, 200, 199, 106, 97, 103, 50, 215, 114>>}
Link to this function sign_digest(digest, private_key)
sign_digest(binary(), ExthCrypto.Key.private_key()) ::
  {signature(), r(), s(), recovery_id()}

Computes an ECDSA signature of the given (already digested) data.

This returns both the r and s results, the recovery id, and the concatenated signature sig.

Examples

iex> {signature, _r, _s, _recovery_id} = ExthCrypto.Signature.sign_digest("12345", ExthCrypto.Test.private_key)
iex> ExthCrypto.Signature.verify("12345", signature, ExthCrypto.Test.public_key)
true
Link to this function verify(digest, signature, public_key)

Verifies a that a given signature for a given digest is valid against a public key.

Examples

iex> msg = ExthCrypto.Math.nonce(32)
iex> {signature, _r, _s, _recovery_id} = ExthCrypto.Signature.sign_digest(msg, ExthCrypto.Test.private_key(:key_a))
iex> ExthCrypto.Signature.verify(msg, signature, ExthCrypto.Test.public_key(:key_a))
true

iex> msg = ExthCrypto.Math.nonce(32)
iex> {signature, _r, _s, _recovery_id} = ExthCrypto.Signature.sign_digest(msg, ExthCrypto.Test.private_key(:key_a))
iex> ExthCrypto.Signature.verify(msg, signature, ExthCrypto.Test.public_key(:key_b))
false

iex> msg = ExthCrypto.Math.nonce(32)
iex> {signature, _r, _s, _recovery_id} = ExthCrypto.Signature.sign_digest(msg, ExthCrypto.Test.private_key(:key_a))
iex> ExthCrypto.Signature.verify(msg |> Binary.drop(1), signature, ExthCrypto.Test.public_key(:key_a))
false