6767//! ``` 
6868
6969use  bitcoin:: blockdata:: constants:: ChainHash ; 
70+ use  bitcoin:: hashes:: { Hash ,  HashEngine } ; 
71+ use  bitcoin:: hashes:: hmac:: { Hmac ,  HmacEngine } ; 
72+ use  bitcoin:: hashes:: sha256:: Hash  as  Sha256 ; 
7073use  bitcoin:: network:: constants:: Network ; 
7174use  bitcoin:: secp256k1:: PublicKey ; 
7275use  core:: convert:: TryFrom ; 
@@ -75,8 +78,10 @@ use core::str::FromStr;
7578use  core:: time:: Duration ; 
7679use  crate :: io; 
7780use  crate :: ln:: features:: OfferFeatures ; 
81+ use  crate :: ln:: inbound_payment:: ExpandedKey ; 
7882use  crate :: ln:: msgs:: MAX_VALUE_MSAT ; 
7983use  crate :: offers:: invoice_request:: InvoiceRequestBuilder ; 
84+ use  crate :: offers:: merkle:: TlvStream ; 
8085use  crate :: offers:: parse:: { Bech32Encode ,  ParseError ,  ParsedMessage ,  SemanticError } ; 
8186use  crate :: onion_message:: BlindedPath ; 
8287use  crate :: util:: ser:: { HighZeroBytesDroppedBigSize ,  WithoutLength ,  Writeable ,  Writer } ; 
@@ -94,6 +99,7 @@ use std::time::SystemTime;
9499/// [module-level documentation]: self 
95100pub  struct  OfferBuilder  { 
96101	offer :  OfferContents , 
102+ 	hmac :  Option < HmacEngine < Sha256 > > , 
97103} 
98104
99105impl  OfferBuilder  { 
@@ -108,7 +114,7 @@ impl OfferBuilder {
108114			features :  OfferFeatures :: empty ( ) ,  absolute_expiry :  None ,  issuer :  None ,  paths :  None , 
109115			supported_quantity :  Quantity :: One ,  signing_pubkey, 
110116		} ; 
111- 		OfferBuilder  {  offer } 
117+ 		OfferBuilder  {  offer,   hmac :   None  } 
112118	} 
113119
114120	/// Adds the chain hash of the given [`Network`] to [`Offer::chains`]. If not called, 
@@ -127,11 +133,24 @@ impl OfferBuilder {
127133		self 
128134	} 
129135
130- 	/// Sets the [`Offer::metadata`]. 
136+ 	/// Sets the [`Offer::metadata`] to the given bytes . 
131137/// 
132- /// Successive calls to this method will override the previous setting. 
138+ /// Successive calls to this method will override the previous setting and any previous calls to 
139+ /// [`OfferBuilder::metadata_derived`]. 
133140pub  fn  metadata ( mut  self ,  metadata :  Vec < u8 > )  -> Self  { 
134141		self . offer . metadata  = Some ( metadata) ; 
142+ 		self . hmac  = None ; 
143+ 		self 
144+ 	} 
145+ 
146+ 	/// Sets the [`Offer::metadata`] derived from the given `key` and any fields set prior to 
147+ /// calling [`OfferBuilder::build`]. 
148+ /// 
149+ /// Successive calls to this method will override the previous setting and any previous calls to 
150+ /// [`OfferBuilder::metadata`]. 
151+ pub  fn  metadata_derived ( mut  self ,  key :  & ExpandedKey )  -> Self  { 
152+ 		self . offer . metadata  = None ; 
153+ 		self . hmac  = Some ( key. hmac_for_offer ( ) ) ; 
135154		self 
136155	} 
137156
@@ -204,6 +223,11 @@ impl OfferBuilder {
204223			} 
205224		} 
206225
226+ 		if  let  Some ( mut  hmac)  = self . hmac  { 
227+ 			self . offer . write ( & mut  hmac) . unwrap ( ) ; 
228+ 			self . offer . metadata  = Some ( Hmac :: from_engine ( hmac) . into_inner ( ) . to_vec ( ) ) ; 
229+ 		} 
230+ 
207231		let  mut  bytes = Vec :: new ( ) ; 
208232		self . offer . write ( & mut  bytes) . unwrap ( ) ; 
209233
@@ -482,6 +506,26 @@ impl OfferContents {
482506		self . signing_pubkey 
483507	} 
484508
509+ 	/// Verifies that the offer metadata was produced from the offer in the TLV stream. 
510+ pub ( super )  fn  verify ( & self ,  tlv_stream :  TlvStream < ' _ > ,  key :  & ExpandedKey )  -> bool  { 
511+ 		match  & self . metadata  { 
512+ 			Some ( metadata)  => { 
513+ 				let  mut  hmac = key. hmac_for_offer ( ) ; 
514+ 
515+ 				for  record in  tlv_stream. range ( OFFER_TYPES )  { 
516+ 					if  record. r#type  != OFFER_METADATA_TYPE  { 
517+ 						hmac. input ( record. record_bytes ) ; 
518+ 					}  else  { 
519+ 						// TODO: Assert value bytes == metadata? 
520+ 					} 
521+ 				} 
522+ 
523+ 				metadata == & Hmac :: from_engine ( hmac) . into_inner ( ) 
524+ 			} , 
525+ 			None  => false , 
526+ 		} 
527+ 	} 
528+ 
485529	pub ( super )  fn  as_tlv_stream ( & self )  -> OfferTlvStreamRef  { 
486530		let  ( currency,  amount)  = match  & self . amount  { 
487531			None  => ( None ,  None ) , 
@@ -565,9 +609,15 @@ impl Quantity {
565609	} 
566610} 
567611
568- tlv_stream ! ( OfferTlvStream ,  OfferTlvStreamRef ,  1 ..80 ,  { 
612+ /// Valid type range for offer TLV records. 
613+ const  OFFER_TYPES :  core:: ops:: Range < u64 >  = 1 ..80 ; 
614+ 
615+ /// TLV record type for [`Offer::metadata`]. 
616+ const  OFFER_METADATA_TYPE :  u64  = 4 ; 
617+ 
618+ tlv_stream ! ( OfferTlvStream ,  OfferTlvStreamRef ,  OFFER_TYPES ,  { 
569619	( 2 ,  chains:  ( Vec <ChainHash >,  WithoutLength ) ) , 
570- 	( 4 ,  metadata:  ( Vec <u8 >,  WithoutLength ) ) , 
620+ 	( OFFER_METADATA_TYPE ,  metadata:  ( Vec <u8 >,  WithoutLength ) ) , 
571621	( 6 ,  currency:  CurrencyCode ) , 
572622	( 8 ,  amount:  ( u64 ,  HighZeroBytesDroppedBigSize ) ) , 
573623	( 10 ,  description:  ( String ,  WithoutLength ) ) , 
@@ -661,17 +711,40 @@ mod tests {
661711
662712	use  bitcoin:: blockdata:: constants:: ChainHash ; 
663713	use  bitcoin:: network:: constants:: Network ; 
664- 	use  bitcoin:: secp256k1:: { PublicKey ,  Secp256k1 ,  SecretKey } ; 
665- 	use  core:: convert:: TryFrom ; 
714+ 	use  bitcoin:: secp256k1:: { KeyPair ,  Message ,  PublicKey ,  Secp256k1 ,  SecretKey } ; 
715+ 	use  bitcoin:: secp256k1:: schnorr:: Signature ; 
716+ 	use  core:: convert:: { Infallible ,  TryFrom } ; 
666717	use  core:: num:: NonZeroU64 ; 
667718	use  core:: time:: Duration ; 
719+ 	use  crate :: chain:: keysinterface:: KeyMaterial ; 
668720	use  crate :: ln:: features:: OfferFeatures ; 
721+ 	use  crate :: ln:: inbound_payment:: ExpandedKey ; 
669722	use  crate :: ln:: msgs:: { DecodeError ,  MAX_VALUE_MSAT } ; 
670723	use  crate :: offers:: parse:: { ParseError ,  SemanticError } ; 
671724	use  crate :: onion_message:: { BlindedHop ,  BlindedPath } ; 
672725	use  crate :: util:: ser:: { BigSize ,  Writeable } ; 
673726	use  crate :: util:: string:: PrintableString ; 
674727
728+ 	fn  payer_keys ( )  -> KeyPair  { 
729+ 		let  secp_ctx = Secp256k1 :: new ( ) ; 
730+ 		KeyPair :: from_secret_key ( & secp_ctx,  & SecretKey :: from_slice ( & [ 42 ;  32 ] ) . unwrap ( ) ) 
731+ 	} 
732+ 
733+ 	fn  payer_sign ( digest :  & Message )  -> Result < Signature ,  Infallible >  { 
734+ 		let  secp_ctx = Secp256k1 :: new ( ) ; 
735+ 		let  keys = KeyPair :: from_secret_key ( & secp_ctx,  & SecretKey :: from_slice ( & [ 42 ;  32 ] ) . unwrap ( ) ) ; 
736+ 		Ok ( secp_ctx. sign_schnorr_no_aux_rand ( digest,  & keys) ) 
737+ 	} 
738+ 
739+ 	fn  payer_pubkey ( )  -> PublicKey  { 
740+ 		payer_keys ( ) . public_key ( ) 
741+ 	} 
742+ 
743+ 	fn  recipient_pubkey ( )  -> PublicKey  { 
744+ 		let  secp_ctx = Secp256k1 :: new ( ) ; 
745+ 		KeyPair :: from_secret_key ( & secp_ctx,  & SecretKey :: from_slice ( & [ 43 ;  32 ] ) . unwrap ( ) ) . public_key ( ) 
746+ 	} 
747+ 
675748	fn  pubkey ( byte :  u8 )  -> PublicKey  { 
676749		let  secp_ctx = Secp256k1 :: new ( ) ; 
677750		PublicKey :: from_secret_key ( & secp_ctx,  & privkey ( byte) ) 
@@ -784,6 +857,35 @@ mod tests {
784857		assert_eq ! ( offer. as_tlv_stream( ) . metadata,  Some ( & vec![ 43 ;  32 ] ) ) ; 
785858	} 
786859
860+ 	#[ test]  
861+ 	fn  builds_offer_with_metadata_derived ( )  { 
862+ 		let  keys = ExpandedKey :: new ( & KeyMaterial ( [ 42 ;  32 ] ) ) ; 
863+ 		let  invoice_request = OfferBuilder :: new ( "foo" . into ( ) ,  recipient_pubkey ( ) ) 
864+ 			. metadata_derived ( & keys) 
865+ 			. amount_msats ( 1000 ) 
866+ 			. build ( ) . unwrap ( ) 
867+ 			. request_invoice ( vec ! [ 1 ;  32 ] ,  payer_pubkey ( ) ) . unwrap ( ) 
868+ 			. build ( ) . unwrap ( ) 
869+ 			. sign ( payer_sign) . unwrap ( ) ; 
870+ 		assert ! ( invoice_request. verify( & keys) ) ; 
871+ 
872+ 		let  offer = OfferBuilder :: new ( "foo" . into ( ) ,  recipient_pubkey ( ) ) 
873+ 			. metadata_derived ( & keys) 
874+ 			. amount_msats ( 1000 ) 
875+ 			. build ( ) . unwrap ( ) ; 
876+ 		let  mut  tlv_stream = offer. as_tlv_stream ( ) ; 
877+ 		tlv_stream. amount  = Some ( 100 ) ; 
878+ 
879+ 		let  mut  encoded_offer = Vec :: new ( ) ; 
880+ 		tlv_stream. write ( & mut  encoded_offer) . unwrap ( ) ; 
881+ 
882+ 		let  invoice_request = Offer :: try_from ( encoded_offer) . unwrap ( ) 
883+ 			. request_invoice ( vec ! [ 1 ;  32 ] ,  payer_pubkey ( ) ) . unwrap ( ) 
884+ 			. build ( ) . unwrap ( ) 
885+ 			. sign ( payer_sign) . unwrap ( ) ; 
886+ 		assert ! ( !invoice_request. verify( & keys) ) ; 
887+ 	} 
888+ 
787889	#[ test]  
788890	fn  builds_offer_with_amount ( )  { 
789891		let  bitcoin_amount = Amount :: Bitcoin  {  amount_msats :  1000  } ; 
0 commit comments