@@ -338,6 +338,168 @@ mod inbound_payment {
338338 }
339339}
340340
341+ /// LDK has multiple reasons to generate fake short channel ids:
342+ /// 1) zero-conf channels that don't have a confirmed channel id yet
343+ /// 2) phantom node payments, to get an scid for the phantom node's phantom channel
344+ mod fake_scid {
345+ use bitcoin:: blockdata:: constants:: genesis_block;
346+ use bitcoin:: hash_types:: BlockHash ;
347+ use bitcoin:: network:: constants:: Network ;
348+ use chain:: keysinterface:: { Sign , KeysInterface } ;
349+ use util:: scid_utils;
350+
351+ use core:: convert:: TryInto ;
352+ use core:: ops:: Deref ;
353+
354+ const TEST_SEGWIT_ACTIVATION_HEIGHT : u32 = 0 ;
355+ const MAINNET_SEGWIT_ACTIVATION_HEIGHT : u32 = 481_824 ;
356+ const MAX_TX_INDEX : u32 = 2_500 ;
357+ const MAX_VOUT : u16 = 3 ;
358+ const MAX_NAMESPACES : u8 = 8 ;
359+ const NAMESPACE_ID_BITMASK : u8 = 0b111 ;
360+
361+ /// Fake scids are divided into namespaces, with each namespace having its own randomly-selected
362+ /// identifier between [0..7], such that `scid_tx_index % MAX_NAMESPACES == namespace_identifier`.
363+ /// This allows us to identify what namespace a fake scid corresponds to upon HTLC receipt, and
364+ /// handle the HTLC accordingly.
365+ pub ( super ) enum Namespace {
366+ Phantom ( u8 ) ,
367+ // Coming soon: a variant for the zero-conf scid namespace
368+ }
369+
370+ impl Namespace {
371+ /// We generate "realistic-looking" random scids here, meaning the scid's block height is
372+ /// between segwit activation and the current best known height, and the tx index and output
373+ /// index are also selected from a "reasonable" range. We add this logic because it makes it
374+ /// non-obvious at a glance that the scid is fake, e.g. if it appears in invoice route hints.
375+ pub ( super ) fn get_fake_scid < Signer : Sign , K : Deref > ( & self , highest_seen_blockheight : u32 , genesis_hash : & BlockHash , keys_manager : & K ) -> u64
376+ where K :: Target : KeysInterface < Signer = Signer > ,
377+ {
378+ const NUM_BLOCKS_24HRS : u32 = 144 ;
379+ let scid_namespace = self . as_u8 ( ) ;
380+ let rand_bytes = keys_manager. get_secure_random_bytes ( ) ;
381+
382+ let mut valid_block_range = highest_seen_blockheight - segwit_activation_height ( genesis_hash) ;
383+ // We want to ensure that this fake channel could've plausibly confirmed on-chain.
384+ if valid_block_range > NUM_BLOCKS_24HRS { valid_block_range -= NUM_BLOCKS_24HRS ; }
385+
386+ let rand_value_for_height = u32:: from_be_bytes ( rand_bytes[ ..4 ] . try_into ( ) . unwrap ( ) ) ;
387+ let fake_scid_height = segwit_activation_height ( genesis_hash) + rand_value_for_height % valid_block_range;
388+
389+ let rand_u32 = u32:: from_be_bytes ( rand_bytes[ 4 ..8 ] . try_into ( ) . unwrap ( ) ) ;
390+ let rand_tx_index = rand_u32 % MAX_TX_INDEX ;
391+ // Put the tx index into the given `scid_namespace`.
392+ let fake_scid_tx_index = ( ( rand_tx_index / 8 ) * 8 ) + scid_namespace as u32 ;
393+
394+ let rand_value_for_vout = u16:: from_be_bytes ( rand_bytes[ 8 ..10 ] . try_into ( ) . unwrap ( ) ) ;
395+ let fake_scid_vout_index = rand_value_for_vout % MAX_VOUT ;
396+ scid_utils:: scid_from_parts ( fake_scid_height as u64 , fake_scid_tx_index as u64 , fake_scid_vout_index as u64 ) . unwrap ( )
397+ }
398+
399+ fn as_u8 ( & self ) -> u8 {
400+ match self {
401+ Namespace :: Phantom ( namespace) => * namespace,
402+ }
403+ }
404+
405+ fn phantom ( fake_scid_offset : u8 ) -> Namespace {
406+ const PHANTOM_OFFSET : u8 = 0 ;
407+ Namespace :: Phantom ( ( fake_scid_offset + PHANTOM_OFFSET ) % MAX_NAMESPACES )
408+ }
409+ }
410+
411+ pub ( super ) fn get_phantom_scid < Signer : Sign , K : Deref > ( fake_scid_offset : u8 , highest_seen_blockheight : u32 , genesis_hash : & BlockHash , keys_manager : & K ) -> u64
412+ where K :: Target : KeysInterface < Signer = Signer > ,
413+ {
414+ let namespace = Namespace :: phantom ( fake_scid_offset) ;
415+ namespace. get_fake_scid ( highest_seen_blockheight, genesis_hash, keys_manager)
416+ }
417+
418+ /// Each LDK node uses a random offset for its fake scid namespaces, to make it harder for a third
419+ /// party to identify phantom node payments.
420+ pub ( super ) fn get_new_offset < Signer : Sign , K : Deref > ( keys_manager : & K ) -> u8
421+ where K :: Target : KeysInterface < Signer = Signer > ,
422+ {
423+ let offset_rand_bytes = keys_manager. get_secure_random_bytes ( ) ;
424+ offset_rand_bytes [ 0 ] & NAMESPACE_ID_BITMASK
425+ }
426+
427+ fn segwit_activation_height ( genesis : & BlockHash ) -> u32 {
428+ if genesis_block ( Network :: Bitcoin ) . header . block_hash ( ) == * genesis {
429+ MAINNET_SEGWIT_ACTIVATION_HEIGHT
430+ } else {
431+ TEST_SEGWIT_ACTIVATION_HEIGHT
432+ }
433+ }
434+
435+ /// Returns whether the given fake scid falls into the given namespace.
436+ pub ( super ) fn is_valid_phantom ( fake_scid_offset : u8 , scid : u64 ) -> bool {
437+ let namespace = Namespace :: phantom ( fake_scid_offset) ;
438+ scid_utils:: tx_index_from_scid ( & scid) % MAX_NAMESPACES as u32 == namespace. as_u8 ( ) as u32
439+ }
440+
441+ #[ cfg( test) ]
442+ mod tests {
443+ use bitcoin:: blockdata:: constants:: genesis_block;
444+ use bitcoin:: network:: constants:: Network ;
445+ use ln:: channelmanager:: fake_scid:: { is_valid_phantom, MAINNET_SEGWIT_ACTIVATION_HEIGHT , MAX_TX_INDEX , MAX_VOUT , Namespace , NAMESPACE_ID_BITMASK , segwit_activation_height, TEST_SEGWIT_ACTIVATION_HEIGHT } ;
446+ use util:: scid_utils;
447+ use util:: test_utils;
448+ use sync:: Arc ;
449+
450+ const TEST_FAKE_SCID_OFFSET : u8 = 0xAB ;
451+
452+ #[ test]
453+ fn namespace_identifier_is_within_range ( ) {
454+ let Namespace :: Phantom ( ns) = Namespace :: phantom ( TEST_FAKE_SCID_OFFSET ) ;
455+ assert ! ( ns <= NAMESPACE_ID_BITMASK ) ;
456+ }
457+
458+ #[ test]
459+ fn test_segwit_activation_height ( ) {
460+ let mainnet_genesis = genesis_block ( Network :: Bitcoin ) . header . block_hash ( ) ;
461+ assert_eq ! ( segwit_activation_height( & mainnet_genesis) , MAINNET_SEGWIT_ACTIVATION_HEIGHT ) ;
462+
463+ let testnet_genesis = genesis_block ( Network :: Testnet ) . header . block_hash ( ) ;
464+ assert_eq ! ( segwit_activation_height( & testnet_genesis) , TEST_SEGWIT_ACTIVATION_HEIGHT ) ;
465+
466+ let signet_genesis = genesis_block ( Network :: Signet ) . header . block_hash ( ) ;
467+ assert_eq ! ( segwit_activation_height( & signet_genesis) , TEST_SEGWIT_ACTIVATION_HEIGHT ) ;
468+
469+ let regtest_genesis = genesis_block ( Network :: Regtest ) . header . block_hash ( ) ;
470+ assert_eq ! ( segwit_activation_height( & regtest_genesis) , TEST_SEGWIT_ACTIVATION_HEIGHT ) ;
471+ }
472+
473+ #[ test]
474+ fn test_is_valid_phantom ( ) {
475+ let namespace = Namespace :: Phantom ( 3 ) ;
476+ let valid_fake_scid = scid_utils:: scid_from_parts ( 0 , 11 , 0 ) . unwrap ( ) ;
477+ assert ! ( is_valid_phantom( namespace. as_u8( ) , valid_fake_scid) ) ;
478+ let invalid_fake_scid = scid_utils:: scid_from_parts ( 0 , 12 , 0 ) . unwrap ( ) ;
479+ assert ! ( !is_valid_phantom( namespace. as_u8( ) , invalid_fake_scid) ) ;
480+ }
481+
482+ #[ test]
483+ fn test_get_fake_scid ( ) {
484+ let mainnet_genesis = genesis_block ( Network :: Bitcoin ) . header . block_hash ( ) ;
485+ let seed = [ 0 as u8 ; 32 ] ;
486+ let keys_manager = Arc :: new ( test_utils:: TestKeysInterface :: new ( & seed, Network :: Testnet ) ) ;
487+ let namespace = Namespace :: phantom ( TEST_FAKE_SCID_OFFSET ) ;
488+ let fake_scid = namespace. get_fake_scid ( 500_000 , & mainnet_genesis, & keys_manager) ;
489+
490+ let fake_height = scid_utils:: block_from_scid ( & fake_scid) ;
491+ assert ! ( fake_height >= MAINNET_SEGWIT_ACTIVATION_HEIGHT ) ;
492+ assert ! ( fake_height <= 500_000 ) ;
493+
494+ let fake_tx_index = scid_utils:: tx_index_from_scid ( & fake_scid) ;
495+ assert ! ( fake_tx_index <= MAX_TX_INDEX ) ;
496+
497+ let fake_vout = fake_scid & scid_utils:: MAX_SCID_VOUT_INDEX ;
498+ assert ! ( fake_vout <= MAX_VOUT . into( ) ) ;
499+ }
500+ }
501+ }
502+
341503// We hold various information about HTLC relay in the HTLC objects in Channel itself:
342504//
343505// Upon receipt of an HTLC from a peer, we'll give it a PendingHTLCStatus indicating if it should
@@ -966,6 +1128,8 @@ pub struct ChannelManager<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref,
9661128
9671129 inbound_payment_key : inbound_payment:: ExpandedKey ,
9681130
1131+ fake_scid_offset : u8 ,
1132+
9691133 /// Used to track the last value sent in a node_announcement "timestamp" field. We ensure this
9701134 /// value increases strictly since we don't assume access to a time source.
9711135 last_node_announcement_serial : AtomicUsize ,
@@ -1685,6 +1849,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
16851849 secp_ctx,
16861850
16871851 inbound_payment_key : expanded_inbound_key,
1852+ fake_scid_offset : fake_scid:: get_new_offset ( & keys_manager) ,
16881853
16891854 last_node_announcement_serial : AtomicUsize :: new ( 0 ) ,
16901855 highest_seen_timestamp : AtomicUsize :: new ( 0 ) ,
@@ -5102,6 +5267,26 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelMana
51025267 inbound_payment:: get_payment_preimage ( payment_hash, payment_secret, & self . inbound_payment_key )
51035268 }
51045269
5270+ /// Gets a fake short channel id for use in receiving phantom node payments.
5271+ ///
5272+ /// A phantom node payment is a payment made to a phantom invoice, which is an invoice that can be
5273+ /// paid to one of multiple nodes. This works because the invoice officially pays to a fake node
5274+ /// (the "phantom"), with route hints containing phantom channels. This method is used to retrieve
5275+ /// the short channel ids for these phantom route hints.
5276+ ///
5277+ /// While these scids can be reused across invoices, it's best for privacy to use new ones when
5278+ /// possible.
5279+ pub fn get_phantom_scid ( & self ) -> u64 {
5280+ let mut channel_state = self . channel_state . lock ( ) . unwrap ( ) ;
5281+ let best_block = self . best_block . read ( ) . unwrap ( ) ;
5282+ let scid_candidate = fake_scid:: get_phantom_scid ( self . fake_scid_offset , best_block. height ( ) , & self . genesis_hash , & self . keys_manager ) ;
5283+ // Ensure the generated scid doesn't conflict with a real channel.
5284+ match channel_state. short_to_id . entry ( scid_candidate) {
5285+ hash_map:: Entry :: Occupied ( _) => scid_candidate + 1 ,
5286+ hash_map:: Entry :: Vacant ( _) => scid_candidate
5287+ }
5288+ }
5289+
51055290 #[ cfg( any( test, feature = "fuzztarget" , feature = "_test_utils" ) ) ]
51065291 pub fn get_and_clear_pending_events ( & self ) -> Vec < events:: Event > {
51075292 let events = core:: cell:: RefCell :: new ( Vec :: new ( ) ) ;
@@ -6189,6 +6374,7 @@ impl<Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> Writeable f
61896374 write_tlv_fields ! ( writer, {
61906375 ( 1 , pending_outbound_payments_no_retry, required) ,
61916376 ( 3 , pending_outbound_payments, required) ,
6377+ ( 5 , self . fake_scid_offset, required) ,
61926378 } ) ;
61936379
61946380 Ok ( ( ) )
@@ -6483,10 +6669,16 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
64836669 // pending_outbound_payments_no_retry is for compatibility with 0.0.101 clients.
64846670 let mut pending_outbound_payments_no_retry: Option < HashMap < PaymentId , HashSet < [ u8 ; 32 ] > > > = None ;
64856671 let mut pending_outbound_payments = None ;
6672+ let mut fake_scid_offset: Option < u8 > = None ;
64866673 read_tlv_fields ! ( reader, {
64876674 ( 1 , pending_outbound_payments_no_retry, option) ,
64886675 ( 3 , pending_outbound_payments, option) ,
6676+ ( 5 , fake_scid_offset, option) ,
64896677 } ) ;
6678+ if fake_scid_offset. is_none ( ) {
6679+ fake_scid_offset = Some ( fake_scid:: get_new_offset ( & args. keys_manager ) ) ;
6680+ }
6681+
64906682 if pending_outbound_payments. is_none ( ) && pending_outbound_payments_no_retry. is_none ( ) {
64916683 pending_outbound_payments = Some ( pending_outbound_payments_compat) ;
64926684 } else if pending_outbound_payments. is_none ( ) {
@@ -6569,6 +6761,7 @@ impl<'a, Signer: Sign, M: Deref, T: Deref, K: Deref, F: Deref, L: Deref>
65696761 inbound_payment_key : expanded_inbound_key,
65706762 pending_inbound_payments : Mutex :: new ( pending_inbound_payments) ,
65716763 pending_outbound_payments : Mutex :: new ( pending_outbound_payments. unwrap ( ) ) ,
6764+ fake_scid_offset : fake_scid_offset. unwrap ( ) ,
65726765
65736766 our_network_key : args. keys_manager . get_node_secret ( ) ,
65746767 our_network_pubkey : PublicKey :: from_secret_key ( & secp_ctx, & args. keys_manager . get_node_secret ( ) ) ,
0 commit comments