@@ -19,14 +19,14 @@ use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
1919use crate :: ln:: msgs;
2020use crate :: ln:: msgs:: MAX_VALUE_MSAT ;
2121use crate :: util:: chacha20:: ChaCha20 ;
22- use crate :: util:: crypto:: hkdf_extract_expand_thrice ;
22+ use crate :: util:: crypto:: hkdf_extract_expand_4x ;
2323use crate :: util:: errors:: APIError ;
2424use crate :: util:: logger:: Logger ;
2525
26- use core:: convert:: TryInto ;
26+ use core:: convert:: { TryFrom , TryInto } ;
2727use core:: ops:: Deref ;
2828
29- const IV_LEN : usize = 16 ;
29+ pub ( crate ) const IV_LEN : usize = 16 ;
3030const METADATA_LEN : usize = 16 ;
3131const METADATA_KEY_LEN : usize = 32 ;
3232const AMT_MSAT_LEN : usize = 8 ;
@@ -48,21 +48,85 @@ pub struct ExpandedKey {
4848 /// The key used to authenticate a user-provided payment hash and metadata as previously
4949 /// registered with LDK.
5050 user_pmt_hash_key : [ u8 ; 32 ] ,
51+ /// The base key used to derive signing keys and authenticate messages for BOLT 12 Offers.
52+ offers_base_key : [ u8 ; 32 ] ,
5153}
5254
5355impl ExpandedKey {
5456 /// Create a new [`ExpandedKey`] for generating an inbound payment hash and secret.
5557 ///
5658 /// It is recommended to cache this value and not regenerate it for each new inbound payment.
5759 pub fn new ( key_material : & KeyMaterial ) -> ExpandedKey {
58- let ( metadata_key, ldk_pmt_hash_key, user_pmt_hash_key) =
59- hkdf_extract_expand_thrice ( b"LDK Inbound Payment Key Expansion" , & key_material. 0 ) ;
60+ let ( metadata_key, ldk_pmt_hash_key, user_pmt_hash_key, offers_base_key ) =
61+ hkdf_extract_expand_4x ( b"LDK Inbound Payment Key Expansion" , & key_material. 0 ) ;
6062 Self {
6163 metadata_key,
6264 ldk_pmt_hash_key,
6365 user_pmt_hash_key,
66+ offers_base_key,
6467 }
6568 }
69+
70+ /// Returns an [`HmacEngine`] used to construct [`Offer::metadata`].
71+ ///
72+ /// [`Offer::metadata`]: crate::offers::offer::Offer::metadata
73+ #[ allow( unused) ]
74+ pub ( crate ) fn hmac_for_offer (
75+ & self , nonce : Nonce , iv_bytes : & [ u8 ; IV_LEN ]
76+ ) -> HmacEngine < Sha256 > {
77+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & self . offers_base_key ) ;
78+ hmac. input ( iv_bytes) ;
79+ hmac. input ( & nonce. 0 ) ;
80+ hmac
81+ }
82+ }
83+
84+ /// A 128-bit number used only once.
85+ ///
86+ /// Needed when constructing [`Offer::metadata`] and deriving [`Offer::signing_pubkey`] from
87+ /// [`ExpandedKey`]. Must not be reused for any other derivation without first hashing.
88+ ///
89+ /// [`Offer::metadata`]: crate::offers::offer::Offer::metadata
90+ /// [`Offer::signing_pubkey`]: crate::offers::offer::Offer::signing_pubkey
91+ #[ allow( unused) ]
92+ #[ derive( Clone , Copy , Debug , PartialEq ) ]
93+ pub ( crate ) struct Nonce ( pub ( crate ) [ u8 ; Self :: LENGTH ] ) ;
94+
95+ impl Nonce {
96+ /// Number of bytes in the nonce.
97+ pub const LENGTH : usize = 16 ;
98+
99+ /// Creates a `Nonce` from the given [`EntropySource`].
100+ pub fn from_entropy_source < ES : Deref > ( entropy_source : ES ) -> Self
101+ where
102+ ES :: Target : EntropySource ,
103+ {
104+ let mut bytes = [ 0u8 ; Self :: LENGTH ] ;
105+ let rand_bytes = entropy_source. get_secure_random_bytes ( ) ;
106+ bytes. copy_from_slice ( & rand_bytes[ ..Self :: LENGTH ] ) ;
107+
108+ Nonce ( bytes)
109+ }
110+
111+ /// Returns a slice of the underlying bytes of size [`Nonce::LENGTH`].
112+ pub fn as_slice ( & self ) -> & [ u8 ] {
113+ & self . 0
114+ }
115+ }
116+
117+ impl TryFrom < & [ u8 ] > for Nonce {
118+ type Error = ( ) ;
119+
120+ fn try_from ( bytes : & [ u8 ] ) -> Result < Self , ( ) > {
121+ if bytes. len ( ) != Self :: LENGTH {
122+ return Err ( ( ) ) ;
123+ }
124+
125+ let mut copied_bytes = [ 0u8 ; Self :: LENGTH ] ;
126+ copied_bytes. copy_from_slice ( bytes) ;
127+
128+ Ok ( Self ( copied_bytes) )
129+ }
66130}
67131
68132enum Method {
0 commit comments