1#![allow(missing_docs)]
2
3use bitcoin::bech32::u5;
4use bitcoin::hash_types::WPubkeyHash;
5use bitcoin::hashes::Hash;
6use bitcoin::secp256k1::ecdh::SharedSecret;
7use bitcoin::secp256k1::ecdsa::{RecoverableSignature, Signature};
8use bitcoin::secp256k1::{All, PublicKey, Scalar, Secp256k1, SecretKey};
9use bitcoin::{ScriptBuf, Transaction, TxOut};
10use lightning::ln::chan_utils::{
11 ChannelPublicKeys, ChannelTransactionParameters, ClosingTransaction, CommitmentTransaction,
12 HTLCOutputInCommitment, HolderCommitmentTransaction,
13};
14use lightning::ln::channel_keys::{DelayedPaymentKey, RevocationKey};
15use lightning::ln::features::ChannelTypeFeatures;
16use lightning::ln::msgs::{DecodeError, UnsignedChannelAnnouncement, UnsignedGossipMessage};
17use lightning::ln::script::ShutdownScript;
18use lightning::ln::{chan_utils, PaymentPreimage};
19use lightning::sign::ecdsa::{EcdsaChannelSigner, WriteableEcdsaChannelSigner};
20use lightning::sign::HTLCDescriptor;
21use lightning::sign::{
22 ChannelSigner, EntropySource, KeyMaterial, NodeSigner, Recipient, SignerProvider,
23 SpendableOutputDescriptor,
24};
25use lightning::util::ser::{Readable, Writeable, Writer};
26
27use log::{debug, error, info};
28
29use crate::channel::{ChannelBase, ChannelId, ChannelSetup, CommitmentType};
30use crate::invoice::Invoice;
31use crate::io_extras::Error as IOError;
32use crate::node::Node;
33use crate::prelude::*;
34use crate::signer::multi_signer::MultiSigner;
35use crate::tx::tx::HTLCInfo2;
36use crate::util::crypto_utils::derive_public_key;
37use crate::util::status::Status;
38use crate::util::INITIAL_COMMITMENT_NUMBER;
39use crate::Arc;
40
41use super::crypto_utils;
42
43pub struct LoopbackSignerKeysInterface {
45 pub node_id: PublicKey,
46 pub signer: Arc<MultiSigner>,
47}
48
49impl LoopbackSignerKeysInterface {
50 pub fn get_node(&self) -> Arc<Node> {
51 self.signer.get_node(&self.node_id).expect("our node is missing")
52 }
53
54 pub fn add_invoice(&self, invoice: Invoice) {
55 self.get_node().add_invoice(invoice).expect("could not add invoice");
56 }
57
58 pub fn spend_spendable_outputs(
59 &self,
60 descriptors: &[&SpendableOutputDescriptor],
61 outputs: Vec<TxOut>,
62 change_destination_script: ScriptBuf,
63 feerate_sat_per_1000_weight: u32,
64 ) -> Result<Transaction, ()> {
65 self.get_node().spend_spendable_outputs(
66 descriptors,
67 outputs,
68 change_destination_script,
69 feerate_sat_per_1000_weight,
70 )
71 }
72
73 fn get_node_secret(&self, recipient: Recipient) -> Result<SecretKey, ()> {
74 match recipient {
75 Recipient::Node => Ok(self.get_node().get_node_secret()),
76 Recipient::PhantomNode => Err(()),
77 }
78 }
79}
80
81#[derive(Clone)]
82pub struct LoopbackChannelSigner {
83 pub node_id: PublicKey,
84 pub channel_id: ChannelId,
85 pub signer: Arc<MultiSigner>,
86 pub pubkeys: ChannelPublicKeys,
87 pub channel_value_sat: u64,
88}
89
90impl LoopbackChannelSigner {
91 fn new(
92 node_id: &PublicKey,
93 channel_id: &ChannelId,
94 signer: Arc<MultiSigner>,
95 channel_value_sat: u64,
96 ) -> LoopbackChannelSigner {
97 info!("new channel {:?} {:?}", node_id, channel_id);
98 let pubkeys = signer
99 .with_channel_base(&node_id, &channel_id, |base| Ok(base.get_channel_basepoints()))
100 .map_err(|s| {
101 error!("bad status {:?} on channel {}", s, channel_id);
102 ()
103 })
104 .expect("must be able to get basepoints");
105 LoopbackChannelSigner {
106 node_id: *node_id,
107 channel_id: channel_id.clone(),
108 signer: signer.clone(),
109 pubkeys,
110 channel_value_sat,
111 }
112 }
113
114 fn get_channel_setup(&self) -> Result<ChannelSetup, ()> {
115 self.signer
116 .with_channel(&self.node_id, &self.channel_id, |chan| Ok(chan.setup.clone()))
117 .map_err(|s| self.bad_status(s))
118 }
119
120 fn bad_status(&self, s: Status) {
121 error!("bad status {:?} on channel {}", s, self.channel_id);
122 }
123
124 fn convert_to_htlc_info2(htlcs: &[HTLCOutputInCommitment]) -> (Vec<HTLCInfo2>, Vec<HTLCInfo2>) {
125 let mut offered_htlcs = Vec::new();
126 let mut received_htlcs = Vec::new();
127 for htlc in htlcs {
128 let htlc_info = HTLCInfo2 {
129 value_sat: htlc.amount_msat / 1000,
130 payment_hash: htlc.payment_hash,
131 cltv_expiry: htlc.cltv_expiry,
132 };
133 if htlc.offered {
134 offered_htlcs.push(htlc_info);
135 } else {
136 received_htlcs.push(htlc_info);
137 }
138 }
139 (offered_htlcs, received_htlcs)
140 }
141
142 fn dest_wallet_path() -> Vec<u32> {
143 vec![1]
144 }
145
146 fn features(&self) -> ChannelTypeFeatures {
147 let setup = self.get_channel_setup().expect("not ready");
148 setup.features()
149 }
150}
151
152impl Writeable for LoopbackChannelSigner {
153 fn write<W: Writer>(&self, writer: &mut W) -> Result<(), IOError> {
154 self.channel_id.inner().write(writer)?;
155 self.channel_value_sat.write(writer)?;
156 Ok(())
157 }
158}
159
160impl ChannelSigner for LoopbackChannelSigner {
161 fn validate_counterparty_revocation(&self, idx: u64, secret: &SecretKey) -> Result<(), ()> {
162 let forward_idx = INITIAL_COMMITMENT_NUMBER - idx;
163 self.signer
164 .with_channel(&self.node_id, &self.channel_id, |chan| {
165 chan.validate_counterparty_revocation(forward_idx, secret)
166 })
167 .map_err(|s| self.bad_status(s))?;
168
169 Ok(())
170 }
171
172 fn get_per_commitment_point(&self, idx: u64, _secp_ctx: &Secp256k1<All>) -> PublicKey {
173 self.signer
176 .with_channel_base(&self.node_id, &self.channel_id, |base| {
177 Ok(base.get_per_commitment_point(INITIAL_COMMITMENT_NUMBER - idx).unwrap())
178 })
179 .map_err(|s| self.bad_status(s))
180 .unwrap()
181 }
182
183 fn release_commitment_secret(&self, commitment_number: u64) -> [u8; 32] {
184 let secret = self.signer.with_channel(&self.node_id, &self.channel_id, |chan| {
187 let secret = chan
188 .get_per_commitment_secret(INITIAL_COMMITMENT_NUMBER - commitment_number)
189 .unwrap();
190 Ok(*secret.as_ref())
191 });
192 secret.expect("missing channel")
193 }
194
195 fn validate_holder_commitment(
196 &self,
197 holder_tx: &HolderCommitmentTransaction,
198 preimages: Vec<PaymentPreimage>,
199 ) -> Result<(), ()> {
200 let commitment_number = INITIAL_COMMITMENT_NUMBER - holder_tx.commitment_number();
201
202 self.signer
203 .with_channel(&self.node_id, &self.channel_id, |chan| {
204 chan.htlcs_fulfilled(preimages);
205 let (offered_htlcs, received_htlcs) =
206 LoopbackChannelSigner::convert_to_htlc_info2(holder_tx.htlcs());
207 chan.validate_holder_commitment_tx_phase2(
208 commitment_number,
209 holder_tx.feerate_per_kw(),
210 holder_tx.to_broadcaster_value_sat(),
211 holder_tx.to_countersignatory_value_sat(),
212 offered_htlcs,
213 received_htlcs,
214 &holder_tx.counterparty_sig,
215 &holder_tx.counterparty_htlc_sigs,
216 )?;
217 chan.revoke_previous_holder_commitment(commitment_number)?;
218 Ok(())
219 })
220 .map_err(|s| self.bad_status(s))?;
221
222 Ok(())
223 }
224
225 fn pubkeys(&self) -> &ChannelPublicKeys {
226 &self.pubkeys
227 }
228
229 fn channel_keys_id(&self) -> [u8; 32] {
230 self.signer
231 .with_channel(&self.node_id, &self.channel_id, |chan| Ok(chan.keys.channel_keys_id()))
232 .expect("missing channel")
233 }
234
235 fn provide_channel_parameters(&mut self, parameters: &ChannelTransactionParameters) {
236 info!("set_remote_channel_pubkeys {:?} {:?}", self.node_id, self.channel_id);
237
238 let funding_outpoint = parameters.funding_outpoint.unwrap().into_bitcoin_outpoint();
240 let counterparty_parameters = parameters.counterparty_parameters.as_ref().unwrap();
241 let setup = ChannelSetup {
242 is_outbound: parameters.is_outbound_from_holder,
243 channel_value_sat: self.channel_value_sat,
244 push_value_msat: 0, funding_outpoint,
246 holder_selected_contest_delay: parameters.holder_selected_contest_delay,
247 holder_shutdown_script: None, counterparty_points: counterparty_parameters.pubkeys.clone(),
249 counterparty_selected_contest_delay: counterparty_parameters.selected_contest_delay,
250 counterparty_shutdown_script: None, commitment_type: CommitmentType::StaticRemoteKey, };
253 let node = self.signer.get_node(&self.node_id).expect("no such node");
254
255 let holder_shutdown_key_path = vec![];
256 node.setup_channel(self.channel_id.clone(), None, setup, &holder_shutdown_key_path)
257 .expect("channel already ready or does not exist");
258 }
259}
260
261impl EcdsaChannelSigner for LoopbackChannelSigner {
262 fn sign_counterparty_commitment(
264 &self,
265 commitment_tx: &CommitmentTransaction,
266 inbound_htlc_preimages: Vec<PaymentPreimage>,
267 outbound_htlc_preimages: Vec<PaymentPreimage>,
268 _secp_ctx: &Secp256k1<All>,
269 ) -> Result<(Signature, Vec<Signature>), ()> {
270 let trusted_tx = commitment_tx.trust();
271 info!(
272 "sign_counterparty_commitment {:?} {:?} txid {}",
273 self.node_id,
274 self.channel_id,
275 trusted_tx.built_transaction().txid,
276 );
277
278 let (offered_htlcs, received_htlcs) =
279 LoopbackChannelSigner::convert_to_htlc_info2(commitment_tx.htlcs());
280
281 let per_commitment_point = trusted_tx.keys().per_commitment_point;
283
284 let commitment_number = INITIAL_COMMITMENT_NUMBER - commitment_tx.commitment_number();
285 let to_holder_value_sat = commitment_tx.to_countersignatory_value_sat();
286 let to_counterparty_value_sat = commitment_tx.to_broadcaster_value_sat();
287 let feerate_per_kw = commitment_tx.feerate_per_kw();
288
289 let (commitment_sig, htlc_sigs) = self
290 .signer
291 .with_channel(&self.node_id, &self.channel_id, |chan| {
292 chan.htlcs_fulfilled(inbound_htlc_preimages);
293 chan.htlcs_fulfilled(outbound_htlc_preimages);
294 chan.sign_counterparty_commitment_tx_phase2(
295 &per_commitment_point,
296 commitment_number,
297 feerate_per_kw,
298 to_holder_value_sat,
299 to_counterparty_value_sat,
300 offered_htlcs,
301 received_htlcs,
302 )
303 })
304 .map_err(|s| self.bad_status(s))?;
305 Ok((commitment_sig, htlc_sigs))
306 }
307
308 fn sign_holder_commitment(
309 &self,
310 hct: &HolderCommitmentTransaction,
311 _secp_ctx: &Secp256k1<All>,
312 ) -> Result<Signature, ()> {
313 let commitment_tx = hct.trust();
314
315 debug!("loopback: sign local txid {}", commitment_tx.built_transaction().txid);
316
317 let commitment_number = INITIAL_COMMITMENT_NUMBER - hct.commitment_number();
318 let to_holder_value_sat = hct.to_broadcaster_value_sat();
319 let to_counterparty_value_sat = hct.to_countersignatory_value_sat();
320 let feerate_per_kw = hct.feerate_per_kw();
321 let (offered_htlcs, received_htlcs) =
322 LoopbackChannelSigner::convert_to_htlc_info2(hct.htlcs());
323
324 let sig = self
325 .signer
326 .with_channel(&self.node_id, &self.channel_id, |chan| {
327 let result = chan.sign_holder_commitment_tx_phase2_redundant(
328 commitment_number,
329 feerate_per_kw,
330 to_holder_value_sat,
331 to_counterparty_value_sat,
332 offered_htlcs.clone(),
333 received_htlcs.clone(),
334 )?;
335 Ok(result)
336 })
337 .map_err(|s| self.bad_status(s))?;
338
339 Ok(sig)
340 }
341
342 fn unsafe_sign_holder_commitment(
343 &self,
344 hct: &HolderCommitmentTransaction,
345 secp_ctx: &Secp256k1<All>,
346 ) -> Result<Signature, ()> {
347 let signature = self
348 .signer
349 .with_channel(&self.node_id, &self.channel_id, |chan| {
350 chan.keys
351 .unsafe_sign_holder_commitment(hct, secp_ctx)
352 .map_err(|_| Status::internal("could not unsafe-sign"))
353 })
354 .map_err(|_s| ())?;
355 Ok(signature)
356 }
357
358 fn sign_justice_revoked_output(
359 &self,
360 justice_tx: &Transaction,
361 input: usize,
362 amount: u64,
363 per_commitment_key: &SecretKey,
364 secp_ctx: &Secp256k1<All>,
365 ) -> Result<Signature, ()> {
366 let per_commitment_point = PublicKey::from_secret_key(secp_ctx, per_commitment_key);
367 let setup = self.get_channel_setup()?;
368 let counterparty_pubkeys = setup.counterparty_points;
369
370 let (revocation_key, delayed_payment_key) = get_delayed_payment_keys(
371 secp_ctx,
372 &per_commitment_point,
373 &counterparty_pubkeys,
374 &self.pubkeys,
375 )?;
376 let redeem_script = chan_utils::get_revokeable_redeemscript(
377 &RevocationKey(revocation_key),
378 setup.holder_selected_contest_delay,
379 &DelayedPaymentKey(delayed_payment_key),
380 );
381
382 let wallet_path = LoopbackChannelSigner::dest_wallet_path();
383
384 let sig = self
386 .signer
387 .with_channel(&self.node_id, &self.channel_id, |chan| {
388 chan.sign_justice_sweep(
389 justice_tx,
390 input,
391 per_commitment_key,
392 &redeem_script,
393 amount,
394 &wallet_path,
395 )
396 })
397 .map_err(|s| self.bad_status(s))?;
398
399 Ok(sig)
400 }
401
402 fn sign_justice_revoked_htlc(
403 &self,
404 justice_tx: &Transaction,
405 input: usize,
406 amount: u64,
407 per_commitment_key: &SecretKey,
408 htlc: &HTLCOutputInCommitment,
409 secp_ctx: &Secp256k1<All>,
410 ) -> Result<Signature, ()> {
411 let per_commitment_point = PublicKey::from_secret_key(secp_ctx, per_commitment_key);
412 let wallet_path = LoopbackChannelSigner::dest_wallet_path();
413
414 let sig = self
416 .signer
417 .with_channel(&self.node_id, &self.channel_id, |chan| {
418 let tx_keys = chan.make_counterparty_tx_keys(&per_commitment_point);
419 let redeem_script =
420 chan_utils::get_htlc_redeemscript(&htlc, &self.features(), &tx_keys);
421 chan.sign_justice_sweep(
422 justice_tx,
423 input,
424 per_commitment_key,
425 &redeem_script,
426 amount,
427 &wallet_path,
428 )
429 })
430 .map_err(|s| self.bad_status(s))?;
431
432 Ok(sig)
433 }
434
435 fn sign_holder_htlc_transaction(
436 &self,
437 htlc_tx: &Transaction,
438 _input: usize,
439 htlc_descriptor: &HTLCDescriptor,
440 secp_ctx: &Secp256k1<All>,
441 ) -> Result<Signature, ()> {
442 let signature = self
443 .signer
444 .with_channel(&self.node_id, &self.channel_id, |channel| {
445 let per_commitment_point = &htlc_descriptor.per_commitment_point;
446 let chan_keys = channel.make_holder_tx_keys(per_commitment_point);
447 let witness_script = htlc_descriptor.witness_script(secp_ctx);
448 let redeem_script = chan_utils::get_htlc_redeemscript(
449 &htlc_descriptor.htlc,
450 &self.features(),
451 &chan_keys,
452 );
453 channel.sign_htlc_tx(
455 htlc_tx,
456 per_commitment_point,
457 &redeem_script,
458 htlc_descriptor.htlc.amount_msat / 1000,
459 &witness_script,
460 false,
461 chan_keys.clone(),
462 )
463 })
464 .expect("sign_htlc_tx");
465 Ok(signature.sig)
466 }
467
468 fn sign_counterparty_htlc_transaction(
469 &self,
470 htlc_tx: &Transaction,
471 input: usize,
472 amount: u64,
473 per_commitment_point: &PublicKey,
474 htlc: &HTLCOutputInCommitment,
475 _secp_ctx: &Secp256k1<All>,
476 ) -> Result<Signature, ()> {
477 let wallet_path = LoopbackChannelSigner::dest_wallet_path();
478
479 let sig = self
481 .signer
482 .with_channel(&self.node_id, &self.channel_id, |chan| {
483 let chan_keys = chan.make_counterparty_tx_keys(per_commitment_point);
484 let redeem_script =
485 chan_utils::get_htlc_redeemscript(htlc, &self.features(), &chan_keys);
486 chan.sign_counterparty_htlc_sweep(
487 htlc_tx,
488 input,
489 per_commitment_point,
490 &redeem_script,
491 amount,
492 &wallet_path,
493 )
494 })
495 .map_err(|s| self.bad_status(s))?;
496
497 Ok(sig)
498 }
499
500 fn sign_closing_transaction(
502 &self,
503 closing_tx: &ClosingTransaction,
504 _secp_ctx: &Secp256k1<All>,
505 ) -> Result<Signature, ()> {
506 info!("sign_closing_transaction {:?} {:?}", self.node_id, self.channel_id);
507
508 self.signer
510 .with_channel(&self.node_id, &self.channel_id, |chan| {
511 let holder_wallet_path_hint = vec![2];
513
514 chan.sign_mutual_close_tx_phase2(
515 closing_tx.to_holder_value_sat(),
516 closing_tx.to_counterparty_value_sat(),
517 &Some(closing_tx.to_holder_script().into()),
518 &Some(closing_tx.to_counterparty_script().into()),
519 &holder_wallet_path_hint,
520 )
521 })
522 .map_err(|_| ())
523 }
524
525 fn sign_holder_anchor_input(
526 &self,
527 _anchor_tx: &Transaction,
528 _input: usize,
529 _secp_ctx: &Secp256k1<All>,
530 ) -> Result<Signature, ()> {
531 todo!()
532 }
533
534 fn sign_channel_announcement_with_funding_key(
535 &self,
536 msg: &UnsignedChannelAnnouncement,
537 _secp_ctx: &Secp256k1<All>,
538 ) -> Result<Signature, ()> {
539 info!("sign_counterparty_commitment {:?} {:?}", self.node_id, self.channel_id);
540
541 self.signer
542 .with_channel(&self.node_id, &self.channel_id, |chan| {
543 Ok(chan.sign_channel_announcement_with_funding_key(&msg.encode()))
544 })
545 .map_err(|s| self.bad_status(s))
546 }
547}
548
549impl WriteableEcdsaChannelSigner for LoopbackChannelSigner {}
550
551impl SignerProvider for LoopbackSignerKeysInterface {
552 type EcdsaSigner = LoopbackChannelSigner;
553
554 fn get_destination_script(&self, _channel_keys_id: [u8; 32]) -> Result<ScriptBuf, ()> {
556 let wallet_path = LoopbackChannelSigner::dest_wallet_path();
557 let pubkey = self.get_node().get_wallet_pubkey(&wallet_path).expect("pubkey");
558 Ok(ScriptBuf::new_v0_p2wpkh(&WPubkeyHash::hash(&pubkey.inner.serialize())))
559 }
560
561 fn get_shutdown_scriptpubkey(&self) -> Result<ShutdownScript, ()> {
562 Ok(self.get_node().get_ldk_shutdown_scriptpubkey())
564 }
565
566 fn generate_channel_keys_id(
567 &self,
568 _inbound: bool,
569 _channel_value_satoshis: u64,
570 _user_channel_id: u128,
571 ) -> [u8; 32] {
572 let node = self.signer.get_node(&self.node_id).unwrap();
573 let (channel_id, _) = node.new_channel_with_random_id(&node).unwrap();
574 channel_id.ldk_channel_keys_id()
575 }
576
577 fn derive_channel_signer(
578 &self,
579 channel_value_satoshis: u64,
580 channel_keys_id: [u8; 32],
581 ) -> Self::EcdsaSigner {
582 let channel_id = ChannelId::new(&channel_keys_id);
583 LoopbackChannelSigner::new(
584 &self.node_id,
585 &channel_id,
586 Arc::clone(&self.signer),
587 channel_value_satoshis,
588 )
589 }
590
591 fn read_chan_signer(&self, mut reader: &[u8]) -> Result<Self::EcdsaSigner, DecodeError> {
592 let channel_id = ChannelId::new(&Vec::read(&mut reader)?);
593 let channel_value_sat = Readable::read(&mut reader)?;
594 Ok(LoopbackChannelSigner::new(
595 &self.node_id,
596 &channel_id,
597 Arc::clone(&self.signer),
598 channel_value_sat,
599 ))
600 }
601}
602
603impl EntropySource for LoopbackSignerKeysInterface {
604 fn get_secure_random_bytes(&self) -> [u8; 32] {
605 self.get_node().get_secure_random_bytes()
606 }
607}
608
609impl NodeSigner for LoopbackSignerKeysInterface {
610 fn get_node_id(&self, recipient: Recipient) -> Result<PublicKey, ()> {
611 let node_secret = self.get_node_secret(recipient)?;
612
613 Ok(PublicKey::from_secret_key(&Secp256k1::signing_only(), &node_secret))
614 }
615
616 fn sign_gossip_message(&self, msg: UnsignedGossipMessage) -> Result<Signature, ()> {
617 let node = self.get_node();
618 let sig = node.sign_gossip_message(&msg).expect("sign_gossip_message");
619 Ok(sig)
620 }
621
622 fn ecdh(
623 &self,
624 recipient: Recipient,
625 other_key: &PublicKey,
626 tweak: Option<&Scalar>,
627 ) -> Result<SharedSecret, ()> {
628 let mut node_secret = self.get_node_secret(recipient)?;
629 if let Some(tweak) = tweak {
630 node_secret = node_secret.mul_tweak(tweak).map_err(|_| ())?;
631 }
632 Ok(SharedSecret::new(other_key, &node_secret))
633 }
634
635 fn sign_invoice(
636 &self,
637 hrp_bytes: &[u8],
638 invoice_data: &[u5],
639 recipient: Recipient,
640 ) -> Result<RecoverableSignature, ()> {
641 match recipient {
642 Recipient::Node => {}
643 Recipient::PhantomNode => return Err(()),
644 };
645 self.get_node().sign_invoice(hrp_bytes, invoice_data).map_err(|_| ())
646 }
647
648 fn sign_bolt12_invoice(
649 &self,
650 _: &lightning::offers::invoice::UnsignedBolt12Invoice,
651 ) -> Result<bitcoin::secp256k1::schnorr::Signature, ()> {
652 todo!()
653 }
654
655 fn sign_bolt12_invoice_request(
656 &self,
657 _: &lightning::offers::invoice_request::UnsignedInvoiceRequest,
658 ) -> Result<bitcoin::secp256k1::schnorr::Signature, ()> {
659 todo!()
660 }
661
662 fn get_inbound_payment_key_material(&self) -> KeyMaterial {
663 self.get_node().get_inbound_payment_key_material()
664 }
665}
666
667fn get_delayed_payment_keys(
668 secp_ctx: &Secp256k1<All>,
669 per_commitment_point: &PublicKey,
670 a_pubkeys: &ChannelPublicKeys,
671 b_pubkeys: &ChannelPublicKeys,
672) -> Result<(PublicKey, PublicKey), ()> {
673 let revocation_key = crypto_utils::derive_public_revocation_key(
674 secp_ctx,
675 &per_commitment_point,
676 &b_pubkeys.revocation_basepoint,
677 )?;
678 let delayed_payment_key =
679 derive_public_key(secp_ctx, &per_commitment_point, &a_pubkeys.delayed_payment_basepoint.0)
680 .map_err(|_| ())?;
681 Ok((revocation_key.0, delayed_payment_key))
682}