Secp256k1.ECDSA (secp256k1 v0.8.0)

View Source

Module implementing ECDSA pubkey derivation and signatures

Summary

Functions

Convert uncompressed pubkey to compressed one

Derive compressed pubkey from seckey

Convert compressed pubkey to uncompressed one

Converts a compact ECDSA signature to its low-S form.

Parses a standard-sized strict DER ECDSA signature into compact 64-byte r || s form.

Derive pubkey from seckey

Serializes a compact 64-byte ECDSA signature as strict DER.

Generate an ECDSA signature of a message hash with random RFC 6979 additional data.

Generate an ECDSA signature with explicit RFC 6979 additional data.

Derive uncompressed pubkey from seckey

Check if ECDSA signature is valid.

Functions

compress_pubkey(pubkey)

@spec compress_pubkey(pubkey :: Secp256k1.uncompressed_pubkey()) ::
  Secp256k1.compressed_pubkey()

Convert uncompressed pubkey to compressed one

compressed_pubkey(seckey)

@spec compressed_pubkey(seckey :: Secp256k1.seckey()) :: Secp256k1.compressed_pubkey()

Derive compressed pubkey from seckey

decompress_pubkey(pubkey)

@spec decompress_pubkey(pubkey :: Secp256k1.compressed_pubkey()) ::
  Secp256k1.uncompressed_pubkey()

Convert compressed pubkey to uncompressed one

normalize(signature)

@spec normalize(signature :: Secp256k1.ecdsa_sig()) ::
  Secp256k1.ecdsa_sig() | {:error, binary() | :allocation_failed}

Converts a compact ECDSA signature to its low-S form.

This operation is idempotent. libsecp256k1 verification rejects high-S signatures. Normalize only when the protocol deliberately accepts the mathematically equivalent high-S form: doing so accepts a malleable signature, and all subsequent identity or hashing operations must use the normalized bytes. Protocols requiring canonical low-S signatures should reject instead.

parse_der(signature)

@spec parse_der(signature :: Secp256k1.ecdsa_der_sig()) ::
  Secp256k1.ecdsa_sig() | {:error, binary() | :allocation_failed}

Parses a standard-sized strict DER ECDSA signature into compact 64-byte r || s form.

Accepts DER signatures from 8 through 72 bytes. Wrong-sized input raises FunctionClauseError; malformed DER within that range raises ArgumentError. As in upstream libsecp256k1, syntactically valid DER containing out-of-range values parses to a compact signature that cannot verify. A trailing Bitcoin transaction sighash byte must be removed before calling this function.

pubkey(seckey, opts \\ [])

Derive pubkey from seckey

Options

  • :compress (default true) - whether to format pubkey in compressed or uncompressed format

Examples

iex> {seckey, _} = Secp256k1.keypair(:compressed)
iex> pubkey = Secp256k1.ECDSA.pubkey(seckey)
iex> byte_size(pubkey)
33

serialize_der(signature)

@spec serialize_der(signature :: Secp256k1.ecdsa_sig()) ::
  Secp256k1.ecdsa_der_sig() | {:error, binary() | :allocation_failed}

Serializes a compact 64-byte ECDSA signature as strict DER.

The returned binary contains only the DER signature. Bitcoin transaction sighash bytes are not part of this encoding and must be handled separately.

sign(msg_hash, seckey)

@spec sign(msg_hash :: Secp256k1.hash(), seckey :: Secp256k1.seckey()) ::
  Secp256k1.ecdsa_sig()

Generate an ECDSA signature of a message hash with random RFC 6979 additional data.

Examples

iex> {seckey, _} = Secp256k1.keypair(:compressed)
iex> msg_hash = :crypto.hash(:sha256, "hello")
iex> signature = Secp256k1.ECDSA.sign(msg_hash, seckey)
iex> byte_size(signature)
64

sign(msg_hash, seckey, nonce_data)

@spec sign(
  msg_hash :: Secp256k1.hash(),
  seckey :: Secp256k1.seckey(),
  nonce_data :: nil | <<_::256>>
) :: Secp256k1.ecdsa_sig()

Generate an ECDSA signature with explicit RFC 6979 additional data.

Deterministic signing is for tests only

Pass nil only in tests that require reproducible signatures, such as interoperability and test-vector checks. Use sign/2 for normal signing.

A 32-byte value is passed as libsecp256k1 ndata to derive a synthetic nonce.

uncompressed_pubkey(seckey)

@spec uncompressed_pubkey(seckey :: Secp256k1.seckey()) ::
  Secp256k1.uncompressed_pubkey()

Derive uncompressed pubkey from seckey

valid?(signature, msg_hash, pubkey)

@spec valid?(
  signature :: Secp256k1.ecdsa_sig(),
  msg_hash :: Secp256k1.hash(),
  pubkey :: Secp256k1.compressed_pubkey() | Secp256k1.uncompressed_pubkey()
) :: boolean()

Check if ECDSA signature is valid.

High-S signatures return false. Call normalize/1 first only when the surrounding protocol deliberately accepts malleable signature encodings.

Examples

iex> {seckey, pubkey} = Secp256k1.keypair(:compressed)
iex> msg_hash = :crypto.hash(:sha256, "hello")
iex> signature = Secp256k1.ECDSA.sign(msg_hash, seckey)
iex> Secp256k1.ECDSA.valid?(signature, msg_hash, pubkey)
true