@@ -2501,6 +2501,187 @@ mod tests {
2501
2501
assert_eq ! ( decrypted_failure. onion_error_code, Some ( 0x400f ) ) ;
2502
2502
}
2503
2503
2504
+ #[ test]
2505
+ fn test_trampoline_onion_decryption ( ) {
2506
+ // In this test, we construct a dummy path that uses Trampoline hops, and ensure that the
2507
+ // correct shared secrets are used to decrypt the error packets. The actual path configuration
2508
+ // is not particularly relevant.
2509
+
2510
+ let dummy_amt_msat = 150_000_000 ;
2511
+
2512
+ let path = Path {
2513
+ hops : vec ! [
2514
+ // Bob
2515
+ RouteHop {
2516
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c" ) . unwrap( ) ) . unwrap( ) ,
2517
+ node_features: NodeFeatures :: empty( ) ,
2518
+ short_channel_id: 0 ,
2519
+ channel_features: ChannelFeatures :: empty( ) ,
2520
+ fee_msat: 3_000 ,
2521
+ cltv_expiry_delta: 24 ,
2522
+ maybe_announced_channel: false ,
2523
+ } ,
2524
+
2525
+ // Carol
2526
+ RouteHop {
2527
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007" ) . unwrap( ) ) . unwrap( ) ,
2528
+ node_features: NodeFeatures :: empty( ) ,
2529
+ short_channel_id: ( 572330 << 40 ) + ( 42 << 16 ) + 2821 ,
2530
+ channel_features: ChannelFeatures :: empty( ) ,
2531
+ fee_msat: 153_000 ,
2532
+ cltv_expiry_delta: 0 ,
2533
+ maybe_announced_channel: false ,
2534
+ } ,
2535
+ ] ,
2536
+ blinded_tail : Some ( BlindedTail {
2537
+ trampoline_hops : vec ! [
2538
+ // Carol's pubkey
2539
+ TrampolineHop {
2540
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007" ) . unwrap( ) ) . unwrap( ) ,
2541
+ node_features: Features :: empty( ) ,
2542
+ fee_msat: 2_500 ,
2543
+ cltv_expiry_delta: 24 ,
2544
+ } ,
2545
+ // Dave's pubkey
2546
+ TrampolineHop {
2547
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "020e2dbadcc2005e859819ddebbe88a834ae8a6d2b049233c07335f15cd1dc5f22" ) . unwrap( ) ) . unwrap( ) ,
2548
+ node_features: Features :: empty( ) ,
2549
+ fee_msat: 2_500 ,
2550
+ cltv_expiry_delta: 24 ,
2551
+ } ,
2552
+ // Emily's pubkey (the intro node needs to be duplicated)
2553
+ TrampolineHop {
2554
+ pubkey: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991" ) . unwrap( ) ) . unwrap( ) ,
2555
+ node_features: Features :: empty( ) ,
2556
+ fee_msat: 150_500 ,
2557
+ cltv_expiry_delta: 36 ,
2558
+ }
2559
+ ] ,
2560
+ hops : vec ! [
2561
+ // Emily's blinded node id
2562
+ BlindedHop {
2563
+ blinded_node_id: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "0295d40514096a8be54859e7dfe947b376eaafea8afe5cb4eb2c13ff857ed0b4be" ) . unwrap( ) ) . unwrap( ) ,
2564
+ encrypted_payload: vec![ ] ,
2565
+ } ,
2566
+ // Forrest's blinded node id
2567
+ BlindedHop {
2568
+ blinded_node_id: PublicKey :: from_slice( & <Vec <u8 >>:: from_hex( "020e2dbadcc2005e859819ddebbe88a834ae8a6d2b049233c07335f15cd1dc5f22" ) . unwrap( ) ) . unwrap( ) ,
2569
+ encrypted_payload: vec![ ] ,
2570
+ }
2571
+ ] ,
2572
+ blinding_point : PublicKey :: from_slice ( & <Vec < u8 > >:: from_hex ( "02988face71e92c345a068f740191fd8e53be14f0bb957ef730d3c5f76087b960e" ) . unwrap ( ) ) . unwrap ( ) ,
2573
+ excess_final_cltv_expiry_delta : 0 ,
2574
+ final_value_msat : dummy_amt_msat
2575
+ } ) ,
2576
+ } ;
2577
+
2578
+ // all dummy values
2579
+ let secp_ctx = Secp256k1 :: new ( ) ;
2580
+ let session_priv = get_test_session_key ( ) ;
2581
+
2582
+ let trampoline_onion_keys = construct_trampoline_onion_keys (
2583
+ & secp_ctx,
2584
+ & path. blinded_tail . as_ref ( ) . unwrap ( ) ,
2585
+ & session_priv,
2586
+ )
2587
+ . unwrap ( ) ;
2588
+
2589
+ let outer_onion_keys = {
2590
+ let session_priv_hash = Sha256 :: hash ( & session_priv. secret_bytes ( ) ) . to_byte_array ( ) ;
2591
+ let outer_session_priv = SecretKey :: from_slice ( & session_priv_hash[ ..] ) . unwrap ( ) ;
2592
+ construct_onion_keys ( & Secp256k1 :: new ( ) , & path, & outer_session_priv) . unwrap ( )
2593
+ } ;
2594
+
2595
+ let logger: Arc < TestLogger > = Arc :: new ( TestLogger :: new ( ) ) ;
2596
+ let htlc_source = HTLCSource :: OutboundRoute {
2597
+ path,
2598
+ session_priv,
2599
+ first_hop_htlc_msat : dummy_amt_msat,
2600
+ payment_id : PaymentId ( [ 1 ; 32 ] ) ,
2601
+ } ;
2602
+
2603
+ {
2604
+ let error_code = 0x2002 ;
2605
+ let onion_error = super :: build_failure_packet (
2606
+ outer_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2607
+ error_code,
2608
+ & [ 0 ; 0 ] ,
2609
+ ) ;
2610
+ let first_hop_error_packet = super :: encrypt_failure_packet (
2611
+ outer_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2612
+ & onion_error. encode ( ) [ ..] ,
2613
+ ) ;
2614
+
2615
+ let decrypted_failure = process_onion_failure (
2616
+ & secp_ctx,
2617
+ & logger,
2618
+ & htlc_source,
2619
+ first_hop_error_packet. data ,
2620
+ None ,
2621
+ ) ;
2622
+ assert_eq ! ( decrypted_failure. onion_error_code, Some ( error_code) ) ;
2623
+ } ;
2624
+
2625
+ {
2626
+ let error_code = 0x2003 ;
2627
+ let onion_error = super :: build_failure_packet (
2628
+ outer_onion_keys[ 1 ] . shared_secret . as_ref ( ) ,
2629
+ error_code,
2630
+ & [ 0 ; 0 ] ,
2631
+ ) ;
2632
+ let error_packet_1 = super :: encrypt_failure_packet (
2633
+ outer_onion_keys[ 1 ] . shared_secret . as_ref ( ) ,
2634
+ & onion_error. encode ( ) [ ..] ,
2635
+ ) ;
2636
+
2637
+ let trampoline_outer_hop_error_packet = super :: encrypt_failure_packet (
2638
+ outer_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2639
+ & error_packet_1. data [ ..] ,
2640
+ ) ;
2641
+
2642
+ let decrypted_failure = process_onion_failure (
2643
+ & secp_ctx,
2644
+ & logger,
2645
+ & htlc_source,
2646
+ trampoline_outer_hop_error_packet. data ,
2647
+ None ,
2648
+ ) ;
2649
+ assert_eq ! ( decrypted_failure. onion_error_code, Some ( error_code) ) ;
2650
+ } ;
2651
+
2652
+ {
2653
+ let error_code = 0x2004 ;
2654
+ let onion_error = super :: build_failure_packet (
2655
+ trampoline_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2656
+ error_code,
2657
+ & [ 0 ; 0 ] ,
2658
+ ) ;
2659
+ let error_packet_t0 = super :: encrypt_failure_packet (
2660
+ trampoline_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2661
+ & onion_error. encode ( ) [ ..] ,
2662
+ ) ;
2663
+
2664
+ let error_packet_1 = super :: encrypt_failure_packet (
2665
+ outer_onion_keys[ 1 ] . shared_secret . as_ref ( ) ,
2666
+ & error_packet_t0. data [ ..] ,
2667
+ ) ;
2668
+
2669
+ let trampoline_inner_hop_error_packet = super :: encrypt_failure_packet (
2670
+ outer_onion_keys[ 0 ] . shared_secret . as_ref ( ) ,
2671
+ & error_packet_1. data [ ..] ,
2672
+ ) ;
2673
+
2674
+ let decrypted_failure = process_onion_failure (
2675
+ & secp_ctx,
2676
+ & logger,
2677
+ & htlc_source,
2678
+ trampoline_inner_hop_error_packet. data ,
2679
+ None ,
2680
+ ) ;
2681
+ assert_eq ! ( decrypted_failure. onion_error_code, Some ( error_code) ) ;
2682
+ }
2683
+ }
2684
+
2504
2685
#[ test]
2505
2686
fn test_non_attributable_failure_packet_onion ( ) {
2506
2687
// Create a failure packet with bogus data.
0 commit comments