Commit graph

52 commits

Author SHA1 Message Date
Jeffrey Czyz
9c2a3d090b
Fix amount overflow in Invoice building
An overflow can occur when multiplying the offer amount by the requested
quantity when no amount is given in the request. Return an error instead
of overflowing.
2023-02-23 18:25:50 -06:00
Jeffrey Czyz
32ed69a2bd
Fix amount overflow in Offer parsing and building
An overflow can occur when multiplying the offer amount by the requested
quantity when checking if the given amount is enough. Return an error
instead of overflowing.
2023-02-23 18:25:50 -06:00
Jeffrey Czyz
56a01de61d
Expose Bech32Encode trait for fuzzing
In order to fuzz test Bech32Encode parsing independent of the underlying
message deserialization, the trait needs to be exposed. Conditionally
expose it only for fuzzing.
2023-02-23 18:25:49 -06:00
Jeffrey Czyz
e049e97993
Fuzz test for parsing InvoiceRequest
An invoice request is serialized as a TLV stream and encoded as bytes.
Add a fuzz test that parses the TLV stream and deserializes the
underlying InvoiceRequest. Then compare the original bytes with those
obtained by re-serializing the InvoiceRequest.
2023-02-23 18:24:41 -06:00
Jeffrey Czyz
9a65709239
Derive traits for InvoiceRequest and Invoice
Offer and Refund derive Debug, Clone, and PartialEq. For consistency,
derive these traits for InvoiceRequest and Invoice as well.
2023-02-21 14:07:51 -06:00
Jeffrey Czyz
0001260f74
Fuzz test for parsing Refund
A refund is serialized as a TLV stream and encoded in bech32 without a
checksum. Add a fuzz test that parses the unencoded TLV stream and
deserializes the underlying Refund. Then compare the original bytes with
those obtained by re-serializing the Refund.
2023-02-08 19:02:17 -06:00
Jeffrey Czyz
fcb67434d9
Make BlindedPayInfo fields public
BlindedPayInfo fields need to be public in order to construct one for
fuzz tests. Typically, they would be constructed from ChannelUpdateInfo
for public channels and ChannelDetails for unannounced channels. For
now, make the fields public so they can be constructed manually.
2023-02-08 18:56:40 -06:00
Jeffrey Czyz
53d2d47360
Fuzz test for parsing Offer
An offer is serialized as a TLV stream and encoded in bech32 without a
checksum. Add a fuzz test that parses the unencoded TLV stream and
deserializes the underlying Offer. Then compare the original bytes with
those obtained by re-serializing the Offer.
2023-02-08 18:47:48 -06:00
Jeffrey Czyz
153d831ccc
Make offers module public
This is needed in order to fuzz test BOLT 12 message deserialization.
2023-02-03 15:23:43 -06:00
Jeffrey Czyz
6388c9a3e5
Add test for requesting invoice from expired offer 2023-02-03 15:23:43 -06:00
Jeffrey Czyz
4763612131
Make separate no-std version for invoice response
Both Refund::respond_with and InvoiceRequest::respond_with take a
created_at since the Unix epoch Duration in no-std. However, this can
cause problems if two downstream dependencies want to use the lightning
crate with different feature flags set. Instead, define
respond_with_no_std versions of each method in addition to a
respond_with version in std.
2023-02-03 15:23:33 -06:00
Jeffrey Czyz
3302f25e9f
Fix BOLT 12 invoice doctests to work with no-std 2023-02-03 15:14:58 -06:00
Jeffrey Czyz
22ea505348
Update docs regarding payment path privacy 2023-01-30 15:44:39 -06:00
Jeffrey Czyz
2d44dbe013
Disallow offer_metadata in Refund
The offer_metadata was optional but is redundant with invreq_metadata
(i.e., payer_metadata) for refunds. It is now disallowed in the spec and
was already unsupported by RefundBuilder.
2023-01-30 15:44:39 -06:00
Jeffrey Czyz
6236e0d472
Allow quantity in Refund
The spec always allowed this but the reason was unclear. It's useful if
the refund is for an invoice paid for offer where a quantity was given
in the request. The description in the refund would be from the offer,
which may have given a unit for each item. So allowing a quantity makes
it clear how many items the refund is for.
2023-01-30 15:44:39 -06:00
Jeffrey Czyz
4059677e8e
Support explicit quantity_max = 1 in Offer
The spec was modified to allow setting offer_quantity_max explicitly to
one. This is to support a use case where more than one item is supported
but only one item is left in the inventory. Introduce a Quantity::One
variant to replace Quantity::Bounded(1) so the later can be used for the
explicit setting.
2023-01-30 15:44:39 -06:00
Jeffrey Czyz
a452551480
Invoice parsing tests
Tests for checking invoice semantics when parsing invoice bytes as
defined by BOLT 12.
2023-01-20 16:04:39 -06:00
Jeffrey Czyz
bf1147f23f
Invoice building tests
Tests for checking invoice message semantics when building an invoice as
defined by BOLT 12.
2023-01-20 16:04:39 -06:00
Jeffrey Czyz
fe83aede0c
Expand invoice module docs and include an example 2023-01-20 16:04:38 -06:00
Jeffrey Czyz
7f52d26e6e
Use SystemTime::now() for Invoice creation time
For std builds, Invoice::created_at can be automatically set upon
construction using SystemTime::now() offset by SystemTime::UNIX_EPOCH.
Change InvoiceRequest::respond_with and Refund::respond_with to only
take a created_at parameter in no-std builds.
2023-01-20 16:04:38 -06:00
Jeffrey Czyz
f779bc066f
Builder for creating invoices for refunds
Add a builder for creating invoices for a refund and required fields.
Other settings are optional and duplicative settings will override
previous settings. Building produces a semantically valid `invoice`
message for the refund, which then can be signed with the key associated
with the provided signing pubkey.
2023-01-20 16:04:38 -06:00
Jeffrey Czyz
88c5197e44
Builder for creating invoices for offers
Add a builder for creating invoices for an offer from a given request
and required fields. Other settings are optional and duplicative
settings will override previous settings. Building produces a
semantically valid `invoice` message for the offer, which then can be
signed with the key associated with the offer's signing pubkey.
2023-01-20 16:04:37 -06:00
Jeffrey Czyz
e1aa18aed8
Invoice encoding and parsing
Define an interface for BOLT 12 `invoice` messages. The underlying
format consists of the original bytes and the parsed contents.

