2020-08-10 15:00:09 -04:00
// This file is Copyright its original authors, visible in version control
// history.
//
// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
// You may not use this file except in accordance with one or both of these
// licenses.
2023-03-24 05:32:56 +00:00
use crate ::ln ::{ PaymentHash , PaymentPreimage } ;
use crate ::ln ::channelmanager ::{ HTLCSource , RecipientOnionFields } ;
2022-10-13 02:35:48 -04:00
use crate ::ln ::msgs ;
use crate ::ln ::wire ::Encode ;
use crate ::routing ::gossip ::NetworkUpdate ;
2023-07-12 22:32:06 -04:00
use crate ::routing ::router ::{ BlindedTail , Path , RouteHop } ;
2023-09-10 01:10:03 -04:00
use crate ::sign ::NodeSigner ;
2022-10-13 02:35:48 -04:00
use crate ::util ::chacha20 ::{ ChaCha20 , ChaChaReader } ;
use crate ::util ::errors ::{ self , APIError } ;
2022-12-01 19:28:32 +00:00
use crate ::util ::ser ::{ Readable , ReadableArgs , Writeable , Writer , LengthCalculatingWriter } ;
2022-10-13 02:35:48 -04:00
use crate ::util ::logger ::Logger ;
2018-12-19 17:02:27 -05:00
2020-04-27 16:41:54 +02:00
use bitcoin ::hashes ::{ Hash , HashEngine } ;
use bitcoin ::hashes ::cmp ::fixed_time_eq ;
use bitcoin ::hashes ::hmac ::{ Hmac , HmacEngine } ;
use bitcoin ::hashes ::sha256 ::Hash as Sha256 ;
2018-12-19 17:02:27 -05:00
2022-08-09 17:39:51 +02:00
use bitcoin ::secp256k1 ::{ SecretKey , PublicKey , Scalar } ;
2020-04-27 16:51:59 +02:00
use bitcoin ::secp256k1 ::Secp256k1 ;
use bitcoin ::secp256k1 ::ecdh ::SharedSecret ;
use bitcoin ::secp256k1 ;
2018-12-19 17:02:27 -05:00
2022-10-13 02:35:48 -04:00
use crate ::prelude ::* ;
use crate ::io ::{ Cursor , Read } ;
2022-05-27 17:47:15 -07:00
use core ::convert ::{ AsMut , TryInto } ;
2021-05-23 23:22:46 +00:00
use core ::ops ::Deref ;
2018-12-19 17:02:27 -05:00
2022-05-27 18:31:27 -07:00
pub ( crate ) struct OnionKeys {
2018-12-19 17:02:27 -05:00
#[ cfg(test) ]
2022-05-27 18:31:27 -07:00
pub ( crate ) shared_secret : SharedSecret ,
2018-12-19 17:02:27 -05:00
#[ cfg(test) ]
2022-05-27 18:31:27 -07:00
pub ( crate ) blinding_factor : [ u8 ; 32 ] ,
pub ( crate ) ephemeral_pubkey : PublicKey ,
pub ( crate ) rho : [ u8 ; 32 ] ,
pub ( crate ) mu : [ u8 ; 32 ] ,
2018-12-19 17:02:27 -05:00
}
2022-05-27 16:25:15 -07:00
#[ inline ]
pub ( crate ) fn gen_rho_from_shared_secret ( shared_secret : & [ u8 ] ) -> [ u8 ; 32 ] {
assert_eq! ( shared_secret . len ( ) , 32 ) ;
let mut hmac = HmacEngine ::< Sha256 > ::new ( & [ 0x72 , 0x68 , 0x6f ] ) ; // rho
hmac . input ( & shared_secret ) ;
2023-04-27 00:16:40 -07:00
Hmac ::from_engine ( hmac ) . to_byte_array ( )
2022-05-27 16:25:15 -07:00
}
2018-12-19 17:02:27 -05:00
#[ inline ]
2022-05-27 18:31:27 -07:00
pub ( crate ) fn gen_rho_mu_from_shared_secret ( shared_secret : & [ u8 ] ) -> ( [ u8 ; 32 ] , [ u8 ; 32 ] ) {
2018-12-19 17:02:27 -05:00
assert_eq! ( shared_secret . len ( ) , 32 ) ;
( {
let mut hmac = HmacEngine ::< Sha256 > ::new ( & [ 0x72 , 0x68 , 0x6f ] ) ; // rho
2022-05-05 17:59:38 +02:00
hmac . input ( & shared_secret ) ;
2023-04-27 00:16:40 -07:00
Hmac ::from_engine ( hmac ) . to_byte_array ( )
2018-12-19 17:02:27 -05:00
} ,
{
let mut hmac = HmacEngine ::< Sha256 > ::new ( & [ 0x6d , 0x75 ] ) ; // mu
2022-05-05 17:59:38 +02:00
hmac . input ( & shared_secret ) ;
2023-04-27 00:16:40 -07:00
Hmac ::from_engine ( hmac ) . to_byte_array ( )
2018-12-19 17:02:27 -05:00
} )
}
#[ inline ]
pub ( super ) fn gen_um_from_shared_secret ( shared_secret : & [ u8 ] ) -> [ u8 ; 32 ] {
assert_eq! ( shared_secret . len ( ) , 32 ) ;
let mut hmac = HmacEngine ::< Sha256 > ::new ( & [ 0x75 , 0x6d ] ) ; // um
2022-05-05 17:59:38 +02:00
hmac . input ( & shared_secret ) ;
2023-04-27 00:16:40 -07:00
Hmac ::from_engine ( hmac ) . to_byte_array ( )
2018-12-19 17:02:27 -05:00
}
#[ inline ]
pub ( super ) fn gen_ammag_from_shared_secret ( shared_secret : & [ u8 ] ) -> [ u8 ; 32 ] {
assert_eq! ( shared_secret . len ( ) , 32 ) ;
let mut hmac = HmacEngine ::< Sha256 > ::new ( & [ 0x61 , 0x6d , 0x6d , 0x61 , 0x67 ] ) ; // ammag
2022-05-05 17:59:38 +02:00
hmac . input ( & shared_secret ) ;
2023-04-27 00:16:40 -07:00
Hmac ::from_engine ( hmac ) . to_byte_array ( )
2018-12-19 17:02:27 -05:00
}
2022-09-30 01:29:02 +02:00
#[ cfg(test) ]
#[ inline ]
pub ( super ) fn gen_pad_from_shared_secret ( shared_secret : & [ u8 ] ) -> [ u8 ; 32 ] {
assert_eq! ( shared_secret . len ( ) , 32 ) ;
let mut hmac = HmacEngine ::< Sha256 > ::new ( & [ 0x70 , 0x61 , 0x64 ] ) ; // pad
hmac . input ( & shared_secret ) ;
2023-04-27 00:16:40 -07:00
Hmac ::from_engine ( hmac ) . to_byte_array ( )
2022-09-30 01:29:02 +02:00
}
2023-06-27 12:35:03 -04:00
/// Calculates a pubkey for the next hop, such as the next hop's packet pubkey or blinding point.
2023-10-28 08:11:21 -07:00
pub ( crate ) fn next_hop_pubkey < T : secp256k1 ::Verification > (
2023-06-27 12:35:03 -04:00
secp_ctx : & Secp256k1 < T > , curr_pubkey : PublicKey , shared_secret : & [ u8 ]
) -> Result < PublicKey , secp256k1 ::Error > {
2022-05-26 17:36:32 -07:00
let blinding_factor = {
let mut sha = Sha256 ::engine ( ) ;
2023-06-27 12:35:03 -04:00
sha . input ( & curr_pubkey . serialize ( ) [ .. ] ) ;
sha . input ( shared_secret ) ;
2023-04-27 00:16:40 -07:00
Sha256 ::from_engine ( sha ) . to_byte_array ( )
2022-05-26 17:36:32 -07:00
} ;
2023-06-27 12:35:03 -04:00
curr_pubkey . mul_tweak ( secp_ctx , & Scalar ::from_be_bytes ( blinding_factor ) . unwrap ( ) )
2022-05-26 17:36:32 -07:00
}
2018-12-19 17:02:27 -05:00
// can only fail if an intermediary hop has an invalid public key or session_priv is invalid
#[ inline ]
2023-07-07 13:35:42 -04:00
pub ( super ) fn construct_onion_keys_callback < T , FType > (
secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey , mut callback : FType
) -> Result < ( ) , secp256k1 ::Error >
where
T : secp256k1 ::Signing ,
FType : FnMut ( SharedSecret , [ u8 ; 32 ] , PublicKey , Option < & RouteHop > , usize )
{
2018-12-19 17:02:27 -05:00
let mut blinded_priv = session_priv . clone ( ) ;
let mut blinded_pub = PublicKey ::from_secret_key ( secp_ctx , & blinded_priv ) ;
2023-07-07 13:35:42 -04:00
let unblinded_hops_iter = path . hops . iter ( ) . map ( | h | ( & h . pubkey , Some ( h ) ) ) ;
let blinded_pks_iter = path . blinded_tail . as_ref ( )
. map ( | t | t . hops . iter ( ) ) . unwrap_or ( [ ] . iter ( ) )
. skip ( 1 ) // Skip the intro node because it's included in the unblinded hops
. map ( | h | ( & h . blinded_node_id , None ) ) ;
for ( idx , ( pubkey , route_hop_opt ) ) in unblinded_hops_iter . chain ( blinded_pks_iter ) . enumerate ( ) {
let shared_secret = SharedSecret ::new ( pubkey , & blinded_priv ) ;
2018-12-19 17:02:27 -05:00
let mut sha = Sha256 ::engine ( ) ;
sha . input ( & blinded_pub . serialize ( ) [ .. ] ) ;
2022-05-05 17:59:38 +02:00
sha . input ( shared_secret . as_ref ( ) ) ;
2023-04-27 00:16:40 -07:00
let blinding_factor = Sha256 ::from_engine ( sha ) . to_byte_array ( ) ;
2018-12-19 17:02:27 -05:00
let ephemeral_pubkey = blinded_pub ;
2022-08-09 17:39:51 +02:00
blinded_priv = blinded_priv . mul_tweak ( & Scalar ::from_be_bytes ( blinding_factor ) . unwrap ( ) ) ? ;
2018-12-19 17:02:27 -05:00
blinded_pub = PublicKey ::from_secret_key ( secp_ctx , & blinded_priv ) ;
2023-07-07 13:35:42 -04:00
callback ( shared_secret , blinding_factor , ephemeral_pubkey , route_hop_opt , idx ) ;
2018-12-19 17:02:27 -05:00
}
Ok ( ( ) )
}
// can only fail if an intermediary hop has an invalid public key or session_priv is invalid
2023-04-09 13:50:44 -04:00
pub ( super ) fn construct_onion_keys < T : secp256k1 ::Signing > ( secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey ) -> Result < Vec < OnionKeys > , secp256k1 ::Error > {
let mut res = Vec ::with_capacity ( path . hops . len ( ) ) ;
2018-12-19 17:02:27 -05:00
2023-07-07 13:35:42 -04:00
construct_onion_keys_callback ( secp_ctx , & path , session_priv ,
| shared_secret , _blinding_factor , ephemeral_pubkey , _ , _ |
{
2022-05-05 17:59:38 +02:00
let ( rho , mu ) = gen_rho_mu_from_shared_secret ( shared_secret . as_ref ( ) ) ;
2018-12-19 17:02:27 -05:00
res . push ( OnionKeys {
#[ cfg(test) ]
shared_secret ,
#[ cfg(test) ]
blinding_factor : _blinding_factor ,
ephemeral_pubkey ,
rho ,
mu ,
} ) ;
} ) ? ;
Ok ( res )
}
/// returns the hop data, as well as the first-hop value_msat and CLTV value we should send.
2023-03-24 14:35:52 -04:00
pub ( super ) fn build_onion_payloads ( path : & Path , total_msat : u64 , mut recipient_onion : RecipientOnionFields , starting_htlc_offset : u32 , keysend_preimage : & Option < PaymentPreimage > ) -> Result < ( Vec < msgs ::OutboundOnionPayload > , u64 , u32 ) , APIError > {
2018-12-19 17:02:27 -05:00
let mut cur_value_msat = 0 u64 ;
let mut cur_cltv = starting_htlc_offset ;
let mut last_short_channel_id = 0 ;
2023-07-12 22:32:06 -04:00
let mut res : Vec < msgs ::OutboundOnionPayload > = Vec ::with_capacity (
path . hops . len ( ) + path . blinded_tail . as_ref ( ) . map_or ( 0 , | t | t . hops . len ( ) )
) ;
2018-12-19 17:02:27 -05:00
2023-04-09 13:50:44 -04:00
for ( idx , hop ) in path . hops . iter ( ) . rev ( ) . enumerate ( ) {
2018-12-19 17:02:27 -05:00
// First hop gets special values so that it can check, on receipt, that everything is
// exactly as it should be (and the next hop isn't trying to probe to find out if we're
// the intended recipient).
let value_msat = if cur_value_msat = = 0 { hop . fee_msat } else { cur_value_msat } ;
let cltv = if cur_cltv = = starting_htlc_offset { hop . cltv_expiry_delta + starting_htlc_offset } else { cur_cltv } ;
2023-07-12 22:32:06 -04:00
if idx = = 0 {
if let Some ( BlindedTail {
blinding_point , hops , final_value_msat , excess_final_cltv_expiry_delta , ..
} ) = & path . blinded_tail {
let mut blinding_point = Some ( * blinding_point ) ;
for ( i , blinded_hop ) in hops . iter ( ) . enumerate ( ) {
if i = = hops . len ( ) - 1 {
cur_value_msat + = final_value_msat ;
cur_cltv + = excess_final_cltv_expiry_delta ;
res . push ( msgs ::OutboundOnionPayload ::BlindedReceive {
amt_msat : * final_value_msat ,
total_msat ,
outgoing_cltv_value : cltv ,
encrypted_tlvs : blinded_hop . encrypted_payload . clone ( ) ,
intro_node_blinding_point : blinding_point . take ( ) ,
} ) ;
} else {
res . push ( msgs ::OutboundOnionPayload ::BlindedForward {
encrypted_tlvs : blinded_hop . encrypted_payload . clone ( ) ,
intro_node_blinding_point : blinding_point . take ( ) ,
} ) ;
}
}
} else {
res . push ( msgs ::OutboundOnionPayload ::Receive {
payment_data : if let Some ( secret ) = recipient_onion . payment_secret . take ( ) {
Some ( msgs ::FinalOnionHopData {
payment_secret : secret ,
total_msat ,
} )
} else { None } ,
payment_metadata : recipient_onion . payment_metadata . take ( ) ,
keysend_preimage : * keysend_preimage ,
custom_tlvs : recipient_onion . custom_tlvs . clone ( ) ,
amt_msat : value_msat ,
outgoing_cltv_value : cltv ,
} ) ;
2023-03-24 14:35:52 -04:00
}
} else {
2023-07-12 22:32:06 -04:00
res . insert ( 0 , msgs ::OutboundOnionPayload ::Forward {
2023-03-24 14:35:52 -04:00
short_channel_id : last_short_channel_id ,
amt_to_forward : value_msat ,
outgoing_cltv_value : cltv ,
2023-07-12 22:32:06 -04:00
} ) ;
}
2018-12-19 17:02:27 -05:00
cur_value_msat + = hop . fee_msat ;
if cur_value_msat > = 21000000 * 100000000 * 1000 {
2023-02-19 18:32:29 -05:00
return Err ( APIError ::InvalidRoute { err : " Channel fees overflowed? " . to_owned ( ) } ) ;
2018-12-19 17:02:27 -05:00
}
cur_cltv + = hop . cltv_expiry_delta as u32 ;
if cur_cltv > = 500000000 {
2023-02-19 18:32:29 -05:00
return Err ( APIError ::InvalidRoute { err : " Channel CLTV overflowed? " . to_owned ( ) } ) ;
2018-12-19 17:02:27 -05:00
}
last_short_channel_id = hop . short_channel_id ;
}
Ok ( ( res , cur_value_msat , cur_cltv ) )
}
2020-02-10 18:28:53 -05:00
/// Length of the onion data packet. Before TLV-based onions this was 20 65-byte hops, though now
/// the hops can be of variable length.
pub ( crate ) const ONION_DATA_LEN : usize = 20 * 65 ;
2023-10-26 14:24:10 -04:00
pub ( super ) const INVALID_ONION_BLINDING : u16 = 0x8000 | 0x4000 | 24 ;
2018-12-19 17:02:27 -05:00
#[ inline ]
2022-05-27 17:47:15 -07:00
fn shift_slice_right ( arr : & mut [ u8 ] , amt : usize ) {
for i in ( amt .. arr . len ( ) ) . rev ( ) {
2019-12-28 13:44:47 -05:00
arr [ i ] = arr [ i - amt ] ;
2018-12-19 17:02:27 -05:00
}
2019-12-28 13:44:47 -05:00
for i in 0 .. amt {
2018-12-19 17:02:27 -05:00
arr [ i ] = 0 ;
}
}
2023-03-24 14:35:52 -04:00
pub ( super ) fn construct_onion_packet (
payloads : Vec < msgs ::OutboundOnionPayload > , onion_keys : Vec < OnionKeys > , prng_seed : [ u8 ; 32 ] ,
associated_data : & PaymentHash
) -> Result < msgs ::OnionPacket , ( ) > {
2020-02-10 18:28:53 -05:00
let mut packet_data = [ 0 ; ONION_DATA_LEN ] ;
2019-11-25 16:12:45 -05:00
let mut chacha = ChaCha20 ::new ( & prng_seed , & [ 0 ; 8 ] ) ;
2020-02-10 18:28:53 -05:00
chacha . process ( & [ 0 ; ONION_DATA_LEN ] , & mut packet_data ) ;
2019-11-25 16:12:45 -05:00
2022-05-27 17:47:15 -07:00
construct_onion_packet_with_init_noise ::< _ , _ > (
payloads , onion_keys , FixedSizeOnionPacket ( packet_data ) , Some ( associated_data ) )
2019-11-25 16:12:45 -05:00
}
2019-12-26 13:45:44 -05:00
#[ cfg(test) ]
2022-09-30 01:29:02 +02:00
/// Used in testing to write bogus `BogusOnionHopData` as well as `RawOnionHopData`, which is
/// otherwise not representable in `msgs::OnionHopData`.
2023-04-05 17:08:49 +02:00
pub ( super ) fn construct_onion_packet_with_writable_hopdata < HD : Writeable > ( payloads : Vec < HD > , onion_keys : Vec < OnionKeys > , prng_seed : [ u8 ; 32 ] , associated_data : & PaymentHash ) -> Result < msgs ::OnionPacket , ( ) > {
2020-02-10 18:28:53 -05:00
let mut packet_data = [ 0 ; ONION_DATA_LEN ] ;
2019-12-26 13:45:44 -05:00
let mut chacha = ChaCha20 ::new ( & prng_seed , & [ 0 ; 8 ] ) ;
2020-02-10 18:28:53 -05:00
chacha . process ( & [ 0 ; ONION_DATA_LEN ] , & mut packet_data ) ;
2019-12-26 13:45:44 -05:00
2022-05-27 17:47:15 -07:00
construct_onion_packet_with_init_noise ::< _ , _ > (
payloads , onion_keys , FixedSizeOnionPacket ( packet_data ) , Some ( associated_data ) )
2019-12-26 13:45:44 -05:00
}
2022-05-27 17:47:15 -07:00
/// Since onion message packets and onion payment packets have different lengths but are otherwise
/// identical, we use this trait to allow `construct_onion_packet_with_init_noise` to return either
/// type.
pub ( crate ) trait Packet {
type Data : AsMut < [ u8 ] > ;
fn new ( pubkey : PublicKey , hop_data : Self ::Data , hmac : [ u8 ; 32 ] ) -> Self ;
}
// Needed for rustc versions older than 1.47 to avoid E0277: "arrays only have std trait
// implementations for lengths 0..=32".
pub ( crate ) struct FixedSizeOnionPacket ( pub ( crate ) [ u8 ; ONION_DATA_LEN ] ) ;
impl AsMut < [ u8 ] > for FixedSizeOnionPacket {
fn as_mut ( & mut self ) -> & mut [ u8 ] {
& mut self . 0
}
}
2022-05-27 18:31:27 -07:00
pub ( crate ) fn payloads_serialized_length < HD : Writeable > ( payloads : & Vec < HD > ) -> usize {
payloads . iter ( ) . map ( | p | p . serialized_length ( ) + 32 /* HMAC */ ) . sum ( )
}
pub ( crate ) fn construct_onion_message_packet < HD : Writeable , P : Packet < Data = Vec < u8 > > > (
2023-04-05 17:08:49 +02:00
payloads : Vec < HD > , onion_keys : Vec < OnionKeys > , prng_seed : [ u8 ; 32 ] , packet_data_len : usize ) -> Result < P , ( ) >
2022-05-27 18:31:27 -07:00
{
let mut packet_data = vec! [ 0 ; packet_data_len ] ;
let mut chacha = ChaCha20 ::new ( & prng_seed , & [ 0 ; 8 ] ) ;
chacha . process_in_place ( & mut packet_data ) ;
construct_onion_packet_with_init_noise ::< _ , _ > ( payloads , onion_keys , packet_data , None )
}
2022-05-27 17:47:15 -07:00
fn construct_onion_packet_with_init_noise < HD : Writeable , P : Packet > (
2023-04-05 17:08:49 +02:00
mut payloads : Vec < HD > , onion_keys : Vec < OnionKeys > , mut packet_data : P ::Data , associated_data : Option < & PaymentHash > ) -> Result < P , ( ) >
2022-05-27 17:47:15 -07:00
{
2018-12-19 17:02:27 -05:00
let filler = {
2022-05-27 17:47:15 -07:00
let packet_data = packet_data . as_mut ( ) ;
2019-12-28 13:44:47 -05:00
const ONION_HOP_DATA_LEN : usize = 65 ; // We may decrease this eventually after TLV is common
let mut res = Vec ::with_capacity ( ONION_HOP_DATA_LEN * ( payloads . len ( ) - 1 ) ) ;
let mut pos = 0 ;
for ( i , ( payload , keys ) ) in payloads . iter ( ) . zip ( onion_keys . iter ( ) ) . enumerate ( ) {
if i = = payloads . len ( ) - 1 { break ; }
2018-12-19 17:02:27 -05:00
let mut chacha = ChaCha20 ::new ( & keys . rho , & [ 0 u8 ; 8 ] ) ;
2022-05-27 17:47:15 -07:00
for _ in 0 .. ( packet_data . len ( ) - pos ) { // TODO: Batch this.
2019-12-28 13:44:47 -05:00
let mut dummy = [ 0 ; 1 ] ;
chacha . process_in_place ( & mut dummy ) ; // We don't have a seek function :(
}
let mut payload_len = LengthCalculatingWriter ( 0 ) ;
payload . write ( & mut payload_len ) . expect ( " Failed to calculate length " ) ;
pos + = payload_len . 0 + 32 ;
2023-04-05 17:08:49 +02:00
if pos > packet_data . len ( ) {
return Err ( ( ) ) ;
}
2019-12-28 13:44:47 -05:00
res . resize ( pos , 0 u8 ) ;
chacha . process_in_place ( & mut res ) ;
2018-12-19 17:02:27 -05:00
}
res
} ;
let mut hmac_res = [ 0 ; 32 ] ;
for ( i , ( payload , keys ) ) in payloads . iter_mut ( ) . zip ( onion_keys . iter ( ) ) . rev ( ) . enumerate ( ) {
2019-12-28 13:44:47 -05:00
let mut payload_len = LengthCalculatingWriter ( 0 ) ;
payload . write ( & mut payload_len ) . expect ( " Failed to calculate length " ) ;
2022-05-27 17:47:15 -07:00
let packet_data = packet_data . as_mut ( ) ;
shift_slice_right ( packet_data , payload_len . 0 + 32 ) ;
2019-12-28 13:44:47 -05:00
packet_data [ 0 .. payload_len . 0 ] . copy_from_slice ( & payload . encode ( ) [ .. ] ) ;
packet_data [ payload_len . 0 .. ( payload_len . 0 + 32 ) ] . copy_from_slice ( & hmac_res ) ;
2018-12-19 17:02:27 -05:00
let mut chacha = ChaCha20 ::new ( & keys . rho , & [ 0 u8 ; 8 ] ) ;
2022-05-27 17:47:15 -07:00
chacha . process_in_place ( packet_data ) ;
2018-12-19 17:02:27 -05:00
if i = = 0 {
2023-04-05 17:08:49 +02:00
let stop_index = packet_data . len ( ) ;
let start_index = stop_index . checked_sub ( filler . len ( ) ) . ok_or ( ( ) ) ? ;
packet_data [ start_index .. stop_index ] . copy_from_slice ( & filler [ .. ] ) ;
2018-12-19 17:02:27 -05:00
}
let mut hmac = HmacEngine ::< Sha256 > ::new ( & keys . mu ) ;
2022-05-27 17:47:15 -07:00
hmac . input ( packet_data ) ;
if let Some ( associated_data ) = associated_data {
hmac . input ( & associated_data . 0 [ .. ] ) ;
}
2023-04-27 00:16:40 -07:00
hmac_res = Hmac ::from_engine ( hmac ) . to_byte_array ( ) ;
2018-12-19 17:02:27 -05:00
}
2023-04-05 17:08:49 +02:00
Ok ( P ::new ( onion_keys . first ( ) . unwrap ( ) . ephemeral_pubkey , packet_data , hmac_res ) )
2018-12-19 17:02:27 -05:00
}
/// Encrypts a failure packet. raw_packet can either be a
/// msgs::DecodedOnionErrorPacket.encode() result or a msgs::OnionErrorPacket.data element.
pub ( super ) fn encrypt_failure_packet ( shared_secret : & [ u8 ] , raw_packet : & [ u8 ] ) -> msgs ::OnionErrorPacket {
let ammag = gen_ammag_from_shared_secret ( & shared_secret ) ;
let mut packet_crypted = Vec ::with_capacity ( raw_packet . len ( ) ) ;
packet_crypted . resize ( raw_packet . len ( ) , 0 ) ;
let mut chacha = ChaCha20 ::new ( & ammag , & [ 0 u8 ; 8 ] ) ;
chacha . process ( & raw_packet , & mut packet_crypted [ .. ] ) ;
msgs ::OnionErrorPacket {
data : packet_crypted ,
}
}
pub ( super ) fn build_failure_packet ( shared_secret : & [ u8 ] , failure_type : u16 , failure_data : & [ u8 ] ) -> msgs ::DecodedOnionErrorPacket {
assert_eq! ( shared_secret . len ( ) , 32 ) ;
assert! ( failure_data . len ( ) < = 256 - 2 ) ;
let um = gen_um_from_shared_secret ( & shared_secret ) ;
let failuremsg = {
let mut res = Vec ::with_capacity ( 2 + failure_data . len ( ) ) ;
res . push ( ( ( failure_type > > 8 ) & 0xff ) as u8 ) ;
res . push ( ( ( failure_type > > 0 ) & 0xff ) as u8 ) ;
res . extend_from_slice ( & failure_data [ .. ] ) ;
res
} ;
let pad = {
let mut res = Vec ::with_capacity ( 256 - 2 - failure_data . len ( ) ) ;
res . resize ( 256 - 2 - failure_data . len ( ) , 0 ) ;
res
} ;
let mut packet = msgs ::DecodedOnionErrorPacket {
hmac : [ 0 ; 32 ] ,
2020-10-06 16:47:23 -07:00
failuremsg ,
pad ,
2018-12-19 17:02:27 -05:00
} ;
let mut hmac = HmacEngine ::< Sha256 > ::new ( & um ) ;
hmac . input ( & packet . encode ( ) [ 32 .. ] ) ;
2023-04-27 00:16:40 -07:00
packet . hmac = Hmac ::from_engine ( hmac ) . to_byte_array ( ) ;
2018-12-19 17:02:27 -05:00
packet
}
2022-12-01 23:30:04 +00:00
#[ cfg(test) ]
2018-12-19 17:02:27 -05:00
pub ( super ) fn build_first_hop_failure_packet ( shared_secret : & [ u8 ] , failure_type : u16 , failure_data : & [ u8 ] ) -> msgs ::OnionErrorPacket {
let failure_packet = build_failure_packet ( shared_secret , failure_type , failure_data ) ;
encrypt_failure_packet ( shared_secret , & failure_packet . encode ( ) [ .. ] )
}
2023-07-20 13:59:23 -04:00
pub ( crate ) struct DecodedOnionFailure {
pub ( crate ) network_update : Option < NetworkUpdate > ,
pub ( crate ) short_channel_id : Option < u64 > ,
2023-09-14 11:33:01 -04:00
pub ( crate ) payment_failed_permanently : bool ,
2023-07-20 13:59:23 -04:00
#[ cfg(test) ]
pub ( crate ) onion_error_code : Option < u16 > ,
#[ cfg(test) ]
pub ( crate ) onion_error_data : Option < Vec < u8 > > ,
}
2023-10-26 12:59:42 -04:00
/// Note that we always decrypt `packet` in-place here even if the deserialization into
/// [`msgs::DecodedOnionErrorPacket`] ultimately fails.
fn decrypt_onion_error_packet (
packet : & mut Vec < u8 > , shared_secret : SharedSecret
) -> Result < msgs ::DecodedOnionErrorPacket , msgs ::DecodeError > {
let ammag = gen_ammag_from_shared_secret ( shared_secret . as_ref ( ) ) ;
let mut chacha = ChaCha20 ::new ( & ammag , & [ 0 u8 ; 8 ] ) ;
chacha . process_in_place ( packet ) ;
msgs ::DecodedOnionErrorPacket ::read ( & mut Cursor ::new ( packet ) )
}
2018-12-20 14:51:18 -05:00
/// Process failure we got back from upstream on a payment we sent (implying htlc_source is an
/// OutboundRoute).
2020-04-20 07:30:16 +10:00
#[ inline ]
2023-08-12 19:02:56 -04:00
pub ( super ) fn process_onion_failure < T : secp256k1 ::Signing , L : Deref > (
2023-10-26 12:59:42 -04:00
secp_ctx : & Secp256k1 < T > , logger : & L , htlc_source : & HTLCSource , mut encrypted_packet : Vec < u8 >
2023-07-20 13:59:23 -04:00
) -> DecodedOnionFailure where L ::Target : Logger {
2023-08-12 19:02:56 -04:00
let ( path , session_priv , first_hop_htlc_msat ) = if let & HTLCSource ::OutboundRoute {
ref path , ref session_priv , ref first_hop_htlc_msat , ..
} = htlc_source {
( path , session_priv , first_hop_htlc_msat )
} else { unreachable! ( ) } ;
2023-09-20 14:49:58 -04:00
// Learnings from the HTLC failure to inform future payment retries and scoring.
struct FailureLearnings {
network_update : Option < NetworkUpdate > ,
short_channel_id : Option < u64 > ,
payment_failed_permanently : bool ,
}
let mut res : Option < FailureLearnings > = None ;
2023-08-12 19:02:56 -04:00
let mut htlc_msat = * first_hop_htlc_msat ;
let mut error_code_ret = None ;
let mut error_packet_ret = None ;
let mut is_from_final_node = false ;
2023-07-07 13:35:42 -04:00
const BADONION : u16 = 0x8000 ;
const PERM : u16 = 0x4000 ;
const NODE : u16 = 0x2000 ;
const UPDATE : u16 = 0x1000 ;
2023-08-12 19:02:56 -04:00
// Handle packed channel/node updates for passing back for the route handler
2023-07-07 13:35:42 -04:00
construct_onion_keys_callback ( secp_ctx , & path , session_priv ,
| shared_secret , _ , _ , route_hop_opt , route_hop_idx |
{
2023-08-12 19:02:56 -04:00
if res . is_some ( ) { return ; }
2023-07-07 13:35:42 -04:00
let route_hop = match route_hop_opt {
Some ( hop ) = > hop ,
None = > {
// Got an error from within a blinded route.
error_code_ret = Some ( BADONION | PERM | 24 ) ; // invalid_onion_blinding
error_packet_ret = Some ( vec! [ 0 ; 32 ] ) ;
2023-09-14 11:41:35 -04:00
res = Some ( FailureLearnings {
network_update : None , short_channel_id : None , payment_failed_permanently : false
} ) ;
2023-07-07 13:35:42 -04:00
return
} ,
} ;
2023-09-14 11:46:02 -04:00
// The failing hop includes either the inbound channel to the recipient or the outbound channel
// from the current hop (i.e., the next hop's inbound channel).
let num_blinded_hops = path . blinded_tail . as_ref ( ) . map_or ( 0 , | bt | bt . hops . len ( ) ) ;
// For 1-hop blinded paths, the final `path.hops` entry is the recipient.
is_from_final_node = route_hop_idx + 1 = = path . hops . len ( ) & & num_blinded_hops < = 1 ;
let failing_route_hop = if is_from_final_node { route_hop } else {
match path . hops . get ( route_hop_idx + 1 ) {
Some ( hop ) = > hop ,
None = > {
// The failing hop is within a multi-hop blinded path.
2023-10-26 13:09:48 -04:00
#[ cfg(not(test)) ] {
error_code_ret = Some ( BADONION | PERM | 24 ) ; // invalid_onion_blinding
error_packet_ret = Some ( vec! [ 0 ; 32 ] ) ;
}
#[ cfg(test) ] {
// Actually parse the onion error data in tests so we can check that blinded hops fail
// back correctly.
let err_packet = decrypt_onion_error_packet (
& mut encrypted_packet , shared_secret
) . unwrap ( ) ;
error_code_ret =
Some ( u16 ::from_be_bytes ( err_packet . failuremsg . get ( 0 .. 2 ) . unwrap ( ) . try_into ( ) . unwrap ( ) ) ) ;
error_packet_ret = Some ( err_packet . failuremsg [ 2 .. ] . to_vec ( ) ) ;
}
2023-09-14 11:46:02 -04:00
res = Some ( FailureLearnings {
network_update : None , short_channel_id : None , payment_failed_permanently : false
} ) ;
return
}
}
} ;
2023-08-12 19:02:56 -04:00
let amt_to_forward = htlc_msat - route_hop . fee_msat ;
htlc_msat = amt_to_forward ;
2023-10-26 12:59:42 -04:00
let err_packet = match decrypt_onion_error_packet ( & mut encrypted_packet , shared_secret ) {
2023-08-12 19:02:56 -04:00
Ok ( p ) = > p ,
Err ( _ ) = > return
} ;
let um = gen_um_from_shared_secret ( shared_secret . as_ref ( ) ) ;
let mut hmac = HmacEngine ::< Sha256 > ::new ( & um ) ;
hmac . input ( & err_packet . encode ( ) [ 32 .. ] ) ;
2023-04-27 00:16:40 -07:00
if ! fixed_time_eq ( & Hmac ::from_engine ( hmac ) . to_byte_array ( ) , & err_packet . hmac ) { return }
2023-08-12 19:02:56 -04:00
let error_code_slice = match err_packet . failuremsg . get ( 0 .. 2 ) {
Some ( s ) = > s ,
None = > {
2023-08-12 19:11:07 -04:00
// Useless packet that we can't use but it passed HMAC, so it definitely came from the peer
// in question
2023-08-12 19:02:56 -04:00
let network_update = Some ( NetworkUpdate ::NodeFailure {
node_id : route_hop . pubkey ,
is_permanent : true ,
} ) ;
let short_channel_id = Some ( route_hop . short_channel_id ) ;
2023-09-20 14:49:58 -04:00
res = Some ( FailureLearnings {
network_update , short_channel_id , payment_failed_permanently : is_from_final_node
} ) ;
2023-08-12 19:02:56 -04:00
return
}
} ;
let error_code = u16 ::from_be_bytes ( error_code_slice . try_into ( ) . expect ( " len is 2 " ) ) ;
error_code_ret = Some ( error_code ) ;
error_packet_ret = Some ( err_packet . failuremsg [ 2 .. ] . to_vec ( ) ) ;
let ( debug_field , debug_field_size ) = errors ::get_onion_debug_field ( error_code ) ;
2023-08-12 19:11:07 -04:00
// indicate that payment parameter has failed and no need to update Route object
2023-08-12 19:02:56 -04:00
let payment_failed = match error_code & 0xff {
15 | 16 | 17 | 18 | 19 | 23 = > true ,
_ = > false ,
} & & is_from_final_node ; // PERM bit observed below even if this error is from the intermediate nodes
let mut network_update = None ;
let mut short_channel_id = None ;
if error_code & BADONION = = BADONION {
2023-08-12 19:11:07 -04:00
// If the error code has the BADONION bit set, always blame the channel from the node
// "originating" the error to its next hop. The "originator" is ultimately actually claiming
// that its counterparty is the one who is failing the HTLC.
// If the "originator" here isn't lying we should really mark the next-hop node as failed
// entirely, but we can't be confident in that, as it would allow any node to get us to
// completely ban one of its counterparties. Instead, we simply remove the channel in
// question.
2023-08-12 19:02:56 -04:00
network_update = Some ( NetworkUpdate ::ChannelFailure {
short_channel_id : failing_route_hop . short_channel_id ,
is_permanent : true ,
} ) ;
} else if error_code & NODE = = NODE {
let is_permanent = error_code & PERM = = PERM ;
network_update = Some ( NetworkUpdate ::NodeFailure { node_id : route_hop . pubkey , is_permanent } ) ;
short_channel_id = Some ( route_hop . short_channel_id ) ;
} else if error_code & PERM = = PERM {
if ! payment_failed {
network_update = Some ( NetworkUpdate ::ChannelFailure {
short_channel_id : failing_route_hop . short_channel_id ,
is_permanent : true ,
} ) ;
short_channel_id = Some ( failing_route_hop . short_channel_id ) ;
}
} else if error_code & UPDATE = = UPDATE {
if let Some ( update_len_slice ) = err_packet . failuremsg . get ( debug_field_size + 2 .. debug_field_size + 4 ) {
let update_len = u16 ::from_be_bytes ( update_len_slice . try_into ( ) . expect ( " len is 2 " ) ) as usize ;
if let Some ( mut update_slice ) = err_packet . failuremsg . get ( debug_field_size + 4 .. debug_field_size + 4 + update_len ) {
// Historically, the BOLTs were unclear if the message type
// bytes should be included here or not. The BOLTs have now
// been updated to indicate that they *are* included, but many
// nodes still send messages without the type bytes, so we
// support both here.
// TODO: Switch to hard require the type prefix, as the current
// permissiveness introduces the (although small) possibility
// that we fail to decode legitimate channel updates that
// happen to start with ChannelUpdate::TYPE, i.e., [0x01, 0x02].
if update_slice . len ( ) > 2 & & update_slice [ 0 .. 2 ] = = msgs ::ChannelUpdate ::TYPE . to_be_bytes ( ) {
update_slice = & update_slice [ 2 .. ] ;
} else {
log_trace! ( logger , " Failure provided features a channel update without type prefix. Deprecated, but allowing for now. " ) ;
}
let update_opt = msgs ::ChannelUpdate ::read ( & mut Cursor ::new ( & update_slice ) ) ;
if update_opt . is_ok ( ) | | update_slice . is_empty ( ) {
// if channel_update should NOT have caused the failure:
// MAY treat the channel_update as invalid.
let is_chan_update_invalid = match error_code & 0xff {
7 = > false ,
11 = > update_opt . is_ok ( ) & &
amt_to_forward >
update_opt . as_ref ( ) . unwrap ( ) . contents . htlc_minimum_msat ,
12 = > update_opt . is_ok ( ) & & amt_to_forward
. checked_mul ( update_opt . as_ref ( ) . unwrap ( )
. contents . fee_proportional_millionths as u64 )
. map ( | prop_fee | prop_fee / 1_000_000 )
. and_then ( | prop_fee | prop_fee . checked_add (
update_opt . as_ref ( ) . unwrap ( ) . contents . fee_base_msat as u64 ) )
. map ( | fee_msats | route_hop . fee_msat > = fee_msats )
. unwrap_or ( false ) ,
13 = > update_opt . is_ok ( ) & &
route_hop . cltv_expiry_delta as u16 > =
update_opt . as_ref ( ) . unwrap ( ) . contents . cltv_expiry_delta ,
14 = > false , // expiry_too_soon; always valid?
20 = > update_opt . as_ref ( ) . unwrap ( ) . contents . flags & 2 = = 0 ,
_ = > false , // unknown error code; take channel_update as valid
} ;
if is_chan_update_invalid {
// This probably indicates the node which forwarded
// to the node in question corrupted something.
2022-09-07 21:08:22 +00:00
network_update = Some ( NetworkUpdate ::ChannelFailure {
2023-08-12 19:02:56 -04:00
short_channel_id : route_hop . short_channel_id ,
2022-09-07 21:08:22 +00:00
is_permanent : true ,
} ) ;
2023-08-12 19:02:56 -04:00
} else {
if let Ok ( chan_update ) = update_opt {
// Make sure the ChannelUpdate contains the expected
// short channel id.
if failing_route_hop . short_channel_id = = chan_update . contents . short_channel_id {
short_channel_id = Some ( failing_route_hop . short_channel_id ) ;
} else {
log_info! ( logger , " Node provided a channel_update for which it was not authoritative, ignoring. " ) ;
2018-12-20 14:51:18 -05:00
}
2023-08-12 19:02:56 -04:00
network_update = Some ( NetworkUpdate ::ChannelUpdateMessage {
msg : chan_update ,
} )
} else {
2023-08-12 20:27:35 -04:00
// The node in question intentionally encoded a 0-length channel update. This is
// likely due to https://github.com/ElementsProject/lightning/issues/6200.
2023-09-15 16:55:12 -04:00
short_channel_id = Some ( failing_route_hop . short_channel_id ) ;
2023-08-12 19:02:56 -04:00
network_update = Some ( NetworkUpdate ::ChannelFailure {
2023-09-15 16:55:12 -04:00
short_channel_id : failing_route_hop . short_channel_id ,
2023-08-12 19:02:56 -04:00
is_permanent : false ,
2018-12-20 14:51:18 -05:00
} ) ;
}
2023-08-12 19:02:56 -04:00
} ;
2018-12-20 14:51:18 -05:00
} else {
2023-08-12 19:02:56 -04:00
// If the channel_update had a non-zero length (i.e. was
// present) but we couldn't read it, treat it as a total
// node failure.
log_info! ( logger ,
" Failed to read a channel_update of len {} in an onion " ,
update_slice . len ( ) ) ;
2018-12-20 14:51:18 -05:00
}
}
}
2023-08-12 19:02:56 -04:00
if network_update . is_none ( ) {
// They provided an UPDATE which was obviously bogus, not worth
// trying to relay through them anymore.
network_update = Some ( NetworkUpdate ::NodeFailure {
node_id : route_hop . pubkey ,
is_permanent : true ,
} ) ;
}
if short_channel_id . is_none ( ) {
short_channel_id = Some ( route_hop . short_channel_id ) ;
}
} else if payment_failed {
2023-08-12 19:11:07 -04:00
// Only blame the hop when a value in the HTLC doesn't match the corresponding value in the
// onion.
2023-08-12 19:02:56 -04:00
short_channel_id = match error_code & 0xff {
18 | 19 = > Some ( route_hop . short_channel_id ) ,
_ = > None ,
} ;
2018-12-20 14:51:18 -05:00
} else {
2023-08-12 19:11:07 -04:00
// We can't understand their error messages and they failed to forward...they probably can't
// understand our forwards so it's really not worth trying any further.
2023-08-12 19:02:56 -04:00
network_update = Some ( NetworkUpdate ::NodeFailure {
node_id : route_hop . pubkey ,
is_permanent : true ,
} ) ;
short_channel_id = Some ( route_hop . short_channel_id ) ;
2018-12-20 14:51:18 -05:00
}
2023-08-12 19:02:56 -04:00
2023-09-20 14:49:58 -04:00
res = Some ( FailureLearnings {
network_update , short_channel_id ,
payment_failed_permanently : error_code & PERM = = PERM & & is_from_final_node
} ) ;
2023-08-12 19:02:56 -04:00
let ( description , title ) = errors ::get_onion_error_description ( error_code ) ;
if debug_field_size > 0 & & err_packet . failuremsg . len ( ) > = 4 + debug_field_size {
log_info! ( logger , " Onion Error[from {}: {}({:#x}) {}({})] {} " , route_hop . pubkey , title , error_code , debug_field , log_bytes! ( & err_packet . failuremsg [ 4 .. 4 + debug_field_size ] ) , description ) ;
} else {
log_info! ( logger , " Onion Error[from {}: {}({:#x})] {} " , route_hop . pubkey , title , error_code , description ) ;
}
} ) . expect ( " Route that we sent via spontaneously grew invalid keys in the middle of it? " ) ;
2023-09-20 14:49:58 -04:00
if let Some ( FailureLearnings {
network_update , short_channel_id , payment_failed_permanently
} ) = res {
2023-07-20 13:59:23 -04:00
DecodedOnionFailure {
2023-09-14 11:33:01 -04:00
network_update , short_channel_id , payment_failed_permanently ,
2023-07-20 13:59:23 -04:00
#[ cfg(test) ]
onion_error_code : error_code_ret ,
#[ cfg(test) ]
onion_error_data : error_packet_ret
}
2023-08-12 19:02:56 -04:00
} else {
// only not set either packet unparseable or hmac does not match with any
// payment not retryable only when garbage is from the final node
2023-07-20 13:59:23 -04:00
DecodedOnionFailure {
2023-09-14 11:33:01 -04:00
network_update : None , short_channel_id : None , payment_failed_permanently : is_from_final_node ,
2023-07-20 13:59:23 -04:00
#[ cfg(test) ]
onion_error_code : None ,
#[ cfg(test) ]
onion_error_data : None
}
2023-08-12 19:02:56 -04:00
}
2018-12-20 14:51:18 -05:00
}
2022-12-01 19:20:19 +00:00
#[ derive(Clone) ] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
2022-12-01 19:28:32 +00:00
pub ( super ) struct HTLCFailReason ( HTLCFailReasonRepr ) ;
#[ derive(Clone) ] // See Channel::revoke_and_ack for why, tl;dr: Rust bug
enum HTLCFailReasonRepr {
2022-12-01 19:20:19 +00:00
LightningError {
err : msgs ::OnionErrorPacket ,
} ,
Reason {
failure_code : u16 ,
data : Vec < u8 > ,
}
}
impl core ::fmt ::Debug for HTLCFailReason {
fn fmt ( & self , f : & mut core ::fmt ::Formatter ) -> Result < ( ) , core ::fmt ::Error > {
2022-12-01 19:28:32 +00:00
match self . 0 {
HTLCFailReasonRepr ::Reason { ref failure_code , .. } = > {
2022-12-01 19:20:19 +00:00
write! ( f , " HTLC error code {} " , failure_code )
} ,
2022-12-01 19:28:32 +00:00
HTLCFailReasonRepr ::LightningError { .. } = > {
2022-12-01 19:20:19 +00:00
write! ( f , " pre-built LightningError " )
}
}
}
}
2022-12-01 19:28:32 +00:00
impl Writeable for HTLCFailReason {
fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , crate ::io ::Error > {
self . 0. write ( writer )
}
}
impl Readable for HTLCFailReason {
fn read < R : Read > ( reader : & mut R ) -> Result < Self , msgs ::DecodeError > {
Ok ( Self ( Readable ::read ( reader ) ? ) )
}
}
impl_writeable_tlv_based_enum! ( HTLCFailReasonRepr ,
2022-12-01 19:20:19 +00:00
( 0 , LightningError ) = > {
( 0 , err , required ) ,
} ,
( 1 , Reason ) = > {
( 0 , failure_code , required ) ,
2023-07-07 18:44:24 +00:00
( 2 , data , required_vec ) ,
2022-12-01 19:20:19 +00:00
} ,
; ) ;
impl HTLCFailReason {
pub ( super ) fn reason ( failure_code : u16 , data : Vec < u8 > ) -> Self {
2022-12-01 20:31:52 +00:00
const BADONION : u16 = 0x8000 ;
const PERM : u16 = 0x4000 ;
const NODE : u16 = 0x2000 ;
const UPDATE : u16 = 0x1000 ;
if failure_code = = 1 | PERM { debug_assert! ( data . is_empty ( ) ) }
else if failure_code = = 2 | NODE { debug_assert! ( data . is_empty ( ) ) }
else if failure_code = = 2 | PERM | NODE { debug_assert! ( data . is_empty ( ) ) }
else if failure_code = = 3 | PERM | NODE { debug_assert! ( data . is_empty ( ) ) }
else if failure_code = = 4 | BADONION | PERM { debug_assert_eq! ( data . len ( ) , 32 ) }
else if failure_code = = 5 | BADONION | PERM { debug_assert_eq! ( data . len ( ) , 32 ) }
else if failure_code = = 6 | BADONION | PERM { debug_assert_eq! ( data . len ( ) , 32 ) }
else if failure_code = = 7 | UPDATE {
debug_assert_eq! ( data . len ( ) - 2 , u16 ::from_be_bytes ( data [ 0 .. 2 ] . try_into ( ) . unwrap ( ) ) as usize ) }
else if failure_code = = 8 | PERM { debug_assert! ( data . is_empty ( ) ) }
else if failure_code = = 9 | PERM { debug_assert! ( data . is_empty ( ) ) }
else if failure_code = = 10 | PERM { debug_assert! ( data . is_empty ( ) ) }
else if failure_code = = 11 | UPDATE {
debug_assert_eq! ( data . len ( ) - 2 - 8 , u16 ::from_be_bytes ( data [ 8 .. 10 ] . try_into ( ) . unwrap ( ) ) as usize ) }
else if failure_code = = 12 | UPDATE {
debug_assert_eq! ( data . len ( ) - 2 - 8 , u16 ::from_be_bytes ( data [ 8 .. 10 ] . try_into ( ) . unwrap ( ) ) as usize ) }
else if failure_code = = 13 | UPDATE {
debug_assert_eq! ( data . len ( ) - 2 - 4 , u16 ::from_be_bytes ( data [ 4 .. 6 ] . try_into ( ) . unwrap ( ) ) as usize ) }
else if failure_code = = 14 | UPDATE {
debug_assert_eq! ( data . len ( ) - 2 , u16 ::from_be_bytes ( data [ 0 .. 2 ] . try_into ( ) . unwrap ( ) ) as usize ) }
else if failure_code = = 15 | PERM { debug_assert_eq! ( data . len ( ) , 12 ) }
else if failure_code = = 18 { debug_assert_eq! ( data . len ( ) , 4 ) }
else if failure_code = = 19 { debug_assert_eq! ( data . len ( ) , 8 ) }
else if failure_code = = 20 | UPDATE {
debug_assert_eq! ( data . len ( ) - 2 - 2 , u16 ::from_be_bytes ( data [ 2 .. 4 ] . try_into ( ) . unwrap ( ) ) as usize ) }
else if failure_code = = 21 { debug_assert! ( data . is_empty ( ) ) }
else if failure_code = = 22 | PERM { debug_assert! ( data . len ( ) < = 11 ) }
else if failure_code = = 23 { debug_assert! ( data . is_empty ( ) ) }
else if failure_code & BADONION ! = 0 {
// We set some bogus BADONION failure codes in test, so ignore unknown ones.
}
else { debug_assert! ( false , " Unknown failure code: {} " , failure_code ) }
2022-12-01 19:28:32 +00:00
Self ( HTLCFailReasonRepr ::Reason { failure_code , data } )
2022-12-01 19:20:19 +00:00
}
pub ( super ) fn from_failure_code ( failure_code : u16 ) -> Self {
2022-12-01 20:31:52 +00:00
Self ::reason ( failure_code , Vec ::new ( ) )
2022-12-01 19:20:19 +00:00
}
pub ( super ) fn from_msg ( msg : & msgs ::UpdateFailHTLC ) -> Self {
2022-12-01 19:28:32 +00:00
Self ( HTLCFailReasonRepr ::LightningError { err : msg . reason . clone ( ) } )
2022-12-01 19:20:19 +00:00
}
pub ( super ) fn get_encrypted_failure_packet ( & self , incoming_packet_shared_secret : & [ u8 ; 32 ] , phantom_shared_secret : & Option < [ u8 ; 32 ] > )
-> msgs ::OnionErrorPacket {
2022-12-01 19:28:32 +00:00
match self . 0 {
HTLCFailReasonRepr ::Reason { ref failure_code , ref data } = > {
2022-12-01 19:20:19 +00:00
if let Some ( phantom_ss ) = phantom_shared_secret {
let phantom_packet = build_failure_packet ( phantom_ss , * failure_code , & data [ .. ] ) . encode ( ) ;
let encrypted_phantom_packet = encrypt_failure_packet ( phantom_ss , & phantom_packet ) ;
encrypt_failure_packet ( incoming_packet_shared_secret , & encrypted_phantom_packet . data [ .. ] )
} else {
let packet = build_failure_packet ( incoming_packet_shared_secret , * failure_code , & data [ .. ] ) . encode ( ) ;
encrypt_failure_packet ( incoming_packet_shared_secret , & packet )
}
} ,
2022-12-01 19:28:32 +00:00
HTLCFailReasonRepr ::LightningError { ref err } = > {
2022-12-01 19:20:19 +00:00
encrypt_failure_packet ( incoming_packet_shared_secret , & err . data )
}
}
}
pub ( super ) fn decode_onion_failure < T : secp256k1 ::Signing , L : Deref > (
& self , secp_ctx : & Secp256k1 < T > , logger : & L , htlc_source : & HTLCSource
2023-07-20 13:59:23 -04:00
) -> DecodedOnionFailure where L ::Target : Logger {
2022-12-01 19:28:32 +00:00
match self . 0 {
HTLCFailReasonRepr ::LightningError { ref err } = > {
2022-12-01 19:20:19 +00:00
process_onion_failure ( secp_ctx , logger , & htlc_source , err . data . clone ( ) )
} ,
2023-07-20 13:59:23 -04:00
#[ allow(unused) ]
2022-12-01 19:28:32 +00:00
HTLCFailReasonRepr ::Reason { ref failure_code , ref data , .. } = > {
2022-12-01 19:20:19 +00:00
// we get a fail_malformed_htlc from the first hop
// TODO: We'd like to generate a NetworkUpdate for temporary
// failures here, but that would be insufficient as find_route
// generally ignores its view of our own channels as we provide them via
// ChannelDetails.
if let & HTLCSource ::OutboundRoute { ref path , .. } = htlc_source {
2023-07-20 13:59:23 -04:00
DecodedOnionFailure {
network_update : None ,
2023-09-14 11:33:01 -04:00
payment_failed_permanently : false ,
2023-07-20 13:59:23 -04:00
short_channel_id : Some ( path . hops [ 0 ] . short_channel_id ) ,
#[ cfg(test) ]
onion_error_code : Some ( * failure_code ) ,
#[ cfg(test) ]
onion_error_data : Some ( data . clone ( ) ) ,
}
2022-12-01 19:20:19 +00:00
} else { unreachable! ( ) ; }
}
}
}
}
2022-05-27 18:39:56 -07:00
/// Allows `decode_next_hop` to return the next hop packet bytes for either payments or onion
/// message forwards.
pub ( crate ) trait NextPacketBytes : AsMut < [ u8 ] > {
fn new ( len : usize ) -> Self ;
}
impl NextPacketBytes for FixedSizeOnionPacket {
fn new ( _len : usize ) -> Self {
Self ( [ 0 as u8 ; ONION_DATA_LEN ] )
}
}
impl NextPacketBytes for Vec < u8 > {
fn new ( len : usize ) -> Self {
vec! [ 0 as u8 ; len ]
}
}
/// Data decrypted from a payment's onion payload.
2021-11-08 19:49:35 -05:00
pub ( crate ) enum Hop {
/// This onion payload was for us, not for forwarding to a next-hop. Contains information for
/// verifying the incoming payment.
2023-03-24 12:46:16 -04:00
Receive ( msgs ::InboundOnionPayload ) ,
2021-11-08 19:49:35 -05:00
/// This onion payload needs to be forwarded to a next-hop.
Forward {
/// Onion payload data used in forwarding the payment.
2023-03-24 12:46:16 -04:00
next_hop_data : msgs ::InboundOnionPayload ,
2021-11-08 19:49:35 -05:00
/// HMAC of the next hop's onion packet.
next_hop_hmac : [ u8 ; 32 ] ,
/// Bytes of the onion packet we're forwarding.
2022-05-27 18:39:56 -07:00
new_packet_bytes : [ u8 ; ONION_DATA_LEN ] ,
2021-11-08 19:49:35 -05:00
} ,
}
/// Error returned when we fail to decode the onion packet.
2022-05-27 18:39:56 -07:00
#[ derive(Debug) ]
2021-11-08 19:49:35 -05:00
pub ( crate ) enum OnionDecodeErr {
/// The HMAC of the onion packet did not match the hop data.
Malformed {
err_msg : & 'static str ,
err_code : u16 ,
} ,
/// We failed to decode the onion payload.
Relay {
err_msg : & 'static str ,
err_code : u16 ,
} ,
}
2023-09-10 01:10:03 -04:00
pub ( crate ) fn decode_next_payment_hop < NS : Deref > (
shared_secret : [ u8 ; 32 ] , hop_data : & [ u8 ] , hmac_bytes : [ u8 ; 32 ] , payment_hash : PaymentHash ,
node_signer : & NS ,
) -> Result < Hop , OnionDecodeErr > where NS ::Target : NodeSigner {
match decode_next_hop ( shared_secret , hop_data , hmac_bytes , Some ( payment_hash ) , node_signer ) {
2022-05-27 18:39:56 -07:00
Ok ( ( next_hop_data , None ) ) = > Ok ( Hop ::Receive ( next_hop_data ) ) ,
Ok ( ( next_hop_data , Some ( ( next_hop_hmac , FixedSizeOnionPacket ( new_packet_bytes ) ) ) ) ) = > {
Ok ( Hop ::Forward {
next_hop_data ,
next_hop_hmac ,
new_packet_bytes
} )
} ,
Err ( e ) = > Err ( e ) ,
}
}
2023-10-28 15:10:00 -07:00
/// Build a payment onion, returning the first hop msat and cltv values as well.
/// `cur_block_height` should be set to the best known block height + 1.
pub fn create_payment_onion < T : secp256k1 ::Signing > (
secp_ctx : & Secp256k1 < T > , path : & Path , session_priv : & SecretKey , total_msat : u64 ,
recipient_onion : RecipientOnionFields , cur_block_height : u32 , payment_hash : & PaymentHash ,
keysend_preimage : & Option < PaymentPreimage > , prng_seed : [ u8 ; 32 ]
) -> Result < ( msgs ::OnionPacket , u64 , u32 ) , APIError > {
let onion_keys = construct_onion_keys ( & secp_ctx , & path , & session_priv )
. map_err ( | _ | APIError ::InvalidRoute {
err : " Pubkey along hop was maliciously selected " . to_owned ( )
} ) ? ;
let ( onion_payloads , htlc_msat , htlc_cltv ) = build_onion_payloads (
& path , total_msat , recipient_onion , cur_block_height , keysend_preimage
) ? ;
let onion_packet = construct_onion_packet ( onion_payloads , onion_keys , prng_seed , payment_hash )
. map_err ( | _ | APIError ::InvalidRoute {
err : " Route size too large considering onion data " . to_owned ( )
} ) ? ;
Ok ( ( onion_packet , htlc_msat , htlc_cltv ) )
}
2022-10-26 19:23:10 +00:00
pub ( crate ) fn decode_next_untagged_hop < T , R : ReadableArgs < T > , N : NextPacketBytes > ( shared_secret : [ u8 ; 32 ] , hop_data : & [ u8 ] , hmac_bytes : [ u8 ; 32 ] , read_args : T ) -> Result < ( R , Option < ( [ u8 ; 32 ] , N ) > ) , OnionDecodeErr > {
decode_next_hop ( shared_secret , hop_data , hmac_bytes , None , read_args )
}
fn decode_next_hop < T , R : ReadableArgs < T > , N : NextPacketBytes > ( shared_secret : [ u8 ; 32 ] , hop_data : & [ u8 ] , hmac_bytes : [ u8 ; 32 ] , payment_hash : Option < PaymentHash > , read_args : T ) -> Result < ( R , Option < ( [ u8 ; 32 ] , N ) > ) , OnionDecodeErr > {
2021-11-08 19:49:35 -05:00
let ( rho , mu ) = gen_rho_mu_from_shared_secret ( & shared_secret ) ;
let mut hmac = HmacEngine ::< Sha256 > ::new ( & mu ) ;
hmac . input ( hop_data ) ;
2022-10-26 19:23:10 +00:00
if let Some ( tag ) = payment_hash {
hmac . input ( & tag . 0 [ .. ] ) ;
2022-05-27 18:39:56 -07:00
}
2023-04-27 00:16:40 -07:00
if ! fixed_time_eq ( & Hmac ::from_engine ( hmac ) . to_byte_array ( ) , & hmac_bytes ) {
2021-11-08 19:49:35 -05:00
return Err ( OnionDecodeErr ::Malformed {
err_msg : " HMAC Check failed " ,
err_code : 0x8000 | 0x4000 | 5 ,
} ) ;
}
let mut chacha = ChaCha20 ::new ( & rho , & [ 0 u8 ; 8 ] ) ;
let mut chacha_stream = ChaChaReader { chacha : & mut chacha , read : Cursor ::new ( & hop_data [ .. ] ) } ;
2022-10-26 19:23:10 +00:00
match R ::read ( & mut chacha_stream , read_args ) {
2021-11-08 19:49:35 -05:00
Err ( err ) = > {
let error_code = match err {
msgs ::DecodeError ::UnknownVersion = > 0x4000 | 1 , // unknown realm byte
msgs ::DecodeError ::UnknownRequiredFeature |
msgs ::DecodeError ::InvalidValue |
msgs ::DecodeError ::ShortRead = > 0x4000 | 22 , // invalid_onion_payload
_ = > 0x2000 | 2 , // Should never happen
} ;
return Err ( OnionDecodeErr ::Relay {
err_msg : " Unable to decode our hop data " ,
err_code : error_code ,
} ) ;
} ,
Ok ( msg ) = > {
let mut hmac = [ 0 ; 32 ] ;
if let Err ( _ ) = chacha_stream . read_exact ( & mut hmac [ .. ] ) {
return Err ( OnionDecodeErr ::Relay {
err_msg : " Unable to decode our hop data " ,
err_code : 0x4000 | 22 ,
} ) ;
}
if hmac = = [ 0 ; 32 ] {
#[ cfg(test) ]
{
// In tests, make sure that the initial onion packet data is, at least, non-0.
// We could do some fancy randomness test here, but, ehh, whatever.
// This checks for the issue where you can calculate the path length given the
// onion data as all the path entries that the originator sent will be here
// as-is (and were originally 0s).
// Of course reverse path calculation is still pretty easy given naive routing
// algorithms, but this fixes the most-obvious case.
let mut next_bytes = [ 0 ; 32 ] ;
chacha_stream . read_exact ( & mut next_bytes ) . unwrap ( ) ;
assert_ne! ( next_bytes [ .. ] , [ 0 ; 32 ] [ .. ] ) ;
chacha_stream . read_exact ( & mut next_bytes ) . unwrap ( ) ;
assert_ne! ( next_bytes [ .. ] , [ 0 ; 32 ] [ .. ] ) ;
}
2022-05-27 18:39:56 -07:00
return Ok ( ( msg , None ) ) ; // We are the final destination for this packet
2021-11-08 19:49:35 -05:00
} else {
2022-05-27 18:39:56 -07:00
let mut new_packet_bytes = N ::new ( hop_data . len ( ) ) ;
2022-07-12 16:04:42 -04:00
let read_pos = hop_data . len ( ) - chacha_stream . read . position ( ) as usize ;
chacha_stream . read_exact ( & mut new_packet_bytes . as_mut ( ) [ .. read_pos ] ) . unwrap ( ) ;
2021-11-08 19:49:35 -05:00
#[ cfg(debug_assertions) ]
{
// Check two things:
// a) that the behavior of our stream here will return Ok(0) even if the TLV
// read above emptied out our buffer and the unwrap() wont needlessly panic
// b) that we didn't somehow magically end up with extra data.
let mut t = [ 0 ; 1 ] ;
debug_assert! ( chacha_stream . read ( & mut t ) . unwrap ( ) = = 0 ) ;
}
// Once we've emptied the set of bytes our peer gave us, encrypt 0 bytes until we
// fill the onion hop data we'll forward to our next-hop peer.
2022-05-27 18:39:56 -07:00
chacha_stream . chacha . process_in_place ( & mut new_packet_bytes . as_mut ( ) [ read_pos .. ] ) ;
return Ok ( ( msg , Some ( ( hmac , new_packet_bytes ) ) ) ) // This packet needs forwarding
2021-11-08 19:49:35 -05:00
}
} ,
}
}
2018-12-19 17:02:27 -05:00
#[ cfg(test) ]
mod tests {
2022-10-13 02:35:48 -04:00
use crate ::io ;
use crate ::prelude ::* ;
use crate ::ln ::PaymentHash ;
use crate ::ln ::features ::{ ChannelFeatures , NodeFeatures } ;
2023-04-09 13:50:44 -04:00
use crate ::routing ::router ::{ Path , Route , RouteHop } ;
2022-10-13 02:35:48 -04:00
use crate ::ln ::msgs ;
2022-09-30 01:29:02 +02:00
use crate ::util ::ser ::{ Writeable , Writer , VecWriter } ;
2018-12-19 17:02:27 -05:00
2023-04-27 00:16:40 -07:00
use bitcoin ::hashes ::hex ::FromHex ;
2020-04-27 16:51:59 +02:00
use bitcoin ::secp256k1 ::Secp256k1 ;
2022-05-05 17:59:38 +02:00
use bitcoin ::secp256k1 ::{ PublicKey , SecretKey } ;
2018-12-19 17:02:27 -05:00
use super ::OnionKeys ;
2022-09-30 01:29:02 +02:00
fn get_test_session_key ( ) -> SecretKey {
2023-04-27 00:16:40 -07:00
SecretKey ::from_slice ( & < Vec < u8 > > ::from_hex ( " 4141414141414141414141414141414141414141414141414141414141414141 " ) . unwrap ( ) [ .. ] ) . unwrap ( )
2022-09-30 01:29:02 +02:00
}
2018-12-19 17:02:27 -05:00
fn build_test_onion_keys ( ) -> Vec < OnionKeys > {
// Keys from BOLT 4, used in both test vector tests
let secp_ctx = Secp256k1 ::new ( ) ;
let route = Route {
2023-04-09 13:50:44 -04:00
paths : vec ! [ Path { hops : vec ! [
2018-12-19 17:02:27 -05:00
RouteHop {
2023-04-27 00:16:40 -07:00
pubkey : PublicKey ::from_slice ( & < Vec < u8 > > ::from_hex ( " 02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619 " ) . unwrap ( ) [ .. ] ) . unwrap ( ) ,
2019-12-28 01:10:14 -05:00
channel_features : ChannelFeatures ::empty ( ) , node_features : NodeFeatures ::empty ( ) ,
2023-09-12 15:51:37 +02:00
short_channel_id : 0 , fee_msat : 0 , cltv_expiry_delta : 0 , maybe_announced_channel : true , // We fill in the payloads manually instead of generating them from RouteHops.
2018-12-19 17:02:27 -05:00
} ,
RouteHop {
2023-04-27 00:16:40 -07:00
pubkey : PublicKey ::from_slice ( & < Vec < u8 > > ::from_hex ( " 0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c " ) . unwrap ( ) [ .. ] ) . unwrap ( ) ,
2019-12-28 01:10:14 -05:00
channel_features : ChannelFeatures ::empty ( ) , node_features : NodeFeatures ::empty ( ) ,
2023-09-12 15:51:37 +02:00
short_channel_id : 0 , fee_msat : 0 , cltv_expiry_delta : 0 , maybe_announced_channel : true , // We fill in the payloads manually instead of generating them from RouteHops.
2018-12-19 17:02:27 -05:00
} ,
RouteHop {
2023-04-27 00:16:40 -07:00
pubkey : PublicKey ::from_slice ( & < Vec < u8 > > ::from_hex ( " 027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007 " ) . unwrap ( ) [ .. ] ) . unwrap ( ) ,
2019-12-28 01:10:14 -05:00
channel_features : ChannelFeatures ::empty ( ) , node_features : NodeFeatures ::empty ( ) ,
2023-09-12 15:51:37 +02:00
short_channel_id : 0 , fee_msat : 0 , cltv_expiry_delta : 0 , maybe_announced_channel : true , // We fill in the payloads manually instead of generating them from RouteHops.
2018-12-19 17:02:27 -05:00
} ,
RouteHop {
2023-04-27 00:16:40 -07:00
pubkey : PublicKey ::from_slice ( & < Vec < u8 > > ::from_hex ( " 032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991 " ) . unwrap ( ) [ .. ] ) . unwrap ( ) ,
2019-12-28 01:10:14 -05:00
channel_features : ChannelFeatures ::empty ( ) , node_features : NodeFeatures ::empty ( ) ,
2023-09-12 15:51:37 +02:00
short_channel_id : 0 , fee_msat : 0 , cltv_expiry_delta : 0 , maybe_announced_channel : true , // We fill in the payloads manually instead of generating them from RouteHops.
2018-12-19 17:02:27 -05:00
} ,
RouteHop {
2023-04-27 00:16:40 -07:00
pubkey : PublicKey ::from_slice ( & < Vec < u8 > > ::from_hex ( " 02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145 " ) . unwrap ( ) [ .. ] ) . unwrap ( ) ,
2019-12-28 01:10:14 -05:00
channel_features : ChannelFeatures ::empty ( ) , node_features : NodeFeatures ::empty ( ) ,
2023-09-12 15:51:37 +02:00
short_channel_id : 0 , fee_msat : 0 , cltv_expiry_delta : 0 , maybe_announced_channel : true , // We fill in the payloads manually instead of generating them from RouteHops.
2018-12-19 17:02:27 -05:00
} ,
2023-04-18 12:06:35 -04:00
] , blinded_tail : None } ] ,
2023-08-31 15:10:09 +02:00
route_params : None ,
2018-12-19 17:02:27 -05:00
} ;
2022-09-30 01:29:02 +02:00
let onion_keys = super ::construct_onion_keys ( & secp_ctx , & route . paths [ 0 ] , & get_test_session_key ( ) ) . unwrap ( ) ;
2023-04-09 13:50:44 -04:00
assert_eq! ( onion_keys . len ( ) , route . paths [ 0 ] . hops . len ( ) ) ;
2018-12-19 17:02:27 -05:00
onion_keys
}
#[ test ]
fn onion_vectors ( ) {
let onion_keys = build_test_onion_keys ( ) ;
2022-09-30 01:29:02 +02:00
// Test generation of ephemeral keys and secrets. These values used to be part of the BOLT4
// test vectors, but have since been removed. We keep them as they provide test coverage.
2023-04-27 00:16:40 -07:00
assert_eq! ( onion_keys [ 0 ] . shared_secret . secret_bytes ( ) , < Vec < u8 > > ::from_hex ( " 53eb63ea8a3fec3b3cd433b85cd62a4b145e1dda09391b348c4e1cd36a03ea66 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 0 ] . blinding_factor [ .. ] , < Vec < u8 > > ::from_hex ( " 2ec2e5da605776054187180343287683aa6a51b4b1c04d6dd49c45d8cffb3c36 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 0 ] . ephemeral_pubkey . serialize ( ) [ .. ] , < Vec < u8 > > ::from_hex ( " 02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 0 ] . rho , < Vec < u8 > > ::from_hex ( " ce496ec94def95aadd4bec15cdb41a740c9f2b62347c4917325fcc6fb0453986 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 0 ] . mu , < Vec < u8 > > ::from_hex ( " b57061dc6d0a2b9f261ac410c8b26d64ac5506cbba30267a649c28c179400eba " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 1 ] . shared_secret . secret_bytes ( ) , < Vec < u8 > > ::from_hex ( " a6519e98832a0b179f62123b3567c106db99ee37bef036e783263602f3488fae " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 1 ] . blinding_factor [ .. ] , < Vec < u8 > > ::from_hex ( " bf66c28bc22e598cfd574a1931a2bafbca09163df2261e6d0056b2610dab938f " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 1 ] . ephemeral_pubkey . serialize ( ) [ .. ] , < Vec < u8 > > ::from_hex ( " 028f9438bfbf7feac2e108d677e3a82da596be706cc1cf342b75c7b7e22bf4e6e2 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 1 ] . rho , < Vec < u8 > > ::from_hex ( " 450ffcabc6449094918ebe13d4f03e433d20a3d28a768203337bc40b6e4b2c59 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 1 ] . mu , < Vec < u8 > > ::from_hex ( " 05ed2b4a3fb023c2ff5dd6ed4b9b6ea7383f5cfe9d59c11d121ec2c81ca2eea9 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 2 ] . shared_secret . secret_bytes ( ) , < Vec < u8 > > ::from_hex ( " 3a6b412548762f0dbccce5c7ae7bb8147d1caf9b5471c34120b30bc9c04891cc " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 2 ] . blinding_factor [ .. ] , < Vec < u8 > > ::from_hex ( " a1f2dadd184eb1627049673f18c6325814384facdee5bfd935d9cb031a1698a5 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 2 ] . ephemeral_pubkey . serialize ( ) [ .. ] , < Vec < u8 > > ::from_hex ( " 03bfd8225241ea71cd0843db7709f4c222f62ff2d4516fd38b39914ab6b83e0da0 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 2 ] . rho , < Vec < u8 > > ::from_hex ( " 11bf5c4f960239cb37833936aa3d02cea82c0f39fd35f566109c41f9eac8deea " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 2 ] . mu , < Vec < u8 > > ::from_hex ( " caafe2820fa00eb2eeb78695ae452eba38f5a53ed6d53518c5c6edf76f3f5b78 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 3 ] . shared_secret . secret_bytes ( ) , < Vec < u8 > > ::from_hex ( " 21e13c2d7cfe7e18836df50872466117a295783ab8aab0e7ecc8c725503ad02d " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 3 ] . blinding_factor [ .. ] , < Vec < u8 > > ::from_hex ( " 7cfe0b699f35525029ae0fa437c69d0f20f7ed4e3916133f9cacbb13c82ff262 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 3 ] . ephemeral_pubkey . serialize ( ) [ .. ] , < Vec < u8 > > ::from_hex ( " 031dde6926381289671300239ea8e57ffaf9bebd05b9a5b95beaf07af05cd43595 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 3 ] . rho , < Vec < u8 > > ::from_hex ( " cbe784ab745c13ff5cffc2fbe3e84424aa0fd669b8ead4ee562901a4a4e89e9e " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 3 ] . mu , < Vec < u8 > > ::from_hex ( " 5052aa1b3d9f0655a0932e50d42f0c9ba0705142c25d225515c45f47c0036ee9 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 4 ] . shared_secret . secret_bytes ( ) , < Vec < u8 > > ::from_hex ( " b5756b9b542727dbafc6765a49488b023a725d631af688fc031217e90770c328 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 4 ] . blinding_factor [ .. ] , < Vec < u8 > > ::from_hex ( " c96e00dddaf57e7edcd4fb5954be5b65b09f17cb6d20651b4e90315be5779205 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 4 ] . ephemeral_pubkey . serialize ( ) [ .. ] , < Vec < u8 > > ::from_hex ( " 03a214ebd875aab6ddfd77f22c5e7311d7f77f17a169e599f157bbcdae8bf071f4 " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 4 ] . rho , < Vec < u8 > > ::from_hex ( " 034e18b8cc718e8af6339106e706c52d8df89e2b1f7e9142d996acf88df8799b " ) . unwrap ( ) [ .. ] ) ;
assert_eq! ( onion_keys [ 4 ] . mu , < Vec < u8 > > ::from_hex ( " 8e45e5c61c2b24cb6382444db6698727afb063adecd72aada233d4bf273d975a " ) . unwrap ( ) [ .. ] ) ;
2018-12-19 17:02:27 -05:00
2022-09-30 01:29:02 +02:00
// Packet creation test vectors from BOLT 4 (see
// https://github.com/lightning/bolts/blob/16973e2b857e853308cafd59e42fa830d75b1642/bolt04/onion-test.json).
// Note that we represent the test vector payloads 2 and 5 through RawOnionHopData::data
// with raw hex instead of our in-memory enums, as the payloads contains custom types, and
// we have no way of representing that with our enums.
2018-12-19 17:02:27 -05:00
let payloads = vec! (
2023-03-24 14:35:52 -04:00
RawOnionHopData ::new ( msgs ::OutboundOnionPayload ::Forward {
short_channel_id : 1 ,
2022-09-30 01:29:02 +02:00
amt_to_forward : 15000 ,
outgoing_cltv_value : 1500 ,
} ) ,
/*
The second payload is represented by raw hex as it contains custom type data . Content :
1. length " 52 " ( payload_length 82 ) .
The first part of the payload has the ` NonFinalNode ` format , with content as follows :
2. amt_to_forward " 020236b0 "
02 ( type amt_to_forward ) 02 ( length 2 ) 36 b0 ( value 14000 )
3. outgoing_cltv_value " 04020578 "
04 ( type outgoing_cltv_value ) 02 ( length 2 ) 0578 ( value 1400 )
4. short_channel_id " 06080000000000000002 "
06 ( type short_channel_id ) 08 ( length 8 ) 0000000000000002 ( value 2 )
The rest of the payload is custom type data :
5. custom_record " fd02013c0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f "
* /
RawOnionHopData {
2023-04-27 00:16:40 -07:00
data : < Vec < u8 > > ::from_hex ( " 52020236b00402057806080000000000000002fd02013c0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f " ) . unwrap ( ) ,
2018-12-19 17:02:27 -05:00
} ,
2023-03-24 14:35:52 -04:00
RawOnionHopData ::new ( msgs ::OutboundOnionPayload ::Forward {
short_channel_id : 3 ,
2022-09-30 01:29:02 +02:00
amt_to_forward : 12500 ,
outgoing_cltv_value : 1250 ,
} ) ,
2023-03-24 14:35:52 -04:00
RawOnionHopData ::new ( msgs ::OutboundOnionPayload ::Forward {
short_channel_id : 4 ,
2022-09-30 01:29:02 +02:00
amt_to_forward : 10000 ,
outgoing_cltv_value : 1000 ,
} ) ,
/*
The fifth payload is represented by raw hex as it contains custom type data . Content :
1. length " fd0110 " ( payload_length 272 ) .
The first part of the payload has the ` FinalNode ` format , with content as follows :
1. amt_to_forward " 02022710 "
02 ( type amt_to_forward ) 02 ( length 2 ) 2710 ( value 10000 )
2. outgoing_cltv_value " 040203e8 "
04 ( type outgoing_cltv_value ) 02 ( length 2 ) 03e8 ( value 1000 )
3. payment_data " 082224a33562c54507a9334e79f0dc4f17d407e6d7c61f0e2f3d0d38599502f617042710 "
08 ( type short_channel_id ) 22 ( length 34 ) 24 a33562c54507a9334e79f0dc4f17d407e6d7c61f0e2f3d0d38599502f61704 ( payment_secret ) 2710 ( total_msat value 10000 )
The rest of the payload is custom type data :
4. custom_record " fd012de02a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a "
* /
RawOnionHopData {
2023-04-27 00:16:40 -07:00
data : < Vec < u8 > > ::from_hex ( " fd011002022710040203e8082224a33562c54507a9334e79f0dc4f17d407e6d7c61f0e2f3d0d38599502f617042710fd012de02a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a " ) . unwrap ( ) ,
2018-12-19 17:02:27 -05:00
} ,
) ;
2022-09-30 01:29:02 +02:00
// Verify that the serialized OnionHopDataFormat::NonFinalNode tlv payloads matches the test vectors
let mut w = VecWriter ( Vec ::new ( ) ) ;
payloads [ 0 ] . write ( & mut w ) . unwrap ( ) ;
let hop_1_serialized_payload = w . 0 ;
2023-04-27 00:16:40 -07:00
let expected_serialized_hop_1_payload = & < Vec < u8 > > ::from_hex ( " 1202023a98040205dc06080000000000000001 " ) . unwrap ( ) [ .. ] ;
2022-09-30 01:29:02 +02:00
assert_eq! ( hop_1_serialized_payload , expected_serialized_hop_1_payload ) ;
w = VecWriter ( Vec ::new ( ) ) ;
payloads [ 2 ] . write ( & mut w ) . unwrap ( ) ;
let hop_3_serialized_payload = w . 0 ;
2023-04-27 00:16:40 -07:00
let expected_serialized_hop_3_payload = & < Vec < u8 > > ::from_hex ( " 12020230d4040204e206080000000000000003 " ) . unwrap ( ) [ .. ] ;
2022-09-30 01:29:02 +02:00
assert_eq! ( hop_3_serialized_payload , expected_serialized_hop_3_payload ) ;
w = VecWriter ( Vec ::new ( ) ) ;
payloads [ 3 ] . write ( & mut w ) . unwrap ( ) ;
let hop_4_serialized_payload = w . 0 ;
2023-04-27 00:16:40 -07:00
let expected_serialized_hop_4_payload = & < Vec < u8 > > ::from_hex ( " 1202022710040203e806080000000000000004 " ) . unwrap ( ) [ .. ] ;
2022-09-30 01:29:02 +02:00
assert_eq! ( hop_4_serialized_payload , expected_serialized_hop_4_payload ) ;
let pad_keytype_seed = super ::gen_pad_from_shared_secret ( & get_test_session_key ( ) . secret_bytes ( ) ) ;
2023-04-05 17:08:49 +02:00
let packet : msgs ::OnionPacket = super ::construct_onion_packet_with_writable_hopdata ::< _ > ( payloads , onion_keys , pad_keytype_seed , & PaymentHash ( [ 0x42 ; 32 ] ) ) . unwrap ( ) ;
2022-09-30 01:29:02 +02:00
2023-04-27 00:16:40 -07:00
assert_eq! ( packet . encode ( ) , < Vec < u8 > > ::from_hex ( " 0002EEC7245D6B7D2CCB30380BFBE2A3648CD7A942653F5AA340EDCEA1F283686619F7F3416A5AA36DC7EEB3EC6D421E9615471AB870A33AC07FA5D5A51DF0A8823AABE3FEA3F90D387529D4F72837F9E687230371CCD8D263072206DBED0234F6505E21E282ABD8C0E4F5B9FF8042800BBAB065036EADD0149B37F27DDE664725A49866E052E809D2B0198AB9610FAA656BBF4EC516763A59F8F42C171B179166BA38958D4F51B39B3E98706E2D14A2DAFD6A5DF808093ABFCA5AEAACA16EDED5DB7D21FB0294DD1A163EDF0FB445D5C8D7D688D6DD9C541762BF5A5123BF9939D957FE648416E88F1B0928BFA034982B22548E1A4D922690EECF546275AFB233ACF4323974680779F1A964CFE687456035CC0FBA8A5428430B390F0057B6D1FE9A8875BFA89693EEB838CE59F09D207A503EE6F6299C92D6361BC335FCBF9B5CD44747AADCE2CE6069CFDC3D671DAEF9F8AE590CF93D957C9E873E9A1BC62D9640DC8FC39C14902D49A1C80239B6C5B7FD91D05878CBF5FFC7DB2569F47C43D6C0D27C438ABFF276E87364DEB8858A37E5A62C446AF95D8B786EAF0B5FCF78D98B41496794F8DCAAC4EEF34B2ACFB94C7E8C32A9E9866A8FA0B6F2A06F00A1CCDE569F97EEC05C803BA7500ACC96691D8898D73D8E6A47B8F43C3D5DE74458D20EDA61474C426359677001FBD75A74D7D5DB6CB4FEB83122F133206203E4E2D293F838BF8C8B3A29ACB321315100B87E80E0EDB272EE80FDA944E3FB6084ED4D7F7C7D21C69D9DA43D31A90B70693F9B0CC3EAC74C11AB8FF655905688916CFA4EF0BD04135F2E50B7C689A21D04E8E981E74C6058188B9B1F9DFC3EEC6838E9FFBCF22CE738D8A177C19318DFFEF090CEE67E12DE1A3E2A39F61247547BA5257489CBC11D7D91ED34617FCC42F7A9DA2E3CF31A94A210A1018143173913C38F60E62B24BF0D7518F38B5BAB3E6A1F8AEB35E31D6442C8ABB5178EFC892D2E787D79C6AD9E2FC271792983FA9955AC4D1D84A36C024071BC6E431B625519D556AF38185601F70E29035EA6A09C8B676C9D88CF7E05E0F17098B584C4168735940263F940033A220F40BE4C85344128B14BEB9E75696DB37014107801A59B13E89CD9D2258C169D523BE6D31552C44C82FF4BB18EC9F099F3BF0E5B1BB2BA9A87D7E26F98D294927B600B5529C47E04D98956677CBCEE8FA2B60F49776D8B8C367465B7C626DA53700684FB6C918EAD0EAB8360E4F60EDD25B4F43816A75ECF70F909301825B512469F8389D79402311D8AECB7B3EF8599E79485A4388D87744D899F7C47EE644361E17040A7958C8911BE6F463AB6A9B2AFACD688EC55EF517B38F1339EFC54487232798BB25522FF4572FF68567FE830F92F7B8113EFCE3E98C3FFFBAEDCE4FD8B50E41DA97C0C08E423A72689CC68E68F752A5E3A9003E64E35C957CA2E1C48BB6F64B05F56B70B575AD2F278D57850A7AD568C24A4D32A3D74B29F03DC125488BC7C637DA582357F40B0A52D16B3B40BB2C2315D03360BC24209E20972C200566BCF3BBE5C5B0AEDD83132A8A4D5B4242BA370B6D67D9B67EB01052D132C7866B9CB502E44796D9D356E4E3CB47CC527322CD24976FE7C9257A2864151A38E568EF7A79F10D6EF27CC04CE382347A2488B1F404FDBF407FE1CA1C9D0D5649E34800E25E18951C98CAE9F43555EEF65FEE1EA8F15828807366C3B612CD5753BF9FB8FCED08855F742CDDD6F765F74254F03186683D646E6F09AC2805586C7CF11998357CAFC5DF3F285329366F475130C928B2DCEBA4AA383758E7A9D20705C4BB9DB619E2992F608A1BA65DB254BB389468741D0502E2588AEB54390AC600C19AF5C8E61383FC1BEBE0029E4474051E4EF908828DB9CCA13277EF65DB3FD47CCC2179126AAEFB627719F421E20 " ) . unwrap ( ) ) ;
2018-12-19 17:02:27 -05:00
}
#[ test ]
fn test_failure_packet_onion ( ) {
// Returning Errors test vectors from BOLT 4
let onion_keys = build_test_onion_keys ( ) ;
2022-05-05 17:59:38 +02:00
let onion_error = super ::build_failure_packet ( onion_keys [ 4 ] . shared_secret . as_ref ( ) , 0x2002 , & [ 0 ; 0 ] ) ;
2023-04-27 00:16:40 -07:00
assert_eq! ( onion_error . encode ( ) , < Vec < u8 > > ::from_hex ( " 4c2fc8bc08510334b6833ad9c3e79cd1b52ae59dfe5c2a4b23ead50f09f7ee0b0002200200fe0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 " ) . unwrap ( ) ) ;
2018-12-19 17:02:27 -05:00
2022-05-05 17:59:38 +02:00
let onion_packet_1 = super ::encrypt_failure_packet ( onion_keys [ 4 ] . shared_secret . as_ref ( ) , & onion_error . encode ( ) [ .. ] ) ;
2023-04-27 00:16:40 -07:00
assert_eq! ( onion_packet_1 . data , < Vec < u8 > > ::from_hex ( " a5e6bd0c74cb347f10cce367f949098f2457d14c046fd8a22cb96efb30b0fdcda8cb9168b50f2fd45edd73c1b0c8b33002df376801ff58aaa94000bf8a86f92620f343baef38a580102395ae3abf9128d1047a0736ff9b83d456740ebbb4aeb3aa9737f18fb4afb4aa074fb26c4d702f42968888550a3bded8c05247e045b866baef0499f079fdaeef6538f31d44deafffdfd3afa2fb4ca9082b8f1c465371a9894dd8c243fb4847e004f5256b3e90e2edde4c9fb3082ddfe4d1e734cacd96ef0706bf63c9984e22dc98851bcccd1c3494351feb458c9c6af41c0044bea3c47552b1d992ae542b17a2d0bba1a096c78d169034ecb55b6e3a7263c26017f033031228833c1daefc0dedb8cf7c3e37c9c37ebfe42f3225c326e8bcfd338804c145b16e34e4 " ) . unwrap ( ) ) ;
2018-12-19 17:02:27 -05:00
2022-05-05 17:59:38 +02:00
let onion_packet_2 = super ::encrypt_failure_packet ( onion_keys [ 3 ] . shared_secret . as_ref ( ) , & onion_packet_1 . data [ .. ] ) ;
2023-04-27 00:16:40 -07:00
assert_eq! ( onion_packet_2 . data , < Vec < u8 > > ::from_hex ( " c49a1ce81680f78f5f2000cda36268de34a3f0a0662f55b4e837c83a8773c22aa081bab1616a0011585323930fa5b9fae0c85770a2279ff59ec427ad1bbff9001c0cd1497004bd2a0f68b50704cf6d6a4bf3c8b6a0833399a24b3456961ba00736785112594f65b6b2d44d9f5ea4e49b5e1ec2af978cbe31c67114440ac51a62081df0ed46d4a3df295da0b0fe25c0115019f03f15ec86fabb4c852f83449e812f141a9395b3f70b766ebbd4ec2fae2b6955bd8f32684c15abfe8fd3a6261e52650e8807a92158d9f1463261a925e4bfba44bd20b166d532f0017185c3a6ac7957adefe45559e3072c8dc35abeba835a8cb01a71a15c736911126f27d46a36168ca5ef7dccd4e2886212602b181463e0dd30185c96348f9743a02aca8ec27c0b90dca270 " ) . unwrap ( ) ) ;
2018-12-19 17:02:27 -05:00
2022-05-05 17:59:38 +02:00
let onion_packet_3 = super ::encrypt_failure_packet ( onion_keys [ 2 ] . shared_secret . as_ref ( ) , & onion_packet_2 . data [ .. ] ) ;
2023-04-27 00:16:40 -07:00
assert_eq! ( onion_packet_3 . data , < Vec < u8 > > ::from_hex ( " a5d3e8634cfe78b2307d87c6d90be6fe7855b4f2cc9b1dfb19e92e4b79103f61ff9ac25f412ddfb7466e74f81b3e545563cdd8f5524dae873de61d7bdfccd496af2584930d2b566b4f8d3881f8c043df92224f38cf094cfc09d92655989531524593ec6d6caec1863bdfaa79229b5020acc034cd6deeea1021c50586947b9b8e6faa83b81fbfa6133c0af5d6b07c017f7158fa94f0d206baf12dda6b68f785b773b360fd0497e16cc402d779c8d48d0fa6315536ef0660f3f4e1865f5b38ea49c7da4fd959de4e83ff3ab686f059a45c65ba2af4a6a79166aa0f496bf04d06987b6d2ea205bdb0d347718b9aeff5b61dfff344993a275b79717cd815b6ad4c0beb568c4ac9c36ff1c315ec1119a1993c4b61e6eaa0375e0aaf738ac691abd3263bf937e3 " ) . unwrap ( ) ) ;
2018-12-19 17:02:27 -05:00
2022-05-05 17:59:38 +02:00
let onion_packet_4 = super ::encrypt_failure_packet ( onion_keys [ 1 ] . shared_secret . as_ref ( ) , & onion_packet_3 . data [ .. ] ) ;
2023-04-27 00:16:40 -07:00
assert_eq! ( onion_packet_4 . data , < Vec < u8 > > ::from_hex ( " aac3200c4968f56b21f53e5e374e3a2383ad2b1b6501bbcc45abc31e59b26881b7dfadbb56ec8dae8857add94e6702fb4c3a4de22e2e669e1ed926b04447fc73034bb730f4932acd62727b75348a648a1128744657ca6a4e713b9b646c3ca66cac02cdab44dd3439890ef3aaf61708714f7375349b8da541b2548d452d84de7084bb95b3ac2345201d624d31f4d52078aa0fa05a88b4e20202bd2b86ac5b52919ea305a8949de95e935eed0319cf3cf19ebea61d76ba92532497fcdc9411d06bcd4275094d0a4a3c5d3a945e43305a5a9256e333e1f64dbca5fcd4e03a39b9012d197506e06f29339dfee3331995b21615337ae060233d39befea925cc262873e0530408e6990f1cbd233a150ef7b004ff6166c70c68d9f8c853c1abca640b8660db2921 " ) . unwrap ( ) ) ;
2018-12-19 17:02:27 -05:00
2022-05-05 17:59:38 +02:00
let onion_packet_5 = super ::encrypt_failure_packet ( onion_keys [ 0 ] . shared_secret . as_ref ( ) , & onion_packet_4 . data [ .. ] ) ;
2023-04-27 00:16:40 -07:00
assert_eq! ( onion_packet_5 . data , < Vec < u8 > > ::from_hex ( " 9c5add3963fc7f6ed7f148623c84134b5647e1306419dbe2174e523fa9e2fbed3a06a19f899145610741c83ad40b7712aefaddec8c6baf7325d92ea4ca4d1df8bce517f7e54554608bf2bd8071a4f52a7a2f7ffbb1413edad81eeea5785aa9d990f2865dc23b4bc3c301a94eec4eabebca66be5cf638f693ec256aec514620cc28ee4a94bd9565bc4d4962b9d3641d4278fb319ed2b84de5b665f307a2db0f7fbb757366067d88c50f7e829138fde4f78d39b5b5802f1b92a8a820865af5cc79f9f30bc3f461c66af95d13e5e1f0381c184572a91dee1c849048a647a1158cf884064deddbf1b0b88dfe2f791428d0ba0f6fb2f04e14081f69165ae66d9297c118f0907705c9c4954a199bae0bb96fad763d690e7daa6cfda59ba7f2c8d11448b604d12d " ) . unwrap ( ) ) ;
2018-12-19 17:02:27 -05:00
}
2019-12-28 13:44:47 -05:00
struct RawOnionHopData {
data : Vec < u8 >
}
impl RawOnionHopData {
2023-03-24 14:35:52 -04:00
fn new ( orig : msgs ::OutboundOnionPayload ) -> Self {
2019-12-28 13:44:47 -05:00
Self { data : orig . encode ( ) }
}
}
impl Writeable for RawOnionHopData {
2021-08-01 18:22:06 +02:00
fn write < W : Writer > ( & self , writer : & mut W ) -> Result < ( ) , io ::Error > {
2019-12-28 13:44:47 -05:00
writer . write_all ( & self . data [ .. ] )
}
}
2018-12-19 17:02:27 -05:00
}