• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

67.72
/lnwire/signature.go
1
package lnwire
2

3
import (
4
        "errors"
5
        "fmt"
6

7
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
8
        "github.com/btcsuite/btcd/btcec/v2/schnorr"
9
        "github.com/lightningnetwork/lnd/input"
10
        "github.com/lightningnetwork/lnd/tlv"
11
)
12

13
var (
14
        errSigTooShort = errors.New("malformed signature: too short")
15
        errBadLength   = errors.New("malformed signature: bad length")
16
        errBadRLength  = errors.New("malformed signature: bogus R length")
17
        errBadSLength  = errors.New("malformed signature: bogus S length")
18
        errRTooLong    = errors.New("R is over 32 bytes long without padding")
19
        errSTooLong    = errors.New("S is over 32 bytes long without padding")
20
)
21

22
// sigType represents the type of signature that is carried within the Sig.
23
// Today this can either be an ECDSA sig or a schnorr sig. Both of these can
24
// fit cleanly into 64 bytes.
25
type sigType uint
26

27
const (
28
        // sigTypeECDSA represents an ECDSA signature.
29
        sigTypeECDSA sigType = iota
30

31
        // sigTypeSchnorr represents a schnorr signature.
32
        sigTypeSchnorr
33
)
34

35
// Sig is a fixed-sized ECDSA signature or 64-byte schnorr signature. For the
36
// ECDSA sig, unlike Bitcoin, we use fixed sized signatures on the wire,
37
// instead of DER encoded signatures. This type provides several methods to
38
// convert to/from a regular Bitcoin DER encoded signature (raw bytes and
39
// *ecdsa.Signature).
40
type Sig struct {
41
        bytes [64]byte
42

43
        sigType sigType
44
}
45

46
// ForceSchnorr forces the signature to be interpreted as a schnorr signature.
47
// This is useful when reading an HTLC sig off the wire for a taproot channel.
48
// In this case, in order to obtain an input.Signature, we need to know that
49
// the sig is a schnorr sig.
50
func (s *Sig) ForceSchnorr() {
3✔
51
        s.sigType = sigTypeSchnorr
3✔
52
}
3✔
53

54
// RawBytes returns the raw bytes of signature.
55
func (s *Sig) RawBytes() []byte {
3✔
56
        return s.bytes[:]
3✔
57
}
3✔
58

59
// Copy copies the signature into a new Sig instance.
UNCOV
60
func (s *Sig) Copy() Sig {
×
UNCOV
61
        var sCopy Sig
×
UNCOV
62
        copy(sCopy.bytes[:], s.bytes[:])
×
UNCOV
63
        sCopy.sigType = s.sigType
×
UNCOV
64

×
UNCOV
65
        return sCopy
×
UNCOV
66
}
×
67

68
// Record returns a Record that can be used to encode or decode the backing
69
// object.
70
//
71
// This returns a record that serializes the sig as a 64-byte fixed size
72
// signature.
UNCOV
73
func (s *Sig) Record() tlv.Record {
×
UNCOV
74
        // We set a type here as zero as it isn't needed when used as a
×
UNCOV
75
        // RecordT.
×
UNCOV
76
        return tlv.MakePrimitiveRecord(0, &s.bytes)
×
UNCOV
77
}
×
78

79
// NewSigFromWireECDSA returns a Sig instance based on an ECDSA signature
80
// that's already in the 64-byte format we expect.
81
func NewSigFromWireECDSA(sig []byte) (Sig, error) {
3✔
82
        if len(sig) != 64 {
3✔
83
                return Sig{}, fmt.Errorf("%w: %v bytes", errSigTooShort,
×
84
                        len(sig))
×
85
        }
×
86

87
        var s Sig
3✔
88
        copy(s.bytes[:], sig)
3✔
89

3✔
90
        return s, nil
3✔
91
}
92

