@@ -78,8 +78,9 @@ use crate::ln::features::OfferFeatures;
7878use  crate :: ln:: inbound_payment:: { ExpandedKey ,  Nonce } ; 
7979use  crate :: ln:: msgs:: MAX_VALUE_MSAT ; 
8080use  crate :: offers:: invoice_request:: InvoiceRequestBuilder ; 
81+ use  crate :: offers:: merkle:: TlvStream ; 
8182use  crate :: offers:: parse:: { Bech32Encode ,  ParseError ,  ParsedMessage ,  SemanticError } ; 
82- use  crate :: offers:: signer:: { MetadataMaterial ,  DerivedPubkey } ; 
83+ use  crate :: offers:: signer:: { MetadataMaterial ,  DerivedPubkey ,   self } ; 
8384use  crate :: onion_message:: BlindedPath ; 
8485use  crate :: util:: ser:: { HighZeroBytesDroppedBigSize ,  WithoutLength ,  Writeable ,  Writer } ; 
8586use  crate :: util:: string:: PrintableString ; 
@@ -543,6 +544,24 @@ impl OfferContents {
543544		self . signing_pubkey 
544545	} 
545546
547+ 	/// Verifies that the offer metadata was produced from the offer in the TLV stream. 
548+  	pub ( super )  fn  verify ( & self ,  tlv_stream :  TlvStream < ' _ > ,  key :  & ExpandedKey )  -> bool  { 
549+ 		match  & self . metadata  { 
550+ 			Some ( metadata)  => { 
551+ 				let  tlv_stream = tlv_stream. range ( OFFER_TYPES ) . filter ( |record| { 
552+ 					match  record. r#type  { 
553+ 						// TODO: Assert value bytes == metadata? 
554+ 						OFFER_METADATA_TYPE  => false , 
555+ 						OFFER_NODE_ID_TYPE  => false , 
556+ 						_ => true , 
557+ 					} 
558+ 				} ) ; 
559+ 				signer:: verify_metadata ( metadata,  key,  tlv_stream) 
560+ 			} , 
561+ 			None  => false , 
562+ 		} 
563+ 	} 
564+ 
546565	pub ( super )  fn  as_tlv_stream ( & self )  -> OfferTlvStreamRef  { 
547566		let  ( currency,  amount)  = match  & self . amount  { 
548567			None  => ( None ,  None ) , 
@@ -630,9 +649,18 @@ impl Quantity {
630649	} 
631650} 
632651
633- tlv_stream ! ( OfferTlvStream ,  OfferTlvStreamRef ,  1 ..80 ,  { 
652+ /// Valid type range for offer TLV records. 
653+ const  OFFER_TYPES :  core:: ops:: Range < u64 >  = 1 ..80 ; 
654+ 
655+ /// TLV record type for [`Offer::metadata`]. 
656+ const  OFFER_METADATA_TYPE :  u64  = 4 ; 
657+ 
658+ /// TLV record type for [`Offer::signing_pubkey`]. 
659+ const  OFFER_NODE_ID_TYPE :  u64  = 22 ; 
660+ 
661+ tlv_stream ! ( OfferTlvStream ,  OfferTlvStreamRef ,  OFFER_TYPES ,  { 
634662	( 2 ,  chains:  ( Vec <ChainHash >,  WithoutLength ) ) , 
635- 	( 4 ,  metadata:  ( Vec <u8 >,  WithoutLength ) ) , 
663+ 	( OFFER_METADATA_TYPE ,  metadata:  ( Vec <u8 >,  WithoutLength ) ) , 
636664	( 6 ,  currency:  CurrencyCode ) , 
637665	( 8 ,  amount:  ( u64 ,  HighZeroBytesDroppedBigSize ) ) , 
638666	( 10 ,  description:  ( String ,  WithoutLength ) ) , 
@@ -641,7 +669,7 @@ tlv_stream!(OfferTlvStream, OfferTlvStreamRef, 1..80, {
641669	( 16 ,  paths:  ( Vec <BlindedPath >,  WithoutLength ) ) , 
642670	( 18 ,  issuer:  ( String ,  WithoutLength ) ) , 
643671	( 20 ,  quantity_max:  ( u64 ,  HighZeroBytesDroppedBigSize ) ) , 
644- 	( 22 ,  node_id:  PublicKey ) , 
672+ 	( OFFER_NODE_ID_TYPE ,  node_id:  PublicKey ) , 
645673} ) ; 
646674
647675impl  Bech32Encode  for  Offer  { 
@@ -729,9 +757,12 @@ mod tests {
729757	use  core:: convert:: TryFrom ; 
730758	use  core:: num:: NonZeroU64 ; 
731759	use  core:: time:: Duration ; 
760+ 	use  crate :: chain:: keysinterface:: KeyMaterial ; 
732761	use  crate :: ln:: features:: OfferFeatures ; 
762+ 	use  crate :: ln:: inbound_payment:: { ExpandedKey ,  Nonce } ; 
733763	use  crate :: ln:: msgs:: { DecodeError ,  MAX_VALUE_MSAT } ; 
734764	use  crate :: offers:: parse:: { ParseError ,  SemanticError } ; 
765+ 	use  crate :: offers:: signer:: DerivedPubkey ; 
735766	use  crate :: offers:: test_utils:: * ; 
736767	use  crate :: onion_message:: { BlindedHop ,  BlindedPath } ; 
737768	use  crate :: util:: ser:: { BigSize ,  Writeable } ; 
@@ -840,6 +871,82 @@ mod tests {
840871		assert_eq ! ( offer. as_tlv_stream( ) . metadata,  Some ( & vec![ 43 ;  32 ] ) ) ; 
841872	} 
842873
874+ 	#[ test]  
875+ 	fn  builds_offer_with_metadata_derived ( )  { 
876+ 		let  expanded_key = ExpandedKey :: new ( & KeyMaterial ( [ 42 ;  32 ] ) ) ; 
877+ 		let  nonce = Nonce ( [ 42 ;  Nonce :: LENGTH ] ) ; 
878+ 
879+ 		let  offer = OfferBuilder :: new ( "foo" . into ( ) ,  recipient_pubkey ( ) ) 
880+ 			. amount_msats ( 1000 ) 
881+ 			. metadata_derived ( & expanded_key,  nonce) . unwrap ( ) 
882+ 			. build ( ) . unwrap ( ) ; 
883+ 		assert_eq ! ( offer. metadata( ) . unwrap( ) [ ..Nonce :: LENGTH ] ,  nonce. 0 ) ; 
884+ 		assert_eq ! ( offer. signing_pubkey( ) ,  recipient_pubkey( ) ) ; 
885+ 
886+ 		let  invoice_request = offer. request_invoice ( vec ! [ 1 ;  32 ] ,  payer_pubkey ( ) ) . unwrap ( ) 
887+ 			. build ( ) . unwrap ( ) 
888+ 			. sign ( payer_sign) . unwrap ( ) ; 
889+ 		assert ! ( invoice_request. verify( & expanded_key) ) ; 
890+ 
891+ 		let  mut  tlv_stream = offer. as_tlv_stream ( ) ; 
892+ 		tlv_stream. amount  = Some ( 100 ) ; 
893+ 
894+ 		let  mut  encoded_offer = Vec :: new ( ) ; 
895+ 		tlv_stream. write ( & mut  encoded_offer) . unwrap ( ) ; 
896+ 
897+ 		let  invoice_request = Offer :: try_from ( encoded_offer) . unwrap ( ) 
898+ 			. request_invoice ( vec ! [ 1 ;  32 ] ,  payer_pubkey ( ) ) . unwrap ( ) 
899+ 			. build ( ) . unwrap ( ) 
900+ 			. sign ( payer_sign) . unwrap ( ) ; 
901+ 		assert ! ( !invoice_request. verify( & expanded_key) ) ; 
902+ 
903+ 		match  OfferBuilder :: new ( "foo" . into ( ) ,  recipient_pubkey ( ) ) 
904+ 			. metadata_derived ( & expanded_key,  nonce) . unwrap ( ) 
905+ 			. metadata_derived ( & expanded_key,  nonce) 
906+ 		{ 
907+ 			Ok ( _)  => panic ! ( "expected error" ) , 
908+ 			Err ( e)  => assert_eq ! ( e,  SemanticError :: UnexpectedMetadata ) , 
909+ 		} 
910+ 	} 
911+ 
912+ 	#[ test]  
913+ 	fn  builds_offer_with_derived_signing_pubkey ( )  { 
914+ 		let  expanded_key = ExpandedKey :: new ( & KeyMaterial ( [ 42 ;  32 ] ) ) ; 
915+ 		let  nonce = Nonce ( [ 42 ;  Nonce :: LENGTH ] ) ; 
916+ 
917+ 		let  recipient_pubkey = DerivedPubkey :: new ( & expanded_key,  nonce) ; 
918+ 		let  offer = OfferBuilder :: deriving_signing_pubkey ( "foo" . into ( ) ,  recipient_pubkey) 
919+ 			. amount_msats ( 1000 ) 
920+ 			. build ( ) . unwrap ( ) ; 
921+ 		assert_eq ! ( offer. metadata( ) . unwrap( ) [ ..Nonce :: LENGTH ] ,  nonce. 0 ) ; 
922+ 		assert_eq ! ( offer. signing_pubkey( ) ,  expanded_key. signing_pubkey_for_offer( nonce) ) ; 
923+ 
924+ 		let  invoice_request = offer. request_invoice ( vec ! [ 1 ;  32 ] ,  payer_pubkey ( ) ) . unwrap ( ) 
925+ 			. build ( ) . unwrap ( ) 
926+ 			. sign ( payer_sign) . unwrap ( ) ; 
927+ 		assert ! ( invoice_request. verify( & expanded_key) ) ; 
928+ 
929+ 		let  mut  tlv_stream = offer. as_tlv_stream ( ) ; 
930+ 		tlv_stream. amount  = Some ( 100 ) ; 
931+ 
932+ 		let  mut  encoded_offer = Vec :: new ( ) ; 
933+ 		tlv_stream. write ( & mut  encoded_offer) . unwrap ( ) ; 
934+ 
935+ 		let  invoice_request = Offer :: try_from ( encoded_offer) . unwrap ( ) 
936+ 			. request_invoice ( vec ! [ 1 ;  32 ] ,  payer_pubkey ( ) ) . unwrap ( ) 
937+ 			. build ( ) . unwrap ( ) 
938+ 			. sign ( payer_sign) . unwrap ( ) ; 
939+ 		assert ! ( !invoice_request. verify( & expanded_key) ) ; 
940+ 
941+ 		let  recipient_pubkey = DerivedPubkey :: new ( & expanded_key,  nonce) ; 
942+ 		match  OfferBuilder :: deriving_signing_pubkey ( "foo" . into ( ) ,  recipient_pubkey) 
943+ 			. metadata_derived ( & expanded_key,  nonce) 
944+ 		{ 
945+ 			Ok ( _)  => panic ! ( "expected error" ) , 
946+ 			Err ( e)  => assert_eq ! ( e,  SemanticError :: UnexpectedMetadata ) , 
947+ 		} 
948+ 	} 
949+ 
843950	#[ test]  
844951	fn  builds_offer_with_amount ( )  { 
845952		let  bitcoin_amount = Amount :: Bitcoin  {  amount_msats :  1000  } ; 
0 commit comments