multi: upgrade new taproot TLVs to use tlv.OptionalRecordT

In this commit, we update new Taproot related TLVs (nonces, partial sig,
sig with nonce, etc). Along the way we were able to get rid of some
boiler plate, but most importantly, we're able to better protect against
API misuse (using a nonce that isn't initialized, etc) with the new
options API. In some areas this introduces a bit of extra boiler plate,
and where applicable I used some new helper functions to help cut down
on the noise.

Note to reviewers: this is done as a single commit, as changing the API
breaks all callers, so if we want things to compile it needs to be in a
wumbo commit.
This commit is contained in:
Olaoluwa Osuntokun committed 2024-02-29 11:32:26 -06:00
1 parent 6bd556d38c
commit 7feb8b21e1
20 files changed
+401 -288

No files matched your search

+7 -7
View File
@@ -110,7 +110,7 @@ type AcceptChannel struct {
// verify the very first commitment transaction signature.
// This will only be populated if the simple taproot channels type was
// negotiated.
LocalNonce *Musig2Nonce
LocalNonce OptMusig2NonceTLV
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
@@ -141,9 +141,9 @@ func (a *AcceptChannel) Encode(w *bytes.Buffer, pver uint32) error {
if a.LeaseExpiry != nil {
recordProducers = append(recordProducers, a.LeaseExpiry)
}
if a.LocalNonce != nil {
recordProducers = append(recordProducers, a.LocalNonce)
}
a.LocalNonce.WhenSome(func(localNonce Musig2NonceTLV) {
recordProducers = append(recordProducers, &localNonce)
})
err := EncodeMessageExtraData(&a.ExtraData, recordProducers...)
if err != nil {
return err
@@ -248,7 +248,7 @@ func (a *AcceptChannel) Decode(r io.Reader, pver uint32) error {
var (
chanType ChannelType
leaseExpiry LeaseExpiry
localNonce Musig2Nonce
localNonce = a.LocalNonce.Zero()
)
typeMap, err := tlvRecords.ExtractRecords(
&a.UpfrontShutdownScript, &chanType, &leaseExpiry,
@@ -265,8 +265,8 @@ func (a *AcceptChannel) Decode(r io.Reader, pver uint32) error {
if val, ok := typeMap[LeaseExpiryRecordType]; ok && val == nil {
a.LeaseExpiry = &leaseExpiry
}
if val, ok := typeMap[NonceRecordType]; ok && val == nil {
a.LocalNonce = &localNonce
if val, ok := typeMap[a.LocalNonce.TlvType()]; ok && val == nil {
a.LocalNonce = tlv.SomeRecordT(localNonce)
}
a.ExtraData = tlvRecords
+7 -7
View File
@@ -31,7 +31,7 @@ type ChannelReady struct {
// This will only be populated if the simple taproot channels type was
// negotiated. This is the local nonce that will be used by the sender
// to accept a new commitment state transition.
NextLocalNonce *Musig2Nonce
NextLocalNonce OptMusig2NonceTLV
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
@@ -77,7 +77,7 @@ func (c *ChannelReady) Decode(r io.Reader, _ uint32) error {
// the AliasScidRecordType.
var (
aliasScid ShortChannelID
localNonce Musig2Nonce
localNonce = c.NextLocalNonce.Zero()
)
typeMap, err := tlvRecords.ExtractRecords(
&aliasScid, &localNonce,
@@ -91,8 +91,8 @@ func (c *ChannelReady) Decode(r io.Reader, _ uint32) error {
if val, ok := typeMap[AliasScidRecordType]; ok && val == nil {
c.AliasScid = &aliasScid
}
if val, ok := typeMap[NonceRecordType]; ok && val == nil {
c.NextLocalNonce = &localNonce
if val, ok := typeMap[c.NextLocalNonce.TlvType()]; ok && val == nil {
c.NextLocalNonce = tlv.SomeRecordT(localNonce)
}
if len(tlvRecords) != 0 {
@@ -121,9 +121,9 @@ func (c *ChannelReady) Encode(w *bytes.Buffer, _ uint32) error {
if c.AliasScid != nil {
recordProducers = append(recordProducers, c.AliasScid)
}
if c.NextLocalNonce != nil {
recordProducers = append(recordProducers, c.NextLocalNonce)
}
c.NextLocalNonce.WhenSome(func(localNonce Musig2NonceTLV) {
recordProducers = append(recordProducers, &localNonce)
})
err := EncodeMessageExtraData(&c.ExtraData, recordProducers...)
if err != nil {
return err
+10 -9
View File
@@ -82,8 +82,7 @@ type ChannelReestablish struct {
// This will only be populated if the simple taproot channels type was
// negotiated.
//
// TODO(roasbeef): rename to verification nonce
LocalNonce *Musig2Nonce
LocalNonce OptMusig2NonceTLV
// DynHeight is an optional field that stores the dynamic commitment
// negotiation height that is incremented upon successful completion of
@@ -138,9 +137,9 @@ func (a *ChannelReestablish) Encode(w *bytes.Buffer, pver uint32) error {
}
recordProducers := make([]tlv.RecordProducer, 0, 1)
if a.LocalNonce != nil {
recordProducers = append(recordProducers, a.LocalNonce)
}
a.LocalNonce.WhenSome(func(localNonce Musig2NonceTLV) {
recordProducers = append(recordProducers, &localNonce)
})
a.DynHeight.WhenSome(func(h DynHeight) {
recordProducers = append(recordProducers, &h)
})
@@ -203,8 +202,10 @@ func (a *ChannelReestablish) Decode(r io.Reader, pver uint32) error {
return err
}
var localNonce Musig2Nonce
var dynHeight DynHeight
var (
dynHeight DynHeight
localNonce = a.LocalNonce.Zero()
)
typeMap, err := tlvRecords.ExtractRecords(
&localNonce, &dynHeight,
)
@@ -212,8 +213,8 @@ func (a *ChannelReestablish) Decode(r io.Reader, pver uint32) error {
return err
}
if val, ok := typeMap[NonceRecordType]; ok && val == nil {
a.LocalNonce = &localNonce
if val, ok := typeMap[a.LocalNonce.TlvType()]; ok && val == nil {
a.LocalNonce = tlv.SomeRecordT(localNonce)
}
if val, ok := typeMap[CRDynHeight]; ok && val == nil {
a.DynHeight = fn.Some(dynHeight)
+3 -3
View File
@@ -50,9 +50,9 @@ type ClosingComplete struct {
// decodeClosingSigs decodes the closing sig TLV records in the passed
// ExtraOpaqueData.
func decodeClosingSigs(c *ClosingSigs, tlvRecords ExtraOpaqueData) error {
sig1 := tlv.ZeroRecordT[tlv.TlvType1, Sig]()
sig2 := tlv.ZeroRecordT[tlv.TlvType2, Sig]()
sig3 := tlv.ZeroRecordT[tlv.TlvType3, Sig]()
sig1 := c.CloserNoClosee.Zero()
sig2 := c.NoCloserClosee.Zero()
sig3 := c.CloserAndClosee.Zero()
typeMap, err := tlvRecords.ExtractRecords(&sig1, &sig2, &sig3)
if err != nil {
+7 -9
View File
@@ -36,7 +36,7 @@ type ClosingSigned struct {
//
// NOTE: This field is only populated if a musig2 taproot channel is
// being signed for. In this case, the above Sig type MUST be blank.
PartialSig *PartialSig
PartialSig OptPartialSigTLV
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
@@ -76,17 +76,15 @@ func (c *ClosingSigned) Decode(r io.Reader, pver uint32) error {
return err
}
var (
partialSig PartialSig
)
partialSig := c.PartialSig.Zero()
typeMap, err := tlvRecords.ExtractRecords(&partialSig)
if err != nil {
return err
}
// Set the corresponding TLV types if they were included in the stream.
if val, ok := typeMap[PartialSigRecordType]; ok && val == nil {
c.PartialSig = &partialSig
if val, ok := typeMap[c.PartialSig.TlvType()]; ok && val == nil {
c.PartialSig = tlv.SomeRecordT(partialSig)
}
if len(tlvRecords) != 0 {
@@ -102,9 +100,9 @@ func (c *ClosingSigned) Decode(r io.Reader, pver uint32) error {
// This is part of the lnwire.Message interface.
func (c *ClosingSigned) Encode(w *bytes.Buffer, pver uint32) error {
recordProducers := make([]tlv.RecordProducer, 0, 1)
if c.PartialSig != nil {
recordProducers = append(recordProducers, c.PartialSig)
}
c.PartialSig.WhenSome(func(sig PartialSigTLV) {
recordProducers = append(recordProducers, &sig)
})
err := EncodeMessageExtraData(&c.ExtraData, recordProducers...)
if err != nil {
return err
+7 -9
View File
@@ -43,7 +43,7 @@ type CommitSig struct {
//
// NOTE: This field is only populated if a musig2 taproot channel is
// being signed for. In this case, the above Sig type MUST be blank.
PartialSig *PartialSigWithNonce
PartialSig OptPartialSigWithNonceTLV
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
@@ -81,17 +81,15 @@ func (c *CommitSig) Decode(r io.Reader, pver uint32) error {
return err
}
var (
partialSig PartialSigWithNonce
)
partialSig := c.PartialSig.Zero()
typeMap, err := tlvRecords.ExtractRecords(&partialSig)
if err != nil {
return err
}
// Set the corresponding TLV types if they were included in the stream.
if val, ok := typeMap[PartialSigWithNonceRecordType]; ok && val == nil {
c.PartialSig = &partialSig
if val, ok := typeMap[c.PartialSig.TlvType()]; ok && val == nil {
c.PartialSig = tlv.SomeRecordT(partialSig)
}
if len(tlvRecords) != 0 {
@@ -107,9 +105,9 @@ func (c *CommitSig) Decode(r io.Reader, pver uint32) error {
// This is part of the lnwire.Message interface.
func (c *CommitSig) Encode(w *bytes.Buffer, pver uint32) error {
recordProducers := make([]tlv.RecordProducer, 0, 1)
if c.PartialSig != nil {
recordProducers = append(recordProducers, c.PartialSig)
}
c.PartialSig.WhenSome(func(sig PartialSigWithNonceTLV) {
recordProducers = append(recordProducers, &sig)
})
err := EncodeMessageExtraData(&c.ExtraData, recordProducers...)
if err != nil {
return err
+7 -9
View File
@@ -32,7 +32,7 @@ type FundingCreated struct {
//
// NOTE: This field is only populated if a musig2 taproot channel is
// being signed for. In this case, the above Sig type MUST be blank.
PartialSig *PartialSigWithNonce
PartialSig OptPartialSigWithNonceTLV
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
@@ -51,9 +51,9 @@ var _ Message = (*FundingCreated)(nil)
// This is part of the lnwire.Message interface.
func (f *FundingCreated) Encode(w *bytes.Buffer, pver uint32) error {
recordProducers := make([]tlv.RecordProducer, 0, 1)
if f.PartialSig != nil {
recordProducers = append(recordProducers, f.PartialSig)
}
f.PartialSig.WhenSome(func(sig PartialSigWithNonceTLV) {
recordProducers = append(recordProducers, &sig)
})
err := EncodeMessageExtraData(&f.ExtraData, recordProducers...)
if err != nil {
return err
@@ -92,17 +92,15 @@ func (f *FundingCreated) Decode(r io.Reader, pver uint32) error {
return err
}
var (
partialSig PartialSigWithNonce
)
partialSig := f.PartialSig.Zero()
typeMap, err := tlvRecords.ExtractRecords(&partialSig)
if err != nil {
return err
}
// Set the corresponding TLV types if they were included in the stream.
if val, ok := typeMap[PartialSigWithNonceRecordType]; ok && val == nil {
f.PartialSig = &partialSig
if val, ok := typeMap[f.PartialSig.TlvType()]; ok && val == nil {
f.PartialSig = tlv.SomeRecordT(partialSig)
}
if len(tlvRecords) != 0 {
+7 -9
View File
@@ -24,7 +24,7 @@ type FundingSigned struct {
//
// NOTE: This field is only populated if a musig2 taproot channel is
// being signed for. In this case, the above Sig type MUST be blank.
PartialSig *PartialSigWithNonce
PartialSig OptPartialSigWithNonceTLV
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
@@ -43,9 +43,9 @@ var _ Message = (*FundingSigned)(nil)
// This is part of the lnwire.Message interface.
func (f *FundingSigned) Encode(w *bytes.Buffer, pver uint32) error {
recordProducers := make([]tlv.RecordProducer, 0, 1)
if f.PartialSig != nil {
recordProducers = append(recordProducers, f.PartialSig)
}
f.PartialSig.WhenSome(func(sig PartialSigWithNonceTLV) {
recordProducers = append(recordProducers, &sig)
})
err := EncodeMessageExtraData(&f.ExtraData, recordProducers...)
if err != nil {
return err
@@ -78,17 +78,15 @@ func (f *FundingSigned) Decode(r io.Reader, pver uint32) error {
return err
}
var (
partialSig PartialSigWithNonce
)
partialSig := f.PartialSig.Zero()
typeMap, err := tlvRecords.ExtractRecords(&partialSig)
if err != nil {
return err
}
// Set the corresponding TLV types if they were included in the stream.
if val, ok := typeMap[PartialSigWithNonceRecordType]; ok && val == nil {
f.PartialSig = &partialSig
if val, ok := typeMap[f.PartialSig.TlvType()]; ok && val == nil {
f.PartialSig = tlv.SomeRecordT(partialSig)
}
if len(tlvRecords) != 0 {
+62 -41
View File
@@ -44,11 +44,19 @@ var (
const letterBytes = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
func randLocalNonce(r *rand.Rand) *Musig2Nonce {
func randLocalNonce(r *rand.Rand) Musig2Nonce {
var nonce Musig2Nonce
_, _ = io.ReadFull(r, nonce[:])
return &nonce
return nonce
}
func someLocalNonce[T tlv.TlvType](
r *rand.Rand) tlv.OptionalRecordT[T, Musig2Nonce] {
return tlv.SomeRecordT(tlv.NewRecordT[T, Musig2Nonce](
randLocalNonce(r),
))
}
func randPartialSig(r *rand.Rand) (*PartialSig, error) {
@@ -65,6 +73,19 @@ func randPartialSig(r *rand.Rand) (*PartialSig, error) {
}, nil
}
func somePartialSig(t *testing.T,
r *rand.Rand) tlv.OptionalRecordT[PartialSigType, PartialSig] {
sig, err := randPartialSig(r)
if err != nil {
t.Fatal(err)
}
return tlv.SomeRecordT(tlv.NewRecordT[PartialSigType, PartialSig](
*sig,
))
}
func randPartialSigWithNonce(r *rand.Rand) (*PartialSigWithNonce, error) {
var sigBytes [32]byte
if _, err := r.Read(sigBytes[:]); err != nil {
@@ -76,10 +97,25 @@ func randPartialSigWithNonce(r *rand.Rand) (*PartialSigWithNonce, error) {
return &PartialSigWithNonce{
PartialSig: NewPartialSig(s),
Nonce: *randLocalNonce(r),
Nonce: randLocalNonce(r),
}, nil
}
func somePartialSigWithNonce(t *testing.T,
r *rand.Rand) OptPartialSigWithNonceTLV {
sig, err := randPartialSigWithNonce(r)
if err != nil {
t.Fatal(err)
}
return tlv.SomeRecordT(
tlv.NewRecordT[PartialSigWithNonceType, PartialSigWithNonce](
*sig,
),
)
}
func randAlias(r *rand.Rand) NodeAlias {
var a NodeAlias
for i := range a {
@@ -480,7 +516,8 @@ func TestLightningWireProtocol(t *testing.T) {
req.LeaseExpiry = new(LeaseExpiry)
*req.LeaseExpiry = LeaseExpiry(1337)
req.LocalNonce = randLocalNonce(r)
//nolint:lll
req.LocalNonce = someLocalNonce[NonceRecordTypeT](r)
} else {
req.UpfrontShutdownScript = []byte{}
}
@@ -554,7 +591,8 @@ func TestLightningWireProtocol(t *testing.T) {
req.LeaseExpiry = new(LeaseExpiry)
*req.LeaseExpiry = LeaseExpiry(1337)
req.LocalNonce = randLocalNonce(r)
//nolint:lll
req.LocalNonce = someLocalNonce[NonceRecordTypeT](r)
} else {
req.UpfrontShutdownScript = []byte{}
}
@@ -591,12 +629,7 @@ func TestLightningWireProtocol(t *testing.T) {
// 1/2 chance to attach a partial sig.
if r.Intn(2) == 0 {
req.PartialSig, err = randPartialSigWithNonce(r)
if err != nil {
t.Fatalf("unable to generate sig: %v",
err)
return
}
req.PartialSig = somePartialSigWithNonce(t, r)
}
v[0] = reflect.ValueOf(req)
@@ -621,12 +654,7 @@ func TestLightningWireProtocol(t *testing.T) {
// 1/2 chance to attach a partial sig.
if r.Intn(2) == 0 {
req.PartialSig, err = randPartialSigWithNonce(r)
if err != nil {
t.Fatalf("unable to generate sig: %v",
err)
return
}
req.PartialSig = somePartialSigWithNonce(t, r)
}
v[0] = reflect.ValueOf(req)
@@ -649,7 +677,9 @@ func TestLightningWireProtocol(t *testing.T) {
if r.Int31()%2 == 0 {
scid := NewShortChanIDFromInt(uint64(r.Int63()))
req.AliasScid = &scid
req.NextLocalNonce = randLocalNonce(r)
//nolint:lll
req.NextLocalNonce = someLocalNonce[NonceRecordTypeT](r)
}
v[0] = reflect.ValueOf(*req)
@@ -676,9 +706,8 @@ func TestLightningWireProtocol(t *testing.T) {
}
if r.Int31()%2 == 0 {
req.ShutdownNonce = (*ShutdownNonce)(
randLocalNonce(r),
)
//nolint:lll
req.ShutdownNonce = someLocalNonce[ShutdownNonceType](r)
}
v[0] = reflect.ValueOf(req)
@@ -701,12 +730,7 @@ func TestLightningWireProtocol(t *testing.T) {
}
if r.Int31()%2 == 0 {
req.PartialSig, err = randPartialSig(r)
if err != nil {
t.Fatalf("unable to generate sig: %v",
err)
return
}
req.PartialSig = somePartialSig(t, r)
}
v[0] = reflect.ValueOf(req)
@@ -854,12 +878,7 @@ func TestLightningWireProtocol(t *testing.T) {
// 50/50 chance to attach a partial sig.
if r.Int31()%2 == 0 {
req.PartialSig, err = randPartialSigWithNonce(r)
if err != nil {
t.Fatalf("unable to generate sig: %v",
err)
return
}
req.PartialSig = somePartialSigWithNonce(t, r)
}
v[0] = reflect.ValueOf(*req)
@@ -883,7 +902,8 @@ func TestLightningWireProtocol(t *testing.T) {
// 50/50 chance to attach a local nonce.
if r.Int31()%2 == 0 {
req.LocalNonce = randLocalNonce(r)
//nolint:lll
req.LocalNonce = someLocalNonce[NonceRecordTypeT](r)
}
v[0] = reflect.ValueOf(*req)
@@ -1107,7 +1127,8 @@ func TestLightningWireProtocol(t *testing.T) {
return
}
req.LocalNonce = randLocalNonce(r)
//nolint:lll
req.LocalNonce = someLocalNonce[NonceRecordTypeT](r)
}
v[0] = reflect.ValueOf(req)
@@ -1232,7 +1253,7 @@ func TestLightningWireProtocol(t *testing.T) {
}
if r.Intn(2) == 0 {
sig := tlv.ZeroRecordT[tlv.TlvType1, Sig]()
sig := req.CloserNoClosee.Zero()
_, err := r.Read(sig.Val.bytes[:])
if err != nil {
t.Fatalf("unable to generate sig: %v",
@@ -1243,7 +1264,7 @@ func TestLightningWireProtocol(t *testing.T) {
req.CloserNoClosee = tlv.SomeRecordT(sig)
}
if r.Intn(2) == 0 {
sig := tlv.ZeroRecordT[tlv.TlvType2, Sig]()
sig := req.NoCloserClosee.Zero()
_, err := r.Read(sig.Val.bytes[:])
if err != nil {
t.Fatalf("unable to generate sig: %v",
@@ -1254,7 +1275,7 @@ func TestLightningWireProtocol(t *testing.T) {
req.NoCloserClosee = tlv.SomeRecordT(sig)
}
if r.Intn(2) == 0 {
sig := tlv.ZeroRecordT[tlv.TlvType3, Sig]()
sig := req.CloserAndClosee.Zero()
_, err := r.Read(sig.Val.bytes[:])
if err != nil {
t.Fatalf("unable to generate sig: %v",
@@ -1281,7 +1302,7 @@ func TestLightningWireProtocol(t *testing.T) {
}
if r.Intn(2) == 0 {
sig := tlv.ZeroRecordT[tlv.TlvType1, Sig]()
sig := req.CloserNoClosee.Zero()
_, err := r.Read(sig.Val.bytes[:])
if err != nil {
t.Fatalf("unable to generate sig: %v",
@@ -1292,7 +1313,7 @@ func TestLightningWireProtocol(t *testing.T) {
req.CloserNoClosee = tlv.SomeRecordT(sig)
}
if r.Intn(2) == 0 {
sig := tlv.ZeroRecordT[tlv.TlvType2, Sig]()
sig := req.NoCloserClosee.Zero()
_, err := r.Read(sig.Val.bytes[:])
if err != nil {
t.Fatalf("unable to generate sig: %v",
@@ -1303,7 +1324,7 @@ func TestLightningWireProtocol(t *testing.T) {
req.NoCloserClosee = tlv.SomeRecordT(sig)
}
if r.Intn(2) == 0 {
sig := tlv.ZeroRecordT[tlv.TlvType3, Sig]()
sig := req.CloserAndClosee.Zero()
_, err := r.Read(sig.Val.bytes[:])
if err != nil {
t.Fatalf("unable to generate sig: %v",
+28 -9
View File
@@ -7,21 +7,33 @@ import (
"github.com/lightningnetwork/lnd/tlv"
)
const (
// NonceRecordType is the TLV type used to encode a local musig2 nonce.
NonceRecordType tlv.Type = 4
)
// NonceRecordTypeT is the TLV type used to encode a local musig2 nonce.
type NonceRecordTypeT = tlv.TlvType4
// Musig2Nonce represents a musig2 public nonce, which is the concatenation of
// two EC points serialized in compressed format.
type Musig2Nonce [musig2.PubNonceSize]byte
// nonceRecordType is the TLV (integer) type used to encode a local musig2
// nonce.
var nonceRecordType tlv.Type = (NonceRecordTypeT)(nil).TypeVal()
type (
// Musig2Nonce represents a musig2 public nonce, which is the
// concatenation of two EC points serialized in compressed format.
Musig2Nonce [musig2.PubNonceSize]byte
// Musig2NonceTLV is a TLV type that can be used to encode/decode a
// musig2 nonce. This is an optional TLV.
Musig2NonceTLV = tlv.RecordT[NonceRecordTypeT, Musig2Nonce]
// OptMusig2NonceTLV is a TLV type that can be used to encode/decode a
// musig2 nonce.
OptMusig2NonceTLV = tlv.OptionalRecordT[NonceRecordTypeT, Musig2Nonce]
)
// Record returns a TLV record that can be used to encode/decode the musig2
// nonce from a given TLV stream.
func (m *Musig2Nonce) Record() tlv.Record {
return tlv.MakeStaticRecord(
NonceRecordType, m, musig2.PubNonceSize, nonceTypeEncoder,
nonceTypeDecoder,
nonceRecordType, m, musig2.PubNonceSize,
nonceTypeEncoder, nonceTypeDecoder,
)
}
@@ -48,3 +60,10 @@ func nonceTypeDecoder(r io.Reader, val interface{}, _ *[8]byte,
val, "lnwire.Musig2Nonce", l, musig2.PubNonceSize,
)
}
// SomeMusig2Nonce is a helper function that creates a musig2 nonce TLV.
func SomeMusig2Nonce(nonce Musig2Nonce) OptMusig2NonceTLV {
return tlv.SomeRecordT(
tlv.NewRecordT[NonceRecordTypeT, Musig2Nonce](nonce),
)
}
+7 -7
View File
@@ -146,7 +146,7 @@ type OpenChannel struct {
// verify the very first commitment transaction signature. This will
// only be populated if the simple taproot channels type was
// negotiated.
LocalNonce *Musig2Nonce
LocalNonce OptMusig2NonceTLV
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
@@ -175,9 +175,9 @@ func (o *OpenChannel) Encode(w *bytes.Buffer, pver uint32) error {
if o.LeaseExpiry != nil {
recordProducers = append(recordProducers, o.LeaseExpiry)
}
if o.LocalNonce != nil {
recordProducers = append(recordProducers, o.LocalNonce)
}
o.LocalNonce.WhenSome(func(localNonce Musig2NonceTLV) {
recordProducers = append(recordProducers, &localNonce)
})
err := EncodeMessageExtraData(&o.ExtraData, recordProducers...)
if err != nil {
return err
@@ -302,7 +302,7 @@ func (o *OpenChannel) Decode(r io.Reader, pver uint32) error {
var (
chanType ChannelType
leaseExpiry LeaseExpiry
localNonce Musig2Nonce
localNonce = o.LocalNonce.Zero()
)
typeMap, err := tlvRecords.ExtractRecords(
&o.UpfrontShutdownScript, &chanType, &leaseExpiry,
@@ -319,8 +319,8 @@ func (o *OpenChannel) Decode(r io.Reader, pver uint32) error {
if val, ok := typeMap[LeaseExpiryRecordType]; ok && val == nil {
o.LeaseExpiry = &leaseExpiry
}
if val, ok := typeMap[NonceRecordType]; ok && val == nil {
o.LocalNonce = &localNonce
if val, ok := typeMap[o.LocalNonce.TlvType()]; ok && val == nil {
o.LocalNonce = tlv.SomeRecordT(localNonce)
}
o.ExtraData = tlvRecords
+55 -9
View File
@@ -11,11 +11,20 @@ import (
const (
// PartialSigLen is the length of a musig2 partial signature.
PartialSigLen = 32
)
// PartialSigRecordType is the type of the tlv record for a musig2
type (
// PartialSigType 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
PartialSigType = tlv.TlvType6
// PartialSigTLV is a tlv record for a musig2 partial signature.
PartialSigTLV = tlv.RecordT[PartialSigType, PartialSig]
// OptPartialSigTLV is a tlv record for a musig2 partial signature.
// This is an optional record type.
OptPartialSigTLV = tlv.OptionalRecordT[PartialSigType, PartialSig]
)
// PartialSig is the base partial sig type. This only encodes the 32-byte
@@ -36,7 +45,7 @@ func NewPartialSig(sig btcec.ModNScalar) PartialSig {
// Record returns the tlv record for the partial sig.
func (p *PartialSig) Record() tlv.Record {
return tlv.MakeStaticRecord(
PartialSigRecordType, p, PartialSigLen,
(PartialSigType)(nil).TypeVal(), p, PartialSigLen,
partialSigTypeEncoder, partialSigTypeDecoder,
)
}
@@ -88,16 +97,35 @@ func (p *PartialSig) Decode(r io.Reader) error {
return partialSigTypeDecoder(r, p, nil, PartialSigLen)
}
// SomePartialSig is a helper function that returns an otional PartialSig.
func SomePartialSig(sig PartialSig) OptPartialSigTLV {
return tlv.SomeRecordT(tlv.NewRecordT[PartialSigType, PartialSig](sig))
}
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
type (
// PartialSigWithNonceType 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.
PartialSigWithNonceType = tlv.TlvType2
// PartialSigWithNonceTLV is a tlv record for a musig2 partial
// signature.
PartialSigWithNonceTLV = tlv.RecordT[
PartialSigWithNonceType, PartialSigWithNonce,
]
// OptPartialSigWithNonceTLV is a tlv record for a musig2 partial
// signature. This is an optional record type.
OptPartialSigWithNonceTLV = tlv.OptionalRecordT[
PartialSigWithNonceType, PartialSigWithNonce,
]
)
// PartialSigWithNonce is a partial signature with the nonce that was used to
@@ -129,8 +157,9 @@ func NewPartialSigWithNonce(nonce [musig2.PubNonceSize]byte,
// 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,
(PartialSigWithNonceType)(nil).TypeVal(), p,
PartialSigWithNonceLen, partialSigWithNonceTypeEncoder,
partialSigWithNonceTypeDecoder,
)
}
@@ -199,3 +228,20 @@ func (p *PartialSigWithNonce) Decode(r io.Reader) error {
r, p, nil, PartialSigWithNonceLen,
)
}
// MaybePartialSigWithNonce is a helper function that returns an optional
// PartialSigWithNonceTLV.
func MaybePartialSigWithNonce(sig *PartialSigWithNonce,
) OptPartialSigWithNonceTLV {
if sig == nil {
var none OptPartialSigWithNonceTLV
return none
}
return tlv.SomeRecordT(
tlv.NewRecordT[PartialSigWithNonceType, PartialSigWithNonce](
*sig,
),
)
}
+8 -8
View File
@@ -36,7 +36,7 @@ type RevokeAndAck struct {
// LocalNonce is the next _local_ nonce for the sending party. This
// allows the receiving party to propose a new commitment using their
// remote nonce and the sender's local nonce.
LocalNonce *Musig2Nonce
LocalNonce OptMusig2NonceTLV
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
@@ -74,15 +74,15 @@ func (c *RevokeAndAck) Decode(r io.Reader, pver uint32) error {
return err
}
var musigNonce Musig2Nonce
typeMap, err := tlvRecords.ExtractRecords(&musigNonce)
localNonce := c.LocalNonce.Zero()
typeMap, err := tlvRecords.ExtractRecords(&localNonce)
if err != nil {
return err
}
// Set the corresponding TLV types if they were included in the stream.
if val, ok := typeMap[NonceRecordType]; ok && val == nil {
c.LocalNonce = &musigNonce
if val, ok := typeMap[c.LocalNonce.TlvType()]; ok && val == nil {
c.LocalNonce = tlv.SomeRecordT(localNonce)
}
if len(tlvRecords) != 0 {
@@ -98,9 +98,9 @@ func (c *RevokeAndAck) Decode(r io.Reader, pver uint32) error {
// This is part of the lnwire.Message interface.
func (c *RevokeAndAck) Encode(w *bytes.Buffer, pver uint32) error {
recordProducers := make([]tlv.RecordProducer, 0, 1)
if c.LocalNonce != nil {
recordProducers = append(recordProducers, c.LocalNonce)
}
c.LocalNonce.WhenSome(func(localNonce Musig2NonceTLV) {
recordProducers = append(recordProducers, &localNonce)
})
err := EncodeMessageExtraData(&c.ExtraData, recordProducers...)
if err != nil {
return err
+19 -48
View File
@@ -4,52 +4,21 @@ import (
"bytes"
"io"
"github.com/btcsuite/btcd/btcec/v2/schnorr/musig2"
"github.com/lightningnetwork/lnd/tlv"
)
const (
// ShutdownNonceRecordType is the type of the shutdown nonce TLV record.
ShutdownNonceRecordType = 8
type (
// ShutdownNonceType is the type of the shutdown nonce TLV record.
ShutdownNonceType = tlv.TlvType8
// ShutdownNonceTLV is the TLV record that contains the shutdown nonce.
ShutdownNonceTLV = tlv.OptionalRecordT[ShutdownNonceType, Musig2Nonce]
)
// ShutdownNonce is the type of the nonce we send during the shutdown flow.
// Unlike the other nonces, this nonce is symmetric w.r.t the message being
// signed (there's only one message for shutdown: the co-op close txn).
type ShutdownNonce Musig2Nonce
// Record returns a TLV record that can be used to encode/decode the musig2
// nonce from a given TLV stream.
func (s *ShutdownNonce) Record() tlv.Record {
return tlv.MakeStaticRecord(
ShutdownNonceRecordType, s, musig2.PubNonceSize,
shutdownNonceTypeEncoder, shutdownNonceTypeDecoder,
)
}
// shutdownNonceTypeEncoder is a custom TLV encoder for the Musig2Nonce type.
func shutdownNonceTypeEncoder(w io.Writer, val interface{},
_ *[8]byte) error {
if v, ok := val.(*ShutdownNonce); ok {
_, err := w.Write(v[:])
return err
}
return tlv.NewTypeForEncodingErr(val, "lnwire.Musig2Nonce")
}
// shutdownNonceTypeDecoder is a custom TLV decoder for the Musig2Nonce record.
func shutdownNonceTypeDecoder(r io.Reader, val interface{}, _ *[8]byte,
l uint64) error {
if v, ok := val.(*ShutdownNonce); ok {
_, err := io.ReadFull(r, v[:])
return err
}
return tlv.NewTypeForDecodingErr(
val, "lnwire.ShutdownNonce", l, musig2.PubNonceSize,
// SomeShutdownNonce returns a ShutdownNonceTLV with the given nonce.
func SomeShutdownNonce(nonce Musig2Nonce) ShutdownNonceTLV {
return tlv.SomeRecordT(
tlv.NewRecordT[ShutdownNonceType, Musig2Nonce](nonce),
)
}
@@ -67,7 +36,7 @@ type Shutdown struct {
// ShutdownNonce is the nonce the sender will use to sign the first
// co-op sign offer.
ShutdownNonce *ShutdownNonce
ShutdownNonce ShutdownNonceTLV
// ExtraData is the set of data that was appended to this message to
// fill out the full maximum transport message size. These fields can
@@ -102,15 +71,15 @@ func (s *Shutdown) Decode(r io.Reader, pver uint32) error {
return err
}
var musigNonce ShutdownNonce
musigNonce := s.ShutdownNonce.Zero()
typeMap, err := tlvRecords.ExtractRecords(&musigNonce)
if err != nil {
return err
}
// Set the corresponding TLV types if they were included in the stream.
if val, ok := typeMap[ShutdownNonceRecordType]; ok && val == nil {
s.ShutdownNonce = &musigNonce
if val, ok := typeMap[s.ShutdownNonce.TlvType()]; ok && val == nil {
s.ShutdownNonce = tlv.SomeRecordT(musigNonce)
}
if len(tlvRecords) != 0 {
@@ -126,9 +95,11 @@ func (s *Shutdown) Decode(r io.Reader, pver uint32) error {
// This is part of the lnwire.Message interface.
func (s *Shutdown) Encode(w *bytes.Buffer, pver uint32) error {
recordProducers := make([]tlv.RecordProducer, 0, 1)
if s.ShutdownNonce != nil {
recordProducers = append(recordProducers, s.ShutdownNonce)
}
s.ShutdownNonce.WhenSome(
func(nonce tlv.RecordT[ShutdownNonceType, Musig2Nonce]) {
recordProducers = append(recordProducers, &nonce)
},
)
err := EncodeMessageExtraData(&s.ExtraData, recordProducers...)
if err != nil {
return err