Fix scid_utils::is_valid* false positive
authorValentine Wallace <vwallace@protonmail.com>
Mon, 7 Nov 2022 22:29:23 +0000 (17:29 -0500)
committerValentine Wallace <vwallace@protonmail.com>
Tue, 8 Nov 2022 21:02:07 +0000 (16:02 -0500)
cargo bench was able to find an scid of 0 as a valid fake scid

lightning/src/ln/channelmanager.rs
lightning/src/util/scid_utils.rs

index c28ca5cf39d1baa3506d57af365479b4b5066e3e..ba3729207077474ec711ac2caa7647881155dd99 100644 (file)
@@ -2313,7 +2313,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
                                                None => { // unknown_next_peer
                                                        // Note that this is likely a timing oracle for detecting whether an scid is a
                                                        // phantom.
-                                                       if fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id) {
+                                                       if fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, *short_channel_id, &self.genesis_hash) {
                                                                None
                                                        } else {
                                                                break Some(("Don't have available channel for forwarding as requested.", 0x4000 | 10, None));
@@ -3202,7 +3202,7 @@ impl<M: Deref, T: Deref, K: Deref, F: Deref, L: Deref> ChannelManager<M, T, K, F
                                                                                }
                                                                                if let PendingHTLCRouting::Forward { onion_packet, .. } = routing {
                                                                                        let phantom_secret_res = self.keys_manager.get_node_secret(Recipient::PhantomNode);
-                                                                                       if phantom_secret_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id) {
+                                                                                       if phantom_secret_res.is_ok() && fake_scid::is_valid_phantom(&self.fake_scid_rand_bytes, short_chan_id, &self.genesis_hash) {
                                                                                                let phantom_shared_secret = SharedSecret::new(&onion_packet.public_key.unwrap(), &phantom_secret_res.unwrap()).secret_bytes();
                                                                                                let next_hop = match onion_utils::decode_next_payment_hop(phantom_shared_secret, &onion_packet.hop_data, onion_packet.hmac, payment_hash) {
                                                                                                        Ok(res) => res,
index b851cca81aa06150327bcd5b1c45cc2238c54fd9..c3529a6cbd229aa0a35eddd65a0187faf8a10ac6 100644 (file)
@@ -73,7 +73,7 @@ pub(crate) mod fake_scid {
        use core::convert::TryInto;
        use core::ops::Deref;
 
-       const TEST_SEGWIT_ACTIVATION_HEIGHT: u32 = 0;
+       const TEST_SEGWIT_ACTIVATION_HEIGHT: u32 = 1;
        const MAINNET_SEGWIT_ACTIVATION_HEIGHT: u32 = 481_824;
        const MAX_TX_INDEX: u32 = 2_500;
        const MAX_NAMESPACES: u8 = 8; // We allocate 3 bits for the namespace identifier.
@@ -151,12 +151,13 @@ pub(crate) mod fake_scid {
        }
 
        /// Returns whether the given fake scid falls into the given namespace.
-       pub fn is_valid_phantom(fake_scid_rand_bytes: &[u8; 32], scid: u64) -> bool {
+       pub fn is_valid_phantom(fake_scid_rand_bytes: &[u8; 32], scid: u64, genesis_hash: &BlockHash) -> bool {
                let block_height = scid_utils::block_from_scid(&scid);
                let tx_index = scid_utils::tx_index_from_scid(&scid);
                let namespace = Namespace::Phantom;
                let valid_vout = namespace.get_encrypted_vout(block_height, tx_index, fake_scid_rand_bytes);
-               valid_vout == scid_utils::vout_from_scid(&scid) as u8
+               block_height >= segwit_activation_height(genesis_hash)
+                       && valid_vout == scid_utils::vout_from_scid(&scid) as u8
        }
 
        #[cfg(test)]
@@ -194,11 +195,12 @@ pub(crate) mod fake_scid {
                fn test_is_valid_phantom() {
                        let namespace = Namespace::Phantom;
                        let fake_scid_rand_bytes = [0; 32];
+                       let testnet_genesis = genesis_block(Network::Testnet).header.block_hash();
                        let valid_encrypted_vout = namespace.get_encrypted_vout(0, 0, &fake_scid_rand_bytes);
-                       let valid_fake_scid = scid_utils::scid_from_parts(0, 0, valid_encrypted_vout as u64).unwrap();
-                       assert!(is_valid_phantom(&fake_scid_rand_bytes, valid_fake_scid));
-                       let invalid_fake_scid = scid_utils::scid_from_parts(0, 0, 12).unwrap();
-                       assert!(!is_valid_phantom(&fake_scid_rand_bytes, invalid_fake_scid));
+                       let valid_fake_scid = scid_utils::scid_from_parts(1, 0, valid_encrypted_vout as u64).unwrap();
+                       assert!(is_valid_phantom(&fake_scid_rand_bytes, valid_fake_scid, &testnet_genesis));
+                       let invalid_fake_scid = scid_utils::scid_from_parts(1, 0, 12).unwrap();
+                       assert!(!is_valid_phantom(&fake_scid_rand_bytes, invalid_fake_scid, &testnet_genesis));
                }
 
                #[test]