93
// NewSigFromECDSARawSignature returns a Sig from a Bitcoin raw signature
94
// encoded in the canonical DER encoding.
95
func NewSigFromECDSARawSignature(sig []byte) (Sig, error) {
3✔
96
        var b [64]byte
3✔
97

3✔
98
        // Check the total length is above the minimal.
3✔
99
        if len(sig) < ecdsa.MinSigLen {
3✔
UNCOV
100
                return Sig{}, errSigTooShort
×
UNCOV
101
        }
×
102

103
        // The DER representation is laid out as:
104
        //   0x30 <length> 0x02 <length r> r 0x02 <length s> s
105
        // which means the length of R is the 4th byte and the length of S is
106
        // the second byte after R ends. 0x02 signifies a length-prefixed,
107
        // zero-padded, big-endian bigint. 0x30 signifies a DER signature.
108
        // See the Serialize() method for ecdsa.Signature for details.
109

110
        // Reading <length>, remaining: [0x02 <length r> r 0x02 <length s> s]
111
        sigLen := int(sig[1])
3✔
112

3✔
113
        // siglen should be less than the entire message and greater than
3✔
114
        // the minimal message size.
3✔
115
        if sigLen+2 > len(sig) || sigLen+2 < ecdsa.MinSigLen {
3✔
UNCOV
116
                return Sig{}, errBadLength
×
UNCOV
117
        }
×
118

119
        // Reading <length r>, remaining: [r 0x02 <length s> s]
120
        rLen := int(sig[3])
3✔
121

3✔
122
        // rLen must be positive and must be able to fit in other elements.
3✔
123
        // Assuming s is one byte, then we have 0x30, <length>, 0x20,
3✔
124
        // <length r>, 0x20, <length s>, s, a total of 7 bytes.
3✔
125
        if rLen <= 0 || rLen+7 > len(sig) {
3✔
UNCOV
126
                return Sig{}, errBadRLength
×
UNCOV
127
        }
×
128

129
        // Reading <length s>, remaining: [s]
130
        sLen := int(sig[5+rLen])
3✔
131

3✔
132
        // S should be the rest of the string.
3✔
133
        // sLen must be positive and must be able to fit in other elements.
3✔
134
        // We know r is rLen bytes, and we have 0x30, <length>, 0x20,
3✔
135
        // <length r>, 0x20, <length s>, a total of rLen+6 bytes.
3✔
136
        if sLen <= 0 || sLen+rLen+6 > len(sig) {
3✔
UNCOV
137
                return Sig{}, errBadSLength
×
UNCOV
138
        }
×
139

140
        // Check to make sure R and S can both fit into their intended buffers.
141
        // We check S first because these code blocks decrement sLen and rLen
142
        // in the case of a 33-byte 0-padded integer returned from Serialize()
143
        // and rLen is used in calculating array indices for S. We can track
144
        // this with additional variables, but it's more efficient to just
145
        // check S first.
146
        if sLen > 32 {
3✔
UNCOV
147
                if (sLen > 33) || (sig[6+rLen] != 0x00) {
×
UNCOV
148
                        return Sig{}, errSTooLong
×
UNCOV
149
                }
×
UNCOV
150
                sLen--
×
UNCOV
151
                copy(b[64-sLen:], sig[7+rLen:])
×
152
        } else {
3✔
153
                copy(b[64-sLen:], sig[6+rLen:])
3✔
154
        }
3✔
155

156
        // Do the same for R as we did for S
157
        if rLen > 32 {
6✔
158
                if (rLen > 33) || (sig[4] != 0x00) {
3✔
UNCOV
159
                        return Sig{}, errRTooLong
×
UNCOV
160
                }
×
161
                rLen--
3✔
162
                copy(b[32-rLen:], sig[5:5+rLen])
3✔
163
        } else {
3✔
164
                copy(b[32-rLen:], sig[4:4+rLen])
3✔
165
        }
3✔
166

167
        return Sig{
3✔
168
                bytes:   b,
3✔
169
                sigType: sigTypeECDSA,
3✔
170
        }, nil
3✔
171
}
172

173
// NewSigFromSchnorrRawSignature converts a raw schnorr signature into an
174
// lnwire.Sig.
175
func NewSigFromSchnorrRawSignature(sig []byte) (Sig, error) {
3✔
176
        var s Sig
3✔
177
        copy(s.bytes[:], sig)
3✔
178
        s.sigType = sigTypeSchnorr
3✔
179

3✔
180
        return s, nil
3✔
181
}
3✔
182

183
// NewSigFromSignature creates a new signature as used on the wire, from an
184
// existing ecdsa.Signature or schnorr.Signature.
185
func NewSigFromSignature(e input.Signature) (Sig, error) {
3✔
186
        if e == nil {
3✔
UNCOV
187
                return Sig{}, fmt.Errorf("cannot decode empty signature")
×
UNCOV
188
        }
×
189

190
        // Nil is still a valid interface, apparently. So we need a more
191
        // explicit check here.
192
        if ecsig, ok := e.(*ecdsa.Signature); ok && ecsig == nil {
3✔
UNCOV
193
                return Sig{}, fmt.Errorf("cannot decode empty signature")
×
UNCOV
194
        }
×
195

196
        switch ecSig := e.(type) {
3✔
197
        // If this is a schnorr signature, then we can just pack it as normal,
198
        // since the default encoding is already 64 bytes.
199
        case *schnorr.Signature:
3✔
200
                return NewSigFromSchnorrRawSignature(e.Serialize())
3✔
201

202
        // For ECDSA signatures, we'll need to do a bit more work to map the
203
        // signature into a compact 64 byte form.
204
        case *ecdsa.Signature:
3✔
205
                // Serialize the signature with all the checks that entails.
3✔
206
                return NewSigFromECDSARawSignature(e.Serialize())
3✔
207

208
        default:
×
209
                return Sig{}, fmt.Errorf("unknown wire sig type: %T", ecSig)
×
210
        }
211
}
212

