In this commit, we update the Sig type to support ECDSA and schnorr
signatures. We need to do this as the HTLC signatures will become
schnorr sigs for taproot channels. The current spec draft opts to
overload this field since both the sigs are actually 64 bytes in length.
The only consideration with this move is that callers need to "coerce" a
sig to the proper type if they need schnorr signatures.
It is very difficult for the fuzzer to create a valid checksum for each
serialized invoice, and we were therefore unable to fuzz deeper than
invoice decoding. We can help the fuzzer generate valid serialized
invoices by calculating and appending the checksum ourselves.
We also switch to using mainnet invoices to make it easier to find valid
invoices for seeding the fuzzer. We prepend the required "lnbc" prefix
ourselves to further help the fuzzer generate valid invoices.
The message signer from invoice_test.go is identical to the one created
in the fuzz test. We're already using the private key from
invoice_test.go, so we may as well use the complete message signer for
simplicity.
The fuzz tests call inv.MinFinalCLTVExpiry() and inv.Expiry() supposedly
to ensure the invoice is well-formed. However, those methods can never
panic or return errors and therefore provide no benefit for this
purpose.
This commit was previously split into the following parts to ease
review:
- 2d746f68: replace imports
- 4008f0fd: use ecdsa.Signature
- 849e33d1: remove btcec.S256()
- b8f6ebbd: use v2 library correctly
- fa80bca9: bump go modules
To make it possible to use a remote lnrpc server as a signer for our
wallet, we need to change our main interface to sign the message instead
of the message's digest. Otherwise we'd need to alter the
lnrpc.SignMessage RPC to accept a digest instead of only the message
which has security implications.
The Core devs decided to us the same bech32 HRP for Signet as is used
for the current Testnet3. This might be okay for on-chain addresses
since they are compatible in theory. But for invoices we want to use a
distinct HRP to distinguish testnet from signet.
Also see spec PR
https://github.com/lightningnetwork/lightning-rfc/pull/844 for more
information about the reasoning.
Modify the SignCompact function passed to invoice.Encode to receive the
message before it's hashed and hash it itself.
With this modification, the SignMessage rpc function from the signrpc
subserver can be used and an invoice can be encoded outside of lnd.
As a preliminary step to isolating zpay32 in migrations 01-11, we'll
split out the encoding and decoding logic into separate files. Migration
11 only requires invoice decoding, so this prevents us from needing to
copy in the encoding logic that would otherwise be unused.
This commit removes the unknown required feature bit check from the
invoice decoding logic. This allows greater utility to users of the
decodepayreq rpc since it can provide inspection of otherwise invalid
invoices. In the prior commit, this check moved into our path finding
logic, so invalid features taken from an invoice will instead cause a
failure when attempting to pay.
This commit updates the BOLT11 test vectors to use the updated versions
from the spec (with TLV bit set). This also pointed out that the
ordering was inconsistent with the spec, in that the payment secret
should be serialized before the feature vector.
This commit adds InvoiceExpryWatcher which is a separate class that
receives new invoices (and existing ones upon restart) from InvoiceRegistry
and actively watches their expiry. When an invoice is expired
InvoiceExpiryWatcher will call into InvoiceRegistry to cancel the
invoice and by that notify all subscribers about the state change.
This commit also consolidates the existing code duplication in parsing
payment hashes and description hashes into a single, combined method for
parsing 32-byte values. A similar change is made for encoding 32-byte
values.
zpay32/invoice: consolidate 32-byte encoding logic
This fixes an issue where the last tagged field of an invoice could get
broken due to the malleability of bech32 checksums.
The addition of a specific character in the second to last position of
the checksum could cause the previous signature field to mutate and thus
point to a different public node.
This commit checks that the size of the bech32 encoded invoice is not
greater than 7092 bytes, which is the maximum number of bytes that can
fit into a QR code. This mitigates a potential DoS vector where an attacker
could craft a very large bech32 invoice string containing an absurd amount
of route and/or hop hints. If sent to an application that processes
payment requests, this would allocate a burdensome amount of memory
due to the public key parsing for each route/hop hint.
For a 1.7MB payment request, this yielded about 38MB in allocations
from just parsing public keys:
```
45.51MB 7.31% 92.07% 45.51MB 7.31% math/big.nat.make
25.50MB 4.09% 96.16% 25.50MB 4.09% github.com/lightningnetwork/lnd/zpay32.bech32VerifyChecksum
1MB 0.16% 96.32% 39.50MB 6.34% github.com/lightningnetwork/lnd/zpay32.parseRouteHint
1MB 0.16% 96.48% 33.50MB 5.38% github.com/btcsuite/btcd/btcec.decompressPoint
0.50MB 0.08% 96.56% 7.50MB 1.20% crypto/elliptic.(*CurveParams).doubleJacobian
0.50MB 0.08% 96.64% 38MB 6.10% github.com/btcsuite/btcd/btcec.ParsePubKey
0 0% 96.64% 12MB 1.93% crypto/ecdsa.Verify
0 0% 96.64% 8MB 1.28% crypto/elliptic.(*CurveParams).ScalarBaseMult
0 0% 96.64% 12MB 1.93% crypto/elliptic.(*CurveParams).ScalarMult
```
With this change, memory usage will be far lower as decoding will exit
early with an error if the invoice is too large.
Since nilling the pubkey curve will lead to a nil-pointer exception if
the key is later used for signature verification, we make sure to make a
copy before nilling and spewing.
Before this commit, if an invoice encoded multiple `r` fields, we would
decode them as one single route. We fix this by allowing an invoice to
store multiple routes.