54
54
55
55
use bitcoin:: blockdata:: constants:: ChainHash ;
56
56
use bitcoin:: network:: constants:: Network ;
57
- use bitcoin:: secp256k1:: { Message , PublicKey , Secp256k1 , self } ;
57
+ use bitcoin:: secp256k1:: { KeyPair , Message , PublicKey , Secp256k1 , self } ;
58
58
use bitcoin:: secp256k1:: schnorr:: Signature ;
59
- use core:: convert:: TryFrom ;
59
+ use core:: convert:: { Infallible , TryFrom } ;
60
+ use core:: ops:: Deref ;
61
+ use crate :: chain:: keysinterface:: EntropySource ;
60
62
use crate :: io;
61
63
use crate :: ln:: PaymentHash ;
62
64
use crate :: ln:: features:: InvoiceRequestFeatures ;
63
- use crate :: ln:: inbound_payment:: ExpandedKey ;
65
+ use crate :: ln:: inbound_payment:: { ExpandedKey , IV_LEN , Nonce } ;
64
66
use crate :: ln:: msgs:: DecodeError ;
65
67
use crate :: offers:: invoice:: { BlindedPayInfo , InvoiceBuilder } ;
66
68
use crate :: offers:: merkle:: { SignError , SignatureTlvStream , SignatureTlvStreamRef , TlvStream , self } ;
67
69
use crate :: offers:: offer:: { Offer , OfferContents , OfferTlvStream , OfferTlvStreamRef } ;
68
70
use crate :: offers:: parse:: { ParseError , ParsedMessage , SemanticError } ;
69
71
use crate :: offers:: payer:: { PayerContents , PayerTlvStream , PayerTlvStreamRef } ;
72
+ use crate :: offers:: signer:: { Metadata , MetadataMaterial } ;
70
73
use crate :: onion_message:: BlindedPath ;
71
74
use crate :: util:: ser:: { HighZeroBytesDroppedBigSize , SeekReadable , WithoutLength , Writeable , Writer } ;
72
75
use crate :: util:: string:: PrintableString ;
@@ -75,28 +78,83 @@ use crate::prelude::*;
75
78
76
79
const SIGNATURE_TAG : & ' static str = concat ! ( "lightning" , "invoice_request" , "signature" ) ;
77
80
81
+ const IV_BYTES : & [ u8 ; IV_LEN ] = b"LDK Invreq ~~~~~" ;
82
+
78
83
/// Builds an [`InvoiceRequest`] from an [`Offer`] for the "offer to be paid" flow.
79
84
///
80
85
/// See [module-level documentation] for usage.
81
86
///
82
87
/// [module-level documentation]: self
83
- pub struct InvoiceRequestBuilder < ' a > {
88
+ pub struct InvoiceRequestBuilder < ' a , ' b , P : PayerIdStrategy , T : secp256k1 :: Signing > {
84
89
offer : & ' a Offer ,
85
- invoice_request : InvoiceRequestContents ,
90
+ invoice_request : InvoiceRequestContentsWithoutPayerId ,
91
+ payer_id : Option < PublicKey > ,
92
+ payer_id_strategy : core:: marker:: PhantomData < P > ,
93
+ secp_ctx : Option < & ' b Secp256k1 < T > > ,
86
94
}
87
95
88
- impl < ' a > InvoiceRequestBuilder < ' a > {
96
+ /// Indicates how [`InvoiceRequest::payer_id`] will be set.
97
+ pub trait PayerIdStrategy { }
98
+
99
+ /// [`InvoiceRequest::payer_id`] will be explicitly set.
100
+ pub struct ExplicitPayerId { }
101
+
102
+ /// [`InvoiceRequest::payer_id`] will be derived.
103
+ pub struct DerivedPayerId { }
104
+
105
+ impl PayerIdStrategy for ExplicitPayerId { }
106
+ impl PayerIdStrategy for DerivedPayerId { }
107
+
108
+ impl < ' a , ' b , T : secp256k1:: Signing > InvoiceRequestBuilder < ' a , ' b , ExplicitPayerId , T > {
89
109
pub ( super ) fn new ( offer : & ' a Offer , metadata : Vec < u8 > , payer_id : PublicKey ) -> Self {
90
110
Self {
91
111
offer,
92
- invoice_request : InvoiceRequestContents {
93
- inner : InvoiceRequestContentsWithoutPayerId {
94
- payer : PayerContents ( metadata) , offer : offer. contents . clone ( ) , chain : None ,
95
- amount_msats : None , features : InvoiceRequestFeatures :: empty ( ) , quantity : None ,
96
- payer_note : None ,
97
- } ,
98
- payer_id,
99
- } ,
112
+ invoice_request : Self :: create_contents ( offer, Metadata :: Bytes ( metadata) ) ,
113
+ payer_id : Some ( payer_id) ,
114
+ payer_id_strategy : core:: marker:: PhantomData ,
115
+ secp_ctx : None ,
116
+ }
117
+ }
118
+
119
+ pub ( super ) fn deriving_metadata < ES : Deref > (
120
+ offer : & ' a Offer , payer_id : PublicKey , expanded_key : & ExpandedKey , entropy_source : ES
121
+ ) -> Self where ES :: Target : EntropySource {
122
+ let nonce = Nonce :: from_entropy_source ( entropy_source) ;
123
+ let derivation_material = MetadataMaterial :: new ( nonce, expanded_key, IV_BYTES ) ;
124
+ let metadata = Metadata :: Derived ( derivation_material) ;
125
+ Self {
126
+ offer,
127
+ invoice_request : Self :: create_contents ( offer, metadata) ,
128
+ payer_id : Some ( payer_id) ,
129
+ payer_id_strategy : core:: marker:: PhantomData ,
130
+ secp_ctx : None ,
131
+ }
132
+ }
133
+ }
134
+
135
+ impl < ' a , ' b , T : secp256k1:: Signing > InvoiceRequestBuilder < ' a , ' b , DerivedPayerId , T > {
136
+ pub ( super ) fn deriving_payer_id < ES : Deref > (
137
+ offer : & ' a Offer , expanded_key : & ExpandedKey , entropy_source : ES , secp_ctx : & ' b Secp256k1 < T >
138
+ ) -> Self where ES :: Target : EntropySource {
139
+ let nonce = Nonce :: from_entropy_source ( entropy_source) ;
140
+ let derivation_material = MetadataMaterial :: new ( nonce, expanded_key, IV_BYTES ) ;
141
+ let metadata = Metadata :: DerivedSigningPubkey ( derivation_material) ;
142
+ Self {
143
+ offer,
144
+ invoice_request : Self :: create_contents ( offer, metadata) ,
145
+ payer_id : None ,
146
+ payer_id_strategy : core:: marker:: PhantomData ,
147
+ secp_ctx : Some ( secp_ctx) ,
148
+ }
149
+ }
150
+ }
151
+
152
+ impl < ' a , ' b , P : PayerIdStrategy , T : secp256k1:: Signing > InvoiceRequestBuilder < ' a , ' b , P , T > {
153
+ fn create_contents ( offer : & Offer , metadata : Metadata ) -> InvoiceRequestContentsWithoutPayerId {
154
+ let offer = offer. contents . clone ( ) ;
155
+ InvoiceRequestContentsWithoutPayerId {
156
+ payer : PayerContents ( metadata) , offer, chain : None , amount_msats : None ,
157
+ features : InvoiceRequestFeatures :: empty ( ) , quantity : None , payer_note : None ,
100
158
}
101
159
}
102
160
@@ -111,7 +169,7 @@ impl<'a> InvoiceRequestBuilder<'a> {
111
169
return Err ( SemanticError :: UnsupportedChain ) ;
112
170
}
113
171
114
- self . invoice_request . inner . chain = Some ( chain) ;
172
+ self . invoice_request . chain = Some ( chain) ;
115
173
Ok ( self )
116
174
}
117
175
@@ -122,10 +180,10 @@ impl<'a> InvoiceRequestBuilder<'a> {
122
180
///
123
181
/// [`quantity`]: Self::quantity
124
182
pub fn amount_msats ( mut self , amount_msats : u64 ) -> Result < Self , SemanticError > {
125
- self . invoice_request . inner . offer . check_amount_msats_for_quantity (
126
- Some ( amount_msats) , self . invoice_request . inner . quantity
183
+ self . invoice_request . offer . check_amount_msats_for_quantity (
184
+ Some ( amount_msats) , self . invoice_request . quantity
127
185
) ?;
128
- self . invoice_request . inner . amount_msats = Some ( amount_msats) ;
186
+ self . invoice_request . amount_msats = Some ( amount_msats) ;
129
187
Ok ( self )
130
188
}
131
189
@@ -134,22 +192,23 @@ impl<'a> InvoiceRequestBuilder<'a> {
134
192
///
135
193
/// Successive calls to this method will override the previous setting.
136
194
pub fn quantity ( mut self , quantity : u64 ) -> Result < Self , SemanticError > {
137
- self . invoice_request . inner . offer . check_quantity ( Some ( quantity) ) ?;
138
- self . invoice_request . inner . quantity = Some ( quantity) ;
195
+ self . invoice_request . offer . check_quantity ( Some ( quantity) ) ?;
196
+ self . invoice_request . quantity = Some ( quantity) ;
139
197
Ok ( self )
140
198
}
141
199
142
200
/// Sets the [`InvoiceRequest::payer_note`].
143
201
///
144
202
/// Successive calls to this method will override the previous setting.
145
203
pub fn payer_note ( mut self , payer_note : String ) -> Self {
146
- self . invoice_request . inner . payer_note = Some ( payer_note) ;
204
+ self . invoice_request . payer_note = Some ( payer_note) ;
147
205
self
148
206
}
149
207
150
- /// Builds an unsigned [`InvoiceRequest`] after checking for valid semantics. It can be signed
151
- /// by [`UnsignedInvoiceRequest::sign`].
152
- pub fn build ( mut self ) -> Result < UnsignedInvoiceRequest < ' a > , SemanticError > {
208
+ fn build_with_checks ( mut self ) -> Result <
209
+ ( UnsignedInvoiceRequest < ' a > , Option < KeyPair > , Option < & ' b Secp256k1 < T > > ) ,
210
+ SemanticError
211
+ > {
153
212
#[ cfg( feature = "std" ) ] {
154
213
if self . offer . is_expired ( ) {
155
214
return Err ( SemanticError :: AlreadyExpired ) ;
@@ -162,49 +221,114 @@ impl<'a> InvoiceRequestBuilder<'a> {
162
221
}
163
222
164
223
if chain == self . offer . implied_chain ( ) {
165
- self . invoice_request . inner . chain = None ;
224
+ self . invoice_request . chain = None ;
166
225
}
167
226
168
- if self . offer . amount ( ) . is_none ( ) && self . invoice_request . inner . amount_msats . is_none ( ) {
227
+ if self . offer . amount ( ) . is_none ( ) && self . invoice_request . amount_msats . is_none ( ) {
169
228
return Err ( SemanticError :: MissingAmount ) ;
170
229
}
171
230
172
- self . invoice_request . inner . offer . check_quantity ( self . invoice_request . inner . quantity ) ?;
173
- self . invoice_request . inner . offer . check_amount_msats_for_quantity (
174
- self . invoice_request . inner . amount_msats , self . invoice_request . inner . quantity
231
+ self . invoice_request . offer . check_quantity ( self . invoice_request . quantity ) ?;
232
+ self . invoice_request . offer . check_amount_msats_for_quantity (
233
+ self . invoice_request . amount_msats , self . invoice_request . quantity
175
234
) ?;
176
235
177
- let InvoiceRequestBuilder { offer, invoice_request } = self ;
178
- Ok ( UnsignedInvoiceRequest { offer, invoice_request } )
236
+ Ok ( self . build_without_checks ( ) )
237
+ }
238
+
239
+ fn build_without_checks ( mut self ) ->
240
+ ( UnsignedInvoiceRequest < ' a > , Option < KeyPair > , Option < & ' b Secp256k1 < T > > )
241
+ {
242
+ // Create the metadata for stateless verification of an Invoice.
243
+ let mut keys = None ;
244
+ let secp_ctx = self . secp_ctx . clone ( ) ;
245
+ if self . invoice_request . payer . 0 . has_derivation_material ( ) {
246
+ let mut metadata = core:: mem:: take ( & mut self . invoice_request . payer . 0 ) ;
247
+
248
+ let mut tlv_stream = self . invoice_request . as_tlv_stream ( ) ;
249
+ debug_assert ! ( tlv_stream. 2 . payer_id. is_none( ) ) ;
250
+ tlv_stream. 0 . metadata = None ;
251
+ if !metadata. derives_keys ( ) {
252
+ tlv_stream. 2 . payer_id = self . payer_id . as_ref ( ) ;
253
+ }
254
+
255
+ let ( derived_metadata, derived_keys) = metadata. derive_from ( tlv_stream, self . secp_ctx ) ;
256
+ metadata = derived_metadata;
257
+ keys = derived_keys;
258
+ if let Some ( keys) = keys {
259
+ debug_assert ! ( self . payer_id. is_none( ) ) ;
260
+ self . payer_id = Some ( keys. public_key ( ) ) ;
261
+ }
262
+
263
+ self . invoice_request . payer . 0 = metadata;
264
+ }
265
+
266
+ debug_assert ! ( self . invoice_request. payer. 0 . as_bytes( ) . is_some( ) ) ;
267
+ debug_assert ! ( self . payer_id. is_some( ) ) ;
268
+ let payer_id = self . payer_id . unwrap ( ) ;
269
+
270
+ let unsigned_invoice = UnsignedInvoiceRequest {
271
+ offer : self . offer ,
272
+ invoice_request : InvoiceRequestContents {
273
+ inner : self . invoice_request ,
274
+ payer_id,
275
+ } ,
276
+ } ;
277
+
278
+ ( unsigned_invoice, keys, secp_ctx)
279
+ }
280
+ }
281
+
282
+ impl < ' a , ' b , T : secp256k1:: Signing > InvoiceRequestBuilder < ' a , ' b , ExplicitPayerId , T > {
283
+ /// Builds an unsigned [`InvoiceRequest`] after checking for valid semantics. It can be signed
284
+ /// by [`UnsignedInvoiceRequest::sign`].
285
+ pub fn build ( self ) -> Result < UnsignedInvoiceRequest < ' a > , SemanticError > {
286
+ let ( unsigned_invoice_request, keys, _) = self . build_with_checks ( ) ?;
287
+ debug_assert ! ( keys. is_none( ) ) ;
288
+ Ok ( unsigned_invoice_request)
289
+ }
290
+ }
291
+
292
+ impl < ' a , ' b , T : secp256k1:: Signing > InvoiceRequestBuilder < ' a , ' b , DerivedPayerId , T > {
293
+ /// Builds a signed [`InvoiceRequest`] after checking for valid semantics.
294
+ pub fn build_and_sign ( self ) -> Result < InvoiceRequest , SemanticError > {
295
+ let ( unsigned_invoice_request, keys, secp_ctx) = self . build_with_checks ( ) ?;
296
+ debug_assert ! ( keys. is_some( ) ) ;
297
+
298
+ let secp_ctx = secp_ctx. unwrap ( ) ;
299
+ let keys = keys. unwrap ( ) ;
300
+ let invoice_request = unsigned_invoice_request
301
+ . sign :: < _ , Infallible > ( |digest| Ok ( secp_ctx. sign_schnorr_no_aux_rand ( digest, & keys) ) )
302
+ . unwrap ( ) ;
303
+ Ok ( invoice_request)
179
304
}
180
305
}
181
306
182
307
#[ cfg( test) ]
183
- impl < ' a > InvoiceRequestBuilder < ' a > {
308
+ impl < ' a , ' b , P : PayerIdStrategy , T : secp256k1 :: Signing > InvoiceRequestBuilder < ' a , ' b , P , T > {
184
309
fn chain_unchecked ( mut self , network : Network ) -> Self {
185
310
let chain = ChainHash :: using_genesis_block ( network) ;
186
- self . invoice_request . inner . chain = Some ( chain) ;
311
+ self . invoice_request . chain = Some ( chain) ;
187
312
self
188
313
}
189
314
190
315
fn amount_msats_unchecked ( mut self , amount_msats : u64 ) -> Self {
191
- self . invoice_request . inner . amount_msats = Some ( amount_msats) ;
316
+ self . invoice_request . amount_msats = Some ( amount_msats) ;
192
317
self
193
318
}
194
319
195
320
fn features_unchecked ( mut self , features : InvoiceRequestFeatures ) -> Self {
196
- self . invoice_request . inner . features = features;
321
+ self . invoice_request . features = features;
197
322
self
198
323
}
199
324
200
325
fn quantity_unchecked ( mut self , quantity : u64 ) -> Self {
201
- self . invoice_request . inner . quantity = Some ( quantity) ;
326
+ self . invoice_request . quantity = Some ( quantity) ;
202
327
self
203
328
}
204
329
205
330
pub ( super ) fn build_unchecked ( self ) -> UnsignedInvoiceRequest < ' a > {
206
- let InvoiceRequestBuilder { offer, invoice_request } = self ;
207
- UnsignedInvoiceRequest { offer, invoice_request }
331
+ self . build_without_checks ( ) . 0
208
332
}
209
333
}
210
334
@@ -290,7 +414,7 @@ impl InvoiceRequest {
290
414
///
291
415
/// [`payer_id`]: Self::payer_id
292
416
pub fn metadata ( & self ) -> & [ u8 ] {
293
- & self . contents . inner . payer . 0 [ .. ]
417
+ self . contents . metadata ( )
294
418
}
295
419
296
420
/// A chain from [`Offer::chains`] that the offer is valid for.
@@ -402,6 +526,10 @@ impl InvoiceRequest {
402
526
}
403
527
404
528
impl InvoiceRequestContents {
529
+ pub fn metadata ( & self ) -> & [ u8 ] {
530
+ self . inner . metadata ( )
531
+ }
532
+
405
533
pub ( super ) fn chain ( & self ) -> ChainHash {
406
534
self . inner . chain ( )
407
535
}
@@ -414,13 +542,17 @@ impl InvoiceRequestContents {
414
542
}
415
543
416
544
impl InvoiceRequestContentsWithoutPayerId {
545
+ pub ( super ) fn metadata ( & self ) -> & [ u8 ] {
546
+ self . payer . 0 . as_bytes ( ) . map ( |bytes| bytes. as_slice ( ) ) . unwrap_or ( & [ ] )
547
+ }
548
+
417
549
pub ( super ) fn chain ( & self ) -> ChainHash {
418
550
self . chain . unwrap_or_else ( || self . offer . implied_chain ( ) )
419
551
}
420
552
421
553
pub ( super ) fn as_tlv_stream ( & self ) -> PartialInvoiceRequestTlvStreamRef {
422
554
let payer = PayerTlvStreamRef {
423
- metadata : Some ( & self . payer . 0 ) ,
555
+ metadata : self . payer . 0 . as_bytes ( ) ,
424
556
} ;
425
557
426
558
let offer = self . offer . as_tlv_stream ( ) ;
@@ -530,7 +662,7 @@ impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
530
662
531
663
let payer = match metadata {
532
664
None => return Err ( SemanticError :: MissingPayerMetadata ) ,
533
- Some ( metadata) => PayerContents ( metadata) ,
665
+ Some ( metadata) => PayerContents ( Metadata :: Bytes ( metadata) ) ,
534
666
} ;
535
667
let offer = OfferContents :: try_from ( offer_tlv_stream) ?;
536
668
@@ -1038,7 +1170,7 @@ mod tests {
1038
1170
let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
1039
1171
. amount_msats ( 1000 )
1040
1172
. build ( ) . unwrap ( )
1041
- . request_invoice ( vec ! [ 42 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1173
+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1042
1174
. build ( ) . unwrap ( )
1043
1175
. sign ( payer_sign) . unwrap ( ) ;
1044
1176
0 commit comments