musig2

package
v0.0.4 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 9, 2024 License: CC0-1.0, ISC Imports: 11 Imported by: 0

Documentation

Index

Constants

View Source
const (
	// PubNonceSize is the size of the public nonces. Each public nonce is
	// serialized the full compressed encoding, which uses 32 bytes for each
	// nonce.
	PubNonceSize = 66
	// SecNonceSize is the size of the secret nonces for musig2. The secret
	// nonces are the corresponding secret keys to the public nonce points.
	SecNonceSize = 97
)

Variables

View Source
var (
	// ErrSignersNotSpecified is returned when a caller attempts to create
	// a context without specifying either the total number of signers, or
	// the complete set of singers.
	ErrSignersNotSpecified = fmt.Errorf("total number of signers or all " +
		"signers must be known")
	// ErrSignerNotInKeySet is returned when a the secret key for a signer
	// isn't included in the set of signing public keys.
	ErrSignerNotInKeySet = fmt.Errorf("signing key is not found in key" +
		" set")
	// ErrAlreadyHaveAllNonces is called when RegisterPubNonce is called too
	// many times for a given signing session.
	//
	// ErrAlreadyHaveAllNonces is returned when a caller attempts to
	// register a signer, once we already have the total set of known
	// signers.
	ErrAlreadyHaveAllNonces = fmt.Errorf("already have all nonces")
	// ErrNotEnoughSigners is returned when a caller attempts to create a
	// session from a context, but before all the required signers are
	// known.
	//
	// ErrNotEnoughSigners is returned if a caller attempts to obtain an
	// early nonce when it wasn't specified
	ErrNotEnoughSigners      = fmt.Errorf("not enough signers")
	ErrAlreadyHaveAllSigners = fmt.Errorf("all signers registered")
	// ErrAlredyHaveAllSigs is called when CombineSig is called too many
	// times for a given signing session.
	ErrAlredyHaveAllSigs = fmt.Errorf("already have all sigs")
	// ErrSigningContextReuse is returned if a user attempts to sign using
	// the same signing context more than once.
	ErrSigningContextReuse = fmt.Errorf("nonce already used")
	// ErrFinalSigInvalid is returned when the combined signature turns out
	// to be invalid.
	ErrFinalSigInvalid = fmt.Errorf("final signature is invalid")
	// ErrCombinedNonceUnavailable is returned when a caller attempts to
	// sign a partial signature, without first having collected all the
	// required combined nonces.
	ErrCombinedNonceUnavailable = fmt.Errorf("missing combined nonce")
	// ErrTaprootInternalKeyUnavailable is returned when a user attempts to
	// obtain the
	ErrTaprootInternalKeyUnavailable = fmt.Errorf("taproot tweak not used")
	ErrNoEarlyNonce                  = fmt.Errorf("no early nonce available")
)
View Source
var (
	// KeyAggTagList is the tagged hash tag used to compute the hash of the
	// list of sorted public keys.
	KeyAggTagList = []byte("KeyAgg list")
	// KeyAggTagCoeff is the tagged hash tag used to compute the key
	// aggregation coefficient for each key.
	KeyAggTagCoeff = []byte("KeyAgg coefficient")
	// ErrTweakedKeyIsInfinity is returned if while tweaking a key, we end
	// up with the point at infinity.
	ErrTweakedKeyIsInfinity = fmt.Errorf("tweaked key is infinity point")
	// ErrTweakedKeyOverflows is returned if a tweaking key is larger than
	// 0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEBAAEDCE6AF48A03BBFD25E8CD0364141.
	ErrTweakedKeyOverflows = fmt.Errorf("tweaked key is too large")
)
View Source
var (
	// NonceAuxTag is the tag used to optionally mix in the secret key with
	// the set of aux randomness.
	NonceAuxTag = []byte("MuSig/aux")
	// NonceGenTag is used to generate the value (from a set of required an
	// optional field) that will be used as the part of the secret nonce.
	NonceGenTag = []byte("MuSig/nonce")

	// ErrPubkeyInvalid is returned when the pubkey of the WithPublicKey
	// option is not passed or of invalid length.
	ErrPubkeyInvalid = errors.New("nonce generation requires a valid pubkey")
)
View Source
var (
	// NonceBlindTag is that tag used to construct the value b, which
	// blinds the second public nonce of each party.
	NonceBlindTag = []byte("MuSig/noncecoef")

	// ChallengeHashTag is the tag used to construct the challenge hash
	ChallengeHashTag = []byte("BIP0340/challenge")

	// ErrNoncePointAtInfinity is returned if during signing, the fully
	// combined public nonce is the point at infinity.
	ErrNoncePointAtInfinity = fmt.Errorf("signing nonce is the infinity " +
		"point")

	// ErrSecKeyZero is returned when the secret key for signing is
	// actually zero.
	ErrSecKeyZero = fmt.Errorf("priv key is zero")

	// ErrPartialSigInvalid is returned when a partial is found to be
	// invalid.
	ErrPartialSigInvalid = fmt.Errorf("partial signature is invalid")

	// ErrSecretNonceZero is returned when a secret nonce is passed in a
	// zero.
	ErrSecretNonceZero = fmt.Errorf("secret nonce is blank")

	// ErrSecNoncePubkey is returned when the signing key does not match the
	// sec nonce pubkey
	ErrSecNoncePubkey = fmt.Errorf("public key does not match secnonce")

	// ErrPubkeyNotIncluded is returned when the signers pubkey is not included
	// in the list of pubkeys.
	ErrPubkeyNotIncluded = fmt.Errorf("signer's pubkey must be included" +
		" in the list of pubkeys")
)
View Source
var WithNoncePrivateKeyAux = WithNonceSecretKeyAux

