lnd/lnwire/partial_sig.go
Olaoluwa Osuntokun 14949c972d
lnwire: add new musig2 partial signature type
In this commit, we add the new types that'll house musig signatures with
and without their nonces. We send the nonce along with the sig
everywhere but the co-op close flow.
2023-08-22 16:29:24 -07:00

202 lines
5.5 KiB
Go

package lnwire
import (
"io"
"github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
"github.com/lightningnetwork/lnd/tlv"
)
const (
// PartialSigLen is the length of a musig2 partial signature.
PartialSigLen = 32
// PartialSigRecordType is the type of the tlv record for a musig2
// partial signature. This is an _even_ type, which means it's required
// if included.
PartialSigRecordType tlv.Type = 6
)
// PartialSig is the base partial sig type. This only encodes the 32-byte
// partial signature. This is used for the co-op close flow, as both sides have
// already exchanged nonces, so they can send just the partial signature.
type PartialSig struct {
// Sig is the 32-byte musig2 partial signature.
Sig btcec.ModNScalar
}
// NewPartialSig creates a new partial sig.
func NewPartialSig(sig btcec.ModNScalar) PartialSig {
return PartialSig{
Sig: sig,
}
}
// Record returns the tlv record for the partial sig.
func (p *PartialSig) Record() tlv.Record {
return tlv.MakeStaticRecord(
PartialSigRecordType, p, PartialSigLen,
partialSigTypeEncoder, partialSigTypeDecoder,
)
}
// partialSigTypeEncoder encodes a 32-byte musig2 partial signature as a TLV
// value.
func partialSigTypeEncoder(w io.Writer, val interface{}, buf *[8]byte) error {
if v, ok := val.(*PartialSig); ok {
sigBytes := v.Sig.Bytes()
return tlv.EBytes32(w, &sigBytes, buf)
}
return tlv.NewTypeForEncodingErr(val, "lnwire.PartialSig")
}
// Encode writes the encoded version of this message to the passed io.Writer.
func (p *PartialSig) Encode(w io.Writer) error {
return partialSigTypeEncoder(w, p, nil)
}
// partialSigTypeDecoder decodes a 32-byte musig2 extended partial signature.
func partialSigTypeDecoder(r io.Reader, val interface{}, buf *[8]byte,
l uint64) error {
if v, ok := val.(*PartialSig); ok && l == PartialSigLen {
var sBytes [32]byte
err := tlv.DBytes32(r, &sBytes, buf, PartialSigLen)
if err != nil {
return err
}
var s btcec.ModNScalar
s.SetBytes(&sBytes)
*v = PartialSig{
Sig: s,
}
return nil
}
return tlv.NewTypeForDecodingErr(val, "lnwire.PartialSig", l,
PartialSigLen)
}
// Decode reads the encoded version of this message from the passed io.Reader.
func (p *PartialSig) Decode(r io.Reader) error {
return partialSigTypeDecoder(r, p, nil, PartialSigLen)
}
const (
// PartialSigWithNonceLen is the length of a serialized
// PartialSigWithNonce. The sig is encoded as the 32 byte S value
// followed by the 66 nonce value.
PartialSigWithNonceLen = 98
// PartialSigWithNonceRecordType is the type of the tlv record for a
// musig2 partial signature with nonce. This is an _even_ type, which
// means it's required if included.
PartialSigWithNonceRecordType tlv.Type = 2
)
// PartialSigWithNonce is a partial signature with the nonce that was used to
// generate the signature. This is used for funding as well as the commitment
// transaction update dance. By sending the nonce only with the signature, we
// enable the sender to generate their nonce just before they create their
// signature. Signers can use this trait to mix in additional contextual data
// such as the commitment txn itself into their nonce generation function.
//
// The final signature is 98 bytes: 32 bytes for the S value, and 66 bytes for
// the public nonce (two compressed points).
type PartialSigWithNonce struct {
PartialSig
// Nonce is the 66-byte musig2 nonce.
Nonce Musig2Nonce
}
// NewPartialSigWithNonce creates a new partial sig with nonce.
func NewPartialSigWithNonce(nonce [musig2.PubNonceSize]byte,
sig btcec.ModNScalar) *PartialSigWithNonce {
return &PartialSigWithNonce{
Nonce: nonce,
PartialSig: NewPartialSig(sig),
}
}
// Record returns the tlv record for the partial sig with nonce.
func (p *PartialSigWithNonce) Record() tlv.Record {
return tlv.MakeStaticRecord(
PartialSigWithNonceRecordType, p, PartialSigWithNonceLen,
partialSigWithNonceTypeEncoder, partialSigWithNonceTypeDecoder,
)
}
// partialSigWithNonceTypeEncoder encodes 98-byte musig2 extended partial
// signature as: s {32} || nonce {66}.
func partialSigWithNonceTypeEncoder(w io.Writer, val interface{},
buf *[8]byte) error {
if v, ok := val.(*PartialSigWithNonce); ok {
sigBytes := v.Sig.Bytes()
if _, err := w.Write(sigBytes[:]); err != nil {
return err
}
if _, err := w.Write(v.Nonce[:]); err != nil {
return err
}
return nil
}
return tlv.NewTypeForEncodingErr(val, "lnwire.PartialSigWithNonce")
}
// Encode writes the encoded version of this message to the passed io.Writer.
func (p *PartialSigWithNonce) Encode(w io.Writer) error {
return partialSigWithNonceTypeEncoder(w, p, nil)
}
// partialSigWithNonceTypeDecoder decodes a 98-byte musig2 extended partial
// signature.
func partialSigWithNonceTypeDecoder(r io.Reader, val interface{}, buf *[8]byte,
l uint64) error {
if v, ok := val.(*PartialSigWithNonce); ok &&
l == PartialSigWithNonceLen {
var sBytes [32]byte
err := tlv.DBytes32(r, &sBytes, buf, PartialSigLen)
if err != nil {
return err
}
var s btcec.ModNScalar
s.SetBytes(&sBytes)
var nonce [66]byte
if _, err := io.ReadFull(r, nonce[:]); err != nil {
return err
}
*v = PartialSigWithNonce{
PartialSig: NewPartialSig(s),
Nonce: nonce,
}
return nil
}
return tlv.NewTypeForDecodingErr(val, "lnwire.PartialSigWithNonce", l,
PartialSigWithNonceLen)
}
// Decode reads the encoded version of this message from the passed io.Reader.
func (p *PartialSigWithNonce) Decode(r io.Reader) error {
return partialSigWithNonceTypeDecoder(
r, p, nil, PartialSigWithNonceLen,
)
}