@@ -65,6 +65,7 @@ use core::{cmp, mem};
65
65
use core:: cell:: RefCell ;
66
66
use io:: { Cursor , Read } ;
67
67
use sync:: { Arc , Condvar , Mutex , MutexGuard , RwLock , RwLockReadGuard } ;
68
+ use core:: convert:: TryInto ;
68
69
use core:: sync:: atomic:: { AtomicUsize , Ordering } ;
69
70
use core:: time:: Duration ;
70
71
#[ cfg( any( test, feature = "allow_wallclock_use" ) ) ]
@@ -642,6 +643,8 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
642
643
our_network_key : SecretKey ,
643
644
our_network_pubkey : PublicKey ,
644
645
646
+ inbound_payment_key : [ u8 ; 32 ] ,
647
+
645
648
/// Used to track the last value sent in a node_announcement "timestamp" field. We ensure this
646
649
/// value increases strictly since we don't assume access to a time source.
647
650
last_node_announcement_serial : AtomicUsize ,
@@ -1342,6 +1345,8 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
1342
1345
our_network_pubkey : PublicKey :: from_secret_key ( & secp_ctx, & keys_manager. get_node_secret ( ) ) ,
1343
1346
secp_ctx,
1344
1347
1348
+ inbound_payment_key : keys_manager. get_inbound_payment_secret ( ) ,
1349
+
1345
1350
last_node_announcement_serial : AtomicUsize :: new ( 0 ) ,
1346
1351
highest_seen_timestamp : AtomicUsize :: new ( 0 ) ,
1347
1352
@@ -2589,6 +2594,75 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2589
2594
}
2590
2595
}
2591
2596
2597
+ // Check that an inbound payment's `payment_data` field is sane.
2598
+ //
2599
+ // LDK does not store any data for pending inbound payments. Instead, we construct our payment
2600
+ // secret (and, if supplied by LDK, our payment preimage) to include encrypted metadata about the
2601
+ // payment.
2602
+ //
2603
+ // The metadata is constructed as:
2604
+ // payment method (4 bits) || payment amount (8 bytes - 4 bits) || expiry (8 bytes)
2605
+ //
2606
+ // Then on payment receipt, we verify in this method that the payment preimage and payment secret
2607
+ // match what was constructed.
2608
+ fn verify_inbound_payment_data ( & self , payment_hash : PaymentHash , payment_data : msgs:: FinalOnionHopData ) -> Result < Option < PaymentPreimage > , ( ) > {
2609
+ let ( metadata_key, user_pmt_hash_key, ldk_pmt_hash_key) = hkdf_extract_expand ( & vec ! [ 0 ] , & self . inbound_payment_key ) ;
2610
+ let ( iv_bytes, encrypted_metadata_bytes) = payment_data. payment_secret . 0 . split_at ( 16 ) ;
2611
+
2612
+ let chacha_block = ChaCha20 :: get_single_block ( & metadata_key, iv_bytes) ;
2613
+ let mut metadata_bytes: [ u8 ; 16 ] = [ 0 ; 16 ] ;
2614
+ for i in 0 ..16 {
2615
+ metadata_bytes[ i] = chacha_block[ i] ^ encrypted_metadata_bytes[ i] ;
2616
+ }
2617
+
2618
+ // Make sure to check to check the HMAC before doing the other checks below, to mitigate DoS.
2619
+ let is_user_payment_hash = metadata_bytes[ 0 ] & 1 << 4 != 0 ;
2620
+ let mut payment_preimage = None ;
2621
+ if is_user_payment_hash {
2622
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & user_pmt_hash_key) ;
2623
+ hmac. input ( & metadata_bytes[ ..] ) ;
2624
+ hmac. input ( & payment_hash. 0 ) ;
2625
+ if !fixed_time_eq ( iv_bytes, & Hmac :: from_engine ( hmac) . into_inner ( ) . split_at_mut ( 16 ) . 0 ) {
2626
+ log_trace ! ( self . logger, "Failing HTLC with user-generated payment_hash {}: unexpected payment_secret" , log_bytes!( payment_hash. 0 ) ) ;
2627
+ return Err ( ( ) )
2628
+ }
2629
+ } else {
2630
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & ldk_pmt_hash_key) ;
2631
+ hmac. input ( iv_bytes) ;
2632
+ hmac. input ( & metadata_bytes) ;
2633
+ let decoded_payment_preimage = Hmac :: from_engine ( hmac) . into_inner ( ) ;
2634
+ if !fixed_time_eq ( & payment_hash. 0 , & Sha256 :: hash ( & decoded_payment_preimage) . into_inner ( ) ) {
2635
+ log_trace ! ( self . logger, "Failing HTLC with payment_hash {}: payment preimage {} did not match" , log_bytes!( payment_hash. 0 ) , log_bytes!( decoded_payment_preimage) ) ;
2636
+ return Err ( ( ) )
2637
+ }
2638
+ payment_preimage = Some ( PaymentPreimage ( decoded_payment_preimage) ) ;
2639
+ }
2640
+
2641
+ let payment_type: u8 = ( metadata_bytes[ 0 ] & 0b1111_0000 ) >> 4 ;
2642
+ if payment_type > 1 { // We only support payment method types of 0000 or 0001
2643
+ log_trace ! ( self . logger, "Failing HTLC with payment hash {} due to unknown payment type {}" , log_bytes!( payment_hash. 0 ) , payment_type) ;
2644
+ return Err ( ( ) ) ;
2645
+ }
2646
+
2647
+ let mut amt_msat_bytes = [ 0 ; 8 ] ;
2648
+ amt_msat_bytes. copy_from_slice ( & metadata_bytes[ ..8 ] ) ;
2649
+ // Zero out the bits reserved to indicate the payment type.
2650
+ amt_msat_bytes[ 0 ] &= 0b00001111 ;
2651
+ let min_amt_msat = u64:: from_be_bytes ( amt_msat_bytes. try_into ( ) . unwrap ( ) ) ;
2652
+ if payment_data. total_msat < min_amt_msat {
2653
+ log_trace ! ( self . logger, "Failing HTLC with payment_hash {} due to total_msat {} being less than the minimum amount of {} msat" , log_bytes!( payment_hash. 0 ) , payment_data. total_msat, min_amt_msat) ;
2654
+ return Err ( ( ) )
2655
+ }
2656
+
2657
+ let expiry = u64:: from_be_bytes ( metadata_bytes[ 8 ..] . try_into ( ) . unwrap ( ) ) ;
2658
+ if expiry < self . highest_seen_timestamp . load ( Ordering :: Acquire ) as u64 {
2659
+ log_trace ! ( self . logger, "Failing HTLC with payment_hash {}: expired payment" , log_bytes!( payment_hash. 0 ) ) ;
2660
+ return Err ( ( ) )
2661
+ }
2662
+
2663
+ Ok ( payment_preimage)
2664
+ }
2665
+
2592
2666
/// Processes HTLCs which are pending waiting on random forward delay.
2593
2667
///
2594
2668
/// Should only really ever be called in response to a PendingHTLCsForwardable event.
@@ -2864,9 +2938,17 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
2864
2938
match payment_secrets. entry ( payment_hash) {
2865
2939
hash_map:: Entry :: Vacant ( _) => {
2866
2940
match claimable_htlc. onion_payload {
2867
- OnionPayload :: Invoice ( _) => {
2868
- log_trace ! ( self . logger, "Failing new HTLC with payment_hash {} as we didn't have a corresponding inbound payment." , log_bytes!( payment_hash. 0 ) ) ;
2869
- fail_htlc ! ( claimable_htlc) ;
2941
+ OnionPayload :: Invoice ( ref payment_data) => {
2942
+ let payment_preimage = match self . verify_inbound_payment_data ( payment_hash, payment_data. clone ( ) ) {
2943
+ Ok ( payment_preimage) => payment_preimage,
2944
+ Err ( ( ) ) => {
2945
+ fail_htlc ! ( claimable_htlc) ;
2946
+ continue
2947
+ }
2948
+ } ;
2949
+ let payment_data_total_msat = payment_data. total_msat ;
2950
+ let payment_secret = payment_data. payment_secret . clone ( ) ;
2951
+ check_total_value ! ( payment_data_total_msat, payment_secret, payment_preimage) ;
2870
2952
} ,
2871
2953
OnionPayload :: Spontaneous ( preimage) => {
2872
2954
match channel_state. claimable_htlcs . entry ( payment_hash) {
@@ -4527,38 +4609,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
4527
4609
}
4528
4610
}
4529
4611
4530
- fn set_payment_hash_secret_map ( & self , payment_hash : PaymentHash , payment_preimage : Option < PaymentPreimage > , min_value_msat : Option < u64 > , invoice_expiry_delta_secs : u32 ) -> Result < PaymentSecret , APIError > {
4531
- assert ! ( invoice_expiry_delta_secs <= 60 * 60 * 24 * 365 ) ; // Sadly bitcoin timestamps are u32s, so panic before 2106
4532
-
4533
- let payment_secret = PaymentSecret ( self . keys_manager . get_secure_random_bytes ( ) ) ;
4534
-
4535
- let _persistence_guard = PersistenceNotifierGuard :: notify_on_drop ( & self . total_consistency_lock , & self . persistence_notifier ) ;
4536
- let mut payment_secrets = self . pending_inbound_payments . lock ( ) . unwrap ( ) ;
4537
- match payment_secrets. entry ( payment_hash) {
4538
- hash_map:: Entry :: Vacant ( e) => {
4539
- e. insert ( PendingInboundPayment {
4540
- payment_secret, min_value_msat, payment_preimage,
4541
- user_payment_id : 0 , // For compatibility with version 0.0.103 and earlier
4542
- // We assume that highest_seen_timestamp is pretty close to the current time -
4543
- // its updated when we receive a new block with the maximum time we've seen in
4544
- // a header. It should never be more than two hours in the future.
4545
- // Thus, we add two hours here as a buffer to ensure we absolutely
4546
- // never fail a payment too early.
4547
- // Note that we assume that received blocks have reasonably up-to-date
4548
- // timestamps.
4549
- expiry_time : self . highest_seen_timestamp . load ( Ordering :: Acquire ) as u64 + invoice_expiry_delta_secs as u64 + 7200 ,
4550
- } ) ;
4551
- } ,
4552
- hash_map:: Entry :: Occupied ( _) => return Err ( APIError :: APIMisuseError { err : "Duplicate payment hash" . to_owned ( ) } ) ,
4553
- }
4554
- Ok ( payment_secret)
4555
- }
4556
-
4557
4612
/// Gets a payment secret and payment hash for use in an invoice given to a third party wishing
4558
4613
/// to pay us.
4559
4614
///
4560
4615
/// This differs from [`create_inbound_payment_for_hash`] only in that it generates the
4561
- /// [`PaymentHash`] and [`PaymentPreimage`] for you, returning the first and storing the second .
4616
+ /// [`PaymentHash`] and [`PaymentPreimage`] for you.
4562
4617
///
4563
4618
/// The [`PaymentPreimage`] will ultimately be returned to you in the [`PaymentReceived`], which
4564
4619
/// will have the [`PaymentReceived::payment_preimage`] field filled in. That should then be
@@ -4570,13 +4625,47 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
4570
4625
/// [`PaymentReceived`]: events::Event::PaymentReceived
4571
4626
/// [`PaymentReceived::payment_preimage`]: events::Event::PaymentReceived::payment_preimage
4572
4627
/// [`create_inbound_payment_for_hash`]: Self::create_inbound_payment_for_hash
4628
+ // For details on the implementation of this method, see `verify_inbound_payment_data`.
4573
4629
pub fn create_inbound_payment ( & self , min_value_msat : Option < u64 > , invoice_expiry_delta_secs : u32 ) -> ( PaymentHash , PaymentSecret ) {
4574
- let payment_preimage = PaymentPreimage ( self . keys_manager . get_secure_random_bytes ( ) ) ;
4575
- let payment_hash = PaymentHash ( Sha256 :: hash ( & payment_preimage. 0 ) . into_inner ( ) ) ;
4630
+ let ( metadata_key, _, ldk_pmt_hash_key) = hkdf_extract_expand ( & vec ! [ 0 ] , & self . inbound_payment_key ) ;
4631
+ let min_amt_msat_bytes: [ u8 ; 8 ] = match min_value_msat {
4632
+ Some ( amt) => amt. to_be_bytes ( ) ,
4633
+ None => [ 0 ; 8 ] ,
4634
+ } ;
4635
+ // We assume that highest_seen_timestamp is pretty close to the current time - its updated when
4636
+ // we receive a new block with the maximum time we've seen in a header. It should never be more
4637
+ // than two hours in the future. Thus, we add two hours here as a buffer to ensure we
4638
+ // absolutely never fail a payment too early.
4639
+ // Note that we assume that received blocks have reasonably up-to-date timestamps.
4640
+ let expiry_bytes = ( self . highest_seen_timestamp . load ( Ordering :: Acquire ) as u64 + invoice_expiry_delta_secs as u64 + 7200 ) . to_be_bytes ( ) ;
4641
+ let mut metadata_bytes: [ u8 ; 16 ] = [ 0 ; 16 ] ;
4642
+ {
4643
+ let ( min_amt_msat_slice, expiry_slice) = metadata_bytes. split_at_mut ( 8 ) ;
4644
+ min_amt_msat_slice. copy_from_slice ( & min_amt_msat_bytes) ;
4645
+ expiry_slice. copy_from_slice ( & expiry_bytes) ;
4646
+ }
4647
+
4648
+ let rand_bytes = self . keys_manager . get_secure_random_bytes ( ) ;
4649
+ let iv_bytes = & rand_bytes[ ..16 ] ;
4650
+
4651
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & ldk_pmt_hash_key) ;
4652
+ hmac. input ( iv_bytes) ;
4653
+ hmac. input ( & metadata_bytes) ;
4654
+ let payment_preimage_bytes = Hmac :: from_engine ( hmac) . into_inner ( ) ;
4576
4655
4577
- ( payment_hash,
4578
- self . set_payment_hash_secret_map ( payment_hash, Some ( payment_preimage) , min_value_msat, invoice_expiry_delta_secs)
4579
- . expect ( "RNG Generated Duplicate PaymentHash" ) )
4656
+ let mut payment_secret_bytes: [ u8 ; 32 ] = [ 0 ; 32 ] ;
4657
+ {
4658
+ let ( iv_slice, encrypted_metadata_slice) = payment_secret_bytes. split_at_mut ( 16 ) ;
4659
+ iv_slice. copy_from_slice ( iv_bytes) ;
4660
+
4661
+ let chacha_block = ChaCha20 :: get_single_block ( & metadata_key, iv_bytes) ;
4662
+ for i in 0 ..16 {
4663
+ encrypted_metadata_slice[ i] = chacha_block[ i] ^ metadata_bytes[ i] ;
4664
+ }
4665
+ }
4666
+
4667
+ let payment_hash = PaymentHash ( Sha256 :: hash ( & payment_preimage_bytes) . into_inner ( ) ) ;
4668
+ ( payment_hash, PaymentSecret ( payment_secret_bytes) )
4580
4669
}
4581
4670
4582
4671
/// Gets a [`PaymentSecret`] for a given [`PaymentHash`], for which the payment preimage is
@@ -4598,17 +4687,11 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
4598
4687
/// in excess of the current time. This should roughly match the expiry time set in the invoice.
4599
4688
/// After this many seconds, we will remove the inbound payment, resulting in any attempts to
4600
4689
/// pay the invoice failing. The BOLT spec suggests 3,600 secs as a default validity time for
4601
- /// invoices when no timeout is set.
4602
- ///
4603
- /// Note that we use block header time to time-out pending inbound payments (with some margin
4604
- /// to compensate for the inaccuracy of block header timestamps). Thus, in practice we will
4605
- /// accept a payment and generate a [`PaymentReceived`] event for some time after the expiry.
4606
- /// If you need exact expiry semantics, you should enforce them upon receipt of
4607
- /// [`PaymentReceived`].
4608
- ///
4609
- /// Pending inbound payments are stored in memory and in serialized versions of this
4610
- /// [`ChannelManager`]. If potentially unbounded numbers of inbound payments may exist and
4611
- /// space is limited, you may wish to rate-limit inbound payment creation.
4690
+ /// invoices when no timeout is set. Note that we use block header time to time-out pending
4691
+ /// inbound payments (with some margin to compensate for the inaccuracy of block header
4692
+ /// timestamps). Thus, in practice we will accept a payment and generate a [`PaymentReceived`]
4693
+ /// event for some time after the expiry. If you need exact expiry semantics, you should enforce
4694
+ /// them upon receipt of [`PaymentReceived`].
4612
4695
///
4613
4696
/// May panic if `invoice_expiry_delta_secs` is greater than one year.
4614
4697
///
@@ -4617,8 +4700,48 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
4617
4700
///
4618
4701
/// [`create_inbound_payment`]: Self::create_inbound_payment
4619
4702
/// [`PaymentReceived`]: events::Event::PaymentReceived
4703
+ // For details on the implementation of this method, see `verify_inbound_payment_data`.
4620
4704
pub fn create_inbound_payment_for_hash ( & self , payment_hash : PaymentHash , min_value_msat : Option < u64 > , invoice_expiry_delta_secs : u32 ) -> Result < PaymentSecret , APIError > {
4621
- self . set_payment_hash_secret_map ( payment_hash, None , min_value_msat, invoice_expiry_delta_secs)
4705
+ let ( metadata_key, user_pmt_hash_key, _) = hkdf_extract_expand ( & vec ! [ 0 ] , & self . inbound_payment_key ) ;
4706
+ let mut min_amt_msat_bytes: [ u8 ; 8 ] = match min_value_msat {
4707
+ Some ( amt) => amt. to_be_bytes ( ) ,
4708
+ None => [ 0 ; 8 ] ,
4709
+ } ;
4710
+ // Set the payment method bits (the top 4 bits of the metadata bytes) to 0001
4711
+ // indicating the payment type is paying a user-generated payment hash.
4712
+ min_amt_msat_bytes[ 0 ] |= 1 << 4 ;
4713
+
4714
+ // We assume that highest_seen_timestamp is pretty close to the current time - its updated when
4715
+ // we receive a new block with the maximum time we've seen in a header. It should never be more
4716
+ // than two hours in the future. Thus, we add two hours here as a buffer to ensure we
4717
+ // absolutely never fail a payment too early.
4718
+ // Note that we assume that received blocks have reasonably up-to-date timestamps.
4719
+ let expiry_bytes = ( self . highest_seen_timestamp . load ( Ordering :: Acquire ) as u64 + invoice_expiry_delta_secs as u64 + 7200 ) . to_be_bytes ( ) ;
4720
+
4721
+ let mut metadata_bytes: [ u8 ; 16 ] = [ 0 ; 16 ] ;
4722
+ {
4723
+ let ( min_amt_msat_slice, expiry_slice) = metadata_bytes. split_at_mut ( 8 ) ;
4724
+ min_amt_msat_slice. copy_from_slice ( & min_amt_msat_bytes) ;
4725
+ expiry_slice. copy_from_slice ( & expiry_bytes) ;
4726
+ }
4727
+
4728
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & user_pmt_hash_key) ;
4729
+ hmac. input ( & metadata_bytes) ;
4730
+ hmac. input ( & payment_hash. 0 ) ;
4731
+ let hmac_bytes = Hmac :: from_engine ( hmac) . into_inner ( ) ;
4732
+ let iv_bytes = & hmac_bytes[ ..16 ] ;
4733
+
4734
+ let mut payment_secret_bytes: [ u8 ; 32 ] = [ 0 ; 32 ] ;
4735
+ {
4736
+ let ( iv_slice, encrypted_metadata_slice) = payment_secret_bytes. split_at_mut ( 16 ) ;
4737
+ iv_slice. copy_from_slice ( iv_bytes) ;
4738
+
4739
+ let chacha_block = ChaCha20 :: get_single_block ( & metadata_key, iv_bytes) ;
4740
+ for i in 0 ..16 {
4741
+ encrypted_metadata_slice[ i] = chacha_block[ i] ^ metadata_bytes[ i] ;
4742
+ }
4743
+ }
4744
+ Ok ( PaymentSecret ( payment_secret_bytes) )
4622
4745
}
4623
4746
4624
4747
#[ cfg( any( test, feature = "fuzztarget" , feature = "_test_utils" ) ) ]
@@ -5690,6 +5813,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
5690
5813
}
5691
5814
write_tlv_fields ! ( writer, {
5692
5815
( 1 , pending_outbound_payments_no_retry, required) ,
5816
+ ( 2 , self . inbound_payment_key, required) ,
5693
5817
( 3 , pending_outbound_payments, required) ,
5694
5818
} ) ;
5695
5819
@@ -5985,10 +6109,15 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
5985
6109
// pending_outbound_payments_no_retry is for compatibility with 0.0.101 clients.
5986
6110
let mut pending_outbound_payments_no_retry: Option < HashMap < PaymentId , HashSet < [ u8 ; 32 ] > > > = None ;
5987
6111
let mut pending_outbound_payments = None ;
6112
+ let mut inbound_payment_key = None ;
5988
6113
read_tlv_fields ! ( reader, {
5989
6114
( 1 , pending_outbound_payments_no_retry, option) ,
6115
+ ( 2 , inbound_payment_key, option) ,
5990
6116
( 3 , pending_outbound_payments, option) ,
5991
6117
} ) ;
6118
+ if inbound_payment_key. is_none ( ) {
6119
+ inbound_payment_key = Some ( args. keys_manager . get_inbound_payment_secret ( ) ) ;
6120
+ }
5992
6121
if pending_outbound_payments. is_none ( ) && pending_outbound_payments_no_retry. is_none ( ) {
5993
6122
pending_outbound_payments = Some ( pending_outbound_payments_compat) ;
5994
6123
} else if pending_outbound_payments. is_none ( ) {
@@ -6066,6 +6195,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
6066
6195
claimable_htlcs,
6067
6196
pending_msg_events : Vec :: new ( ) ,
6068
6197
} ) ,
6198
+ inbound_payment_key : inbound_payment_key. unwrap ( ) ,
6069
6199
pending_inbound_payments : Mutex :: new ( pending_inbound_payments) ,
6070
6200
pending_outbound_payments : Mutex :: new ( pending_outbound_payments. unwrap ( ) ) ,
6071
6201
@@ -6099,6 +6229,27 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
6099
6229
}
6100
6230
}
6101
6231
6232
+ fn hkdf_extract_expand ( salt : & [ u8 ] , ikm : & [ u8 ] ) -> ( [ u8 ; 32 ] , [ u8 ; 32 ] , [ u8 ; 32 ] ) {
6233
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( salt) ;
6234
+ hmac. input ( ikm) ;
6235
+ let prk = Hmac :: from_engine ( hmac) . into_inner ( ) ;
6236
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & prk[ ..] ) ;
6237
+ hmac. input ( & [ 1 ; 1 ] ) ;
6238
+ let t1 = Hmac :: from_engine ( hmac) . into_inner ( ) ;
6239
+
6240
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & prk[ ..] ) ;
6241
+ hmac. input ( & t1) ;
6242
+ hmac. input ( & [ 2 ; 1 ] ) ;
6243
+ let t2 = Hmac :: from_engine ( hmac) . into_inner ( ) ;
6244
+
6245
+ let mut hmac = HmacEngine :: < Sha256 > :: new ( & prk[ ..] ) ;
6246
+ hmac. input ( & t2) ;
6247
+ hmac. input ( & [ 3 ; 1 ] ) ;
6248
+ let t3 = Hmac :: from_engine ( hmac) . into_inner ( ) ;
6249
+
6250
+ ( t1, t2, t3)
6251
+ }
6252
+
6102
6253
#[ cfg( test) ]
6103
6254
mod tests {
6104
6255
use bitcoin:: hashes:: Hash ;
0 commit comments