213
// ToSignature converts the fixed-sized signature to a input.Signature which
214
// can be used for signature validation checks.
215
func (s *Sig) ToSignature() (input.Signature, error) {
3✔
216
        switch s.sigType {
3✔
217
        case sigTypeSchnorr:
3✔
218
                return schnorr.ParseSignature(s.bytes[:])
3✔
219

220
        case sigTypeECDSA:
3✔
221
                // Parse the signature with strict checks.
3✔
222
                sigBytes := s.ToSignatureBytes()
3✔
223
                sig, err := ecdsa.ParseDERSignature(sigBytes)
3✔
224
                if err != nil {
3✔
UNCOV
225
                        return nil, err
×
UNCOV
226
                }
×
227

228
                return sig, nil
3✔
229

230
        default:
×
231
                return nil, fmt.Errorf("unknown sig type: %v", s.sigType)
×
232
        }
233
}
234

235
// ToSignatureBytes serializes the target fixed-sized signature into the
236
// encoding of the primary domain for the signature. For ECDSA signatures, this
237
// is the raw bytes of a DER encoding.
238
func (s *Sig) ToSignatureBytes() []byte {
3✔
239
        switch s.sigType {
3✔
240
        // For ECDSA signatures, we'll convert to DER encoding.
241
        case sigTypeECDSA:
3✔
242
                // Extract canonically-padded bigint representations from buffer
3✔
243
                r := extractCanonicalPadding(s.bytes[0:32])
3✔
244
                s := extractCanonicalPadding(s.bytes[32:64])
3✔
245
                rLen := uint8(len(r))
3✔
246
                sLen := uint8(len(s))
3✔
247

3✔
248
                // Create a canonical serialized signature. DER format is:
3✔
249
                // 0x30 <length> 0x02 <length r> r 0x02 <length s> s
3✔
250
                sigBytes := make([]byte, 6+rLen+sLen)
3✔
251
                sigBytes[0] = 0x30            // DER signature magic value
3✔
252
                sigBytes[1] = 4 + rLen + sLen // Length of rest of signature
3✔
253
                sigBytes[2] = 0x02            // Big integer magic value
3✔
254
                sigBytes[3] = rLen            // Length of R
3✔
255
                sigBytes[rLen+4] = 0x02       // Big integer magic value
3✔
256
                sigBytes[rLen+5] = sLen       // Length of S
3✔
257
                copy(sigBytes[4:], r)         // Copy R
3✔
258
                copy(sigBytes[rLen+6:], s)    // Copy S
3✔
259

3✔
260
                return sigBytes
3✔
261

262
        // For schnorr signatures, we can use the same internal 64 bytes.
263
        case sigTypeSchnorr:
×
264
                // We'll make a copy of the signature so we don't return a
×
265
                // reference into the raw slice.
×
266
                var sig [64]byte
×
267
                copy(sig[:], s.bytes[:])
×
268
                return sig[:]
×
269

270
        default:
×
271
                // TODO(roasbeef): can only be called via public methods so
×
272
                // never reachable?
×
273
                panic("sig type not set")
×
274
        }
275
}
276

277
// extractCanonicalPadding is a utility function to extract the canonical
278
// padding of a big-endian integer from the wire encoding (a 0-padded
279
// big-endian integer) such that it passes btcec.canonicalPadding test.
280
func extractCanonicalPadding(b []byte) []byte {
3✔
281
        for i := 0; i < len(b); i++ {
6✔
282
                // Found first non-zero byte.
3✔
283
                if b[i] > 0 {
6✔
284
                        // If the MSB is set, we need zero padding.
3✔
285
                        if b[i]&0x80 == 0x80 {
6✔
286
                                return append([]byte{0x00}, b[i:]...)
3✔
287
                        }
3✔
288
                        return b[i:]
3✔
289
                }
290
        }
UNCOV
291
        return []byte{0x00}
×
292
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc