Secp256k1.MuSig (secp256k1 v0.7.1)

View Source

Module implementing MuSig2 multi-signatures as defined in BIP327. EXPERIMENTAL: This module uses experimental features of libsecp256k1.

Example

# 1. Key Aggregation
{alice_sec, alice_pub} = Secp256k1.keypair(:compressed)
{bob_sec, bob_pub} = Secp256k1.keypair(:compressed)

{:ok, agg_pubkey, cache} = Secp256k1.MuSig.pubkey_agg([alice_pub, bob_pub])

# 2. Nonce Generation
msg_hash = :crypto.hash(:sha256, "Joint Account")
{:ok, alice_secnonce, alice_pubnonce} = Secp256k1.MuSig.nonce_gen(alice_sec, alice_pub, msg_hash, cache, nil)
{:ok, bob_secnonce, bob_pubnonce} = Secp256k1.MuSig.nonce_gen(bob_sec, bob_pub, msg_hash, cache, nil)

# 3. Nonce Aggregation
aggnonce = Secp256k1.MuSig.nonce_agg([alice_pubnonce, bob_pubnonce])

# 4. Session Setup
session = Secp256k1.MuSig.nonce_process(aggnonce, msg_hash, cache)

# 5. Partial Signing
alice_sig = Secp256k1.MuSig.partial_sign(alice_secnonce, alice_sec, cache, session)
bob_sig = Secp256k1.MuSig.partial_sign(bob_secnonce, bob_sec, cache, session)

# 6. Signature Aggregation
final_sig = Secp256k1.MuSig.partial_sig_agg(session, [alice_sig, bob_sig])

# 7. Verification
Secp256k1.Schnorr.valid?(final_sig, msg_hash, agg_pubkey)
# => true

Summary

Functions

Aggregates public nonces from all signers.

Generates a nonce for the signing session.

Processes the aggregate nonce and creates a signing session.

Aggregates partial signatures into the final Schnorr signature.

Creates a partial signature.

Aggregates public keys.

Applies a plain EC tweak to the aggregated public key.

Gets the full public key from the key aggregation cache.

Applies an x-only tweak to the aggregated public key.

Types

aggnonce()

@type aggnonce() :: <<_::1056>>

keyagg_cache()

@type keyagg_cache() :: binary()

partial_sig()

@type partial_sig() :: <<_::288>>

pubnonce()

@type pubnonce() :: <<_::528>>

secnonce()

@type secnonce() :: reference()

session()

@type session() :: binary()

Functions

nonce_agg(pubnonces)

@spec nonce_agg([pubnonce()]) :: aggnonce() | {:error, term()}

Aggregates public nonces from all signers.

nonce_gen(seckey, pubkey, msg, cache, extra)

@spec nonce_gen(
  Secp256k1.seckey() | nil,
  Secp256k1.pubkey() | nil,
  binary() | nil,
  keyagg_cache() | nil,
  binary() | nil
) :: {:ok, secnonce(), pubnonce()} | {:error, term()}

Generates a nonce for the signing session.

Arguments:

  • seckey: (Optional) The secret key of the signer.
  • pubkey: (Optional) The public key of the signer.
  • msg: (Optional) The message to be signed (32-byte hash).
  • cache: (Optional) The key aggregation cache.
  • extra: (Optional) Extra input for nonce derivation (32 bytes).

Returns a secret nonce resource and a public nonce.

nonce_process(aggnonce, msg, cache)

@spec nonce_process(aggnonce(), binary(), keyagg_cache()) ::
  session() | {:error, term()}

Processes the aggregate nonce and creates a signing session.

partial_sig_agg(session, partial_sigs)

@spec partial_sig_agg(session(), [partial_sig()]) ::
  Secp256k1.schnorr_sig() | {:error, term()}

Aggregates partial signatures into the final Schnorr signature.

partial_sig_verify(partial_sig, pubnonce, pubkey, cache, session)

@spec partial_sig_verify(
  partial_sig(),
  pubnonce(),
  Secp256k1.pubkey(),
  keyagg_cache(),
  session()
) :: boolean()

Verifies a partial signature.

partial_sign(secnonce, seckey, cache, session)

@spec partial_sign(secnonce(), Secp256k1.seckey(), keyagg_cache(), session()) ::
  partial_sig() | {:error, term()}

Creates a partial signature.

This function consumes the secret nonce.

pubkey_agg(pubkeys)

@spec pubkey_agg([Secp256k1.pubkey()]) ::
  {:ok, Secp256k1.xonly_pubkey(), keyagg_cache()} | {:error, term()}

Aggregates public keys.

Returns the aggregated x-only public key and a key aggregation cache.

pubkey_ec_tweak_add(cache, tweak)

@spec pubkey_ec_tweak_add(keyagg_cache(), <<_::256>>) ::
  {:ok, keyagg_cache(), Secp256k1.pubkey()} | {:error, term()}

Applies a plain EC tweak to the aggregated public key.

Returns the new cache and the tweaked public key.

pubkey_get(cache)

@spec pubkey_get(keyagg_cache()) :: Secp256k1.pubkey() | {:error, term()}

Gets the full public key from the key aggregation cache.

pubkey_xonly_tweak_add(cache, tweak)

@spec pubkey_xonly_tweak_add(keyagg_cache(), <<_::256>>) ::
  {:ok, keyagg_cache(), Secp256k1.pubkey()} | {:error, term()}

Applies an x-only tweak to the aggregated public key.

Returns the new cache and the tweaked public key.