The bytes are later needed for serialization. This is because it must
mirror all the `offer` and `invoice_request` TLV records, including
unknown ones, which aren't represented in the contents.

Invoices may be created for an Offer (from an InvoiceRequest) or for a
Refund. The primary difference is how the signing pubkey is given -- by
the writer of the offer or the reader of the refund.
2023-01-20 16:04:37 -06:00
Jeffrey Czyz
243f448701
Encoding for TLV stream without signature records
When using bytes from an InvoiceRequest to constructing bytes for an
Invoice, any signature TLV records in the bytes must be excluded. Define
a wrapper for encoding such pre-serialized bytes in this manner. This
will allow the forthcoming InvoiceBuilder to construct bytes for an
Invoice properly.
2023-01-18 15:31:48 -06:00
Jeffrey Czyz
6b3535451e
Define TlvStream::skip_signatures
Provide a helper for skipping signature TLV records from a TLV stream.
This prevents needing to duplicate the check for signature TLV records
when writing a TLV stream without signatures in an upcoming commit.
2023-01-18 15:31:48 -06:00
Jeffrey Czyz
bd0040a02b
Drop AsRef<[u8]> implementation for TlvRecord
Explicitly using TlvRecord::record_bytes makes reading the code more
obvious than hiding which bytes are used in AsRef<[u8]>::as_ref.
2023-01-18 15:31:48 -06:00
Jeffrey Czyz
ea1a68c6e6
Use explicit WithoutLength for BOLT 12 features
Most BOLT 12 features are used as the value of a TLV record and thus
don't use an explicit length. One exception is the features inside the
blinded payinfo subtype since the TLV record contains a list of them.
However, these features are also used in the BOLT 4 encrypted_data_tlv
TLV stream as a single record, where the length is implicit.

