@@ -19,14 +19,14 @@ use crate::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
19
19
use crate :: ln:: msgs;
20
20
use crate :: ln:: msgs:: MAX_VALUE_MSAT ;
21
21
use crate :: util:: chacha20:: ChaCha20 ;
22
- use crate :: util:: crypto:: hkdf_extract_expand_thrice ;
22
+ use crate :: util:: crypto:: hkdf_extract_expand_4x ;
23
23
use crate :: util:: errors:: APIError ;
24
24
use crate :: util:: logger:: Logger ;
25
25
26
- use core:: convert:: TryInto ;
26
+ use core:: convert:: { TryFrom , TryInto } ;
27
27
use core:: ops:: Deref ;
28
28
29
- const IV_LEN : usize = 16 ;
29
+ pub ( crate ) const IV_LEN : usize = 16 ;
30
30
const METADATA_LEN : usize = 16 ;
31
31
const METADATA_KEY_LEN : usize = 32 ;
32
32
const AMT_MSAT_LEN : usize = 8 ;
@@ -48,21 +48,85 @@ pub struct ExpandedKey {
48
48
/// The key used to authenticate a user-provided payment hash and metadata as previously
49
49
/// registered with LDK.
50
50
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 ] ,
51
53
}
52
54
53
55
impl ExpandedKey {
54
56
/// Create a new [`ExpandedKey`] for generating an inbound payment hash and secret.
55
57
///
56
58
/// It is recommended to cache this value and not regenerate it for each new inbound payment.
57
59
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 ) ;
60
62
Self {
61
63
metadata_key,
62
64
ldk_pmt_hash_key,
63
65
user_pmt_hash_key,
66
+ offers_base_key,
64
67
}
65
68
}
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
+ }
66
130
}
67
131
68
132
enum Method {
0 commit comments