10
10
//! Keys used to generate commitment transactions.
11
11
//! See: <https://github.com/lightning/bolts/blob/master/03-transactions.md#keys>
12
12
13
- use bitcoin:: hashes:: Hash ;
14
- use bitcoin:: hashes:: HashEngine ;
15
- use bitcoin:: secp256k1:: Scalar ;
16
- use bitcoin:: secp256k1:: SecretKey ;
17
- use bitcoin:: secp256k1:: Secp256k1 ;
18
- use bitcoin:: secp256k1;
13
+ use crate :: io;
19
14
use crate :: ln:: msgs:: DecodeError ;
20
15
use crate :: util:: ser:: Readable ;
21
- use crate :: io;
22
- use crate :: util:: ser:: Writer ;
23
16
use crate :: util:: ser:: Writeable ;
24
- use bitcoin :: secp256k1 :: PublicKey ;
17
+ use crate :: util :: ser :: Writer ;
25
18
use bitcoin:: hashes:: sha256:: Hash as Sha256 ;
19
+ use bitcoin:: hashes:: Hash ;
20
+ use bitcoin:: hashes:: HashEngine ;
21
+ use bitcoin:: secp256k1;
22
+ use bitcoin:: secp256k1:: PublicKey ;
23
+ use bitcoin:: secp256k1:: Scalar ;
24
+ use bitcoin:: secp256k1:: Secp256k1 ;
25
+ use bitcoin:: secp256k1:: SecretKey ;
26
26
27
27
macro_rules! doc_comment {
28
28
( $x: expr, $( $tt: tt) * ) => {
@@ -37,15 +37,28 @@ macro_rules! basepoint_impl {
37
37
pub fn to_public_key( & self ) -> PublicKey {
38
38
self . 0
39
39
}
40
+
41
+ /// Derives a per-commitment-transaction (eg an htlc key or delayed_payment key) private key addition tweak
42
+ /// from a basepoint and a per_commitment_point:
43
+ /// `privkey = basepoint_secret + SHA256(per_commitment_point || basepoint)`
44
+ /// This calculates the hash part in the tweak derivation process, which is used to ensure
45
+ /// that each key is unique and cannot be guessed by an external party. It is equivalent
46
+ /// to the `from_basepoint` method, but without the addition operation, providing just the
47
+ /// tweak from the hash of the per_commitment_point and the basepoint.
48
+ pub fn derive_add_tweak( & self , per_commitment_point: & PublicKey ) -> [ u8 ; 32 ] {
49
+ let mut sha = Sha256 :: engine( ) ;
50
+ sha. input( & per_commitment_point. serialize( ) ) ;
51
+ sha. input( & self . to_public_key( ) . serialize( ) ) ;
52
+ Sha256 :: from_engine( sha) . to_byte_array( )
53
+ }
40
54
}
41
55
42
56
impl From <PublicKey > for $BasepointT {
43
57
fn from( value: PublicKey ) -> Self {
44
58
Self ( value)
45
59
}
46
60
}
47
-
48
- }
61
+ } ;
49
62
}
50
63
macro_rules! key_impl {
51
64
( $BasepointT: ty, $KeyName: expr) => {
@@ -87,11 +100,9 @@ macro_rules! key_read_write {
87
100
Ok ( Self ( key) )
88
101
}
89
102
}
90
- }
103
+ } ;
91
104
}
92
105
93
-
94
-
95
106
/// Base key used in conjunction with a `per_commitment_point` to generate a [`DelayedPaymentKey`].
96
107
///
97
108
/// The delayed payment key is used to pay the commitment state broadcaster their
@@ -102,7 +113,6 @@ pub struct DelayedPaymentBasepoint(pub PublicKey);
102
113
basepoint_impl ! ( DelayedPaymentBasepoint ) ;
103
114
key_read_write ! ( DelayedPaymentBasepoint ) ;
104
115
105
-
106
116
/// A derived key built from a [`DelayedPaymentBasepoint`] and `per_commitment_point`.
107
117
///
108
118
/// The delayed payment key is used to pay the commitment state broadcaster their
@@ -150,14 +160,26 @@ key_read_write!(HtlcKey);
150
160
/// Derives a per-commitment-transaction public key (eg an htlc key or a delayed_payment key)
151
161
/// from the base point and the per_commitment_key. This is the public equivalent of
152
162
/// derive_private_key - using only public keys to derive a public key instead of private keys.
153
- fn derive_public_key < T : secp256k1:: Signing > ( secp_ctx : & Secp256k1 < T > , per_commitment_point : & PublicKey , base_point : & PublicKey ) -> PublicKey {
163
+ fn derive_public_key < T : secp256k1:: Signing > (
164
+ secp_ctx : & Secp256k1 < T > , per_commitment_point : & PublicKey , base_point : & PublicKey ,
165
+ ) -> PublicKey {
154
166
let mut sha = Sha256 :: engine ( ) ;
155
167
sha. input ( & per_commitment_point. serialize ( ) ) ;
156
168
sha. input ( & base_point. serialize ( ) ) ;
157
169
let res = Sha256 :: from_engine ( sha) . to_byte_array ( ) ;
158
170
159
- let hashkey = PublicKey :: from_secret_key ( & secp_ctx,
160
- & SecretKey :: from_slice ( & res) . expect ( "Hashes should always be valid keys unless SHA-256 is broken" ) ) ;
171
+ add_public_key_tweak ( secp_ctx, base_point, & res)
172
+ }
173
+
174
+ /// Adds a tweak to a public key to derive a new public key.
175
+ pub fn add_public_key_tweak < T : secp256k1:: Signing > (
176
+ secp_ctx : & Secp256k1 < T > , base_point : & PublicKey , tweak : & [ u8 ; 32 ] ,
177
+ ) -> PublicKey {
178
+ let hashkey = PublicKey :: from_secret_key (
179
+ & secp_ctx,
180
+ & SecretKey :: from_slice ( tweak)
181
+ . expect ( "Hashes should always be valid keys unless SHA-256 is broken" ) ,
182
+ ) ;
161
183
base_point. combine ( & hashkey)
162
184
. expect ( "Addition only fails if the tweak is the inverse of the key. This is not possible when the tweak contains the hash of the key." )
163
185
}
@@ -169,7 +191,6 @@ pub struct RevocationBasepoint(pub PublicKey);
169
191
basepoint_impl ! ( RevocationBasepoint ) ;
170
192
key_read_write ! ( RevocationBasepoint ) ;
171
193
172
-
173
194
/// The revocation key is used to allow a channel party to revoke their state - giving their
174
195
/// counterparty the required material to claim all of their funds if they broadcast that state.
175
196
///
@@ -192,8 +213,7 @@ impl RevocationKey {
192
213
///
193
214
/// [`chan_utils::derive_private_revocation_key`]: crate::ln::chan_utils::derive_private_revocation_key
194
215
pub fn from_basepoint < T : secp256k1:: Verification > (
195
- secp_ctx : & Secp256k1 < T > ,
196
- countersignatory_basepoint : & RevocationBasepoint ,
216
+ secp_ctx : & Secp256k1 < T > , countersignatory_basepoint : & RevocationBasepoint ,
197
217
per_commitment_point : & PublicKey ,
198
218
) -> Self {
199
219
let rev_append_commit_hash_key = {
@@ -227,28 +247,56 @@ impl RevocationKey {
227
247
}
228
248
key_read_write ! ( RevocationKey ) ;
229
249
230
-
231
250
#[ cfg( test) ]
232
251
mod test {
233
- use bitcoin:: secp256k1:: { Secp256k1 , SecretKey , PublicKey } ;
234
- use bitcoin:: hashes:: hex:: FromHex ;
235
252
use super :: derive_public_key;
253
+ use bitcoin:: hashes:: hex:: FromHex ;
254
+ use bitcoin:: secp256k1:: { PublicKey , Secp256k1 , SecretKey } ;
236
255
237
256
#[ test]
238
257
fn test_key_derivation ( ) {
239
258
// Test vectors from BOLT 3 Appendix E:
240
259
let secp_ctx = Secp256k1 :: new ( ) ;
241
260
242
- let base_secret = SecretKey :: from_slice ( & <Vec < u8 > >:: from_hex ( "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" ) . unwrap ( ) [ ..] ) . unwrap ( ) ;
243
- let per_commitment_secret = SecretKey :: from_slice ( & <Vec < u8 > >:: from_hex ( "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100" ) . unwrap ( ) [ ..] ) . unwrap ( ) ;
261
+ let base_secret = SecretKey :: from_slice (
262
+ & <Vec < u8 > >:: from_hex (
263
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f" ,
264
+ )
265
+ . unwrap ( ) [ ..] ,
266
+ )
267
+ . unwrap ( ) ;
268
+ let per_commitment_secret = SecretKey :: from_slice (
269
+ & <Vec < u8 > >:: from_hex (
270
+ "1f1e1d1c1b1a191817161514131211100f0e0d0c0b0a09080706050403020100" ,
271
+ )
272
+ . unwrap ( ) [ ..] ,
273
+ )
274
+ . unwrap ( ) ;
244
275
245
276
let base_point = PublicKey :: from_secret_key ( & secp_ctx, & base_secret) ;
246
- assert_eq ! ( base_point. serialize( ) [ ..] , <Vec <u8 >>:: from_hex( "036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2" ) . unwrap( ) [ ..] ) ;
277
+ assert_eq ! (
278
+ base_point. serialize( ) [ ..] ,
279
+ <Vec <u8 >>:: from_hex(
280
+ "036d6caac248af96f6afa7f904f550253a0f3ef3f5aa2fe6838a95b216691468e2"
281
+ )
282
+ . unwrap( ) [ ..]
283
+ ) ;
247
284
248
285
let per_commitment_point = PublicKey :: from_secret_key ( & secp_ctx, & per_commitment_secret) ;
249
- assert_eq ! ( per_commitment_point. serialize( ) [ ..] , <Vec <u8 >>:: from_hex( "025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486" ) . unwrap( ) [ ..] ) ;
250
-
251
- assert_eq ! ( derive_public_key( & secp_ctx, & per_commitment_point, & base_point) . serialize( ) [ ..] ,
252
- <Vec <u8 >>:: from_hex( "0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5" ) . unwrap( ) [ ..] ) ;
286
+ assert_eq ! (
287
+ per_commitment_point. serialize( ) [ ..] ,
288
+ <Vec <u8 >>:: from_hex(
289
+ "025f7117a78150fe2ef97db7cfc83bd57b2e2c0d0dd25eaf467a4a1c2a45ce1486"
290
+ )
291
+ . unwrap( ) [ ..]
292
+ ) ;
293
+
294
+ assert_eq ! (
295
+ derive_public_key( & secp_ctx, & per_commitment_point, & base_point) . serialize( ) [ ..] ,
296
+ <Vec <u8 >>:: from_hex(
297
+ "0235f2dbfaa89b57ec7b055afe29849ef7ddfeb1cefdb9ebdc43f5494984db29e5"
298
+ )
299
+ . unwrap( ) [ ..]
300
+ ) ;
253
301
}
254
302
}
0 commit comments