Implement Readable and Writeable for Features wrapped in WithoutLength
such that either serialization can be used where required.
2023-01-05 22:39:24 -06:00
Jeffrey Czyz
1a437f4150
Remove Option from InvoiceRequest::signature
Refunds don't have signatures and now use their own abstraction.
Therefore, signatures can be required in invoice requests as per the
spec.
2023-01-05 22:39:24 -06:00
Jeffrey Czyz
7964b9f745
Correct documentation about Refund::payer_id
The docs incorrectly stated that Refund::payer_id is for signing, where
it is only used for identifying a node if Refund::paths is not present.
2023-01-05 22:38:31 -06:00
Jeffrey Czyz
8e36737dac
Refund parsing tests
Tests for checking refund semantics when parsing invoice_request bytes
as defined by BOLT 12.
2022-12-14 16:22:44 -06:00
Jeffrey Czyz
77c082229b
Refund building tests
Tests for checking invoice_request message semantics when building a
refund as defined by BOLT 12.
2022-12-14 16:22:24 -06:00
Jeffrey Czyz
73e743fb53
Builder for creating refunds
Add a builder for creating refunds given a payer_id and other required
fields. Other settings are optional and duplicative settings will
override previous settings. Building produces a semantically valid
`invoice_request` message representing the refund, which then may be
communicated out of band (e.g., via QR code).
2022-12-14 16:20:53 -06:00
Jeffrey Czyz
d47763af57
Refund parsing from bech32 strings
Implement Bech32Encode for Refund, which supports creating and parsing
QR codes for the merchant-pays-user (i.e., offer for money) flow.
2022-12-14 16:20:53 -06:00
Jeffrey Czyz
92a53dd7aa
Refund encoding and parsing
Define an interface for BOLT 12 refunds (i.e., an `invoice_request`
message without an `offer_node_id`). A refund is more generally an
"offer for money". While it is encoded using the same TLV streams as an
`invoice_request` message, it has different semantics.
2022-12-14 16:20:40 -06:00
Jeffrey Czyz
7e81f8dcb4
Remove Option from OfferContents::signing_pubkey
Refunds (i.e., `invoice_request` without an `offer`) will have its own
contents type, so OfferContents::signing_pubkey can be required.
2022-12-13 16:05:59 -06:00
Jeffrey Czyz
04d64f0808
Check entire TLV stream instead of by field
This causes a compilation error if a new field is added but missed in
the tests.
2022-12-09 14:45:56 -06:00
Jeffrey Czyz
b25c8df648
Add BOLT 12 merkle root test for invoice_request
A BOLT 12 test vector uses an `invoice_request` message that has a
currency, which aren't supported, so using OfferBuilder::build_unchecked
is required to avoid a panic.
2022-12-09 13:28:53 -06:00
Jeffrey Czyz
984c906406
Invoice request parsing tests
Tests for checking invoice_request message semantics when parsing bytes
as defined by BOLT 12.
2022-12-09 13:28:52 -06:00
Jeffrey Czyz
d666eb6700
Invoice request building tests
Tests for checking invoice_request message semantics when building as
defined by BOLT 12.
2022-12-09 13:28:26 -06:00
Jeffrey Czyz
13ba7cc523
Builder for creating invoice requests
Add a builder for creating invoice requests for an offer given a
payer_id. Other settings may be optional depending on the offer and
duplicative settings will override previous settings. Building produces
a semantically valid `invoice_request` message for the offer, which then
can be signed for the payer_id.
2022-12-09 08:53:46 -06:00
Jeffrey Czyz
59a7bd29fe
Invoice request raw byte encoding and decoding
When reading an offer, an `invoice_request` message is sent over the
wire. Implement Writeable for encoding the message and TryFrom for
decoding it by defining in terms of TLV streams. These streams represent
content for the payer metadata (0), reflected `offer` (1-79),
`invoice_request` (80-159), and signature (240).
2022-12-09 08:53:46 -06:00
Jeffrey Czyz
a7adc7602a
Merkle root hash computation
Offers uses a merkle root hash construction for signature calculation
and verification. Add a submodule implementing this so that it can be
used when parsing and signing invoice_request and invoice messages.
2022-12-09 08:53:45 -06:00
Jeffrey Czyz
0c621646a6
Invoice request message interface and data format
Define an interface for BOLT 12 `invoice_request` messages. The
underlying format consists of the original bytes and the parsed
contents.

The bytes are later needed when constructing an `invoice` message. This
is because it must mirror all the `offer` and `invoice_request` TLV
records, including unknown ones, which aren't represented in the
contents.

The contents will be used in `invoice` messages to avoid duplication.
Some fields while required in a typical user-pays-merchant flow may not
be necessary in the merchant-pays-user flow (e.g., refund, ATM).
2022-12-09 08:53:33 -06:00
Jeffrey Czyz
3e17e7f9bb
Remove unused mut from OfferBuilder::amount_msats
Seen when removing `#[allow(unused)]` from `offers` module.
2022-12-02 15:28:02 -08:00
Jeffrey Czyz
4b8b17d72f
Reduce visibility for offer auxiliary types 2022-12-02 15:26:27 -08:00
Jeffrey Czyz
1e26a2bc19
Expose the default Quantity::one as pub 2022-11-18 11:33:07 -06:00
Jeffrey Czyz
94a07d9cae
Limit TLV stream decoding to type ranges
BOLT 12 messages are limited to a range of TLV record types. Refactor
decode_tlv_stream into a decode_tlv_stream_range macro for limiting
which types are parsed. Requires a SeekReadable trait for rewinding when
a type outside of the range is seen. This allows for composing TLV
streams of different ranges.

Updates offer parsing accordingly and adds a test demonstrating failure
if a type outside of the range is included.
2022-11-18 11:33:07 -06:00
Jeffrey Czyz
03d0a4b497
Offer parsing tests
Test semantic errors when parsing offer bytes.
2022-11-18 11:33:07 -06:00
Jeffrey Czyz
3a6d7b867e
Use SemanticError in OfferBuilder::build 2022-11-18 11:33:06 -06:00
Jeffrey Czyz
60d7ffce10
Offer parsing from bech32 strings
Add common bech32 parsing for BOLT 12 messages. The encoding is similar
to bech32 only without a checksum and with support for continuing
messages across multiple parts.

Messages implementing Bech32Encode are parsed into a TLV stream, which
is converted to the desired message content while performing semantic
checks. Checking after conversion allows for more elaborate checks of
data composed of multiple TLV records and for more meaningful error
messages.

The parsed bytes are also saved to allow creating messages with mirrored
data, even if TLV records are unknown.
2022-11-18 11:33:06 -06:00