+ self.inner.get_secure_random_bytes()
+ }
+}
+
+impl NodeSigner for PhantomKeysManager {
+ fn get_node_id(&self, recipient: Recipient) -> Result<PublicKey, ()> {
+ match recipient {
+ Recipient::Node => self.inner.get_node_id(Recipient::Node),
+ Recipient::PhantomNode => Ok(self.phantom_node_id.clone()),
+ }
+ }
+
+ fn ecdh(&self, recipient: Recipient, other_key: &PublicKey, tweak: Option<&Scalar>) -> Result<SharedSecret, ()> {
+ let mut node_secret = match recipient {
+ Recipient::Node => self.inner.node_secret.clone(),
+ Recipient::PhantomNode => self.phantom_secret.clone(),
+ };
+ if let Some(tweak) = tweak {
+ node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?;
+ }
+ Ok(SharedSecret::new(other_key, &node_secret))
+ }
+
+ fn get_inbound_payment_key_material(&self) -> KeyMaterial {
+ self.inbound_payment_key.clone()
+ }
+
+ fn sign_invoice(&self, hrp_bytes: &[u8], invoice_data: &[u5], recipient: Recipient) -> Result<RecoverableSignature, ()> {
+ let preimage = construct_invoice_preimage(&hrp_bytes, &invoice_data);
+ let secret = match recipient {
+ Recipient::Node => &self.inner.node_secret,
+ Recipient::PhantomNode => &self.phantom_secret,
+ };
+ Ok(self.inner.secp_ctx.sign_ecdsa_recoverable(&hash_to_message!(&Sha256::hash(&preimage)), secret))
+ }
+
+ fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()> {
+ self.inner.sign_gossip_message(msg)
+ }
+}
+
+impl SignerProvider for PhantomKeysManager {
+ type Signer = InMemorySigner;
+
+ fn generate_channel_keys_id(&self, inbound: bool, channel_value_satoshis: u64, user_channel_id: u128) -> [u8; 32] {
+ self.inner.generate_channel_keys_id(inbound, channel_value_satoshis, user_channel_id)
+ }
+
+ fn derive_channel_signer(&self, channel_value_satoshis: u64, channel_keys_id: [u8; 32]) -> Self::Signer {
+ self.inner.derive_channel_signer(channel_value_satoshis, channel_keys_id)
+ }
+
+ fn read_chan_signer(&self, reader: &[u8]) -> Result<Self::Signer, DecodeError> {
+ self.inner.read_chan_signer(reader)
+ }
+
+ fn get_destination_script(&self) -> Script {
+ self.inner.get_destination_script()
+ }
+
+ fn get_shutdown_scriptpubkey(&self) -> ShutdownScript {
+ self.inner.get_shutdown_scriptpubkey()
+ }
+}
+
+impl PhantomKeysManager {
+ /// Constructs a [`PhantomKeysManager`] given a 32-byte seed and an additional `cross_node_seed`
+ /// that is shared across all nodes that intend to participate in [phantom node payments]
+ /// together.
+ ///
+ /// See [`KeysManager::new`] for more information on `seed`, `starting_time_secs`, and
+ /// `starting_time_nanos`.
+ ///
+ /// `cross_node_seed` must be the same across all phantom payment-receiving nodes and also the
+ /// same across restarts, or else inbound payments may fail.
+ ///
+ /// [phantom node payments]: PhantomKeysManager
+ pub fn new(seed: &[u8; 32], starting_time_secs: u64, starting_time_nanos: u32, cross_node_seed: &[u8; 32]) -> Self {
+ let inner = KeysManager::new(seed, starting_time_secs, starting_time_nanos);
+ let (inbound_key, phantom_key) = hkdf_extract_expand_twice(b"LDK Inbound and Phantom Payment Key Expansion", cross_node_seed);
+ let phantom_secret = SecretKey::from_slice(&phantom_key).unwrap();
+ let phantom_node_id = PublicKey::from_secret_key(&inner.secp_ctx, &phantom_secret);
+ Self {
+ inner,
+ inbound_payment_key: KeyMaterial(inbound_key),
+ phantom_secret,
+ phantom_node_id,
+ }
+ }