1010//! Data structures and encoding for `invoice_request` messages. 
1111
1212use  bitcoin:: hash_types:: BlockHash ; 
13- use  bitcoin:: secp256k1:: PublicKey ; 
13+ use  bitcoin:: hashes:: { Hash ,  sha256} ; 
14+ use  bitcoin:: secp256k1:: { Message ,  PublicKey ,  Secp256k1 ,  self } ; 
1415use  bitcoin:: secp256k1:: schnorr:: Signature ; 
1516use  core:: convert:: TryFrom ; 
1617use  core:: str:: FromStr ; 
1718use  ln:: features:: OfferFeatures ; 
1819use  offers:: PayerTlvStream ; 
19- use  offers:: merkle:: SignatureTlvStream ; 
20- use  offers:: offer:: { OfferContents ,  OfferTlvStream } ; 
20+ use  offers:: merkle:: { SignatureTlvStream ,   self } ; 
21+ use  offers:: offer:: { Amount ,   OfferContents ,  OfferTlvStream } ; 
2122use  offers:: parse:: { Bech32Encode ,  ParseError ,  SemanticError } ; 
2223
2324/// 
@@ -30,15 +31,33 @@ pub struct InvoiceRequest {
3031pub ( crate )  struct  InvoiceRequestContents  { 
3132	offer :  OfferContents , 
3233	chain :  Option < BlockHash > , 
33- 	amount_msat :  Option < u64 > , 
34+ 	amount_msats :  Option < u64 > , 
3435	features :  Option < OfferFeatures > , 
3536	quantity :  Option < u64 > , 
36- 	payer_id :  Option < PublicKey > , 
37+ 	payer_id :  PublicKey , 
3738	payer_note :  Option < String > , 
3839	payer_info :  Option < Vec < u8 > > , 
3940	signature :  Option < Signature > , 
4041} 
4142
43+ impl  InvoiceRequestContents  { 
44+ 	pub  fn  verify_signature ( & self ,  bytes :  & [ u8 ] )  -> Result < ( ) ,  secp256k1:: Error >  { 
45+ 		if  let  Some ( signature)  = & self . signature  { 
46+ 			let  tag = sha256:: Hash :: hash ( 
47+ 				concat ! ( "lightning" ,  "invoice_request" ,  "signature" ) . as_bytes ( ) 
48+ 			) ; 
49+ 			let  merkle_root = merkle:: root_hash ( bytes) ; 
50+ 			let  digest = Message :: from_slice ( & merkle:: tagged_hash ( tag,  merkle_root) ) . unwrap ( ) ; 
51+ 			let  pubkey = self . payer_id . into ( ) ; 
52+ 			let  secp_ctx = Secp256k1 :: verification_only ( ) ; 
53+ 			secp_ctx. verify_schnorr ( signature,  & digest,  & pubkey) 
54+ 		}  else  { 
55+ 			Ok ( ( ) ) 
56+ 		} 
57+ 	} 
58+ 
59+ } 
60+ 
4261impl  AsRef < [ u8 ] >  for  InvoiceRequest  { 
4362	fn  as_ref ( & self )  -> & [ u8 ]  { 
4463		& self . bytes 
@@ -69,6 +88,8 @@ impl FromStr for InvoiceRequest {
6988	fn  from_str ( s :  & str )  -> Result < Self ,  <Self  as  FromStr >:: Err >  { 
7089		let  ( tlv_stream,  bytes)  = InvoiceRequest :: from_bech32_str ( s) ?; 
7190		let  contents = InvoiceRequestContents :: try_from ( tlv_stream) ?; 
91+ 		contents. verify_signature ( & bytes) ?; 
92+ 
7293		Ok ( InvoiceRequest  {  bytes,  contents } ) 
7394	} 
7495} 
@@ -93,16 +114,44 @@ impl TryFrom<FullInvoiceRequestTlvStream> for InvoiceRequestContents {
93114		} ; 
94115
95116		// TODO: Check remaining fields against the reflected offer 
96- 		let  amount_msat = amount. map ( Into :: into) ; 
97117
98- 		let  quantity = quantity. map ( Into :: into) ; 
118+ 		// TODO: Determine whether quantity should be accounted for 
119+ 		let  amount_msats = match  ( offer. amount ( ) ,  amount. map ( Into :: into) )  { 
120+ 			// TODO: Handle currency case 
121+ 			( Some ( Amount :: Currency  {  .. } ) ,  _)  => return  Err ( SemanticError :: UnexpectedCurrency ) , 
122+ 			( Some ( _) ,  None )  => return  Err ( SemanticError :: MissingAmount ) , 
123+ 			( Some ( Amount :: Bitcoin  {  amount_msats :  offer_amount_msats } ) ,  Some ( amount_msats) )  => { 
124+ 				if  amount_msats < * offer_amount_msats { 
125+ 					return  Err ( SemanticError :: InsufficientAmount ) ; 
126+ 				}  else  { 
127+ 					Some ( amount_msats) 
128+ 				} 
129+ 			} , 
130+ 			( _,  amount_msats)  => amount_msats, 
131+ 		} ; 
132+ 
133+ 		if  let  Some ( features)  = & features { 
134+ 			if  features. requires_unknown_bits ( )  { 
135+ 				return  Err ( SemanticError :: UnknownRequiredFeatures ) ; 
136+ 			} 
137+ 		} 
138+ 
139+ 		let  quantity = match  quantity. map ( Into :: into)  { 
140+ 			Some ( quantity)  if  offer. is_valid_quantity ( quantity)  => Some ( quantity) , 
141+ 			_ => return  Err ( SemanticError :: InvalidQuantity ) , 
142+ 		} ; 
143+ 
144+ 		let  payer_id = match  payer_id { 
145+ 			None  => return  Err ( SemanticError :: MissingPayerId ) , 
146+ 			Some ( payer_id)  => payer_id, 
147+ 		} ; 
99148
100149		let  payer_note = payer_note. map ( Into :: into) ; 
101150
102151		let  payer_info = payer_info. map ( Into :: into) ; 
103152
104153		Ok ( InvoiceRequestContents  { 
105- 			offer,  chain,  amount_msat ,  features,  quantity,  payer_id,  payer_note,  payer_info, 
154+ 			offer,  chain,  amount_msats ,  features,  quantity,  payer_id,  payer_note,  payer_info, 
106155			signature, 
107156		} ) 
108157	} 
0 commit comments