Functions

func AggregateNonces

func AggregateNonces(pubNonces [][PubNonceSize]byte) ([PubNonceSize]byte,
	error)

AggregateNonces aggregates the set of a pair of public nonces for each party into a single aggregated nonces to be used for multi-signing.

func CombineSigs

func CombineSigs(combinedNonce *ec.PublicKey,
	partialSigs []*PartialSignature,
	combineOpts ...CombineOption) *schnorr.Signature

CombineSigs combines the set of public keys given the final aggregated nonce, and the series of partial signatures for each nonce.

Types

type AggregateKey

type AggregateKey struct {
	// FinalKey is the final aggregated key which may include one or more
	// tweaks applied to it.
	FinalKey *ec.PublicKey
	// PreTweakedKey is the aggregated *before* any tweaks have been
	// applied.  This should be used as the internal key in taproot
	// contexts.
	PreTweakedKey *ec.PublicKey
}

AggregateKey is a final aggregated key along with a possible version of the key without any tweaks applied.

func AggregateKeys

func AggregateKeys(keys []*ec.PublicKey, sort bool,
	keyOpts ...KeyAggOption) (
	*AggregateKey, *ec.ModNScalar, *ec.ModNScalar, error)

AggregateKeys takes a list of possibly unsorted keys and returns a single aggregated key as specified by the musig2 key aggregation algorithm. A nil value can be passed for keyHash, which causes this function to re-derive it. In addition to the combined public key, the parity accumulator and the tweak accumulator are returned as well.

type CombineOption

type CombineOption func(*combineOptions)

CombineOption is a functional option argument that allows callers to modify the way we combine musig2 schnorr signatures.

func WithBip86TweakedCombine

func WithBip86TweakedCombine(msg [32]byte, keys []*ec.PublicKey,
	sort bool) CombineOption

WithBip86TweakedCombine is similar to the WithTaprootTweakedCombine option, but assumes a BIP 341 + BIP 86 context where the final tweaked key is to be used as the output key, where the internal key is the aggregated key pre-tweak.

This option should be used over WithTaprootTweakedCombine when attempting to aggregate signatures for a top-level taproot keyspend, where the output key was generated using BIP 86.

func WithTaprootTweakedCombine

func WithTaprootTweakedCombine(msg [32]byte, keys []*ec.PublicKey,
	scriptRoot []byte, sort bool) CombineOption

WithTaprootTweakedCombine is similar to the WithTweakedCombine option, but assumes a BIP 341 context where the final tweaked key is to be used as the output key, where the internal key is the aggregated key pre-tweak.

This option should be used over WithTweakedCombine when attempting to aggregate signatures for a top-level taproot keyspend, where the output key commits to a script root.

func WithTweakedCombine

func WithTweakedCombine(msg [32]byte, keys []*ec.PublicKey,
	tweaks []KeyTweakDesc, sort bool) CombineOption

WithTweakedCombine is a functional option that allows callers to specify that the signature was produced using a tweaked aggregated public key. In order to properly aggregate the partial signatures, the caller must specify enough information to reconstruct the challenge, and also the final accumulated tweak value.

type Context

type Context struct {
	// contains filtered or unexported fields
}

