@@ -942,7 +942,7 @@ pub(crate) struct DecodedOnionFailure {
942
942
#[ inline]
943
943
pub ( super ) fn process_onion_failure < T : secp256k1:: Signing , L : Deref > (
944
944
secp_ctx : & Secp256k1 < T > , logger : & L , htlc_source : & HTLCSource ,
945
- mut encrypted_packet : OnionErrorPacket ,
945
+ mut encrypted_packet : OnionErrorPacket , secondary_session_priv : Option < SecretKey > ,
946
946
) -> DecodedOnionFailure
947
947
where
948
948
L :: Target : Logger ,
@@ -1004,8 +1004,10 @@ where
1004
1004
1005
1005
let outer_session_priv = path. has_trampoline_hops ( ) . then ( || {
1006
1006
// if we have Trampoline hops, the outer onion session_priv is a hash of the inner one
1007
- let session_priv_hash = Sha256 :: hash ( & session_priv. secret_bytes ( ) ) . to_byte_array ( ) ;
1008
- SecretKey :: from_slice ( & session_priv_hash[ ..] ) . expect ( "You broke SHA-256!" )
1007
+ secondary_session_priv. unwrap_or_else ( || {
1008
+ let session_priv_hash = Sha256 :: hash ( & session_priv. secret_bytes ( ) ) . to_byte_array ( ) ;
1009
+ SecretKey :: from_slice ( & session_priv_hash[ ..] ) . expect ( "You broke SHA-256!" )
1010
+ } )
1009
1011
} ) ;
1010
1012
1011
1013
let mut onion_keys = Vec :: with_capacity ( path. hops . len ( ) ) ;
@@ -1469,7 +1471,7 @@ impl HTLCFailReason {
1469
1471
{
1470
1472
match self . 0 {
1471
1473
HTLCFailReasonRepr :: LightningError { ref err } => {
1472
- process_onion_failure ( secp_ctx, logger, & htlc_source, err. clone ( ) )
1474
+ process_onion_failure ( secp_ctx, logger, & htlc_source, err. clone ( ) , None )
1473
1475
} ,
1474
1476
#[ allow( unused) ]
1475
1477
HTLCFailReasonRepr :: Reason { ref failure_code, ref data, .. } => {
@@ -2037,11 +2039,11 @@ mod tests {
2037
2039
use crate :: prelude:: * ;
2038
2040
use crate :: util:: test_utils:: TestLogger ;
2039
2041
2042
+ use super :: * ;
2040
2043
use bitcoin:: hex:: FromHex ;
2041
2044
use bitcoin:: secp256k1:: Secp256k1 ;
2042
2045
use bitcoin:: secp256k1:: { PublicKey , SecretKey } ;
2043
-
2044
- use super :: * ;
2046
+ use types:: features:: Features ;
2045
2047
2046
2048
fn get_test_session_key ( ) -> SecretKey {
2047
2049
let hex = "4141414141414141414141414141414141414141414141414141414141414141" ;
@@ -2397,11 +2399,284 @@ mod tests {
2397
2399
2398
2400
// Assert that the original failure can be retrieved and that all hmacs check out.
2399
2401
let decrypted_failure =
2400
- process_onion_failure ( & ctx_full, & logger, & htlc_source, onion_error) ;
2402
+ process_onion_failure ( & ctx_full, & logger, & htlc_source, onion_error, None ) ;
2401
2403
2402
2404
assert_eq ! ( decrypted_failure. onion_error_code, Some ( 0x2002 ) ) ;
2403
2405
}
2404
2406
2407
+ #[ test]
2408
+ fn test_trampoline_onion_error_vectors ( ) {
2409
+ // as per https://github.com/lightning/bolts/blob/079f761bf68caa48544bd6bf0a29591d43425b0b/bolt04/trampoline-onion-error-test.json
2410
+ // TODO(arik): check intermediate hops' perspectives once we have implemented forwarding
2411
+
2412
+ let dummy_amt_msat = 150_000_000 ;
2413
+ let path = Path {
2414
+ hops : vec ! [
2415
+ // Bob
2416
+ RouteHop {
2417
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c" ) . unwrap( ) ) . unwrap( ) ,
2418
+ node_features: NodeFeatures :: empty( ) ,
2419
+ short_channel_id: 0 ,
2420
+ channel_features: ChannelFeatures :: empty( ) ,
2421
+ fee_msat: 3_000 ,
2422
+ cltv_expiry_delta: 24 ,
2423
+ maybe_announced_channel: false ,
2424
+ } ,
2425
+
2426
+ // Carol
2427
+ RouteHop {
2428
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007" ) . unwrap( ) ) . unwrap( ) ,
2429
+ node_features: NodeFeatures :: empty( ) ,
2430
+ short_channel_id: ( 572330 << 40 ) + ( 42 << 16 ) + 2821 ,
2431
+ channel_features: ChannelFeatures :: empty( ) ,
2432
+ fee_msat: 153_000 ,
2433
+ cltv_expiry_delta: 0 ,
2434
+ maybe_announced_channel: false ,
2435
+ } ,
2436
+ ] ,
2437
+ blinded_tail : Some ( BlindedTail {
2438
+ trampoline_hops : vec ! [
2439
+ // Carol's pubkey
2440
+ TrampolineHop {
2441
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007" ) . unwrap( ) ) . unwrap( ) ,
2442
+ node_features: Features :: empty( ) ,
2443
+ fee_msat: 2_500 ,
2444
+ cltv_expiry_delta: 24 ,
2445
+ } ,
2446
+
2447
+ // Eve's pubkey
2448
+ TrampolineHop {
2449
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145" ) . unwrap( ) ) . unwrap( ) ,
2450
+ node_features: Features :: empty( ) ,
2451
+ fee_msat: 2_500 ,
2452
+ cltv_expiry_delta: 24 ,
2453
+ } ,
2454
+ ] ,
2455
+
2456
+ // Dummy blinded hop (because LDK doesn't allow unblinded Trampoline receives)
2457
+ hops : vec ! [
2458
+ // Eve's dummy blinded node id
2459
+ BlindedHop {
2460
+ blinded_node_id: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "0295d40514096a8be54859e7dfe947b376eaafea8afe5cb4eb2c13ff857ed0b4be" ) . unwrap( ) ) . unwrap( ) ,
2461
+ encrypted_payload: vec![ ] ,
2462
+ }
2463
+ ] ,
2464
+ blinding_point : PublicKey :: from_slice ( & <Vec < u8 > >:: from_hex ( "02988face71e92c345a068f740191fd8e53be14f0bb957ef730d3c5f76087b960e" ) . unwrap ( ) ) . unwrap ( ) ,
2465
+ excess_final_cltv_expiry_delta : 0 ,
2466
+ final_value_msat : dummy_amt_msat
2467
+ } ) ,
2468
+ } ;
2469
+
2470
+ // all dummy values
2471
+ let secp_ctx = Secp256k1 :: new ( ) ;
2472
+ let trampoline_session_priv = SecretKey :: from_slice ( & [ 3 ; 32 ] ) . unwrap ( ) ;
2473
+ let outer_session_priv = SecretKey :: from_slice ( & [ 4 ; 32 ] ) . unwrap ( ) ;
2474
+
2475
+ let logger: Arc < TestLogger > = Arc :: new ( TestLogger :: new ( ) ) ;
2476
+ let htlc_source = HTLCSource :: OutboundRoute {
2477
+ path,
2478
+ session_priv : trampoline_session_priv,
2479
+ first_hop_htlc_msat : dummy_amt_msat,
2480
+ payment_id : PaymentId ( [ 1 ; 32 ] ) ,
2481
+ } ;
2482
+
2483
+ let error_packet_hex = "f8941a320b8fde4ad7b9b920c69cbf334114737497d93059d77e591eaa78d6334d3e2aeefcb0cc83402eaaf91d07d695cd895d9cad1018abdaf7d2a49d7657b1612729db7f393f0bb62b25afaaaa326d72a9214666025385033f2ec4605dcf1507467b5726d806da180ea224a7d8631cd31b0bdd08eead8bfe14fc8c7475e17768b1321b54dd4294aecc96da391efe0ca5bd267a45ee085c85a60cf9a9ac152fa4795fff8700a3ea4f848817f5e6943e855ab2e86f6929c9e885d8b20c49b14d2512c59ed21f10bd38691110b0d82c00d9fa48a20f10c7550358724c6e8e2b966e56a0aadf458695b273768062fa7c6e60eb72d4cdc67bf525c194e4a17fdcaa0e9d80480b586bf113f14eea530b6728a1c53fe5cee092e24a90f21f4b764015e7ed5e23" ;
2484
+ let error_packet =
2485
+ OnionErrorPacket { data : <Vec < u8 > >:: from_hex ( error_packet_hex) . unwrap ( ) } ;
2486
+ let decrypted_failure = process_onion_failure (
2487
+ & secp_ctx,
2488
+ & logger,
2489
+ & htlc_source,
2490
+ error_packet,
2491
+ Some ( outer_session_priv) ,
2492
+ ) ;
2493
+ assert_eq ! ( decrypted_failure. onion_error_code, Some ( 0x400f ) ) ;
2494
+ }
2495
+
2496
+ #[ test]
2497
+ fn test_trampoline_onion_decryption ( ) {
2498
+ // In this test, we construct a dummy path that uses Trampoline hops, and ensure that the
2499
+ // correct shared secrets are used to decrypt the error packets. The actual path configuration
2500
+ // is not particularly relevant.
2501
+
2502
+ let dummy_amt_msat = 150_000_000 ;
2503
+
2504
+ let path = Path {
2505
+ hops : vec ! [
2506
+ // Bob
2507
+ RouteHop {
2508
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c" ) . unwrap( ) ) . unwrap( ) ,
2509
+ node_features: NodeFeatures :: empty( ) ,
2510
+ short_channel_id: 0 ,
2511
+ channel_features: ChannelFeatures :: empty( ) ,
2512
+ fee_msat: 3_000 ,
2513
+ cltv_expiry_delta: 24 ,
2514
+ maybe_announced_channel: false ,
2515
+ } ,
2516
+
2517
+ // Carol
2518
+ RouteHop {
2519
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007" ) . unwrap( ) ) . unwrap( ) ,
2520
+ node_features: NodeFeatures :: empty( ) ,
2521
+ short_channel_id: ( 572330 << 40 ) + ( 42 << 16 ) + 2821 ,
2522
+ channel_features: ChannelFeatures :: empty( ) ,
2523
+ fee_msat: 153_000 ,
2524
+ cltv_expiry_delta: 0 ,
2525
+ maybe_announced_channel: false ,
2526
+ } ,
2527
+ ] ,
2528
+ blinded_tail : Some ( BlindedTail {
2529
+ trampoline_hops : vec ! [
2530
+ // Carol's pubkey
2531
+ TrampolineHop {
2532
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007" ) . unwrap( ) ) . unwrap( ) ,
2533
+ node_features: Features :: empty( ) ,
2534
+ fee_msat: 2_500 ,
2535
+ cltv_expiry_delta: 24 ,
2536
+ } ,
2537
+ // Dave's pubkey
2538
+ TrampolineHop {
2539
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "020e2dbadcc2005e859819ddebbe88a834ae8a6d2b049233c07335f15cd1dc5f22" ) . unwrap( ) ) . unwrap( ) ,
2540
+ node_features: Features :: empty( ) ,
2541
+ fee_msat: 2_500 ,
2542
+ cltv_expiry_delta: 24 ,
2543
+ } ,
2544
+ // Emily's pubkey (the intro node needs to be duplicated)
2545
+ TrampolineHop {
2546
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991" ) . unwrap( ) ) . unwrap( ) ,
2547
+ node_features: Features :: empty( ) ,
2548
+ fee_msat: 150_500 ,
2549
+ cltv_expiry_delta: 36 ,
2550
+ }
2551
+ ] ,
2552
+ hops : vec ! [
2553
+ // Emily's blinded node id
2554
+ BlindedHop {
2555
+ blinded_node_id: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "0295d40514096a8be54859e7dfe947b376eaafea8afe5cb4eb2c13ff857ed0b4be" ) . unwrap( ) ) . unwrap( ) ,
2556
+ encrypted_payload: vec![ ] ,
2557
+ } ,
2558
+ // Forrest's blinded node id
2559
+ BlindedHop {
2560
+ blinded_node_id: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "020e2dbadcc2005e859819ddebbe88a834ae8a6d2b049233c07335f15cd1dc5f22" ) . unwrap( ) ) . unwrap( ) ,
2561
+ encrypted_payload: vec![ ] ,
2562
+ }
2563
+ ] ,
2564
+ blinding_point : PublicKey :: from_slice ( & <Vec < u8 > >:: from_hex ( "02988face71e92c345a068f740191fd8e53be14f0bb957ef730d3c5f76087b960e" ) . unwrap ( ) ) . unwrap ( ) ,
2565
+ excess_final_cltv_expiry_delta : 0 ,
2566
+ final_value_msat : dummy_amt_msat
2567
+ } ) ,
2568
+ } ;
2569
+
2570
+ // all dummy values
2571
+ let secp_ctx = Secp256k1 :: new ( ) ;
2572
+ let session_priv = get_test_session_key ( ) ;
2573
+
2574
+ let trampoline_onion_keys = construct_trampoline_onion_keys (
2575
+ & secp_ctx,
2576
+ & path. blinded_tail . as_ref ( ) . unwrap ( ) ,
2577
+ & session_priv,
2578
+ )
2579
+ . unwrap ( ) ;
2580
+
2581
+ let outer_onion_keys = {
2582
+ let session_priv_hash = Sha256 :: hash ( & session_priv. secret_bytes ( ) ) . to_byte_array ( ) ;
2583
+ let outer_session_priv = SecretKey :: from_slice ( & session_priv_hash[ ..] ) . unwrap ( ) ;
2584
+ construct_onion_keys ( & Secp256k1 :: new ( ) , & path, & outer_session_priv) . unwrap ( )
2585
+ } ;
2586
+
2587
+ let logger: Arc < TestLogger > = Arc :: new ( TestLogger :: new ( ) ) ;
2588
+ let htlc_source = HTLCSource :: OutboundRoute {
2589
+ path,
2590
+ session_priv,
2591
+ first_hop_htlc_msat : dummy_amt_msat,
2592
+ payment_id : PaymentId ( [ 1 ; 32 ] ) ,
2593
+ } ;
2594
+
2595
+ {
2596
+ let error_code = 0x2002 ;
2597
+ let mut first_hop_error_packet = build_unencrypted_failure_packet (
2598
+ outer_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2599
+ error_code,
2600
+ & [ 0 ; 0 ] ,
2601
+ ) ;
2602
+
2603
+ crypt_failure_packet (
2604
+ outer_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2605
+ & mut first_hop_error_packet,
2606
+ ) ;
2607
+
2608
+ let decrypted_failure = process_onion_failure (
2609
+ & secp_ctx,
2610
+ & logger,
2611
+ & htlc_source,
2612
+ first_hop_error_packet,
2613
+ None ,
2614
+ ) ;
2615
+ assert_eq ! ( decrypted_failure. onion_error_code, Some ( error_code) ) ;
2616
+ } ;
2617
+
2618
+ {
2619
+ let error_code = 0x2003 ;
2620
+ let mut trampoline_outer_hop_error_packet = build_unencrypted_failure_packet (
2621
+ outer_onion_keys[ 1 ] . shared_secret . as_ref ( ) ,
2622
+ error_code,
2623
+ & [ 0 ; 0 ] ,
2624
+ ) ;
2625
+
2626
+ crypt_failure_packet (
2627
+ outer_onion_keys[ 1 ] . shared_secret . as_ref ( ) ,
2628
+ & mut trampoline_outer_hop_error_packet,
2629
+ ) ;
2630
+
2631
+ crypt_failure_packet (
2632
+ outer_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2633
+ & mut trampoline_outer_hop_error_packet,
2634
+ ) ;
2635
+
2636
+ let decrypted_failure = process_onion_failure (
2637
+ & secp_ctx,
2638
+ & logger,
2639
+ & htlc_source,
2640
+ trampoline_outer_hop_error_packet,
2641
+ None ,
2642
+ ) ;
2643
+ assert_eq ! ( decrypted_failure. onion_error_code, Some ( error_code) ) ;
2644
+ } ;
2645
+
2646
+ {
2647
+ let error_code = 0x2004 ;
2648
+ let mut trampoline_inner_hop_error_packet = build_unencrypted_failure_packet (
2649
+ trampoline_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2650
+ error_code,
2651
+ & [ 0 ; 0 ] ,
2652
+ ) ;
2653
+
2654
+ crypt_failure_packet (
2655
+ trampoline_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2656
+ & mut trampoline_inner_hop_error_packet,
2657
+ ) ;
2658
+
2659
+ crypt_failure_packet (
2660
+ outer_onion_keys[ 1 ] . shared_secret . as_ref ( ) ,
2661
+ & mut trampoline_inner_hop_error_packet,
2662
+ ) ;
2663
+
2664
+ crypt_failure_packet (
2665
+ outer_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2666
+ & mut trampoline_inner_hop_error_packet,
2667
+ ) ;
2668
+
2669
+ let decrypted_failure = process_onion_failure (
2670
+ & secp_ctx,
2671
+ & logger,
2672
+ & htlc_source,
2673
+ trampoline_inner_hop_error_packet,
2674
+ None ,
2675
+ ) ;
2676
+ assert_eq ! ( decrypted_failure. onion_error_code, Some ( error_code) ) ;
2677
+ }
2678
+ }
2679
+
2405
2680
#[ test]
2406
2681
fn test_non_attributable_failure_packet_onion ( ) {
2407
2682
// Create a failure packet with bogus data.
@@ -2487,7 +2762,8 @@ mod tests {
2487
2762
payment_id : PaymentId ( [ 1 ; 32 ] ) ,
2488
2763
} ;
2489
2764
2490
- let decrypted_failure = process_onion_failure ( & ctx_full, & logger, & htlc_source, packet) ;
2765
+ let decrypted_failure =
2766
+ process_onion_failure ( & ctx_full, & logger, & htlc_source, packet, None ) ;
2491
2767
2492
2768
decrypted_failure
2493
2769
}
0 commit comments