@@ -2493,6 +2493,190 @@ mod tests {
2493
2493
assert_eq ! ( decrypted_failure. onion_error_code, Some ( 0x400f ) ) ;
2494
2494
}
2495
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
+
2496
2680
#[ test]
2497
2681
fn test_non_attributable_failure_packet_onion ( ) {
2498
2682
// Create a failure packet with bogus data.
0 commit comments