Context is a managed signing context for musig2. It takes care of things like securely generating secret nonces, aggregating keys and nonces, etc.

func NewContext

func NewContext(signingKey *ec.SecretKey, shouldSort bool,
	ctxOpts ...ContextOption) (*Context, error)

NewContext creates a new signing context with the passed singing key and set of public keys for each of the other signers.

NOTE: This struct should be used over the raw Sign API whenever possible.

func (*Context) CombinedKey

func (c *Context) CombinedKey() (*ec.PublicKey, error)

CombinedKey returns the combined public key that will be used to generate multi-signatures against.

func (*Context) EarlySessionNonce

func (c *Context) EarlySessionNonce() (*Nonces, error)

EarlySessionNonce returns the early session nonce, if available.

func (*Context) NewSession

func (c *Context) NewSession(options ...SessionOption) (*Session, error)

NewSession creates a new musig2 signing session.

func (*Context) NumRegisteredSigners

func (c *Context) NumRegisteredSigners() int

NumRegisteredSigners returns the total number of registered signers.

func (*Context) PubKey

func (c *Context) PubKey() ec.PublicKey

PubKey returns the public key of the signer of this session.

func (*Context) RegisterSigner

func (c *Context) RegisterSigner(pub *ec.PublicKey) (bool, error)

RegisterSigner allows a caller to register a signer after the context has been created. This will be used in scenarios where the total number of signers is known, but nonce exchange needs to happen before all the signers are known.

A bool is returned which indicates if all the signers have been registered.

NOTE: If the set of keys are not to be sorted during signing, then the ordering each key is registered with MUST match the desired ordering.

func (*Context) SigningKeys

func (c *Context) SigningKeys() []*ec.PublicKey

SigningKeys returns the set of keys used for signing.

func (*Context) TaprootInternalKey

func (c *Context) TaprootInternalKey() (*ec.PublicKey, error)

TaprootInternalKey returns the internal taproot key, which is the aggregated key _before_ the tweak is applied. If a taproot tweak was specified, then CombinedKey() will return the fully tweaked output key, with this method returning the internal key. If a taproot tweak wasn't specified, then this method will return an error.

type ContextOption

type ContextOption func(*contextOptions)

ContextOption is a functional option argument that allows callers to modify the musig2 signing is done within a context.

func WithBip86TweakCtx

func WithBip86TweakCtx() ContextOption

WithBip86TweakCtx specifies that within this context, the final key should use the taproot tweak as defined in BIP 341, with the BIP 86 modification: outputKey = internalKey + h_tapTweak(internalKey)*G. In this case, the aggreaged key before the tweak will be used as the internal key.

func WithEarlyNonceGen

func WithEarlyNonceGen() ContextOption

WithEarlyNonceGen allow a caller to specify that a nonce should be generated early, before the session is created. This should be used in protocols that require some partial nonce exchange before all the signers are known.

NOTE: This option must only be specified with the WithNumSigners option.

func WithKnownSigners

func WithKnownSigners(signers []*ec.PublicKey) ContextOption

WithKnownSigners is an optional parameter that should be used if a session can be created as soon as all the singers are known.

func WithNumSigners

func WithNumSigners(n int) ContextOption

WithNumSigners is a functional option used to specify that a context should be created without knowing all the signers. Instead the total number of signers is specified to ensure that a session can only be created once all the signers are known.

NOTE: Either WithKnownSigners or WithNumSigners MUST be specified.

func WithTaprootTweakCtx

func WithTaprootTweakCtx(scriptRoot []byte) ContextOption

WithTaprootTweakCtx specifies that within this context, the final key should use the taproot tweak as defined in BIP 341: outputKey = internalKey + h_tapTweak(internalKey || scriptRoot). In this case, the aggreaged key before the tweak will be used as the internal key.

func WithTweakedContext

func WithTweakedContext(tweaks ...KeyTweakDesc) ContextOption

WithTweakedContext specifies that within the context, the aggregated public key should be tweaked with the specified tweaks.

type KeyAggOption

type KeyAggOption func(*keyAggOption)

KeyAggOption is a functional option argument that allows callers to specify more or less information that has been pre-computed to the main routine.

func WithBIP86KeyTweak

func WithBIP86KeyTweak() KeyAggOption

WithBIP86KeyTweak specifies that then during key aggregation, the BIP 86 tweak which just commits to the hash of the serialized public key should be used. This option should be used when signing with a key that was derived using BIP 86.

func WithKeyTweaks

