Secp256k1 (secp256k1 v0.8.0)
View SourceThis is the unified API for the stable secp256k1 functions this library provides.
Experimental MuSig2 signing uses process-local resources and intentionally remains outside
this facade. See Secp256k1.MuSig for its protocol API.
Examples
Generate new keypair
iex> {_seckey, _pubkey} = Secp256k1.keypair(:xonly)Derive pubkey from your awesome seckey
iex> seckey = <<0x1111111111111111111111111111111111111111111111111111111111111111::256>>
iex> pubkey = Secp256k1.pubkey(seckey, :compressed)
iex> Base.encode16(pubkey, case: :lower)
"034f355bdcb7cc0af728ef3cceb9615d90684bb5b2ca5f859ab0f0b704075871aa"Calculate ECDSA signature
iex> # your keypair
iex> {seckey, pubkey} = Secp256k1.keypair(:compressed)
iex> # prepare your message hash
iex> msg_hash = :crypto.hash(:sha256, "My awesome message")
iex> # generate signature
iex> sig = Secp256k1.ecdsa_sign(msg_hash, seckey)
iex> # validate your signature
iex> Secp256k1.ecdsa_valid?(sig, msg_hash, pubkey)
trueCalculate Schnorr signature
iex> # your keypair
iex> {seckey, pubkey} = Secp256k1.keypair(:xonly)
iex> # prepare your message hash
iex> msg_hash = :crypto.hash(:sha256, "My awesome message")
iex> # generate signature
iex> sig = Secp256k1.schnorr_sign(msg_hash, seckey)
iex> # validate your signature
iex> Secp256k1.schnorr_valid?(sig, msg_hash, pubkey)
trueCalculate ECDH shared secret
iex> {alice_seckey, _alice_pubkey} = Secp256k1.keypair(<<1::256>>, :compressed)
iex> {_bob_seckey, bob_pubkey} = Secp256k1.keypair(<<2::256>>, :compressed)
iex> shared_secret = Secp256k1.ecdh(alice_seckey, bob_pubkey)
iex> byte_size(shared_secret)
32
Summary
Types
Compressed pubkey is binary of 33 byte length
Standard-sized strict DER-encoded ECDSA signature (8-72 bytes), excluding any Bitcoin transaction sighash byte
Serialized compressed ECDSA signature is 64 bytes long binary
Hash is 32 bytes long binary
Pubkey is binary of 32, 33 or 65 byte length
Parity of a full public key represented in x-only form
Pubkey can be parsed in compressed (33 bytes), uncompressed (65 bytes) or xonly (32 bytes) format
Schnorr signature is 64 bytes long binary
EC secp256k1 seckey is 32 bytes long binary
libsecp256k1 default hashed ECDH shared secret is 32 bytes long binary
Scalar tweak is a 32-byte big-endian integer
Uncompressed pubkey is binary of 65 byte length
X-only pubkey is binary of 32 byte length
Functions
Convert a public key to another serialization format.
Adds a scalar multiple of the generator to a compressed or uncompressed public key.
Adds a scalar tweak to a secret key for BIP-32-style private derivation.
Compute libsecp256k1's default hashed ECDH shared secret.
Create an ECDSA signature
Converts a compact ECDSA signature to the low-S form required by libsecp256k1 verification.
Parses an 8-72-byte strict DER ECDSA signature into compact 64-byte r || s form.
Serializes a compact 64-byte ECDSA signature as strict DER.
Validate ECDSA signature.
Generate new secp256k1 keypair
Generate new secp256k1 keypair from provided seckey
Derive pubkey from provided seckey
Calculate Schnorr signature according to BIP 340
Validate Schnorr signature
Checks whether a binary encodes a valid secp256k1 public key.
Checks whether a 32-byte binary is a valid secp256k1 secret key.
Adds a scalar tweak to an x-only internal public key.
Checks an x-only public-key tweak result and parity.
Tweaks a secret key using x-only semantics for signing Taproot outputs.
Types
@type compressed_pubkey() :: <<_::264>>
Compressed pubkey is binary of 33 byte length
@type ecdsa_der_sig() :: binary()
Standard-sized strict DER-encoded ECDSA signature (8-72 bytes), excluding any Bitcoin transaction sighash byte
@type ecdsa_sig() :: <<_::512>>
Serialized compressed ECDSA signature is 64 bytes long binary
@type hash() :: <<_::256>>
Hash is 32 bytes long binary
@type pubkey() :: xonly_pubkey() | compressed_pubkey() | uncompressed_pubkey()
Pubkey is binary of 32, 33 or 65 byte length
@type pubkey_parity() :: 0 | 1
Parity of a full public key represented in x-only form
@type pubkey_type() :: :compressed | :uncompressed | :xonly
Pubkey can be parsed in compressed (33 bytes), uncompressed (65 bytes) or xonly (32 bytes) format
@type schnorr_sig() :: <<_::512>>
Schnorr signature is 64 bytes long binary
@type seckey() :: <<_::256>>
EC secp256k1 seckey is 32 bytes long binary
@type tweak() :: <<_::256>>
Scalar tweak is a 32-byte big-endian integer
@type uncompressed_pubkey() :: <<_::520>>
Uncompressed pubkey is binary of 65 byte length
@type xonly_pubkey() :: <<_::256>>
X-only pubkey is binary of 32 byte length
Functions
@spec convert_pubkey( pubkey :: compressed_pubkey() | uncompressed_pubkey(), type :: :compressed | :uncompressed | :xonly ) :: compressed_pubkey() | uncompressed_pubkey() | xonly_pubkey() | {:error, binary() | :allocation_failed}
Convert a public key to another serialization format.
Inputs
pubkeyan uncompressed public key when converting to:compressed, or a compressed public key when converting to:uncompressedor:xonlytypethe target format, either:compressed,:uncompressed, or:xonly
Returns the converted public key, or {:error, reason} when the correctly sized input does not
encode a valid secp256k1 public key.
@spec ec_pubkey_tweak_add(compressed_pubkey() | uncompressed_pubkey(), tweak()) :: compressed_pubkey() | uncompressed_pubkey() | {:error, binary() | :allocation_failed}
Adds a scalar multiple of the generator to a compressed or uncompressed public key.
The output preserves the input serialization format. This is the public-key
counterpart of ec_seckey_tweak_add/2 for BIP-32-style public derivation.
Adds a scalar tweak to a secret key for BIP-32-style private derivation.
Returns an error when the tweak is outside the scalar field or the resulting key would be zero.
@spec ecdh(seckey :: seckey(), pubkey :: compressed_pubkey() | uncompressed_pubkey()) :: shared_secret()
Compute libsecp256k1's default hashed ECDH shared secret.
Inputs
seckey32 byte long binarypubkeycompressed or uncompressed secp256k1 public key
Output
shared_secret32 byte binary
This wraps libsecp256k1's ECDH module. It returns the upstream library's
default hashed ECDH output, currently SHA256 over the compressed shared point.
For generic raw ECDH, use :crypto.compute_key/4.
Create an ECDSA signature
Inputs
msg_hash32 byte long message hash to signseckey32 byte long binary
Output
signatureECDSA signature serialized in compressed format (64 byte binary)
@spec ecdsa_signature_normalize(ecdsa_sig()) :: ecdsa_sig() | {:error, binary() | :allocation_failed}
Converts a compact ECDSA signature to the low-S form required by libsecp256k1 verification.
Already-normalized signatures are returned unchanged. Normalization accepts a malleable alternate encoding; use it only when the protocol deliberately accepts mathematical equivalence, and use the normalized bytes thereafter. Protocols requiring canonical low-S signatures should reject high-S instead.
@spec ecdsa_signature_parse_der(ecdsa_der_sig()) :: ecdsa_sig() | {:error, binary() | :allocation_failed}
Parses an 8-72-byte strict DER ECDSA signature into compact 64-byte r || s form.
Remove any trailing Bitcoin transaction sighash byte before parsing. Wrong-sized
input raises FunctionClauseError; malformed DER in the accepted size range
raises ArgumentError.
@spec ecdsa_signature_serialize_der(ecdsa_sig()) :: ecdsa_der_sig() | {:error, binary() | :allocation_failed}
Serializes a compact 64-byte ECDSA signature as strict DER.
The result does not include a Bitcoin transaction sighash byte.
@spec ecdsa_valid?( signature :: ecdsa_sig(), msg_hash :: hash(), pubkey :: compressed_pubkey() | uncompressed_pubkey() ) :: boolean()
Validate ECDSA signature.
High-S signatures return false. Normalize only if the surrounding protocol
deliberately accepts malleable signature encodings.
Inputs
signature64 byte long binarymsg_hash32 byte long message hash that was signedpubkeycompressed (33-byte) or uncompressed (65-byte) public key
@spec keypair(type :: pubkey_type()) :: {seckey(), pubkey()}
Generate new secp256k1 keypair
Input
type(seepubkey/2)
Output
- 2-tuple with seckey on the first place and pubkey on the second place
@spec keypair(seckey :: seckey(), type :: pubkey_type()) :: {seckey(), pubkey()}
Generate new secp256k1 keypair from provided seckey
For options see pubkey/2
@spec pubkey(seckey :: seckey(), type :: pubkey_type()) :: pubkey()
Derive pubkey from provided seckey
Inputs
seckey32 byte long binarytypeone of:xonly,:compressedor:uncompressed
Output
pubkeyserialization type depends on the type provided
@spec schnorr_sign(message :: binary(), seckey :: seckey()) :: schnorr_sig()
Calculate Schnorr signature according to BIP 340
Inputs
messagecan accept arbitrary long binary but only 32 byte long hash is the only option strictly according to specificationseckey32 byte long binary
Output
signatureSchnorr signature is 64 byte long binary
Note: automatic random nonce is added to every run so generated signature is not deterministic
@spec schnorr_valid?( signature :: schnorr_sig(), message :: binary(), pubkey :: xonly_pubkey() ) :: boolean()
Validate Schnorr signature
Inputs
signature64 byte long binarymessagearbitrary long binarypubkeyxonly pubkey (32 byte long binary)
Checks whether a binary encodes a valid secp256k1 public key.
Accepts x-only (32-byte), compressed (33-byte), and uncompressed (65-byte)
public-key encodings. Returns false for unsupported encodings, wrong-sized
binaries, and non-binary terms.
Checks whether a 32-byte binary is a valid secp256k1 secret key.
This validates the scalar value, not only the binary size. A valid secret key is
greater than zero and smaller than the secp256k1 curve order. Returns false
for wrong-sized binaries and non-binary terms.
@spec xonly_pubkey_tweak_add(xonly_pubkey(), tweak()) :: {:ok, xonly_pubkey(), pubkey_parity()} | {:error, binary() | :allocation_failed}
Adds a scalar tweak to an x-only internal public key.
Returns the x-only output key and its full-point parity. Keep both values when constructing and verifying Taproot commitments.
@spec xonly_pubkey_tweak_add_check( xonly_pubkey(), pubkey_parity(), xonly_pubkey(), tweak() ) :: boolean()
Checks an x-only public-key tweak result and parity.
This verifies the key arithmetic only. The caller remains responsible for deriving the tweak according to BIP-341 when using it as a Taproot commitment.
@spec xonly_seckey_tweak_add(seckey(), tweak()) :: seckey() | {:error, binary() | :allocation_failed}
Tweaks a secret key using x-only semantics for signing Taproot outputs.
The keypair is normalized to an even-Y internal public key before adding the tweak.