5454
5555use bitcoin:: blockdata:: constants:: ChainHash ;
5656use bitcoin:: network:: constants:: Network ;
57- use bitcoin:: secp256k1:: { Message , PublicKey , Secp256k1 , self } ;
57+ use bitcoin:: secp256k1:: { KeyPair , Message , PublicKey , Secp256k1 , self } ;
5858use 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 ;
6062use crate :: io;
6163use crate :: ln:: PaymentHash ;
6264use crate :: ln:: features:: InvoiceRequestFeatures ;
63- use crate :: ln:: inbound_payment:: ExpandedKey ;
65+ use crate :: ln:: inbound_payment:: { ExpandedKey , IV_LEN , Nonce } ;
6466use crate :: ln:: msgs:: DecodeError ;
6567use crate :: offers:: invoice:: { BlindedPayInfo , InvoiceBuilder } ;
6668use crate :: offers:: merkle:: { SignError , SignatureTlvStream , SignatureTlvStreamRef , TlvStream , self } ;
6769use crate :: offers:: offer:: { Offer , OfferContents , OfferTlvStream , OfferTlvStreamRef } ;
6870use crate :: offers:: parse:: { ParseError , ParsedMessage , SemanticError } ;
6971use crate :: offers:: payer:: { PayerContents , PayerTlvStream , PayerTlvStreamRef } ;
72+ use crate :: offers:: signer:: { Metadata , MetadataMaterial } ;
7073use crate :: onion_message:: BlindedPath ;
7174use crate :: util:: ser:: { HighZeroBytesDroppedBigSize , SeekReadable , WithoutLength , Writeable , Writer } ;
7275use crate :: util:: string:: PrintableString ;
@@ -75,28 +78,83 @@ use crate::prelude::*;
7578
7679const SIGNATURE_TAG : & ' static str = concat ! ( "lightning" , "invoice_request" , "signature" ) ;
7780
81+ const IV_BYTES : & [ u8 ; IV_LEN ] = b"LDK Invreq ~~~~~" ;
82+
7883/// Builds an [`InvoiceRequest`] from an [`Offer`] for the "offer to be paid" flow.
7984///
8085/// See [module-level documentation] for usage.
8186///
8287/// [module-level documentation]: self
83- pub struct InvoiceRequestBuilder < ' a > {
88+ pub struct InvoiceRequestBuilder < ' a , ' b , P : PayerIdStrategy , T : secp256k1 :: Signing > {
8489 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 > > ,
8694}
8795
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 > {
89109 pub ( super ) fn new ( offer : & ' a Offer , metadata : Vec < u8 > , payer_id : PublicKey ) -> Self {
90110 Self {
91111 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 ,
100158 }
101159 }
102160
@@ -111,7 +169,7 @@ impl<'a> InvoiceRequestBuilder<'a> {
111169 return Err ( SemanticError :: UnsupportedChain ) ;
112170 }
113171
114- self . invoice_request . inner . chain = Some ( chain) ;
172+ self . invoice_request . chain = Some ( chain) ;
115173 Ok ( self )
116174 }
117175
@@ -122,10 +180,10 @@ impl<'a> InvoiceRequestBuilder<'a> {
122180 ///
123181 /// [`quantity`]: Self::quantity
124182 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
127185 ) ?;
128- self . invoice_request . inner . amount_msats = Some ( amount_msats) ;
186+ self . invoice_request . amount_msats = Some ( amount_msats) ;
129187 Ok ( self )
130188 }
131189
@@ -134,22 +192,23 @@ impl<'a> InvoiceRequestBuilder<'a> {
134192 ///
135193 /// Successive calls to this method will override the previous setting.
136194 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) ;
139197 Ok ( self )
140198 }
141199
142200 /// Sets the [`InvoiceRequest::payer_note`].
143201 ///
144202 /// Successive calls to this method will override the previous setting.
145203 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) ;
147205 self
148206 }
149207
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+ > {
153212 #[ cfg( feature = "std" ) ] {
154213 if self . offer . is_expired ( ) {
155214 return Err ( SemanticError :: AlreadyExpired ) ;
@@ -162,49 +221,111 @@ impl<'a> InvoiceRequestBuilder<'a> {
162221 }
163222
164223 if chain == self . offer . implied_chain ( ) {
165- self . invoice_request . inner . chain = None ;
224+ self . invoice_request . chain = None ;
166225 }
167226
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 ( ) {
169228 return Err ( SemanticError :: MissingAmount ) ;
170229 }
171230
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
175234 ) ?;
176235
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+
252+ let ( derived_metadata, derived_keys) = metadata. derive_from ( tlv_stream, self . secp_ctx ) ;
253+ metadata = derived_metadata;
254+ keys = derived_keys;
255+ if let Some ( keys) = keys {
256+ debug_assert ! ( self . payer_id. is_none( ) ) ;
257+ self . payer_id = Some ( keys. public_key ( ) ) ;
258+ }
259+
260+ self . invoice_request . payer . 0 = metadata;
261+ }
262+
263+ debug_assert ! ( self . invoice_request. payer. 0 . as_bytes( ) . is_some( ) ) ;
264+ debug_assert ! ( self . payer_id. is_some( ) ) ;
265+ let payer_id = self . payer_id . unwrap ( ) ;
266+
267+ let unsigned_invoice = UnsignedInvoiceRequest {
268+ offer : self . offer ,
269+ invoice_request : InvoiceRequestContents {
270+ inner : self . invoice_request ,
271+ payer_id,
272+ } ,
273+ } ;
274+
275+ ( unsigned_invoice, keys, secp_ctx)
276+ }
277+ }
278+
279+ impl < ' a , ' b , T : secp256k1:: Signing > InvoiceRequestBuilder < ' a , ' b , ExplicitPayerId , T > {
280+ /// Builds an unsigned [`InvoiceRequest`] after checking for valid semantics. It can be signed
281+ /// by [`UnsignedInvoiceRequest::sign`].
282+ pub fn build ( self ) -> Result < UnsignedInvoiceRequest < ' a > , SemanticError > {
283+ let ( unsigned_invoice_request, keys, _) = self . build_with_checks ( ) ?;
284+ debug_assert ! ( keys. is_none( ) ) ;
285+ Ok ( unsigned_invoice_request)
286+ }
287+ }
288+
289+ impl < ' a , ' b , T : secp256k1:: Signing > InvoiceRequestBuilder < ' a , ' b , DerivedPayerId , T > {
290+ /// Builds a signed [`InvoiceRequest`] after checking for valid semantics.
291+ pub fn build_and_sign ( self ) -> Result < InvoiceRequest , SemanticError > {
292+ let ( unsigned_invoice_request, keys, secp_ctx) = self . build_with_checks ( ) ?;
293+ debug_assert ! ( keys. is_some( ) ) ;
294+
295+ let secp_ctx = secp_ctx. unwrap ( ) ;
296+ let keys = keys. unwrap ( ) ;
297+ let invoice_request = unsigned_invoice_request
298+ . sign :: < _ , Infallible > ( |digest| Ok ( secp_ctx. sign_schnorr_no_aux_rand ( digest, & keys) ) )
299+ . unwrap ( ) ;
300+ Ok ( invoice_request)
179301 }
180302}
181303
182304#[ cfg( test) ]
183- impl < ' a > InvoiceRequestBuilder < ' a > {
305+ impl < ' a , ' b , P : PayerIdStrategy , T : secp256k1 :: Signing > InvoiceRequestBuilder < ' a , ' b , P , T > {
184306 fn chain_unchecked ( mut self , network : Network ) -> Self {
185307 let chain = ChainHash :: using_genesis_block ( network) ;
186- self . invoice_request . inner . chain = Some ( chain) ;
308+ self . invoice_request . chain = Some ( chain) ;
187309 self
188310 }
189311
190312 fn amount_msats_unchecked ( mut self , amount_msats : u64 ) -> Self {
191- self . invoice_request . inner . amount_msats = Some ( amount_msats) ;
313+ self . invoice_request . amount_msats = Some ( amount_msats) ;
192314 self
193315 }
194316
195317 fn features_unchecked ( mut self , features : InvoiceRequestFeatures ) -> Self {
196- self . invoice_request . inner . features = features;
318+ self . invoice_request . features = features;
197319 self
198320 }
199321
200322 fn quantity_unchecked ( mut self , quantity : u64 ) -> Self {
201- self . invoice_request . inner . quantity = Some ( quantity) ;
323+ self . invoice_request . quantity = Some ( quantity) ;
202324 self
203325 }
204326
205327 pub ( super ) fn build_unchecked ( self ) -> UnsignedInvoiceRequest < ' a > {
206- let InvoiceRequestBuilder { offer, invoice_request } = self ;
207- UnsignedInvoiceRequest { offer, invoice_request }
328+ self . build_without_checks ( ) . 0
208329 }
209330}
210331
@@ -290,7 +411,7 @@ impl InvoiceRequest {
290411 ///
291412 /// [`payer_id`]: Self::payer_id
292413 pub fn metadata ( & self ) -> & [ u8 ] {
293- & self . contents . inner . payer . 0 [ .. ]
414+ self . contents . metadata ( )
294415 }
295416
296417 /// A chain from [`Offer::chains`] that the offer is valid for.
@@ -402,6 +523,10 @@ impl InvoiceRequest {
402523}
403524
404525impl InvoiceRequestContents {
526+ pub fn metadata ( & self ) -> & [ u8 ] {
527+ self . inner . metadata ( )
528+ }
529+
405530 pub ( super ) fn chain ( & self ) -> ChainHash {
406531 self . inner . chain ( )
407532 }
@@ -414,13 +539,17 @@ impl InvoiceRequestContents {
414539}
415540
416541impl InvoiceRequestContentsWithoutPayerId {
542+ pub ( super ) fn metadata ( & self ) -> & [ u8 ] {
543+ self . payer . 0 . as_bytes ( ) . map ( |bytes| bytes. as_slice ( ) ) . unwrap_or ( & [ ] )
544+ }
545+
417546 pub ( super ) fn chain ( & self ) -> ChainHash {
418547 self . chain . unwrap_or_else ( || self . offer . implied_chain ( ) )
419548 }
420549
421550 pub ( super ) fn as_tlv_stream ( & self ) -> PartialInvoiceRequestTlvStreamRef {
422551 let payer = PayerTlvStreamRef {
423- metadata : Some ( & self . payer . 0 ) ,
552+ metadata : self . payer . 0 . as_bytes ( ) ,
424553 } ;
425554
426555 let offer = self . offer . as_tlv_stream ( ) ;
@@ -530,7 +659,7 @@ impl TryFrom<PartialInvoiceRequestTlvStream> for InvoiceRequestContents {
530659
531660 let payer = match metadata {
532661 None => return Err ( SemanticError :: MissingPayerMetadata ) ,
533- Some ( metadata) => PayerContents ( metadata) ,
662+ Some ( metadata) => PayerContents ( Metadata :: Bytes ( metadata) ) ,
534663 } ;
535664 let offer = OfferContents :: try_from ( offer_tlv_stream) ?;
536665
@@ -1038,7 +1167,7 @@ mod tests {
10381167 let invoice_request = OfferBuilder :: new ( "foo" . into ( ) , recipient_pubkey ( ) )
10391168 . amount_msats ( 1000 )
10401169 . build ( ) . unwrap ( )
1041- . request_invoice ( vec ! [ 42 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
1170+ . request_invoice ( vec ! [ 1 ; 32 ] , payer_pubkey ( ) ) . unwrap ( )
10421171 . build ( ) . unwrap ( )
10431172 . sign ( payer_sign) . unwrap ( ) ;
10441173
0 commit comments