func WithKeyTweaks(tweaks ...KeyTweakDesc) KeyAggOption

WithKeyTweaks allows a caller to specify a series of 32-byte tweaks that should be applied to the final aggregated public key.

func WithKeysHash

func WithKeysHash(keyHash []byte) KeyAggOption

WithKeysHash allows key aggregation to be optimize, by allowing the caller to specify the hash of all the keys.

func WithTaprootKeyTweak

func WithTaprootKeyTweak(scriptRoot []byte) KeyAggOption

WithTaprootKeyTweak specifies that within this context, the final key should use the taproot tweak as defined in BIP 341: outputKey = internalKey + h_tapTweak(internalKey || scriptRoot). In this case, the aggregated key before the tweak will be used as the internal key.

This option should be used instead of WithKeyTweaks when the aggregated key is intended to be used as a taproot output key that commits to a script root.

func WithUniqueKeyIndex

func WithUniqueKeyIndex(idx int) KeyAggOption

WithUniqueKeyIndex allows the caller to specify the index of the second unique key.

type KeyTweakDesc

type KeyTweakDesc struct {
	// Tweak is the 32-byte value that will modify the public key.
	Tweak [32]byte
	// IsXOnly if true, then the public key will be mapped to an x-only key
	// before the tweaking operation is applied.
	IsXOnly bool
}

KeyTweakDesc describes a tweak to be applied to the aggregated public key generation and signing process. The IsXOnly specifies if the target key should be converted to an x-only public key before tweaking.

type NonceGenOption

type NonceGenOption func(*nonceGenOpts)

NonceGenOption is a function option that allows callers to modify how nonce generation happens.

func WithCustomRand

func WithCustomRand(r io.Reader) NonceGenOption

WithCustomRand allows a caller to use a custom random number generator in place for crypto/rand. This should only really be used to generate determinstic tests.

func WithNonceAuxInput

func WithNonceAuxInput(aux []byte) NonceGenOption

WithNonceAuxInput is a set of auxiliary randomness, similar to BIP 340 that can be used to further augment the nonce generation process.

func WithNonceCombinedKeyAux

func WithNonceCombinedKeyAux(combinedKey *ec.PublicKey) NonceGenOption

WithNonceCombinedKeyAux allows a caller to optionally specify the combined key used in this signing session to further augment the randomness used to generate nonces.

func WithNonceMessageAux

func WithNonceMessageAux(msg [32]byte) NonceGenOption

WithNonceMessageAux allows a caller to optionally specify a message to be mixed into the randomness generated to create the nonce.

func WithNonceSecretKeyAux

func WithNonceSecretKeyAux(secKey *ec.SecretKey) NonceGenOption

WithNonceSecretKeyAux allows a caller to optionally specify a secret key that should be used to augment the randomness used to generate the nonces.

func WithPublicKey

func WithPublicKey(pubKey *ec.PublicKey) NonceGenOption

WithPublicKey is the mandatory public key that will be mixed into the nonce generation.

type Nonces

type Nonces struct {
	// PubNonce holds the two 33-byte compressed encoded points that serve
	// as the public set of nonces.
	PubNonce [PubNonceSize]byte
	// SecNonce holds the two 32-byte scalar values that are the secret
	// keys to the two public nonces.
	SecNonce [SecNonceSize]byte
}

Nonces holds the public and secret nonces required for musig2.

TODO(roasbeef): methods on this to help w/ parsing, etc?

func GenNonces

func GenNonces(options ...NonceGenOption) (*Nonces, error)

GenNonces generates the secret nonces, as well as the public nonces which correspond to an EC point generated using the secret nonce as a secret key.

type PartialSignature

type PartialSignature struct {
	S *ec.ModNScalar

	R *ec.PublicKey
}

PartialSignature reprints a partial (s-only) musig2 multi-signature. This isn't a valid schnorr signature by itself, as it needs to be aggregated along with the other partial signatures to be completed.

func NewPartialSignature

func NewPartialSignature(s *ec.ModNScalar,
	r *ec.PublicKey) PartialSignature

NewPartialSignature returns a new instances of the partial sig struct.

func Sign

func Sign(secNonce [SecNonceSize]byte, privKey *ec.SecretKey,
	combinedNonce [PubNonceSize]byte, pubKeys []*ec.PublicKey,
	msg [32]byte, signOpts ...SignOption) (*PartialSignature, error)

Sign generates a musig2 partial signature given the passed key set, secret nonce, public nonce, and secret keys. This method returns an error if the generated nonces are either too large, or end up mapping to the point at infinity.

func (*PartialSignature) Decode

func (p *PartialSignature) Decode(r io.Reader) error

Decode attempts to parse a serialized PartialSignature stored in the passed io reader.

func (*PartialSignature) Encode

func (p *PartialSignature) Encode(w io.Writer) error

Encode writes a serialized version of the partial signature to the passed io.Writer

func (*PartialSignature) Verify

func (p *PartialSignature) Verify(pubNonce [PubNonceSize]byte,
	combinedNonce [PubNonceSize]byte, keySet []*ec.PublicKey,
	signingKey *ec.PublicKey, msg [32]byte, signOpts ...SignOption) bool

Verify implements partial signature verification given the public nonce for the signer, aggregate nonce, signer set and finally the message being signed.

type Session

type Session struct {
	// contains filtered or unexported fields
}

Session represents a musig2 signing session. A new instance should be created each time a multi-signature is needed. The session struct handles nonces management, incremental partial sig vitrifaction, as well as final signature combination. Errors are returned when unsafe behavior such as nonce re-use is attempted.

NOTE: This struct should be used over the raw Sign API whenever possible.

func (*Session) CombineSig

func (s *Session) CombineSig(sig *PartialSignature) (bool, error)

CombineSig buffers a partial signature received from a signing party. The method returns true once all the signatures are available, and can be combined into the final signature.

func (*Session) FinalSig

func (s *Session) FinalSig() *schnorr.Signature

FinalSig returns the final combined multi-signature, if present.

func (*Session) NumRegisteredNonces

func (s *Session) NumRegisteredNonces() int

NumRegisteredNonces returns the total number of nonces that have been regsitered so far.

func (*Session) PublicNonce

func (s *Session) PublicNonce() [PubNonceSize]byte

PublicNonce returns the public nonce for a signer. This should be sent to other parties before signing begins, so they can compute the aggregated public nonce.

func (*Session) RegisterPubNonce

func (s *Session) RegisterPubNonce(nonce [PubNonceSize]byte) (bool, error)

RegisterPubNonce should be called for each public nonce from the set of signers. This method returns true once all the public nonces have been accounted for.

func (*Session) Sign

func (s *Session) Sign(msg [32]byte,
	signOpts ...SignOption) (*PartialSignature, error)

Sign generates a partial signature for the target message, using the target context. If this method is called more than once per context, then an error is returned, as that means a nonce was re-used.

type SessionOption

type SessionOption func(*sessionOptions)

SessionOption is a functional option argument that allows callers to modify the musig2 signing is done within a session.

func WithPreGeneratedNonce

func WithPreGeneratedNonce(nonce *Nonces) SessionOption

WithPreGeneratedNonce allows a caller to start a session using a nonce they've generated themselves. This may be useful in protocols where all the signer keys may not be known before nonce exchange needs to occur.

type SignOption

type SignOption func(*signOptions)

SignOption is a functional option argument that allows callers to modify the way we generate musig2 schnorr signatures.

func WithBip86SignTweak

func WithBip86SignTweak() SignOption

WithBip86SignTweak allows a caller to specify a tweak that should be used in a bip 340 manner when signing, factoring in BIP 86 as well. This differs from WithTaprootSignTweak as no true script root will be committed to, instead we just commit to the internal key.

This option should be used in the taproot context to create a valid signature for the keypath spend for taproot, when the output key was generated using BIP 86.

func WithFastSign

func WithFastSign() SignOption

WithFastSign forces signing to skip the extra verification step at the end. Performance sensitive applications may opt to use this option to speed up the signing operation.

func WithSortedKeys

func WithSortedKeys() SignOption

WithSortedKeys determines if the set of signing public keys are to be sorted or not before doing key aggregation.

func WithTaprootSignTweak

func WithTaprootSignTweak(scriptRoot []byte) SignOption

WithTaprootSignTweak allows a caller to specify a tweak that should be used in a bip 340 manner when signing. This differs from WithTweaks as the tweak will be assumed to always be x-only and the intermediate aggregate key before tweaking will be used to generate part of the tweak (as the taproot tweak also commits to the internal key).

This option should be used in the taproot context to create a valid signature for the keypath spend for taproot, when the output key is actually committing to a script path, or some other data.

func WithTweaks

func WithTweaks(tweaks ...KeyTweakDesc) SignOption

WithTweaks determines if the aggregated public key used should apply a series of tweaks before key aggregation.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL