1use super::msgs::OnionErrorPacket;
13use crate::blinded_path::BlindedHop;
14use crate::crypto::streams::ChaChaReader;
15use crate::events::HTLCHandlingFailureReason;
16use crate::ln::channel::TOTAL_BITCOIN_SUPPLY_SATOSHIS;
17use crate::ln::channelmanager::HTLCSource;
18use crate::ln::msgs::{self, DecodeError, InboundOnionDummyPayload, OnionPacket, UpdateAddHTLC};
19use crate::ln::onion_payment::{HopConnector, NextPacketDetails};
20use crate::ln::outbound_payment::RecipientOnionFields;
21use crate::offers::invoice_request::InvoiceRequest;
22use crate::routing::gossip::NetworkUpdate;
23use crate::routing::router::{BlindedTail, Path, RouteHop, RouteParameters, TrampolineHop};
24use crate::sign::{NodeSigner, Recipient};
25use crate::types::features::{ChannelFeatures, NodeFeatures};
26use crate::types::payment::{PaymentHash, PaymentPreimage};
27use crate::util::errors::APIError;
28use crate::util::logger::Logger;
29use crate::util::ser::{
30 LengthCalculatingWriter, Readable, ReadableArgs, VecWriter, Writeable, Writer,
31};
32
33use bitcoin::hashes::cmp::fixed_time_eq;
34use bitcoin::hashes::hmac::{Hmac, HmacEngine};
35use bitcoin::hashes::sha256::Hash as Sha256;
36use bitcoin::hashes::{Hash, HashEngine};
37
38use bitcoin::secp256k1;
39use bitcoin::secp256k1::ecdh::SharedSecret;
40use bitcoin::secp256k1::{PublicKey, Scalar, Secp256k1, SecretKey};
41
42use chacha20_poly1305::chacha20::{ChaCha20, Key, Nonce};
43
44use crate::io::{Cursor, Read};
45
46#[allow(unused_imports)]
47use crate::prelude::*;
48
49const DEFAULT_MIN_FAILURE_PACKET_LEN: usize = 256;
50
51pub(crate) const HOLD_TIME_UNIT_MILLIS: u128 = 100;
53
54pub(crate) struct OnionKeys {
55 #[cfg(test)]
56 pub(crate) shared_secret: SharedSecret,
57 #[cfg(test)]
58 pub(crate) blinding_factor: [u8; 32],
59 pub(crate) ephemeral_pubkey: PublicKey,
60 pub(crate) rho: [u8; 32],
61 pub(crate) mu: [u8; 32],
62}
63
64#[inline]
65pub(crate) fn gen_rho_from_shared_secret(shared_secret: &[u8]) -> [u8; 32] {
66 assert_eq!(shared_secret.len(), 32);
67 let mut hmac = HmacEngine::<Sha256>::new(b"rho");
68 hmac.input(&shared_secret);
69 Hmac::from_engine(hmac).to_byte_array()
70}
71
72#[inline]
73pub(crate) fn gen_rho_mu_from_shared_secret(shared_secret: &[u8]) -> ([u8; 32], [u8; 32]) {
74 assert_eq!(shared_secret.len(), 32);
75 let mut engine_rho = HmacEngine::<Sha256>::new(b"rho");
76 engine_rho.input(&shared_secret);
77 let hmac_rho = Hmac::from_engine(engine_rho).to_byte_array();
78
79 let mut engine_mu = HmacEngine::<Sha256>::new(b"mu");
80 engine_mu.input(&shared_secret);
81 let hmac_mu = Hmac::from_engine(engine_mu).to_byte_array();
82
83 (hmac_rho, hmac_mu)
84}
85
86#[inline]
87pub(super) fn gen_um_from_shared_secret(shared_secret: &[u8]) -> [u8; 32] {
88 assert_eq!(shared_secret.len(), 32);
89 let mut hmac = HmacEngine::<Sha256>::new(b"um");
90 hmac.input(&shared_secret);
91 Hmac::from_engine(hmac).to_byte_array()
92}
93
94#[inline]
95pub(super) fn gen_ammag_from_shared_secret(shared_secret: &[u8]) -> [u8; 32] {
96 assert_eq!(shared_secret.len(), 32);
97 let mut hmac = HmacEngine::<Sha256>::new(b"ammag");
98 hmac.input(&shared_secret);
99 Hmac::from_engine(hmac).to_byte_array()
100}
101
102#[inline]
103pub(super) fn gen_ammagext_from_shared_secret(shared_secret: &[u8]) -> [u8; 32] {
104 assert_eq!(shared_secret.len(), 32);
105 let mut hmac = HmacEngine::<Sha256>::new(b"ammagext");
106 hmac.input(&shared_secret);
107 Hmac::from_engine(hmac).to_byte_array()
108}
109
110#[cfg(test)]
111#[inline]
112pub(super) fn gen_pad_from_shared_secret(shared_secret: &[u8]) -> [u8; 32] {
113 assert_eq!(shared_secret.len(), 32);
114 let mut hmac = HmacEngine::<Sha256>::new(b"pad");
115 hmac.input(&shared_secret);
116 Hmac::from_engine(hmac).to_byte_array()
117}
118
119pub(crate) fn next_hop_pubkey<T: secp256k1::Verification>(
121 secp_ctx: &Secp256k1<T>, curr_pubkey: PublicKey, shared_secret: &[u8],
122) -> Result<PublicKey, secp256k1::Error> {
123 let blinding_factor = {
124 let mut sha = Sha256::engine();
125 sha.input(&curr_pubkey.serialize()[..]);
126 sha.input(shared_secret);
127 Sha256::from_engine(sha).to_byte_array()
128 };
129
130 curr_pubkey.mul_tweak(secp_ctx, &Scalar::from_be_bytes(blinding_factor).unwrap())
131}
132
133trait HopInfo {
134 fn node_pubkey(&self) -> &PublicKey;
135}
136
137trait PathHop {
138 type HopId;
139 fn hop_id(&self) -> Self::HopId;
140 fn fee_msat(&self) -> u64;
141 fn cltv_expiry_delta(&self) -> u32;
142}
143
144impl HopInfo for RouteHop {
145 fn node_pubkey(&self) -> &PublicKey {
146 &self.pubkey
147 }
148}
149
150impl<'a> PathHop for &'a RouteHop {
151 type HopId = u64; fn hop_id(&self) -> Self::HopId {
154 self.short_channel_id
155 }
156
157 fn fee_msat(&self) -> u64 {
158 self.fee_msat
159 }
160
161 fn cltv_expiry_delta(&self) -> u32 {
162 self.cltv_expiry_delta
163 }
164}
165
166impl HopInfo for TrampolineHop {
167 fn node_pubkey(&self) -> &PublicKey {
168 &self.pubkey
169 }
170}
171
172impl<'a> PathHop for &'a TrampolineHop {
173 type HopId = PublicKey;
174
175 fn hop_id(&self) -> Self::HopId {
176 self.pubkey
177 }
178
179 fn fee_msat(&self) -> u64 {
180 self.fee_msat
181 }
182
183 fn cltv_expiry_delta(&self) -> u32 {
184 self.cltv_expiry_delta
185 }
186}
187
188trait OnionPayload<'a, 'b> {
189 type PathHopForId: PathHop + 'b;
190 type ReceiveType: OnionPayload<'a, 'b>;
191 fn new_forward(
192 hop_id: <<Self as OnionPayload<'a, 'b>>::PathHopForId as PathHop>::HopId,
193 amt_to_forward: u64, outgoing_cltv_value: u32,
194 ) -> Self;
195 fn new_receive(
196 recipient_onion: &'a RecipientOnionFields, keysend_preimage: Option<PaymentPreimage>,
197 sender_intended_htlc_amt_msat: u64, cltv_expiry_height: u32,
198 ) -> Result<Self::ReceiveType, APIError>;
199 fn new_blinded_forward(
200 encrypted_tlvs: &'a Vec<u8>, intro_node_blinding_point: Option<PublicKey>,
201 ) -> Self;
202 fn new_blinded_receive(
203 sender_intended_htlc_amt_msat: u64, total_msat: u64, cltv_expiry_height: u32,
204 encrypted_tlvs: &'a Vec<u8>, intro_node_blinding_point: Option<PublicKey>,
205 keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<&'a InvoiceRequest>,
206 custom_tlvs: &'a Vec<(u64, Vec<u8>)>,
207 ) -> Self;
208 fn new_trampoline_entry(
209 amt_to_forward: u64, outgoing_cltv_value: u32, recipient_onion: &'a RecipientOnionFields,
210 packet: msgs::TrampolineOnionPacket,
211 ) -> Result<Self::ReceiveType, APIError>;
212}
213impl<'a, 'b> OnionPayload<'a, 'b> for msgs::OutboundOnionPayload<'a> {
214 type PathHopForId = &'b RouteHop;
215 type ReceiveType = msgs::OutboundOnionPayload<'a>;
216 fn new_forward(short_channel_id: u64, amt_to_forward: u64, outgoing_cltv_value: u32) -> Self {
217 Self::Forward { short_channel_id, amt_to_forward, outgoing_cltv_value }
218 }
219 fn new_receive(
220 recipient_onion: &'a RecipientOnionFields, keysend_preimage: Option<PaymentPreimage>,
221 sender_intended_htlc_amt_msat: u64, cltv_expiry_height: u32,
222 ) -> Result<Self::ReceiveType, APIError> {
223 Ok(Self::Receive {
224 payment_data: recipient_onion.payment_secret.map(|payment_secret| {
225 msgs::FinalOnionHopData {
226 payment_secret,
227 total_msat: recipient_onion.total_mpp_amount_msat,
228 }
229 }),
230 payment_metadata: recipient_onion.payment_metadata.as_ref(),
231 keysend_preimage,
232 custom_tlvs: &recipient_onion.custom_tlvs,
233 sender_intended_htlc_amt_msat,
234 cltv_expiry_height,
235 })
236 }
237 fn new_blinded_forward(
238 encrypted_tlvs: &'a Vec<u8>, intro_node_blinding_point: Option<PublicKey>,
239 ) -> Self {
240 Self::BlindedForward { encrypted_tlvs, intro_node_blinding_point }
241 }
242 fn new_blinded_receive(
243 sender_intended_htlc_amt_msat: u64, total_msat: u64, cltv_expiry_height: u32,
244 encrypted_tlvs: &'a Vec<u8>, intro_node_blinding_point: Option<PublicKey>,
245 keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<&'a InvoiceRequest>,
246 custom_tlvs: &'a Vec<(u64, Vec<u8>)>,
247 ) -> Self {
248 Self::BlindedReceive {
249 sender_intended_htlc_amt_msat,
250 total_msat,
251 cltv_expiry_height,
252 encrypted_tlvs,
253 intro_node_blinding_point,
254 keysend_preimage,
255 invoice_request,
256 custom_tlvs,
257 }
258 }
259
260 fn new_trampoline_entry(
261 amt_to_forward: u64, outgoing_cltv_value: u32, recipient_onion: &'a RecipientOnionFields,
262 packet: msgs::TrampolineOnionPacket,
263 ) -> Result<Self, APIError> {
264 Ok(Self::TrampolineEntrypoint {
265 amt_to_forward,
266 outgoing_cltv_value,
267 multipath_trampoline_data: recipient_onion.payment_secret.map(|payment_secret| {
268 msgs::FinalOnionHopData {
269 payment_secret,
270 total_msat: recipient_onion.total_mpp_amount_msat,
271 }
272 }),
273 trampoline_packet: packet,
274 })
275 }
276}
277impl<'a, 'b> OnionPayload<'a, 'b> for msgs::OutboundTrampolinePayload<'a> {
278 type PathHopForId = &'b TrampolineHop;
279 type ReceiveType = msgs::OutboundTrampolinePayload<'a>;
280 fn new_forward(
281 outgoing_node_id: PublicKey, amt_to_forward: u64, outgoing_cltv_value: u32,
282 ) -> Self {
283 Self::Forward { outgoing_node_id, amt_to_forward, outgoing_cltv_value }
284 }
285 fn new_receive(
286 _recipient_onion: &'a RecipientOnionFields, _keysend_preimage: Option<PaymentPreimage>,
287 _sender_intended_htlc_amt_msat: u64, _cltv_expiry_height: u32,
288 ) -> Result<Self::ReceiveType, APIError> {
289 Err(APIError::InvalidRoute {
290 err: "Unblinded receiving is not supported for Trampoline!".to_string(),
291 })
292 }
293 fn new_blinded_forward(
294 encrypted_tlvs: &'a Vec<u8>, intro_node_blinding_point: Option<PublicKey>,
295 ) -> Self {
296 Self::BlindedForward { encrypted_tlvs, intro_node_blinding_point }
297 }
298 fn new_blinded_receive(
299 sender_intended_htlc_amt_msat: u64, total_msat: u64, cltv_expiry_height: u32,
300 encrypted_tlvs: &'a Vec<u8>, intro_node_blinding_point: Option<PublicKey>,
301 keysend_preimage: Option<PaymentPreimage>, _invoice_request: Option<&'a InvoiceRequest>,
302 custom_tlvs: &'a Vec<(u64, Vec<u8>)>,
303 ) -> Self {
304 Self::BlindedReceive {
305 sender_intended_htlc_amt_msat,
306 total_msat,
307 cltv_expiry_height,
308 encrypted_tlvs,
309 intro_node_blinding_point,
310 keysend_preimage,
311 custom_tlvs,
312 }
313 }
314
315 fn new_trampoline_entry(
316 _amt_to_forward: u64, _outgoing_cltv_value: u32,
317 _recipient_onion: &'a RecipientOnionFields, _packet: msgs::TrampolineOnionPacket,
318 ) -> Result<Self::ReceiveType, APIError> {
319 Err(APIError::InvalidRoute {
320 err: "Trampoline onions cannot contain Trampoline entrypoints!".to_string(),
321 })
322 }
323}
324
325fn construct_onion_keys_generic<'a, T, H>(
326 secp_ctx: &'a Secp256k1<T>, hops: &'a [H], blinded_tail: Option<&'a BlindedTail>,
327 session_priv: &SecretKey,
328) -> impl Iterator<Item = (SharedSecret, [u8; 32], PublicKey, Option<&'a H>, usize)> + 'a
329where
330 T: secp256k1::Signing,
331 H: HopInfo,
332{
333 let mut blinded_priv = session_priv.clone();
334 let mut blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv);
335
336 let unblinded_hops = hops.iter().map(|h| (h.node_pubkey(), Some(h)));
337 let blinded_pubkeys = blinded_tail
338 .map(|t| t.hops.iter())
339 .unwrap_or([].iter())
340 .skip(1) .map(|h| (&h.blinded_node_id, None));
342
343 unblinded_hops.chain(blinded_pubkeys).enumerate().map(move |(idx, (pubkey, route_hop_opt))| {
344 let shared_secret = SharedSecret::new(pubkey, &blinded_priv);
345
346 let mut sha = Sha256::engine();
347 sha.input(&blinded_pub.serialize()[..]);
348 sha.input(shared_secret.as_ref());
349 let blinding_factor = Sha256::from_engine(sha).to_byte_array();
350
351 let ephemeral_pubkey = blinded_pub;
352
353 blinded_priv = blinded_priv
354 .mul_tweak(&Scalar::from_be_bytes(blinding_factor).expect("You broke SHA-256"))
355 .expect("Blinding are never invalid as we picked the starting private key randomly");
356 blinded_pub = PublicKey::from_secret_key(secp_ctx, &blinded_priv);
357
358 (shared_secret, blinding_factor, ephemeral_pubkey, route_hop_opt, idx)
359 })
360}
361
362pub(super) fn construct_onion_keys<T: secp256k1::Signing>(
364 secp_ctx: &Secp256k1<T>, path: &Path, session_priv: &SecretKey,
365) -> Vec<OnionKeys> {
366 let mut res = Vec::with_capacity(path.hops.len());
367
368 let blinded_tail = path.blinded_tail.as_ref().and_then(|t| {
369 if !t.trampoline_hops.is_empty() {
370 return None;
371 }
372 Some(t)
373 });
374 let iter = construct_onion_keys_generic(secp_ctx, &path.hops, blinded_tail, session_priv);
375 for (shared_secret, _blinding_factor, ephemeral_pubkey, _, _) in iter {
376 let (rho, mu) = gen_rho_mu_from_shared_secret(shared_secret.as_ref());
377
378 res.push(OnionKeys {
379 #[cfg(test)]
380 shared_secret,
381 #[cfg(test)]
382 blinding_factor: _blinding_factor,
383 ephemeral_pubkey,
384 rho,
385 mu,
386 });
387 }
388
389 res
390}
391
392pub(super) fn construct_trampoline_onion_keys<T: secp256k1::Signing>(
394 secp_ctx: &Secp256k1<T>, blinded_tail: &BlindedTail, session_priv: &SecretKey,
395) -> Vec<OnionKeys> {
396 let mut res = Vec::with_capacity(blinded_tail.trampoline_hops.len());
397
398 let hops = &blinded_tail.trampoline_hops;
399 let iter = construct_onion_keys_generic(secp_ctx, &hops, Some(blinded_tail), session_priv);
400 for (shared_secret, _blinding_factor, ephemeral_pubkey, _, _) in iter {
401 let (rho, mu) = gen_rho_mu_from_shared_secret(shared_secret.as_ref());
402
403 res.push(OnionKeys {
404 #[cfg(test)]
405 shared_secret,
406 #[cfg(test)]
407 blinding_factor: _blinding_factor,
408 ephemeral_pubkey,
409 rho,
410 mu,
411 });
412 }
413
414 res
415}
416
417pub(super) fn build_trampoline_onion_payloads<'a>(
418 blinded_tail: &'a BlindedTail, recipient_onion: &'a RecipientOnionFields,
419 cur_block_height: u32, keysend_preimage: &Option<PaymentPreimage>,
420) -> Result<(Vec<msgs::OutboundTrampolinePayload<'a>>, u64), APIError> {
421 let mut res: Vec<msgs::OutboundTrampolinePayload> =
422 Vec::with_capacity(blinded_tail.trampoline_hops.len() + blinded_tail.hops.len());
423 let blinded_tail_with_hop_iter = BlindedTailDetails::DirectEntry {
424 hops: blinded_tail.hops.iter(),
425 blinding_point: blinded_tail.blinding_point,
426 final_value_msat: blinded_tail.final_value_msat,
427 excess_final_cltv_expiry_delta: blinded_tail.excess_final_cltv_expiry_delta,
428 };
429
430 let (value_msat, _) = build_onion_payloads_callback(
431 blinded_tail.trampoline_hops.iter(),
432 Some(blinded_tail_with_hop_iter),
433 recipient_onion,
434 cur_block_height,
435 keysend_preimage,
436 None,
437 |action, payload| match action {
438 PayloadCallbackAction::PushBack => res.push(payload),
439 PayloadCallbackAction::PushFront => res.insert(0, payload),
440 },
441 )?;
442 Ok((res, value_msat))
443}
444
445#[cfg(any(test, feature = "_externalize_tests"))]
447pub(crate) fn test_build_onion_payloads<'a>(
448 path: &'a Path, recipient_onion: &'a RecipientOnionFields, cur_block_height: u32,
449 keysend_preimage: &Option<PaymentPreimage>, invoice_request: Option<&'a InvoiceRequest>,
450 trampoline_packet: Option<msgs::TrampolineOnionPacket>,
451) -> Result<(Vec<msgs::OutboundOnionPayload<'a>>, u64, u32), APIError> {
452 build_onion_payloads(
453 path,
454 recipient_onion,
455 cur_block_height,
456 keysend_preimage,
457 invoice_request,
458 trampoline_packet,
459 )
460}
461
462fn build_onion_payloads<'a>(
464 path: &'a Path, recipient_onion: &'a RecipientOnionFields, cur_block_height: u32,
465 keysend_preimage: &Option<PaymentPreimage>, invoice_request: Option<&'a InvoiceRequest>,
466 trampoline_packet: Option<msgs::TrampolineOnionPacket>,
467) -> Result<(Vec<msgs::OutboundOnionPayload<'a>>, u64, u32), APIError> {
468 let mut res: Vec<msgs::OutboundOnionPayload> = Vec::with_capacity(
469 path.hops.len() + path.blinded_tail.as_ref().map_or(0, |t| t.hops.len()),
470 );
471
472 let blinded_tail_with_hop_iter = path.blinded_tail.as_ref().map(|bt| {
476 if let Some(trampoline_packet) = trampoline_packet {
477 return BlindedTailDetails::TrampolineEntry {
478 trampoline_packet,
479 final_value_msat: bt.final_value_msat,
480 };
481 }
482 BlindedTailDetails::DirectEntry {
483 hops: bt.hops.iter(),
484 blinding_point: bt.blinding_point,
485 final_value_msat: bt.final_value_msat,
486 excess_final_cltv_expiry_delta: bt.excess_final_cltv_expiry_delta,
487 }
488 });
489
490 let (value_msat, cltv) = build_onion_payloads_callback(
491 path.hops.iter(),
492 blinded_tail_with_hop_iter,
493 recipient_onion,
494 cur_block_height,
495 keysend_preimage,
496 invoice_request,
497 |action, payload| match action {
498 PayloadCallbackAction::PushBack => res.push(payload),
499 PayloadCallbackAction::PushFront => res.insert(0, payload),
500 },
501 )?;
502 Ok((res, value_msat, cltv))
503}
504
505enum BlindedTailDetails<'a, I: Iterator<Item = &'a BlindedHop>> {
506 DirectEntry {
507 hops: I,
508 blinding_point: PublicKey,
509 final_value_msat: u64,
510 excess_final_cltv_expiry_delta: u32,
511 },
512 TrampolineEntry {
513 trampoline_packet: msgs::TrampolineOnionPacket,
514 final_value_msat: u64,
515 },
516}
517
518enum PayloadCallbackAction {
519 PushBack,
520 PushFront,
521}
522fn build_onion_payloads_callback<'a, 'b, H, B, F, OP>(
523 hops: H, mut blinded_tail: Option<BlindedTailDetails<'a, B>>,
524 recipient_onion: &'a RecipientOnionFields, cur_block_height: u32,
525 keysend_preimage: &Option<PaymentPreimage>, invoice_request: Option<&'a InvoiceRequest>,
526 mut callback: F,
527) -> Result<(u64, u32), APIError>
528where
529 H: DoubleEndedIterator<Item = OP::PathHopForId>,
530 B: ExactSizeIterator<Item = &'a BlindedHop>,
531 F: FnMut(PayloadCallbackAction, OP),
532 OP: OnionPayload<'a, 'b, ReceiveType = OP>,
533{
534 let mut cur_value_msat = 0u64;
535 let mut cur_cltv = cur_block_height;
536 let mut last_hop_id = None;
537
538 for (idx, hop) in hops.rev().enumerate() {
539 let value_msat = if cur_value_msat == 0 { hop.fee_msat() } else { cur_value_msat };
543 if idx == 0 {
544 let declared_incoming_cltv = hop.cltv_expiry_delta().saturating_add(cur_cltv);
545 match blinded_tail.take() {
546 Some(BlindedTailDetails::DirectEntry {
547 blinding_point,
548 hops,
549 final_value_msat,
550 excess_final_cltv_expiry_delta,
551 ..
552 }) => {
553 let mut blinding_point = Some(blinding_point);
554 let hops_len = hops.len();
555 for (i, blinded_hop) in hops.enumerate() {
556 if i == hops_len - 1 {
557 cur_value_msat += final_value_msat;
558 callback(
559 PayloadCallbackAction::PushBack,
560 OP::new_blinded_receive(
561 final_value_msat,
562 recipient_onion.total_mpp_amount_msat,
563 cur_block_height + excess_final_cltv_expiry_delta,
564 &blinded_hop.encrypted_payload,
565 blinding_point.take(),
566 *keysend_preimage,
567 invoice_request,
568 &recipient_onion.custom_tlvs,
569 ),
570 );
571 } else {
572 callback(
573 PayloadCallbackAction::PushBack,
574 OP::new_blinded_forward(
575 &blinded_hop.encrypted_payload,
576 blinding_point.take(),
577 ),
578 );
579 }
580 }
581 },
582 Some(BlindedTailDetails::TrampolineEntry {
583 trampoline_packet,
584 final_value_msat,
585 }) => {
586 cur_value_msat += final_value_msat;
587 callback(
588 PayloadCallbackAction::PushBack,
589 OP::new_trampoline_entry(
590 final_value_msat + hop.fee_msat(),
591 declared_incoming_cltv,
592 &recipient_onion,
593 trampoline_packet,
594 )?,
595 );
596 },
597 None => {
598 callback(
599 PayloadCallbackAction::PushBack,
600 OP::new_receive(
601 &recipient_onion,
602 *keysend_preimage,
603 value_msat,
604 declared_incoming_cltv,
605 )?,
606 );
607 },
608 }
609 } else {
610 let payload = OP::new_forward(
611 last_hop_id.ok_or(APIError::InvalidRoute {
612 err: "Next hop ID must be known for non-final hops".to_string(),
613 })?,
614 value_msat,
615 cur_cltv,
616 );
617 callback(PayloadCallbackAction::PushFront, payload);
618 }
619 cur_value_msat += hop.fee_msat();
620 if cur_value_msat >= 21000000 * 100000000 * 1000 {
621 return Err(APIError::InvalidRoute { err: "Channel fees overflowed?".to_owned() });
622 }
623 cur_cltv = cur_cltv.saturating_add(hop.cltv_expiry_delta() as u32);
624 if cur_cltv >= 500000000 {
625 return Err(APIError::InvalidRoute { err: "Channel CLTV overflowed?".to_owned() });
626 }
627 last_hop_id = Some(hop.hop_id());
628 }
629 Ok((cur_value_msat, cur_cltv))
630}
631
632pub(crate) const MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY: u64 = 100_000_000;
633
634pub(crate) fn set_max_path_length(
635 route_params: &mut RouteParameters, recipient_onion: &RecipientOnionFields,
636 keysend_preimage: Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
637 best_block_height: u32,
638) -> Result<(), ()> {
639 const PAYLOAD_HMAC_LEN: usize = 32;
640 let unblinded_intermed_payload_len = msgs::OutboundOnionPayload::Forward {
641 short_channel_id: 42,
642 amt_to_forward: TOTAL_BITCOIN_SUPPLY_SATOSHIS,
643 outgoing_cltv_value: route_params.payment_params.max_total_cltv_expiry_delta,
644 }
645 .serialized_length()
646 .saturating_add(PAYLOAD_HMAC_LEN);
647
648 const OVERPAY_ESTIMATE_MULTIPLER: u64 = 3;
649 let final_value_msat_with_overpay_buffer = route_params
650 .final_value_msat
651 .saturating_mul(OVERPAY_ESTIMATE_MULTIPLER)
652 .clamp(MIN_FINAL_VALUE_ESTIMATE_WITH_OVERPAY, 0x1000_0000);
653
654 let blinded_tail_opt = route_params
655 .payment_params
656 .payee
657 .blinded_route_hints()
658 .iter()
659 .max_by_key(|path| path.inner_blinded_path().serialized_length())
660 .map(|largest_path| BlindedTailDetails::DirectEntry {
661 hops: largest_path.blinded_hops().iter(),
662 blinding_point: largest_path.blinding_point(),
663 final_value_msat: final_value_msat_with_overpay_buffer,
664 excess_final_cltv_expiry_delta: 0,
665 });
666
667 let cltv_expiry_delta =
668 core::cmp::min(route_params.payment_params.max_total_cltv_expiry_delta, 0x1000_0000);
669 let unblinded_route_hop = RouteHop {
670 pubkey: PublicKey::from_slice(&[2; 33]).unwrap(),
671 node_features: NodeFeatures::empty(),
672 short_channel_id: 42,
673 channel_features: ChannelFeatures::empty(),
674 fee_msat: final_value_msat_with_overpay_buffer,
675 cltv_expiry_delta,
676 maybe_announced_channel: false,
677 };
678 let mut num_reserved_bytes: usize = 0;
679 let mut recipient_onion_with_excess_value = recipient_onion.clone();
682 recipient_onion_with_excess_value.total_mpp_amount_msat = final_value_msat_with_overpay_buffer;
683 let build_payloads_res = build_onion_payloads_callback(
684 core::iter::once(&unblinded_route_hop),
685 blinded_tail_opt,
686 &recipient_onion_with_excess_value,
687 best_block_height,
688 &keysend_preimage,
689 invoice_request,
690 |_, payload: msgs::OutboundOnionPayload| {
691 num_reserved_bytes = num_reserved_bytes
692 .saturating_add(payload.serialized_length())
693 .saturating_add(PAYLOAD_HMAC_LEN);
694 },
695 );
696 debug_assert!(build_payloads_res.is_ok());
697
698 let max_path_length = 1300usize
699 .checked_sub(num_reserved_bytes)
700 .map(|p| p / unblinded_intermed_payload_len)
701 .and_then(|l| u8::try_from(l.saturating_add(1)).ok())
702 .ok_or(())?;
703
704 route_params.payment_params.max_path_length =
705 core::cmp::min(max_path_length, route_params.payment_params.max_path_length);
706 Ok(())
707}
708
709pub(crate) const ONION_DATA_LEN: usize = 20 * 65;
712
713#[inline]
714fn shift_slice_right(arr: &mut [u8], amt: usize) {
715 for i in (amt..arr.len()).rev() {
716 arr[i] = arr[i - amt];
717 }
718 for i in 0..amt {
719 arr[i] = 0;
720 }
721}
722
723pub(super) fn construct_onion_packet(
724 payloads: Vec<msgs::OutboundOnionPayload>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32],
725 associated_data: &PaymentHash,
726) -> Result<msgs::OnionPacket, ()> {
727 let mut packet_data = [0; ONION_DATA_LEN];
728
729 let mut chacha = ChaCha20::new(Key::new(prng_seed), Nonce::new([0; 12]), 0);
730 chacha.apply_keystream(&mut packet_data);
731
732 debug_assert_eq!(payloads.len(), onion_keys.len(), "Payloads and keys must have equal lengths");
733
734 let packet = FixedSizeOnionPacket(packet_data);
735 construct_onion_packet_with_init_noise::<_, _>(
736 payloads,
737 onion_keys,
738 packet,
739 Some(associated_data),
740 )
741}
742
743pub(super) fn construct_trampoline_onion_packet(
744 payloads: Vec<msgs::OutboundTrampolinePayload>, onion_keys: Vec<OnionKeys>,
745 prng_seed: [u8; 32], associated_data: &PaymentHash, length: Option<u16>,
746) -> Result<msgs::TrampolineOnionPacket, ()> {
747 let minimum_packet_length = payloads.iter().map(|p| p.serialized_length() + 32).sum();
748
749 debug_assert!(
750 minimum_packet_length < ONION_DATA_LEN,
751 "Trampoline onion packet must be smaller than outer onion"
752 );
753 if minimum_packet_length >= ONION_DATA_LEN {
754 return Err(());
755 }
756
757 let packet_length = length.map(|l| usize::from(l)).unwrap_or(minimum_packet_length);
758 debug_assert!(
759 packet_length >= minimum_packet_length,
760 "Packet length cannot be smaller than the payloads require."
761 );
762 if packet_length < minimum_packet_length {
763 return Err(());
764 }
765
766 let mut packet_data = vec![0u8; packet_length];
767 let mut chacha = ChaCha20::new(Key::new(prng_seed), Nonce::new([0; 12]), 0);
768 chacha.apply_keystream(&mut packet_data);
769
770 construct_onion_packet_with_init_noise::<_, _>(
771 payloads,
772 onion_keys,
773 packet_data,
774 Some(associated_data),
775 )
776}
777
778#[cfg(test)]
779pub(super) fn construct_onion_packet_with_writable_hopdata<HD: Writeable>(
782 payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32],
783 associated_data: &PaymentHash,
784) -> Result<msgs::OnionPacket, ()> {
785 let mut packet_data = [0; ONION_DATA_LEN];
786
787 let mut chacha = ChaCha20::new(Key::new(prng_seed), Nonce::new([0; 12]), 0);
788 chacha.apply_keystream(&mut packet_data);
789
790 let packet = FixedSizeOnionPacket(packet_data);
791 construct_onion_packet_with_init_noise::<_, _>(
792 payloads,
793 onion_keys,
794 packet,
795 Some(associated_data),
796 )
797}
798
799pub(crate) trait Packet {
803 type Data: AsMut<[u8]>;
804 fn new(pubkey: PublicKey, hop_data: Self::Data, hmac: [u8; 32]) -> Self;
805}
806
807pub(crate) struct FixedSizeOnionPacket(pub(crate) [u8; ONION_DATA_LEN]);
810
811impl AsMut<[u8]> for FixedSizeOnionPacket {
812 fn as_mut(&mut self) -> &mut [u8] {
813 &mut self.0
814 }
815}
816
817pub(crate) fn payloads_serialized_length<HD: Writeable>(payloads: &Vec<HD>) -> usize {
818 payloads.iter().map(|p| p.serialized_length() + 32 ).sum()
819}
820
821pub(crate) fn construct_onion_message_packet<HD: Writeable, P: Packet<Data = Vec<u8>>>(
822 payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], packet_data_len: usize,
823) -> Result<P, ()> {
824 let mut packet_data = vec![0; packet_data_len];
825
826 let mut chacha = ChaCha20::new(Key::new(prng_seed), Nonce::new([0; 12]), 0);
827 chacha.apply_keystream(&mut packet_data);
828
829 construct_onion_packet_with_init_noise::<_, _>(payloads, onion_keys, packet_data, None)
830}
831
832fn construct_onion_packet_with_init_noise<HD: Writeable, P: Packet>(
833 mut payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, mut packet_data: P::Data,
834 associated_data: Option<&PaymentHash>,
835) -> Result<P, ()> {
836 if payloads.is_empty() {
837 return Err(());
838 }
839
840 let filler = {
841 let packet_data = packet_data.as_mut();
842 const ONION_HOP_DATA_LEN: usize = 65; let mut res = Vec::with_capacity(ONION_HOP_DATA_LEN * (payloads.len() - 1));
844
845 let mut pos = 0;
846 for (i, (payload, keys)) in payloads.iter().zip(onion_keys.iter()).enumerate() {
847 let seek_pos = (packet_data.len() - pos) as u32;
849 let mut chacha = ChaCha20::new(Key::new(keys.rho), Nonce::new([0; 12]), seek_pos);
850
851 let mut payload_len = LengthCalculatingWriter(0);
852 payload.write(&mut payload_len).expect("Failed to calculate length");
853 pos += payload_len.0 + 32;
854 if pos > packet_data.len() {
855 return Err(());
856 }
857
858 if i == payloads.len() - 1 {
859 break;
860 }
861
862 res.resize(pos, 0u8);
863 chacha.apply_keystream(&mut res);
864 }
865 res
866 };
867
868 let mut hmac_res = [0; 32];
869 for (i, (payload, keys)) in payloads.iter_mut().zip(onion_keys.iter()).rev().enumerate() {
870 let mut payload_len = LengthCalculatingWriter(0);
871 payload.write(&mut payload_len).expect("Failed to calculate length");
872
873 let packet_data = packet_data.as_mut();
874 shift_slice_right(packet_data, payload_len.0 + 32);
875 packet_data[0..payload_len.0].copy_from_slice(&payload.encode()[..]);
876 packet_data[payload_len.0..(payload_len.0 + 32)].copy_from_slice(&hmac_res);
877
878 let mut chacha = ChaCha20::new(Key::new(keys.rho), Nonce::new([0; 12]), 0);
879 chacha.apply_keystream(packet_data);
880
881 if i == 0 {
882 let stop_index = packet_data.len();
883 let start_index = stop_index.checked_sub(filler.len()).ok_or(())?;
884 packet_data[start_index..stop_index].copy_from_slice(&filler[..]);
885 }
886
887 let mut hmac = HmacEngine::<Sha256>::new(&keys.mu);
888 hmac.input(packet_data);
889 if let Some(associated_data) = associated_data {
890 hmac.input(&associated_data.0[..]);
891 }
892 hmac_res = Hmac::from_engine(hmac).to_byte_array();
893 }
894
895 Ok(P::new(onion_keys.first().unwrap().ephemeral_pubkey, packet_data, hmac_res))
896}
897
898fn crypt_failure_packet(shared_secret: &[u8], packet: &mut OnionErrorPacket) {
900 let ammag = gen_ammag_from_shared_secret(&shared_secret);
901 let mut chacha = ChaCha20::new(Key::new(ammag), Nonce::new([0; 12]), 0);
902 chacha.apply_keystream(&mut packet.data);
903
904 if let Some(ref mut attribution_data) = packet.attribution_data {
905 attribution_data.crypt(shared_secret);
906 }
907}
908
909#[cfg(test)]
910pub(super) fn test_crypt_failure_packet(shared_secret: &[u8], packet: &mut OnionErrorPacket) {
911 crypt_failure_packet(shared_secret, packet)
912}
913
914fn build_unencrypted_failure_packet(
915 shared_secret: &[u8], failure_reason: LocalHTLCFailureReason, failure_data: &[u8],
916 hold_time: u32, min_packet_len: usize,
917) -> OnionErrorPacket {
918 assert_eq!(shared_secret.len(), 32);
919 assert!(failure_data.len() <= 64531);
920
921 let failure_len = 2 + failure_data.len();
923
924 let pad_len = min_packet_len.saturating_sub(failure_len);
926
927 let total_len = 32 + 2 + failure_len + 2 + pad_len;
929
930 let mut writer = VecWriter(Vec::with_capacity(total_len));
931
932 writer.0.extend_from_slice(&[0; 32]);
934
935 (failure_len as u16).write(&mut writer).unwrap();
937 failure_reason.failure_code().write(&mut writer).unwrap();
938 writer.0.extend_from_slice(&failure_data[..]);
939
940 (pad_len as u16).write(&mut writer).unwrap();
942 writer.0.resize(total_len, 0);
943
944 let um = gen_um_from_shared_secret(&shared_secret);
946 let mut hmac = HmacEngine::<Sha256>::new(&um);
947 hmac.input(&writer.0[32..]);
948 let hmac = Hmac::from_engine(hmac).to_byte_array();
949 writer.0[..32].copy_from_slice(&hmac);
950
951 let mut packet = OnionErrorPacket { data: writer.0, attribution_data: None };
953 update_attribution_data(&mut packet, shared_secret, hold_time);
954
955 packet
956}
957
958fn update_attribution_data(
959 onion_error_packet: &mut OnionErrorPacket, shared_secret: &[u8], hold_time: u32,
960) {
961 let attribution_data =
965 onion_error_packet.attribution_data.get_or_insert(AttributionData::new());
966
967 attribution_data.update(&onion_error_packet.data, shared_secret, hold_time);
968}
969
970pub(super) fn build_failure_packet(
971 shared_secret: &[u8], failure_reason: LocalHTLCFailureReason, failure_data: &[u8],
972 hold_time: u32,
973) -> OnionErrorPacket {
974 let mut onion_error_packet = build_unencrypted_failure_packet(
975 shared_secret,
976 failure_reason,
977 failure_data,
978 hold_time,
979 DEFAULT_MIN_FAILURE_PACKET_LEN,
980 );
981
982 crypt_failure_packet(shared_secret, &mut onion_error_packet);
983
984 onion_error_packet
985}
986
987mod fuzzy_onion_utils {
988 use super::*;
989
990 pub struct DecodedOnionFailure {
991 pub(crate) network_update: Option<NetworkUpdate>,
992 pub(crate) short_channel_id: Option<u64>,
993 pub(crate) payment_failed_permanently: bool,
994 pub(crate) failed_within_blinded_path: bool,
995 #[allow(dead_code)]
996 pub(crate) hold_times: Vec<u32>,
997 #[cfg(any(test, feature = "_test_utils"))]
998 pub(crate) onion_error_code: Option<LocalHTLCFailureReason>,
999 #[cfg(any(test, feature = "_test_utils"))]
1000 pub(crate) onion_error_data: Option<Vec<u8>>,
1001 #[cfg(test)]
1002 pub(crate) attribution_failed_channel: Option<u64>,
1003 }
1004
1005 pub fn process_onion_failure<T: secp256k1::Signing, L: Logger>(
1006 secp_ctx: &Secp256k1<T>, logger: &L, htlc_source: &HTLCSource,
1007 encrypted_packet: OnionErrorPacket,
1008 ) -> DecodedOnionFailure {
1009 let (path, session_priv) = match htlc_source {
1010 HTLCSource::OutboundRoute { ref path, ref session_priv, .. } => (path, session_priv),
1011 _ => unreachable!(),
1012 };
1013
1014 process_onion_failure_inner(secp_ctx, logger, path, &session_priv, None, encrypted_packet)
1015 }
1016
1017 pub fn decode_fulfill_attribution_data<T: secp256k1::Signing, L: Logger>(
1019 secp_ctx: &Secp256k1<T>, logger: &L, path: &Path, outer_session_priv: &SecretKey,
1020 mut attribution_data: AttributionData,
1021 ) -> Vec<u32> {
1022 let mut hold_times = Vec::new();
1023
1024 let shared_secrets =
1026 construct_onion_keys_generic(secp_ctx, &path.hops, None, outer_session_priv)
1027 .map(|(shared_secret, _, _, _, _)| shared_secret);
1028
1029 let attributable_hop_count = usize::min(path.hops.len(), MAX_HOPS);
1032
1033 for (route_hop_idx, shared_secret) in
1034 shared_secrets.enumerate().take(attributable_hop_count)
1035 {
1036 attribution_data.crypt(shared_secret.as_ref());
1037
1038 let position = attributable_hop_count - route_hop_idx - 1;
1042 let res = attribution_data.verify(&Vec::new(), shared_secret.as_ref(), position);
1043 match res {
1044 Ok(hold_time) => {
1045 hold_times.push(hold_time);
1046
1047 attribution_data.shift_left();
1049 },
1050 Err(()) => {
1051 log_debug!(
1053 logger,
1054 "Invalid fulfill HMAC in attribution data for node at pos {}",
1055 route_hop_idx
1056 );
1057
1058 break;
1059 },
1060 }
1061 }
1062
1063 hold_times
1064 }
1065}
1066#[cfg(fuzzing)]
1067pub use self::fuzzy_onion_utils::*;
1068#[cfg(not(fuzzing))]
1069pub(crate) use self::fuzzy_onion_utils::*;
1070
1071fn process_onion_failure_inner<T: secp256k1::Signing, L: Logger>(
1074 secp_ctx: &Secp256k1<T>, logger: &L, path: &Path, session_priv: &SecretKey,
1075 trampoline_session_priv_override: Option<SecretKey>, mut encrypted_packet: OnionErrorPacket,
1076) -> DecodedOnionFailure {
1077 if encrypted_packet.data.len() < 32 {
1080 log_warn!(
1081 logger,
1082 "Non-attributable failure encountered on route {}",
1083 path.hops.iter().map(|h| h.pubkey.to_string()).collect::<Vec<_>>().join("->")
1084 );
1085
1086 return DecodedOnionFailure {
1089 network_update: None,
1090 short_channel_id: None,
1091 payment_failed_permanently: true,
1092 failed_within_blinded_path: false,
1093 hold_times: Vec::new(),
1094 #[cfg(any(test, feature = "_test_utils"))]
1095 onion_error_code: None,
1096 #[cfg(any(test, feature = "_test_utils"))]
1097 onion_error_data: None,
1098 #[cfg(test)]
1099 attribution_failed_channel: None,
1100 };
1101 }
1102
1103 struct FailureLearnings {
1105 network_update: Option<NetworkUpdate>,
1106 short_channel_id: Option<u64>,
1107 payment_failed_permanently: bool,
1108 failed_within_blinded_path: bool,
1109 }
1110 let mut res: Option<FailureLearnings> = None;
1111 let mut _error_code_ret = None;
1112 let mut _error_packet_ret = None;
1113 let mut is_from_final_non_blinded_node = false;
1114 let mut hop_hold_times: Vec<u32> = Vec::new();
1115
1116 enum ErrorHop<'a> {
1117 RouteHop(&'a RouteHop),
1118 TrampolineHop(&'a TrampolineHop),
1119 }
1120
1121 impl<'a> ErrorHop<'a> {
1122 fn pubkey(&self) -> &PublicKey {
1123 match self {
1124 ErrorHop::RouteHop(rh) => rh.node_pubkey(),
1125 ErrorHop::TrampolineHop(th) => th.node_pubkey(),
1126 }
1127 }
1128
1129 fn short_channel_id(&self) -> Option<u64> {
1130 match self {
1131 ErrorHop::RouteHop(rh) => Some(rh.short_channel_id),
1132 ErrorHop::TrampolineHop(_) => None,
1133 }
1134 }
1135 }
1136
1137 let num_blinded_hops = path.blinded_tail.as_ref().map_or(0, |bt| bt.hops.len());
1138
1139 let nontrampoline_bt =
1141 if path.has_trampoline_hops() { None } else { path.blinded_tail.as_ref() };
1142 let nontrampolines =
1143 construct_onion_keys_generic(secp_ctx, &path.hops, nontrampoline_bt, session_priv).map(
1144 |(shared_secret, _, _, route_hop_option, _)| {
1145 (route_hop_option.map(|rh| ErrorHop::RouteHop(rh)), shared_secret)
1146 },
1147 );
1148
1149 let trampolines = if path.has_trampoline_hops() {
1150 let blinded_tail = path.blinded_tail.as_ref();
1152 let hops = &blinded_tail.unwrap().trampoline_hops;
1153 let trampoline_session_priv = trampoline_session_priv_override
1154 .unwrap_or_else(|| compute_trampoline_session_priv(session_priv));
1155 Some(
1156 construct_onion_keys_generic(secp_ctx, hops, blinded_tail, &trampoline_session_priv)
1157 .map(|(shared_secret, _, _, route_hop_option, _)| {
1158 (
1159 route_hop_option.map(|tram_hop| ErrorHop::TrampolineHop(tram_hop)),
1160 shared_secret,
1161 )
1162 }),
1163 )
1164 } else {
1165 None
1166 };
1167
1168 let attributable_hop_count = usize::min(path.hops.len(), MAX_HOPS);
1171
1172 let mut attribution_failed_channel = None;
1174
1175 let mut iter = nontrampolines.chain(trampolines.into_iter().flatten()).enumerate().peekable();
1177 while let Some((route_hop_idx, (route_hop_option, shared_secret))) = iter.next() {
1178 let route_hop = match route_hop_option.as_ref() {
1179 Some(hop) => hop,
1180 None => {
1181 _error_code_ret = Some(LocalHTLCFailureReason::InvalidOnionBlinding);
1183 _error_packet_ret = Some(vec![0; 32]);
1184 res = Some(FailureLearnings {
1185 network_update: None,
1186 short_channel_id: None,
1187 payment_failed_permanently: false,
1188 failed_within_blinded_path: true,
1189 });
1190 break;
1191 },
1192 };
1193
1194 let next_hop = iter.peek();
1200 is_from_final_non_blinded_node = next_hop.is_none() && num_blinded_hops <= 1;
1201 let failing_route_hop = if is_from_final_non_blinded_node {
1202 route_hop
1203 } else {
1204 match next_hop {
1205 Some((_, (Some(hop), _))) => hop,
1206 _ => {
1207 #[cfg(not(test))]
1209 {
1210 _error_code_ret = Some(LocalHTLCFailureReason::InvalidOnionBlinding);
1211 _error_packet_ret = Some(vec![0; 32]);
1212 }
1213 #[cfg(test)]
1214 {
1215 crypt_failure_packet(shared_secret.as_ref(), &mut encrypted_packet);
1218 let err_packet = msgs::DecodedOnionErrorPacket::read(&mut Cursor::new(
1219 &encrypted_packet.data,
1220 ))
1221 .unwrap();
1222 _error_code_ret = Some(
1223 u16::from_be_bytes(
1224 err_packet.failuremsg.get(0..2).unwrap().try_into().unwrap(),
1225 )
1226 .into(),
1227 );
1228 _error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
1229 }
1230
1231 res = Some(FailureLearnings {
1232 network_update: None,
1233 short_channel_id: None,
1234 payment_failed_permanently: false,
1235 failed_within_blinded_path: true,
1236 });
1237 break;
1238 },
1239 }
1240 };
1241
1242 crypt_failure_packet(shared_secret.as_ref(), &mut encrypted_packet);
1243
1244 let um = gen_um_from_shared_secret(shared_secret.as_ref());
1245
1246 if attribution_failed_channel.is_none() {
1248 if let Some(ref mut attribution_data) = encrypted_packet.attribution_data {
1250 if route_hop_idx < attributable_hop_count {
1253 let position = attributable_hop_count - route_hop_idx - 1;
1259 let res = attribution_data.verify(
1260 &encrypted_packet.data,
1261 shared_secret.as_ref(),
1262 position,
1263 );
1264 match res {
1265 Ok(hold_time) => {
1266 hop_hold_times.push(hold_time);
1267
1268 log_debug!(
1269 logger,
1270 "Htlc hold time at pos {}: {} ms",
1271 route_hop_idx,
1272 (hold_time as u128) * HOLD_TIME_UNIT_MILLIS
1273 );
1274
1275 attribution_data.shift_left();
1277 },
1278 Err(()) => {
1279 attribution_failed_channel = route_hop.short_channel_id();
1283
1284 log_debug!(
1285 logger,
1286 "Invalid failure HMAC in attribution data for node at pos {}",
1287 route_hop_idx
1288 );
1289 },
1290 }
1291 }
1292 } else {
1293 attribution_failed_channel = route_hop.short_channel_id();
1296 }
1297 }
1298
1299 let mut hmac = HmacEngine::<Sha256>::new(&um);
1301 hmac.input(&encrypted_packet.data[32..]);
1302
1303 if &Hmac::from_engine(hmac).to_byte_array() != &encrypted_packet.data[..32] {
1304 continue;
1305 }
1306
1307 let err_packet =
1308 match msgs::DecodedOnionErrorPacket::read(&mut Cursor::new(&encrypted_packet.data)) {
1309 Ok(p) => p,
1310 Err(_) => {
1311 log_warn!(logger, "Unreadable failure from {}", route_hop.pubkey());
1312
1313 let network_update = Some(NetworkUpdate::NodeFailure {
1314 node_id: *route_hop.pubkey(),
1315 is_permanent: true,
1316 });
1317 let short_channel_id = route_hop.short_channel_id();
1318 res = Some(FailureLearnings {
1319 network_update,
1320 short_channel_id,
1321 payment_failed_permanently: is_from_final_non_blinded_node,
1322 failed_within_blinded_path: false,
1323 });
1324 break;
1325 },
1326 };
1327
1328 let error_code_slice = match err_packet.failuremsg.get(0..2) {
1329 Some(s) => s,
1330 None => {
1331 log_warn!(logger, "Missing error code in failure from {}", route_hop.pubkey());
1334
1335 let network_update = Some(NetworkUpdate::NodeFailure {
1336 node_id: *route_hop.pubkey(),
1337 is_permanent: true,
1338 });
1339 let short_channel_id = route_hop.short_channel_id();
1340 res = Some(FailureLearnings {
1341 network_update,
1342 short_channel_id,
1343 payment_failed_permanently: is_from_final_non_blinded_node,
1344 failed_within_blinded_path: false,
1345 });
1346 break;
1347 },
1348 };
1349
1350 let error_code = u16::from_be_bytes(error_code_slice.try_into().expect("len is 2")).into();
1351 _error_code_ret = Some(error_code);
1352 _error_packet_ret = Some(err_packet.failuremsg[2..].to_vec());
1353
1354 let (debug_field, debug_field_size) = error_code.get_onion_debug_field();
1355
1356 let payment_failed = error_code.is_recipient_failure() && is_from_final_non_blinded_node;
1358
1359 let mut network_update = None;
1360 let mut short_channel_id = None;
1361
1362 if error_code.is_badonion() {
1363 if let ErrorHop::RouteHop(failing_route_hop) = failing_route_hop {
1371 network_update = Some(NetworkUpdate::ChannelFailure {
1372 short_channel_id: failing_route_hop.short_channel_id,
1373 is_permanent: true,
1374 });
1375 }
1376 } else if error_code.is_node() {
1377 network_update = Some(NetworkUpdate::NodeFailure {
1378 node_id: *route_hop.pubkey(),
1379 is_permanent: error_code.is_permanent(),
1380 });
1381 short_channel_id = route_hop.short_channel_id();
1382 } else if error_code.is_permanent() {
1383 if !payment_failed {
1384 if let ErrorHop::RouteHop(failing_route_hop) = failing_route_hop {
1385 network_update = Some(NetworkUpdate::ChannelFailure {
1386 short_channel_id: failing_route_hop.short_channel_id,
1387 is_permanent: true,
1388 });
1389 }
1390 short_channel_id = failing_route_hop.short_channel_id();
1391 }
1392 } else if error_code.is_temporary() {
1393 if let Some(update_len_slice) =
1394 err_packet.failuremsg.get(debug_field_size + 2..debug_field_size + 4)
1395 {
1396 let update_len =
1397 u16::from_be_bytes(update_len_slice.try_into().expect("len is 2")) as usize;
1398 if err_packet
1399 .failuremsg
1400 .get(debug_field_size + 4..debug_field_size + 4 + update_len)
1401 .is_some()
1402 {
1403 if let ErrorHop::RouteHop(failing_route_hop) = failing_route_hop {
1404 network_update = Some(NetworkUpdate::ChannelFailure {
1405 short_channel_id: failing_route_hop.short_channel_id,
1406 is_permanent: false,
1407 });
1408 }
1409 short_channel_id = failing_route_hop.short_channel_id();
1410 }
1411 }
1412 if network_update.is_none() {
1413 network_update = Some(NetworkUpdate::NodeFailure {
1416 node_id: *route_hop.pubkey(),
1417 is_permanent: true,
1418 });
1419 }
1420 if short_channel_id.is_none() {
1421 short_channel_id = route_hop.short_channel_id();
1422 }
1423 } else if payment_failed {
1424 short_channel_id = match error_code {
1427 LocalHTLCFailureReason::FinalIncorrectCLTVExpiry
1428 | LocalHTLCFailureReason::FinalIncorrectHTLCAmount => route_hop.short_channel_id(),
1429 _ => None,
1430 };
1431 } else {
1432 network_update = Some(NetworkUpdate::NodeFailure {
1435 node_id: *route_hop.pubkey(),
1436 is_permanent: true,
1437 });
1438 short_channel_id = route_hop.short_channel_id()
1439 }
1440
1441 res = Some(FailureLearnings {
1442 network_update,
1443 short_channel_id,
1444 payment_failed_permanently: error_code.is_permanent() && is_from_final_non_blinded_node,
1445 failed_within_blinded_path: false,
1446 });
1447
1448 if debug_field_size > 0 && err_packet.failuremsg.len() >= 4 + debug_field_size {
1449 log_info!(
1450 logger,
1451 "Onion Error[from {}: {:?}({:#x}) {}({})]",
1452 route_hop.pubkey(),
1453 error_code,
1454 error_code.failure_code(),
1455 debug_field,
1456 log_bytes!(&err_packet.failuremsg[4..4 + debug_field_size]),
1457 );
1458 } else {
1459 log_info!(
1460 logger,
1461 "Onion Error[from {}: {:?}({:#x})]",
1462 route_hop.pubkey(),
1463 error_code,
1464 error_code.failure_code(),
1465 );
1466 }
1467
1468 break;
1469 }
1470
1471 if let Some(FailureLearnings {
1472 network_update,
1473 short_channel_id,
1474 payment_failed_permanently,
1475 failed_within_blinded_path,
1476 }) = res
1477 {
1478 DecodedOnionFailure {
1479 network_update,
1480 short_channel_id,
1481 payment_failed_permanently,
1482 failed_within_blinded_path,
1483 hold_times: hop_hold_times,
1484 #[cfg(any(test, feature = "_test_utils"))]
1485 onion_error_code: _error_code_ret,
1486 #[cfg(any(test, feature = "_test_utils"))]
1487 onion_error_data: _error_packet_ret,
1488 #[cfg(test)]
1489 attribution_failed_channel,
1490 }
1491 } else {
1492 log_warn!(
1495 logger,
1496 "Non-attributable failure encountered on route {}. Attributation data failed for channel {}",
1497 path.hops.iter().map(|h| h.pubkey.to_string()).collect::<Vec<_>>().join("->"),
1498 attribution_failed_channel.unwrap_or_default(),
1499 );
1500
1501 DecodedOnionFailure {
1502 network_update: None,
1503 short_channel_id: None,
1504 payment_failed_permanently: is_from_final_non_blinded_node,
1505 failed_within_blinded_path: false,
1506 hold_times: hop_hold_times,
1507 #[cfg(any(test, feature = "_test_utils"))]
1508 onion_error_code: None,
1509 #[cfg(any(test, feature = "_test_utils"))]
1510 onion_error_data: None,
1511 #[cfg(test)]
1512 attribution_failed_channel,
1513 }
1514 }
1515}
1516
1517const BADONION: u16 = 0x8000;
1518const PERM: u16 = 0x4000;
1519const NODE: u16 = 0x2000;
1520const UPDATE: u16 = 0x1000;
1521
1522#[derive(Copy, Clone, Debug, Hash, PartialEq, Eq)]
1534pub enum LocalHTLCFailureReason {
1535 TemporaryNodeFailure,
1537 PermanentNodeFailure,
1539 RequiredNodeFeature,
1543 InvalidOnionVersion,
1545 InvalidOnionHMAC,
1547 InvalidOnionKey,
1549 TemporaryChannelFailure,
1551 PermanentChannelFailure,
1553 RequiredChannelFeature,
1555 UnknownNextPeer,
1557 AmountBelowMinimum,
1561 FeeInsufficient,
1565 IncorrectCLTVExpiry,
1572 CLTVExpiryTooSoon,
1574 IncorrectPaymentDetails,
1577 FinalIncorrectCLTVExpiry,
1582 FinalIncorrectHTLCAmount,
1586 ChannelDisabled,
1589 CLTVExpiryTooFar,
1594 InvalidOnionPayload,
1596 MPPTimeout,
1599 InvalidOnionBlinding,
1605 UnknownFailureCode {
1613 code: u16,
1615 },
1616 ForwardExpiryBuffer,
1620 InvalidTrampolineForward,
1622 PaymentClaimBuffer,
1626 DustLimitHolder,
1630 DustLimitCounterparty,
1634 FeeSpikeBuffer,
1638 PrivateChannelForward,
1641 RealSCIDForward,
1645 ChannelNotReady,
1647 InvalidKeysendPreimage,
1649 InvalidTrampolinePayload,
1651 PaymentSecretRequired,
1654 OutgoingCLTVTooSoon,
1657 ChannelClosed,
1660 OnChainTimeout,
1663 ZeroAmount,
1665 HTLCMinimum,
1671 HTLCMaximum,
1678 PeerOffline,
1680 ChannelBalanceOverdrawn,
1682 TemporaryTrampolineFailure,
1685 TrampolineFeeOrExpiryInsufficient,
1687 UnknownNextTrampoline,
1689}
1690
1691impl LocalHTLCFailureReason {
1692 pub(super) fn failure_code(&self) -> u16 {
1693 match self {
1694 Self::TemporaryNodeFailure | Self::ForwardExpiryBuffer => NODE | 2,
1695 Self::PermanentNodeFailure => PERM | NODE | 2,
1696 Self::RequiredNodeFeature | Self::PaymentSecretRequired => PERM | NODE | 3,
1697 Self::InvalidOnionVersion => BADONION | PERM | 4,
1698 Self::InvalidOnionHMAC => BADONION | PERM | 5,
1699 Self::InvalidOnionKey => BADONION | PERM | 6,
1700 Self::TemporaryChannelFailure
1701 | Self::DustLimitHolder
1702 | Self::DustLimitCounterparty
1703 | Self::FeeSpikeBuffer
1704 | Self::ChannelNotReady
1705 | Self::ZeroAmount
1706 | Self::HTLCMinimum
1707 | Self::HTLCMaximum
1708 | Self::PeerOffline
1709 | Self::ChannelBalanceOverdrawn => UPDATE | 7,
1710 Self::PermanentChannelFailure | Self::ChannelClosed | Self::OnChainTimeout => PERM | 8,
1711 Self::RequiredChannelFeature => PERM | 9,
1712 Self::UnknownNextPeer
1713 | Self::PrivateChannelForward
1714 | Self::RealSCIDForward
1715 | Self::InvalidTrampolineForward => PERM | 10,
1716 Self::AmountBelowMinimum => UPDATE | 11,
1717 Self::FeeInsufficient => UPDATE | 12,
1718 Self::IncorrectCLTVExpiry => UPDATE | 13,
1719 Self::CLTVExpiryTooSoon | Self::OutgoingCLTVTooSoon => UPDATE | 14,
1720 Self::IncorrectPaymentDetails
1721 | Self::PaymentClaimBuffer
1722 | Self::InvalidKeysendPreimage => PERM | 15,
1723 Self::FinalIncorrectCLTVExpiry => 18,
1724 Self::FinalIncorrectHTLCAmount => 19,
1725 Self::ChannelDisabled => UPDATE | 20,
1726 Self::CLTVExpiryTooFar => 21,
1727 Self::InvalidOnionPayload | Self::InvalidTrampolinePayload => PERM | 22,
1728 Self::MPPTimeout => 23,
1729 Self::InvalidOnionBlinding => BADONION | PERM | 24,
1730 Self::TemporaryTrampolineFailure => NODE | 25,
1731 Self::TrampolineFeeOrExpiryInsufficient => NODE | 26,
1732 Self::UnknownNextTrampoline => PERM | 27,
1733 Self::UnknownFailureCode { code } => *code,
1734 }
1735 }
1736
1737 fn get_onion_debug_field(&self) -> (&'static str, usize) {
1739 match self {
1740 Self::InvalidOnionVersion | Self::InvalidOnionHMAC | Self::InvalidOnionKey => {
1741 ("sha256_of_onion", 32)
1742 },
1743 Self::AmountBelowMinimum | Self::FeeInsufficient => ("htlc_msat", 8),
1744 Self::IncorrectCLTVExpiry | Self::FinalIncorrectCLTVExpiry => ("cltv_expiry", 4),
1745 Self::FinalIncorrectHTLCAmount => ("incoming_htlc_msat", 8),
1746 Self::ChannelDisabled => ("flags", 2),
1747 _ => ("", 0),
1748 }
1749 }
1750
1751 pub(super) fn is_temporary(&self) -> bool {
1752 self.failure_code() & UPDATE == UPDATE
1753 }
1754
1755 pub(super) fn is_permanent(&self) -> bool {
1756 self.failure_code() & PERM == PERM
1757 }
1758
1759 fn is_badonion(&self) -> bool {
1760 self.failure_code() & BADONION == BADONION
1761 }
1762
1763 fn is_node(&self) -> bool {
1764 self.failure_code() & NODE == NODE
1765 }
1766
1767 fn is_recipient_failure(&self) -> bool {
1771 self.failure_code() == LocalHTLCFailureReason::IncorrectPaymentDetails.failure_code()
1772 || *self == LocalHTLCFailureReason::FinalIncorrectCLTVExpiry
1773 || *self == LocalHTLCFailureReason::FinalIncorrectHTLCAmount
1774 || *self == LocalHTLCFailureReason::MPPTimeout
1775 }
1776}
1777
1778macro_rules! impl_from_u16_for_htlc_reason {
1779 ($enum:ident, [$($variant:ident),* $(,)?]) => {
1780 impl From<u16> for $enum {
1781 fn from(value: u16) -> Self {
1782 $(
1783 if value == $enum::$variant.failure_code() {
1784 return $enum::$variant;
1785 }
1786 )*
1787 $enum::UnknownFailureCode { code: value }
1788 }
1789 }
1790 };
1791}
1792
1793impl_from_u16_for_htlc_reason!(
1795 LocalHTLCFailureReason,
1796 [
1797 TemporaryNodeFailure,
1798 PermanentNodeFailure,
1799 RequiredNodeFeature,
1800 InvalidOnionVersion,
1801 InvalidOnionHMAC,
1802 InvalidOnionKey,
1803 TemporaryChannelFailure,
1804 PermanentChannelFailure,
1805 RequiredChannelFeature,
1806 UnknownNextPeer,
1807 AmountBelowMinimum,
1808 FeeInsufficient,
1809 IncorrectCLTVExpiry,
1810 CLTVExpiryTooSoon,
1811 IncorrectPaymentDetails,
1812 FinalIncorrectCLTVExpiry,
1813 FinalIncorrectHTLCAmount,
1814 ChannelDisabled,
1815 CLTVExpiryTooFar,
1816 InvalidOnionPayload,
1817 MPPTimeout,
1818 InvalidOnionBlinding,
1819 TemporaryTrampolineFailure,
1820 TrampolineFeeOrExpiryInsufficient,
1821 UnknownNextTrampoline,
1822 ]
1823);
1824
1825macro_rules! ser_failure_reasons {
1826 ($(($idx: expr, $name: ident)),*) => {
1827 impl Readable for LocalHTLCFailureReason {
1828 fn read<R: Read>(r: &mut R) -> Result<LocalHTLCFailureReason, DecodeError> {
1829 let code: u16 = Readable::read(r)?;
1830 let reason: u8 = Readable::read(r)?;
1831 read_tlv_fields!(r, {});
1832 match reason {
1833 $($idx => Ok(LocalHTLCFailureReason::$name),)*
1834 _ => Ok(code.into()),
1835 }
1836 }
1837 }
1838 impl Writeable for LocalHTLCFailureReason {
1839 fn write<W: Writer>(&self, writer: &mut W) -> Result<(), bitcoin::io::Error> {
1840 self.failure_code().write(writer)?;
1841 let reason: u8 = match self {
1842 $(LocalHTLCFailureReason::$name => $idx,)*
1843 LocalHTLCFailureReason::UnknownFailureCode { .. } => 0xff,
1844 };
1845 reason.write(writer)?;
1846 write_tlv_fields!(writer, {});
1847 Ok(())
1848 }
1849 }
1850 }
1851}
1852
1853ser_failure_reasons!(
1854 (1, TemporaryNodeFailure),
1855 (2, PermanentNodeFailure),
1856 (3, RequiredNodeFeature),
1857 (4, InvalidOnionVersion),
1858 (5, InvalidOnionHMAC),
1859 (6, InvalidOnionKey),
1860 (7, TemporaryChannelFailure),
1861 (8, PermanentChannelFailure),
1862 (9, RequiredChannelFeature),
1863 (10, UnknownNextPeer),
1864 (11, AmountBelowMinimum),
1865 (12, FeeInsufficient),
1866 (13, IncorrectCLTVExpiry),
1867 (14, CLTVExpiryTooSoon),
1868 (15, IncorrectPaymentDetails),
1869 (16, FinalIncorrectCLTVExpiry),
1870 (17, FinalIncorrectHTLCAmount),
1871 (18, ChannelDisabled),
1872 (19, CLTVExpiryTooFar),
1873 (20, InvalidOnionPayload),
1874 (21, MPPTimeout),
1875 (22, InvalidOnionBlinding),
1876 (23, ForwardExpiryBuffer),
1877 (24, InvalidTrampolineForward),
1878 (25, PaymentClaimBuffer),
1879 (26, DustLimitHolder),
1880 (27, DustLimitCounterparty),
1881 (28, FeeSpikeBuffer),
1882 (29, PrivateChannelForward),
1883 (30, RealSCIDForward),
1884 (31, ChannelNotReady),
1885 (32, InvalidKeysendPreimage),
1886 (33, InvalidTrampolinePayload),
1887 (34, PaymentSecretRequired),
1888 (35, OutgoingCLTVTooSoon),
1889 (36, ChannelClosed),
1890 (37, OnChainTimeout),
1891 (38, ZeroAmount),
1892 (39, HTLCMinimum),
1893 (40, HTLCMaximum),
1894 (41, PeerOffline),
1895 (42, ChannelBalanceOverdrawn),
1896 (43, TemporaryTrampolineFailure),
1897 (44, TrampolineFeeOrExpiryInsufficient),
1898 (45, UnknownNextTrampoline)
1899);
1900
1901impl From<&HTLCFailReason> for HTLCHandlingFailureReason {
1902 fn from(value: &HTLCFailReason) -> Self {
1903 match value.0 {
1904 HTLCFailReasonRepr::LightningError { .. } => HTLCHandlingFailureReason::Downstream,
1905 HTLCFailReasonRepr::Reason { failure_reason, .. } => {
1906 HTLCHandlingFailureReason::Local { reason: failure_reason }
1907 },
1908 }
1909 }
1910}
1911
1912#[derive(Clone)] #[cfg_attr(test, derive(PartialEq))]
1914pub(super) struct HTLCFailReason(HTLCFailReasonRepr);
1915
1916#[derive(Clone)] #[cfg_attr(test, derive(PartialEq))]
1918enum HTLCFailReasonRepr {
1919 LightningError { err: msgs::OnionErrorPacket, hold_time: Option<u32> },
1920 Reason { data: Vec<u8>, failure_reason: LocalHTLCFailureReason },
1921}
1922
1923impl HTLCFailReason {
1924 pub fn set_hold_time(&mut self, hold_time: u32) {
1925 match self.0 {
1926 HTLCFailReasonRepr::LightningError { hold_time: ref mut current_hold_time, .. } => {
1927 *current_hold_time = Some(hold_time);
1928 },
1929 _ => {},
1930 }
1931 }
1932}
1933
1934impl core::fmt::Debug for HTLCFailReason {
1935 fn fmt(&self, f: &mut core::fmt::Formatter) -> Result<(), core::fmt::Error> {
1936 match self.0 {
1937 HTLCFailReasonRepr::Reason { ref failure_reason, .. } => {
1938 write!(
1939 f,
1940 "HTLC failure {:?} error code {}",
1941 failure_reason,
1942 failure_reason.failure_code()
1943 )
1944 },
1945 HTLCFailReasonRepr::LightningError { .. } => {
1946 write!(f, "pre-built LightningError")
1947 },
1948 }
1949 }
1950}
1951
1952impl Writeable for HTLCFailReason {
1953 fn write<W: Writer>(&self, writer: &mut W) -> Result<(), crate::io::Error> {
1954 self.0.write(writer)
1955 }
1956}
1957impl Readable for HTLCFailReason {
1958 fn read<R: Read>(reader: &mut R) -> Result<Self, msgs::DecodeError> {
1959 Ok(Self(Readable::read(reader)?))
1960 }
1961}
1962
1963impl_writeable_tlv_based_enum!(HTLCFailReasonRepr,
1964 (0, LightningError) => {
1965 (0, data, (legacy, Vec<u8>, |_| Ok(()), |us|
1966 if let &HTLCFailReasonRepr::LightningError { err: msgs::OnionErrorPacket { ref data, .. }, .. } = us {
1967 Some(data)
1968 } else {
1969 None
1970 })
1971 ),
1972 (1, attribution_data, (legacy, AttributionData, |_| Ok(()), |us|
1973 if let &HTLCFailReasonRepr::LightningError { err: msgs::OnionErrorPacket { ref attribution_data, .. }, .. } = us {
1974 attribution_data.as_ref()
1975 } else {
1976 None
1977 })
1978 ),
1979 (3, hold_time, option),
1980 (_unused, err, (static_value, msgs::OnionErrorPacket { data: data.ok_or(DecodeError::InvalidValue)?, attribution_data })),
1981 },
1982 (1, Reason) => {
1983 (0, _failure_code, (legacy, u16, |_| Ok(()),
1984 |r: &HTLCFailReasonRepr| match r {
1985 HTLCFailReasonRepr::LightningError{ .. } => None,
1986 HTLCFailReasonRepr::Reason{ failure_reason, .. } => Some(failure_reason.failure_code())
1987 })),
1988 (1, failure_reason, (default_value, LocalHTLCFailureReason::from(_failure_code.ok_or(DecodeError::InvalidValue)?))),
1991 (2, data, required_vec),
1992 },
1993);
1994
1995impl HTLCFailReason {
1996 pub(super) fn reason(failure_reason: LocalHTLCFailureReason, data: Vec<u8>) -> Self {
1997 match failure_reason {
1998 LocalHTLCFailureReason::TemporaryNodeFailure
1999 | LocalHTLCFailureReason::ForwardExpiryBuffer => debug_assert!(data.is_empty()),
2000 LocalHTLCFailureReason::PermanentNodeFailure => debug_assert!(data.is_empty()),
2001 LocalHTLCFailureReason::RequiredNodeFeature
2002 | LocalHTLCFailureReason::PaymentSecretRequired => debug_assert!(data.is_empty()),
2003 LocalHTLCFailureReason::InvalidOnionVersion => debug_assert_eq!(data.len(), 32),
2004 LocalHTLCFailureReason::InvalidOnionHMAC => debug_assert_eq!(data.len(), 32),
2005 LocalHTLCFailureReason::InvalidOnionKey => debug_assert_eq!(data.len(), 32),
2006 LocalHTLCFailureReason::TemporaryChannelFailure
2007 | LocalHTLCFailureReason::DustLimitHolder
2008 | LocalHTLCFailureReason::DustLimitCounterparty
2009 | LocalHTLCFailureReason::FeeSpikeBuffer
2010 | LocalHTLCFailureReason::ChannelNotReady
2011 | LocalHTLCFailureReason::ZeroAmount
2012 | LocalHTLCFailureReason::HTLCMinimum
2013 | LocalHTLCFailureReason::HTLCMaximum
2014 | LocalHTLCFailureReason::PeerOffline
2015 | LocalHTLCFailureReason::ChannelBalanceOverdrawn => {
2016 debug_assert_eq!(
2017 data.len() - 2,
2018 u16::from_be_bytes(data[0..2].try_into().unwrap()) as usize
2019 )
2020 },
2021 LocalHTLCFailureReason::PermanentChannelFailure
2022 | LocalHTLCFailureReason::OnChainTimeout
2023 | LocalHTLCFailureReason::ChannelClosed => debug_assert!(data.is_empty()),
2024 LocalHTLCFailureReason::RequiredChannelFeature => debug_assert!(data.is_empty()),
2025 LocalHTLCFailureReason::UnknownNextPeer
2026 | LocalHTLCFailureReason::PrivateChannelForward
2027 | LocalHTLCFailureReason::RealSCIDForward
2028 | LocalHTLCFailureReason::InvalidTrampolineForward => debug_assert!(data.is_empty()),
2029 LocalHTLCFailureReason::AmountBelowMinimum => debug_assert_eq!(
2030 data.len() - 2 - 8,
2031 u16::from_be_bytes(data[8..10].try_into().unwrap()) as usize
2032 ),
2033 LocalHTLCFailureReason::FeeInsufficient => debug_assert_eq!(
2034 data.len() - 2 - 8,
2035 u16::from_be_bytes(data[8..10].try_into().unwrap()) as usize
2036 ),
2037 LocalHTLCFailureReason::IncorrectCLTVExpiry => debug_assert_eq!(
2038 data.len() - 2 - 4,
2039 u16::from_be_bytes(data[4..6].try_into().unwrap()) as usize
2040 ),
2041 LocalHTLCFailureReason::CLTVExpiryTooSoon
2042 | LocalHTLCFailureReason::OutgoingCLTVTooSoon => debug_assert_eq!(
2043 data.len() - 2,
2044 u16::from_be_bytes(data[0..2].try_into().unwrap()) as usize
2045 ),
2046 LocalHTLCFailureReason::IncorrectPaymentDetails
2047 | LocalHTLCFailureReason::PaymentClaimBuffer
2048 | LocalHTLCFailureReason::InvalidKeysendPreimage => debug_assert_eq!(data.len(), 12),
2049 LocalHTLCFailureReason::FinalIncorrectCLTVExpiry => debug_assert_eq!(data.len(), 4),
2050 LocalHTLCFailureReason::FinalIncorrectHTLCAmount => debug_assert_eq!(data.len(), 8),
2051 LocalHTLCFailureReason::ChannelDisabled => debug_assert_eq!(
2052 data.len() - 2 - 2,
2053 u16::from_be_bytes(data[2..4].try_into().unwrap()) as usize
2054 ),
2055 LocalHTLCFailureReason::CLTVExpiryTooFar => debug_assert!(data.is_empty()),
2056 LocalHTLCFailureReason::InvalidOnionPayload
2057 | LocalHTLCFailureReason::InvalidTrampolinePayload => debug_assert!(data.len() <= 11),
2058 LocalHTLCFailureReason::MPPTimeout => debug_assert!(data.is_empty()),
2059 LocalHTLCFailureReason::InvalidOnionBlinding => debug_assert_eq!(data.len(), 32),
2060 LocalHTLCFailureReason::UnknownFailureCode { code } => {
2061 if code & BADONION == 0 {
2063 debug_assert!(false, "Unknown failure code: {}", code)
2064 }
2065 },
2066 LocalHTLCFailureReason::TemporaryTrampolineFailure => debug_assert!(data.is_empty()),
2067 LocalHTLCFailureReason::TrampolineFeeOrExpiryInsufficient => {
2068 debug_assert_eq!(data.len(), 10)
2069 },
2070 LocalHTLCFailureReason::UnknownNextTrampoline => debug_assert!(data.is_empty()),
2071 }
2072
2073 Self(HTLCFailReasonRepr::Reason { data, failure_reason })
2074 }
2075
2076 pub(super) fn from_failure_code(failure_reason: LocalHTLCFailureReason) -> Self {
2077 Self::reason(failure_reason, Vec::new())
2078 }
2079
2080 pub(super) fn from_msg(msg: &msgs::UpdateFailHTLC) -> Self {
2081 Self(HTLCFailReasonRepr::LightningError {
2082 err: OnionErrorPacket {
2083 data: msg.reason.clone(),
2084 attribution_data: msg.attribution_data.clone(),
2085 },
2086 hold_time: None,
2087 })
2088 }
2089
2090 pub(super) fn get_encrypted_failure_packet(
2096 &self, incoming_packet_shared_secret: &[u8; 32], secondary_shared_secret: &Option<[u8; 32]>,
2097 ) -> msgs::OnionErrorPacket {
2098 match self.0 {
2099 HTLCFailReasonRepr::Reason { ref data, ref failure_reason } => {
2100 let hold_time: u32 = 0;
2102
2103 if let Some(secondary_shared_secret) = secondary_shared_secret {
2104 let mut packet = build_failure_packet(
2106 secondary_shared_secret,
2107 *failure_reason,
2108 &data[..],
2109 hold_time,
2110 );
2111
2112 process_failure_packet(&mut packet, incoming_packet_shared_secret, hold_time);
2113 crypt_failure_packet(incoming_packet_shared_secret, &mut packet);
2114
2115 packet
2116 } else {
2117 build_failure_packet(
2118 incoming_packet_shared_secret,
2119 *failure_reason,
2120 &data[..],
2121 hold_time,
2122 )
2123 }
2124 },
2125 HTLCFailReasonRepr::LightningError { ref err, hold_time } => {
2126 let mut err = err.clone();
2127 let hold_time = hold_time.unwrap_or(0);
2128
2129 process_failure_packet(&mut err, incoming_packet_shared_secret, hold_time);
2130 crypt_failure_packet(incoming_packet_shared_secret, &mut err);
2131
2132 err
2133 },
2134 }
2135 }
2136
2137 pub(super) fn decode_onion_failure<T: secp256k1::Signing, L: Logger>(
2138 &self, secp_ctx: &Secp256k1<T>, logger: &L, htlc_source: &HTLCSource,
2139 ) -> DecodedOnionFailure {
2140 match self.0 {
2141 HTLCFailReasonRepr::LightningError { ref err, .. } => {
2142 process_onion_failure(secp_ctx, logger, &htlc_source, err.clone())
2143 },
2144 #[allow(unused)]
2145 HTLCFailReasonRepr::Reason { ref data, ref failure_reason } => {
2146 if let &HTLCSource::OutboundRoute { ref path, .. } = htlc_source {
2152 DecodedOnionFailure {
2153 network_update: None,
2154 payment_failed_permanently: false,
2155 short_channel_id: Some(path.hops[0].short_channel_id),
2156 failed_within_blinded_path: false,
2157 hold_times: Vec::new(),
2158 #[cfg(any(test, feature = "_test_utils"))]
2159 onion_error_code: Some(*failure_reason),
2160 #[cfg(any(test, feature = "_test_utils"))]
2161 onion_error_data: Some(data.clone()),
2162 #[cfg(test)]
2163 attribution_failed_channel: None,
2164 }
2165 } else {
2166 unreachable!();
2167 }
2168 },
2169 }
2170 }
2171}
2172
2173pub(crate) trait NextPacketBytes: AsMut<[u8]> {
2176 fn new(len: usize) -> Self;
2177}
2178
2179impl NextPacketBytes for FixedSizeOnionPacket {
2180 fn new(_len: usize) -> Self {
2181 Self([0 as u8; ONION_DATA_LEN])
2182 }
2183}
2184
2185impl NextPacketBytes for Vec<u8> {
2186 fn new(len: usize) -> Self {
2187 vec![0 as u8; len]
2188 }
2189}
2190
2191pub(crate) enum Hop {
2193 Forward {
2195 next_hop_data: msgs::InboundOnionForwardPayload,
2197 shared_secret: SharedSecret,
2199 next_hop_hmac: [u8; 32],
2201 new_packet_bytes: [u8; ONION_DATA_LEN],
2203 },
2204 TrampolineForward {
2207 #[allow(unused)]
2208 outer_hop_data: msgs::InboundTrampolineEntrypointPayload,
2209 outer_shared_secret: SharedSecret,
2210 incoming_trampoline_public_key: PublicKey,
2211 trampoline_shared_secret: SharedSecret,
2212 next_trampoline_hop_data: msgs::InboundTrampolineForwardPayload,
2213 next_trampoline_hop_hmac: [u8; 32],
2214 new_trampoline_packet_bytes: Vec<u8>,
2215 },
2216 TrampolineBlindedForward {
2219 outer_hop_data: msgs::InboundTrampolineEntrypointPayload,
2220 outer_shared_secret: SharedSecret,
2221 #[allow(unused)]
2222 incoming_trampoline_public_key: PublicKey,
2223 trampoline_shared_secret: SharedSecret,
2224 next_trampoline_hop_data: msgs::InboundTrampolineBlindedForwardPayload,
2225 next_trampoline_hop_hmac: [u8; 32],
2226 new_trampoline_packet_bytes: Vec<u8>,
2227 },
2228 BlindedForward {
2230 next_hop_data: msgs::InboundOnionBlindedForwardPayload,
2232 shared_secret: SharedSecret,
2234 next_hop_hmac: [u8; 32],
2236 new_packet_bytes: [u8; ONION_DATA_LEN],
2238 },
2239 Dummy {
2241 dummy_hop_data: msgs::InboundOnionDummyPayload,
2243 shared_secret: SharedSecret,
2245 next_hop_hmac: [u8; 32],
2247 new_packet_bytes: [u8; ONION_DATA_LEN],
2249 },
2250 Receive {
2253 hop_data: msgs::InboundOnionReceivePayload,
2255 shared_secret: SharedSecret,
2257 },
2258 BlindedReceive {
2261 hop_data: msgs::InboundOnionBlindedReceivePayload,
2263 shared_secret: SharedSecret,
2265 },
2266 TrampolineReceive {
2269 #[allow(unused)]
2270 outer_hop_data: msgs::InboundTrampolineEntrypointPayload,
2271 outer_shared_secret: SharedSecret,
2272 trampoline_hop_data: msgs::InboundOnionReceivePayload,
2273 trampoline_shared_secret: SharedSecret,
2274 },
2275 TrampolineBlindedReceive {
2278 #[allow(unused)]
2279 outer_hop_data: msgs::InboundTrampolineEntrypointPayload,
2280 outer_shared_secret: SharedSecret,
2281 trampoline_hop_data: msgs::InboundOnionBlindedReceivePayload,
2282 trampoline_shared_secret: SharedSecret,
2283 },
2284}
2285
2286impl Hop {
2287 pub(crate) fn is_intro_node_blinded_forward(&self) -> bool {
2288 match self {
2289 Self::BlindedForward {
2290 next_hop_data:
2291 msgs::InboundOnionBlindedForwardPayload {
2292 intro_node_blinding_point: Some(_), ..
2293 },
2294 ..
2295 } => true,
2296 _ => false,
2297 }
2298 }
2299
2300 pub(crate) fn shared_secret(&self) -> &SharedSecret {
2301 match self {
2302 Hop::Forward { shared_secret, .. } => shared_secret,
2303 Hop::BlindedForward { shared_secret, .. } => shared_secret,
2304 Hop::Dummy { shared_secret, .. } => shared_secret,
2305 Hop::TrampolineForward { outer_shared_secret, .. } => outer_shared_secret,
2306 Hop::TrampolineBlindedForward { outer_shared_secret, .. } => outer_shared_secret,
2307 Hop::Receive { shared_secret, .. } => shared_secret,
2308 Hop::BlindedReceive { shared_secret, .. } => shared_secret,
2309 Hop::TrampolineReceive { outer_shared_secret, .. } => outer_shared_secret,
2310 Hop::TrampolineBlindedReceive { outer_shared_secret, .. } => outer_shared_secret,
2311 }
2312 }
2313}
2314
2315#[derive(Debug)]
2317pub(crate) enum OnionDecodeErr {
2318 Malformed { err_msg: &'static str, reason: LocalHTLCFailureReason },
2320 Relay {
2325 err_msg: &'static str,
2326 reason: LocalHTLCFailureReason,
2327 shared_secret: SharedSecret,
2328 trampoline_shared_secret: Option<SharedSecret>,
2329 },
2330}
2331
2332pub(crate) fn decode_next_payment_hop<NS: NodeSigner>(
2333 recipient: Recipient, hop_pubkey: &PublicKey, hop_data: &[u8], hmac_bytes: [u8; 32],
2334 payment_hash: PaymentHash, blinding_point: Option<PublicKey>, node_signer: NS,
2335) -> Result<Hop, OnionDecodeErr> {
2336 let blinded_node_id_tweak = blinding_point.map(|bp| {
2337 let blinded_tlvs_ss = node_signer.ecdh(recipient, &bp, None).unwrap().secret_bytes();
2338 let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
2339 hmac.input(blinded_tlvs_ss.as_ref());
2340 Scalar::from_be_bytes(Hmac::from_engine(hmac).to_byte_array()).unwrap()
2341 });
2342 let shared_secret =
2343 node_signer.ecdh(recipient, hop_pubkey, blinded_node_id_tweak.as_ref()).unwrap();
2344
2345 let decoded_hop: Result<(msgs::InboundOnionPayload, Option<_>), _> = decode_next_hop(
2346 shared_secret.secret_bytes(),
2347 hop_data,
2348 hmac_bytes,
2349 Some(payment_hash),
2350 (blinding_point, &node_signer),
2351 );
2352 match decoded_hop {
2353 Ok((next_hop_data, Some((next_hop_hmac, FixedSizeOnionPacket(new_packet_bytes))))) => {
2354 match next_hop_data {
2355 msgs::InboundOnionPayload::Forward(next_hop_data) => Ok(Hop::Forward {
2356 shared_secret,
2357 next_hop_data,
2358 next_hop_hmac,
2359 new_packet_bytes,
2360 }),
2361 msgs::InboundOnionPayload::BlindedForward(next_hop_data) => {
2362 Ok(Hop::BlindedForward {
2363 shared_secret,
2364 next_hop_data,
2365 next_hop_hmac,
2366 new_packet_bytes,
2367 })
2368 },
2369 msgs::InboundOnionPayload::Dummy(dummy_hop_data) => Ok(Hop::Dummy {
2370 dummy_hop_data,
2371 shared_secret,
2372 next_hop_hmac,
2373 new_packet_bytes,
2374 }),
2375 _ => {
2376 if blinding_point.is_some() {
2377 return Err(OnionDecodeErr::Malformed {
2378 err_msg:
2379 "Final Node OnionHopData provided for us as an intermediary node",
2380 reason: LocalHTLCFailureReason::InvalidOnionBlinding,
2381 });
2382 }
2383 Err(OnionDecodeErr::Relay {
2384 err_msg: "Final Node OnionHopData provided for us as an intermediary node",
2385 reason: LocalHTLCFailureReason::InvalidOnionPayload,
2386 shared_secret,
2387 trampoline_shared_secret: None,
2388 })
2389 },
2390 }
2391 },
2392 Ok((next_hop_data, None)) => match next_hop_data {
2393 msgs::InboundOnionPayload::Receive(hop_data) => {
2394 Ok(Hop::Receive { shared_secret, hop_data })
2395 },
2396 msgs::InboundOnionPayload::BlindedReceive(hop_data) => {
2397 Ok(Hop::BlindedReceive { shared_secret, hop_data })
2398 },
2399 msgs::InboundOnionPayload::TrampolineEntrypoint(hop_data) => {
2400 let incoming_trampoline_public_key = hop_data.trampoline_packet.public_key;
2401 let trampoline_blinded_node_id_tweak = hop_data.current_path_key.map(|bp| {
2402 let blinded_tlvs_ss =
2403 node_signer.ecdh(recipient, &bp, None).unwrap().secret_bytes();
2404 let mut hmac = HmacEngine::<Sha256>::new(b"blinded_node_id");
2405 hmac.input(blinded_tlvs_ss.as_ref());
2406 Scalar::from_be_bytes(Hmac::from_engine(hmac).to_byte_array()).unwrap()
2407 });
2408 let trampoline_shared_secret = node_signer
2409 .ecdh(
2410 recipient,
2411 &incoming_trampoline_public_key,
2412 trampoline_blinded_node_id_tweak.as_ref(),
2413 )
2414 .unwrap()
2415 .secret_bytes();
2416 let decoded_trampoline_hop: Result<
2417 (msgs::InboundTrampolinePayload, Option<([u8; 32], Vec<u8>)>),
2418 _,
2419 > = decode_next_hop(
2420 trampoline_shared_secret,
2421 &hop_data.trampoline_packet.hop_data,
2422 hop_data.trampoline_packet.hmac,
2423 Some(payment_hash),
2424 (blinding_point, &node_signer),
2425 );
2426 match decoded_trampoline_hop {
2427 Ok((
2428 msgs::InboundTrampolinePayload::Forward(trampoline_hop_data),
2429 Some((next_trampoline_hop_hmac, new_trampoline_packet_bytes)),
2430 )) => Ok(Hop::TrampolineForward {
2431 outer_hop_data: hop_data,
2432 outer_shared_secret: shared_secret,
2433 incoming_trampoline_public_key,
2434 trampoline_shared_secret: SharedSecret::from_bytes(
2435 trampoline_shared_secret,
2436 ),
2437 next_trampoline_hop_data: trampoline_hop_data,
2438 next_trampoline_hop_hmac,
2439 new_trampoline_packet_bytes,
2440 }),
2441 Ok((
2442 msgs::InboundTrampolinePayload::BlindedForward(trampoline_hop_data),
2443 Some((next_trampoline_hop_hmac, new_trampoline_packet_bytes)),
2444 )) => Ok(Hop::TrampolineBlindedForward {
2445 outer_hop_data: hop_data,
2446 outer_shared_secret: shared_secret,
2447 incoming_trampoline_public_key,
2448 trampoline_shared_secret: SharedSecret::from_bytes(
2449 trampoline_shared_secret,
2450 ),
2451 next_trampoline_hop_data: trampoline_hop_data,
2452 next_trampoline_hop_hmac,
2453 new_trampoline_packet_bytes,
2454 }),
2455 Ok((msgs::InboundTrampolinePayload::Receive(trampoline_hop_data), None)) => {
2456 Ok(Hop::TrampolineReceive {
2457 outer_hop_data: hop_data,
2458 outer_shared_secret: shared_secret,
2459 trampoline_hop_data,
2460 trampoline_shared_secret: SharedSecret::from_bytes(
2461 trampoline_shared_secret,
2462 ),
2463 })
2464 },
2465 Ok((
2466 msgs::InboundTrampolinePayload::BlindedReceive(trampoline_hop_data),
2467 None,
2468 )) => Ok(Hop::TrampolineBlindedReceive {
2469 outer_hop_data: hop_data,
2470 outer_shared_secret: shared_secret,
2471 trampoline_hop_data,
2472 trampoline_shared_secret: SharedSecret::from_bytes(
2473 trampoline_shared_secret,
2474 ),
2475 }),
2476 Ok((msgs::InboundTrampolinePayload::BlindedForward(hop_data), None)) => {
2477 if hop_data.intro_node_blinding_point.is_some() {
2478 return Err(OnionDecodeErr::Relay {
2479 err_msg: "Non-final intro node Trampoline onion data provided to us as last hop",
2480 reason: LocalHTLCFailureReason::InvalidOnionPayload,
2481 shared_secret,
2482 trampoline_shared_secret: Some(SharedSecret::from_bytes(
2483 trampoline_shared_secret,
2484 )),
2485 });
2486 }
2487 Err(OnionDecodeErr::Malformed {
2488 err_msg: "Non-final Trampoline onion data provided to us as last hop",
2489 reason: LocalHTLCFailureReason::InvalidOnionBlinding,
2490 })
2491 },
2492 Ok((msgs::InboundTrampolinePayload::BlindedReceive(hop_data), Some(_))) => {
2493 if hop_data.intro_node_blinding_point.is_some() {
2494 return Err(OnionDecodeErr::Relay {
2495 err_msg: "Final Trampoline intro node onion data provided to us as intermediate hop",
2496 reason: LocalHTLCFailureReason::InvalidTrampolinePayload,
2497 shared_secret,
2498 trampoline_shared_secret: Some(SharedSecret::from_bytes(
2499 trampoline_shared_secret,
2500 )),
2501 });
2502 }
2503 Err(OnionDecodeErr::Malformed {
2504 err_msg:
2505 "Final Trampoline onion data provided to us as intermediate hop",
2506 reason: LocalHTLCFailureReason::InvalidOnionBlinding,
2507 })
2508 },
2509 Ok((msgs::InboundTrampolinePayload::Forward(_), None)) => {
2510 Err(OnionDecodeErr::Relay {
2511 err_msg: "Non-final Trampoline onion data provided to us as last hop",
2512 reason: LocalHTLCFailureReason::InvalidTrampolinePayload,
2513 shared_secret,
2514 trampoline_shared_secret: Some(SharedSecret::from_bytes(
2515 trampoline_shared_secret,
2516 )),
2517 })
2518 },
2519 Ok((msgs::InboundTrampolinePayload::Receive(_), Some(_))) => {
2520 Err(OnionDecodeErr::Relay {
2521 err_msg:
2522 "Final Trampoline onion data provided to us as intermediate hop",
2523 reason: LocalHTLCFailureReason::InvalidTrampolinePayload,
2524 shared_secret,
2525 trampoline_shared_secret: Some(SharedSecret::from_bytes(
2526 trampoline_shared_secret,
2527 )),
2528 })
2529 },
2530 Err(e) => Err(e),
2531 }
2532 },
2533 _ => {
2534 if blinding_point.is_some() {
2535 return Err(OnionDecodeErr::Malformed {
2536 err_msg: "Intermediate Node OnionHopData provided for us as a final node",
2537 reason: LocalHTLCFailureReason::InvalidOnionBlinding,
2538 });
2539 }
2540 Err(OnionDecodeErr::Relay {
2541 err_msg: "Intermediate Node OnionHopData provided for us as a final node",
2542 reason: LocalHTLCFailureReason::InvalidOnionPayload,
2543 shared_secret,
2544 trampoline_shared_secret: None,
2545 })
2546 },
2547 },
2548 Err(e) => Err(e),
2549 }
2550}
2551
2552pub(super) fn peel_dummy_hop_update_add_htlc<NS: NodeSigner, T: secp256k1::Verification>(
2563 msg: &UpdateAddHTLC, dummy_hop_data: InboundOnionDummyPayload, next_hop_hmac: [u8; 32],
2564 new_packet_bytes: [u8; ONION_DATA_LEN], next_packet_details: NextPacketDetails,
2565 node_signer: NS, secp_ctx: &Secp256k1<T>,
2566) -> UpdateAddHTLC {
2567 let NextPacketDetails {
2568 next_packet_pubkey,
2569 outgoing_amt_msat,
2570 outgoing_connector,
2571 outgoing_cltv_value,
2572 } = next_packet_details;
2573
2574 debug_assert!(
2575 matches!(outgoing_connector, HopConnector::Dummy),
2576 "Dummy hop must always map to HopConnector::Dummy"
2577 );
2578
2579 let next_blinding_point = dummy_hop_data
2580 .intro_node_blinding_point
2581 .or(msg.blinding_point)
2582 .and_then(|blinding_point| {
2583 let ss = node_signer.ecdh(Recipient::Node, &blinding_point, None).ok()?.secret_bytes();
2584
2585 next_hop_pubkey(secp_ctx, blinding_point, &ss).ok()
2586 });
2587
2588 let new_onion_packet = OnionPacket {
2589 version: 0,
2590 public_key: next_packet_pubkey,
2591 hop_data: new_packet_bytes,
2592 hmac: next_hop_hmac,
2593 };
2594
2595 UpdateAddHTLC {
2596 onion_routing_packet: new_onion_packet,
2597 blinding_point: next_blinding_point,
2598 amount_msat: outgoing_amt_msat,
2599 cltv_expiry: outgoing_cltv_value,
2600 ..msg.clone()
2601 }
2602}
2603
2604pub fn create_payment_onion<T: secp256k1::Signing>(
2608 secp_ctx: &Secp256k1<T>, path: &Path, session_priv: &SecretKey,
2609 recipient_onion: &RecipientOnionFields, cur_block_height: u32, payment_hash: &PaymentHash,
2610 keysend_preimage: &Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
2611 prng_seed: [u8; 32],
2612) -> Result<(msgs::OnionPacket, u64, u32), APIError> {
2613 create_payment_onion_internal(
2614 secp_ctx,
2615 path,
2616 session_priv,
2617 recipient_onion,
2618 cur_block_height,
2619 payment_hash,
2620 keysend_preimage,
2621 invoice_request,
2622 prng_seed,
2623 None,
2624 None,
2625 )
2626}
2627
2628pub(super) fn compute_trampoline_session_priv(outer_onion_session_priv: &SecretKey) -> SecretKey {
2629 let session_priv_hash = Sha256::hash(&outer_onion_session_priv.secret_bytes()).to_byte_array();
2632 SecretKey::from_slice(&session_priv_hash[..]).expect("You broke SHA-256!")
2633}
2634
2635pub(crate) fn create_payment_onion_internal<T: secp256k1::Signing>(
2638 secp_ctx: &Secp256k1<T>, path: &Path, session_priv: &SecretKey,
2639 recipient_onion: &RecipientOnionFields, cur_block_height: u32, payment_hash: &PaymentHash,
2640 keysend_preimage: &Option<PaymentPreimage>, invoice_request: Option<&InvoiceRequest>,
2641 prng_seed: [u8; 32], trampoline_session_priv_override: Option<SecretKey>,
2642 trampoline_prng_seed_override: Option<[u8; 32]>,
2643) -> Result<(msgs::OnionPacket, u64, u32), APIError> {
2644 let mut trampoline_outer_onion = RecipientOnionFields {
2650 payment_secret: recipient_onion.payment_secret,
2651 total_mpp_amount_msat: 0,
2652 payment_metadata: None,
2653 custom_tlvs: Vec::new(),
2654 };
2655 let (outer_onion, trampoline_packet_option) = if let Some(blinded_tail) = &path.blinded_tail {
2656 if recipient_onion.payment_metadata.is_some() {
2657 return Err(APIError::InvalidRoute {
2658 err: "Cannot pass payment_metadata to a blinded recipient".to_owned(),
2659 });
2660 }
2661
2662 if !blinded_tail.trampoline_hops.is_empty() {
2663 let trampoline_payloads;
2664 let outer_total_msat;
2665 (trampoline_payloads, outer_total_msat) = build_trampoline_onion_payloads(
2666 &blinded_tail,
2667 recipient_onion,
2668 cur_block_height,
2669 keysend_preimage,
2670 )?;
2671 trampoline_outer_onion.total_mpp_amount_msat = outer_total_msat;
2672
2673 let trampoline_session_priv = trampoline_session_priv_override
2674 .unwrap_or_else(|| compute_trampoline_session_priv(session_priv));
2675 let trampoline_prng_seed = trampoline_prng_seed_override.unwrap_or(prng_seed);
2676 let onion_keys =
2677 construct_trampoline_onion_keys(&secp_ctx, &blinded_tail, &trampoline_session_priv);
2678 let trampoline_packet = construct_trampoline_onion_packet(
2679 trampoline_payloads,
2680 onion_keys,
2681 trampoline_prng_seed,
2682 payment_hash,
2683 None,
2685 )
2686 .map_err(|_| APIError::InvalidRoute {
2687 err: "Route size too large (or empty) considering onion data".to_owned(),
2688 })?;
2689
2690 (&trampoline_outer_onion, Some(trampoline_packet))
2691 } else {
2692 (recipient_onion, None)
2693 }
2694 } else {
2695 (recipient_onion, None)
2696 };
2697
2698 let (onion_payloads, htlc_msat, htlc_cltv) = build_onion_payloads(
2699 &path,
2700 outer_onion,
2701 cur_block_height,
2702 keysend_preimage,
2703 invoice_request,
2704 trampoline_packet_option,
2705 )?;
2706 debug_assert_eq!(htlc_cltv - cur_block_height, path.total_cltv_expiry_delta());
2707
2708 let onion_keys = construct_onion_keys(&secp_ctx, &path, session_priv);
2709 let onion_packet = construct_onion_packet(onion_payloads, onion_keys, prng_seed, payment_hash)
2710 .map_err(|_| APIError::InvalidRoute {
2711 err: "Route size too large (or empty) considering onion data".to_owned(),
2712 })?;
2713 Ok((onion_packet, htlc_msat, htlc_cltv))
2714}
2715
2716pub(crate) fn decode_next_untagged_hop<T, R: ReadableArgs<T>, N: NextPacketBytes>(
2717 shared_secret: [u8; 32], hop_data: &[u8], hmac_bytes: [u8; 32], read_args: T,
2718) -> Result<(R, Option<([u8; 32], N)>), OnionDecodeErr> {
2719 decode_next_hop(shared_secret, hop_data, hmac_bytes, None, read_args)
2720}
2721
2722fn decode_next_hop<T, R: ReadableArgs<T>, N: NextPacketBytes>(
2723 shared_secret: [u8; 32], hop_data: &[u8], hmac_bytes: [u8; 32],
2724 payment_hash: Option<PaymentHash>, read_args: T,
2725) -> Result<(R, Option<([u8; 32], N)>), OnionDecodeErr> {
2726 let (rho, mu) = gen_rho_mu_from_shared_secret(&shared_secret);
2727 let mut hmac = HmacEngine::<Sha256>::new(&mu);
2728 hmac.input(hop_data);
2729 if let Some(tag) = payment_hash {
2730 hmac.input(&tag.0[..]);
2731 }
2732 if !fixed_time_eq(&Hmac::from_engine(hmac).to_byte_array(), &hmac_bytes) {
2733 return Err(OnionDecodeErr::Malformed {
2734 err_msg: "HMAC Check failed",
2735 reason: LocalHTLCFailureReason::InvalidOnionHMAC,
2736 });
2737 }
2738
2739 let mut chacha = ChaCha20::new(Key::new(rho), Nonce::new([0; 12]), 0);
2740 let mut chacha_stream = ChaChaReader { chacha: &mut chacha, read: Cursor::new(&hop_data[..]) };
2741 match R::read(&mut chacha_stream, read_args) {
2742 Err(err) => {
2743 let reason = match err {
2744 msgs::DecodeError::UnknownVersion => LocalHTLCFailureReason::InvalidOnionVersion,
2746 msgs::DecodeError::UnknownRequiredFeature
2748 | msgs::DecodeError::InvalidValue
2749 | msgs::DecodeError::ShortRead => LocalHTLCFailureReason::InvalidOnionPayload,
2750 _ => LocalHTLCFailureReason::TemporaryNodeFailure,
2752 };
2753 return Err(OnionDecodeErr::Relay {
2754 err_msg: "Unable to decode our hop data",
2755 reason,
2756 shared_secret: SharedSecret::from_bytes(shared_secret),
2757 trampoline_shared_secret: None,
2758 });
2759 },
2760 Ok(msg) => {
2761 let mut hmac = [0; 32];
2762 if let Err(_) = chacha_stream.read_exact(&mut hmac[..]) {
2763 return Err(OnionDecodeErr::Relay {
2764 err_msg: "Unable to decode our hop data",
2765 reason: LocalHTLCFailureReason::InvalidOnionPayload,
2766 shared_secret: SharedSecret::from_bytes(shared_secret),
2767 trampoline_shared_secret: None,
2768 });
2769 }
2770 if hmac == [0; 32] {
2771 #[cfg(test)]
2772 {
2773 if chacha_stream.read.position() < hop_data.len() as u64 - 64 {
2774 let mut next_bytes = [0; 32];
2782 chacha_stream.read_exact(&mut next_bytes).unwrap();
2783 assert_ne!(next_bytes[..], [0; 32][..]);
2784 chacha_stream.read_exact(&mut next_bytes).unwrap();
2785 assert_ne!(next_bytes[..], [0; 32][..]);
2786 }
2787 }
2788 return Ok((msg, None)); } else {
2790 let mut new_packet_bytes = N::new(hop_data.len());
2791 let read_pos = hop_data.len() - chacha_stream.read.position() as usize;
2792 chacha_stream.read_exact(&mut new_packet_bytes.as_mut()[..read_pos]).unwrap();
2793 #[cfg(debug_assertions)]
2794 {
2795 let mut t = [0; 1];
2800 debug_assert!(chacha_stream.read(&mut t).unwrap() == 0);
2801 }
2802 chacha_stream.chacha.apply_keystream(&mut new_packet_bytes.as_mut()[read_pos..]);
2805 return Ok((msg, Some((hmac, new_packet_bytes)))); }
2807 },
2808 }
2809}
2810
2811pub(crate) const HOLD_TIME_LEN: usize = 4;
2812pub(crate) const MAX_HOPS: usize = 20;
2813pub(crate) const HMAC_LEN: usize = 4;
2814
2815pub(crate) const HMAC_COUNT: usize = MAX_HOPS * (MAX_HOPS + 1) / 2;
2818
2819#[derive(Clone, Debug, Hash, PartialEq, Eq)]
2820pub struct AttributionData {
2827 hold_times: [u8; MAX_HOPS * HOLD_TIME_LEN],
2828 hmacs: [u8; HMAC_LEN * HMAC_COUNT],
2829}
2830
2831impl AttributionData {
2832 pub(crate) fn new() -> Self {
2833 Self { hold_times: [0; MAX_HOPS * HOLD_TIME_LEN], hmacs: [0; HMAC_LEN * HMAC_COUNT] }
2834 }
2835}
2836
2837impl_writeable!(AttributionData, {
2838 hold_times,
2839 hmacs
2840});
2841
2842impl AttributionData {
2843 pub(crate) fn crypt(&mut self, shared_secret: &[u8]) {
2845 let ammagext = gen_ammagext_from_shared_secret(&shared_secret);
2846 let mut chacha = ChaCha20::new(Key::new(ammagext), Nonce::new([0; 12]), 0);
2847 chacha.apply_keystream(&mut self.hold_times);
2848 chacha.apply_keystream(&mut self.hmacs);
2849 }
2850
2851 pub(crate) fn add_hmacs(&mut self, shared_secret: &[u8], message: &[u8]) {
2853 let um: [u8; 32] = gen_um_from_shared_secret(&shared_secret);
2854
2855 for hmac_idx in 0..MAX_HOPS {
2858 let position: usize = MAX_HOPS - hmac_idx - 1;
2860
2861 let mut hmac_engine = HmacEngine::<Sha256>::new(&um);
2864 hmac_engine.input(&message);
2865 hmac_engine.input(&self.hold_times[..(position + 1) * HOLD_TIME_LEN]);
2866 self.write_downstream_hmacs(position, &mut hmac_engine);
2867
2868 let full_hmac = Hmac::from_engine(hmac_engine).to_byte_array();
2869
2870 let hmac = &full_hmac[..HMAC_LEN];
2873
2874 self.get_hmac_mut(hmac_idx).copy_from_slice(hmac);
2876 }
2877 }
2878
2879 pub(crate) fn write_downstream_hmacs(&self, position: usize, w: &mut HmacEngine<Sha256>) {
2882 let mut hmac_idx = MAX_HOPS + MAX_HOPS - position - 1;
2885
2886 for j in 0..position {
2888 w.input(self.get_hmac(hmac_idx));
2889
2890 let block_size = MAX_HOPS - j - 1;
2892
2893 hmac_idx += block_size;
2895 }
2896 }
2897
2898 fn verify(&self, message: &[u8], shared_secret: &[u8], position: usize) -> Result<u32, ()> {
2901 let um = gen_um_from_shared_secret(shared_secret);
2903 let mut hmac = HmacEngine::<Sha256>::new(&um);
2904 hmac.input(&message);
2905 hmac.input(&self.hold_times[..(position + 1) * HOLD_TIME_LEN]);
2906 self.write_downstream_hmacs(position, &mut hmac);
2907 let expected_hmac = &Hmac::from_engine(hmac).to_byte_array()[..HMAC_LEN];
2908
2909 let hmac_idx = MAX_HOPS - position - 1;
2911 let actual_hmac = self.get_hmac(hmac_idx);
2912 if !fixed_time_eq(expected_hmac, actual_hmac) {
2913 return Err(());
2914 }
2915
2916 let hold_time: u32 = u32::from_be_bytes(self.get_hold_time_bytes(0).try_into().unwrap());
2918
2919 Ok(hold_time)
2920 }
2921
2922 fn shift_left(&mut self) {
2925 self.hold_times.copy_within(HOLD_TIME_LEN.., 0);
2927
2928 let mut src_idx = MAX_HOPS;
2930 let mut dest_idx = 1;
2931 let mut copy_len = MAX_HOPS - 1;
2932
2933 for _ in 0..MAX_HOPS - 1 {
2934 self.hmacs.copy_within(
2935 src_idx * HMAC_LEN..(src_idx + copy_len) * HMAC_LEN,
2936 dest_idx * HMAC_LEN,
2937 );
2938
2939 src_idx += copy_len;
2940 dest_idx += copy_len + 1;
2941 copy_len -= 1;
2942 }
2943 }
2944
2945 fn shift_right(&mut self) {
2948 self.hold_times.copy_within(..(MAX_HOPS - 1) * HOLD_TIME_LEN, HOLD_TIME_LEN);
2950
2951 let mut src_idx = HMAC_COUNT - 2;
2954 let mut dest_idx = HMAC_COUNT - 1;
2955 let mut copy_len = 1;
2956
2957 for i in 0..MAX_HOPS - 1 {
2958 self.hmacs.copy_within(
2959 src_idx * HMAC_LEN..(src_idx + copy_len) * HMAC_LEN,
2960 dest_idx * HMAC_LEN,
2961 );
2962
2963 if i == MAX_HOPS - 2 {
2965 break;
2966 }
2967
2968 copy_len += 1;
2969 src_idx -= copy_len + 1;
2970 dest_idx -= copy_len;
2971 }
2972 }
2973
2974 fn get_hmac(&self, idx: usize) -> &[u8] {
2975 &self.hmacs[idx * HMAC_LEN..(idx + 1) * HMAC_LEN]
2976 }
2977
2978 fn get_hmac_mut(&mut self, idx: usize) -> &mut [u8] {
2979 &mut self.hmacs[idx * HMAC_LEN..(idx + 1) * HMAC_LEN]
2980 }
2981
2982 fn get_hold_time_bytes(&self, idx: usize) -> &[u8] {
2983 &self.hold_times[idx * HOLD_TIME_LEN..(idx + 1) * HOLD_TIME_LEN]
2984 }
2985
2986 fn update(&mut self, message: &[u8], shared_secret: &[u8], hold_time: u32) {
2987 let hold_time_bytes: [u8; 4] = hold_time.to_be_bytes();
2988 self.hold_times[..HOLD_TIME_LEN].copy_from_slice(&hold_time_bytes);
2989 self.add_hmacs(shared_secret, message);
2990 }
2991}
2992
2993fn process_failure_packet(
2995 onion_error: &mut OnionErrorPacket, shared_secret: &[u8], hold_time: u32,
2996) {
2997 if let Some(ref mut attribution_data) = onion_error.attribution_data {
2999 attribution_data.shift_right();
3000 }
3001
3002 update_attribution_data(onion_error, shared_secret, hold_time);
3004}
3005
3006pub(crate) fn process_fulfill_attribution_data(
3010 attribution_data: Option<AttributionData>, shared_secret: &[u8], hold_time: u32,
3011) -> AttributionData {
3012 let mut attribution_data =
3013 attribution_data.map_or(AttributionData::new(), |mut attribution_data| {
3014 attribution_data.shift_right();
3016
3017 attribution_data
3018 });
3019
3020 attribution_data.update(&[], &shared_secret, hold_time);
3023 attribution_data.crypt(&shared_secret);
3024
3025 attribution_data
3026}
3027
3028#[cfg(test)]
3029mod tests {
3030 use core::iter;
3031 use std::sync::Arc;
3032
3033 use crate::io;
3034 use crate::ln::channelmanager::PaymentId;
3035 use crate::ln::msgs::{self, UpdateFailHTLC};
3036 use crate::ln::types::ChannelId;
3037 use crate::routing::router::{Path, PaymentParameters, Route, RouteHop};
3038 use crate::types::features::{ChannelFeatures, NodeFeatures};
3039 use crate::types::payment::PaymentHash;
3040 use crate::util::ser::{VecWriter, Writeable, Writer};
3041
3042 #[allow(unused_imports)]
3043 use crate::prelude::*;
3044 use crate::util::test_utils::TestLogger;
3045
3046 use super::*;
3047 use bitcoin::hex::{DisplayHex, FromHex};
3048 use bitcoin::secp256k1::Secp256k1;
3049 use bitcoin::secp256k1::{PublicKey, SecretKey};
3050 use types::features::Features;
3051
3052 fn get_test_session_key() -> SecretKey {
3053 let hex = "4141414141414141414141414141414141414141414141414141414141414141";
3054 SecretKey::from_slice(&<Vec<u8>>::from_hex(hex).unwrap()[..]).unwrap()
3055 }
3056
3057 fn build_test_path() -> Path {
3058 Path {
3059 hops: vec![
3060 RouteHop {
3061 pubkey: PublicKey::from_slice(
3062 &<Vec<u8>>::from_hex(
3063 "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619",
3064 )
3065 .unwrap()[..],
3066 )
3067 .unwrap(),
3068 channel_features: ChannelFeatures::empty(),
3069 node_features: NodeFeatures::empty(),
3070 short_channel_id: 0,
3071 fee_msat: 0,
3072 cltv_expiry_delta: 0,
3073 maybe_announced_channel: true, },
3075 RouteHop {
3076 pubkey: PublicKey::from_slice(
3077 &<Vec<u8>>::from_hex(
3078 "0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c",
3079 )
3080 .unwrap()[..],
3081 )
3082 .unwrap(),
3083 channel_features: ChannelFeatures::empty(),
3084 node_features: NodeFeatures::empty(),
3085 short_channel_id: 1,
3086 fee_msat: 0,
3087 cltv_expiry_delta: 0,
3088 maybe_announced_channel: true, },
3090 RouteHop {
3091 pubkey: PublicKey::from_slice(
3092 &<Vec<u8>>::from_hex(
3093 "027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007",
3094 )
3095 .unwrap()[..],
3096 )
3097 .unwrap(),
3098 channel_features: ChannelFeatures::empty(),
3099 node_features: NodeFeatures::empty(),
3100 short_channel_id: 2,
3101 fee_msat: 0,
3102 cltv_expiry_delta: 0,
3103 maybe_announced_channel: true, },
3105 RouteHop {
3106 pubkey: PublicKey::from_slice(
3107 &<Vec<u8>>::from_hex(
3108 "032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991",
3109 )
3110 .unwrap()[..],
3111 )
3112 .unwrap(),
3113 channel_features: ChannelFeatures::empty(),
3114 node_features: NodeFeatures::empty(),
3115 short_channel_id: 3,
3116 fee_msat: 0,
3117 cltv_expiry_delta: 0,
3118 maybe_announced_channel: true, },
3120 RouteHop {
3121 pubkey: PublicKey::from_slice(
3122 &<Vec<u8>>::from_hex(
3123 "02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145",
3124 )
3125 .unwrap()[..],
3126 )
3127 .unwrap(),
3128 channel_features: ChannelFeatures::empty(),
3129 node_features: NodeFeatures::empty(),
3130 short_channel_id: 4,
3131 fee_msat: 0,
3132 cltv_expiry_delta: 0,
3133 maybe_announced_channel: true, },
3135 ],
3136 blinded_tail: None,
3137 }
3138 }
3139
3140 fn build_test_onion_keys() -> Vec<OnionKeys> {
3141 let secp_ctx = Secp256k1::new();
3143
3144 let path = build_test_path();
3145 let route = Route { paths: vec![path], route_params: None };
3146
3147 let onion_keys =
3148 super::construct_onion_keys(&secp_ctx, &route.paths[0], &get_test_session_key());
3149 assert_eq!(onion_keys.len(), route.paths[0].hops.len());
3150 onion_keys
3151 }
3152
3153 #[test]
3154 fn onion_vectors() {
3155 let onion_keys = build_test_onion_keys();
3156
3157 let hex = "53eb63ea8a3fec3b3cd433b85cd62a4b145e1dda09391b348c4e1cd36a03ea66";
3160 assert_eq!(
3161 onion_keys[0].shared_secret.secret_bytes(),
3162 <Vec<u8>>::from_hex(hex).unwrap()[..]
3163 );
3164
3165 let hex = "2ec2e5da605776054187180343287683aa6a51b4b1c04d6dd49c45d8cffb3c36";
3166 assert_eq!(onion_keys[0].blinding_factor[..], <Vec<u8>>::from_hex(hex).unwrap()[..]);
3167
3168 let hex = "02eec7245d6b7d2ccb30380bfbe2a3648cd7a942653f5aa340edcea1f283686619";
3169 assert_eq!(
3170 onion_keys[0].ephemeral_pubkey.serialize()[..],
3171 <Vec<u8>>::from_hex(hex).unwrap()[..]
3172 );
3173
3174 let hex = "ce496ec94def95aadd4bec15cdb41a740c9f2b62347c4917325fcc6fb0453986";
3175 assert_eq!(onion_keys[0].rho, <Vec<u8>>::from_hex(hex).unwrap()[..]);
3176
3177 let hex = "b57061dc6d0a2b9f261ac410c8b26d64ac5506cbba30267a649c28c179400eba";
3178 assert_eq!(onion_keys[0].mu, <Vec<u8>>::from_hex(hex).unwrap()[..]);
3179
3180 let hex = "a6519e98832a0b179f62123b3567c106db99ee37bef036e783263602f3488fae";
3181 assert_eq!(
3182 onion_keys[1].shared_secret.secret_bytes(),
3183 <Vec<u8>>::from_hex(hex).unwrap()[..]
3184 );
3185
3186 let hex = "bf66c28bc22e598cfd574a1931a2bafbca09163df2261e6d0056b2610dab938f";
3187 assert_eq!(onion_keys[1].blinding_factor[..], <Vec<u8>>::from_hex(hex).unwrap()[..]);
3188
3189 let hex = "028f9438bfbf7feac2e108d677e3a82da596be706cc1cf342b75c7b7e22bf4e6e2";
3190 assert_eq!(
3191 onion_keys[1].ephemeral_pubkey.serialize()[..],
3192 <Vec<u8>>::from_hex(hex).unwrap()[..]
3193 );
3194
3195 let hex = "450ffcabc6449094918ebe13d4f03e433d20a3d28a768203337bc40b6e4b2c59";
3196 assert_eq!(onion_keys[1].rho, <Vec<u8>>::from_hex(hex).unwrap()[..]);
3197
3198 let hex = "05ed2b4a3fb023c2ff5dd6ed4b9b6ea7383f5cfe9d59c11d121ec2c81ca2eea9";
3199 assert_eq!(onion_keys[1].mu, <Vec<u8>>::from_hex(hex).unwrap()[..]);
3200
3201 let hex = "3a6b412548762f0dbccce5c7ae7bb8147d1caf9b5471c34120b30bc9c04891cc";
3202 assert_eq!(
3203 onion_keys[2].shared_secret.secret_bytes(),
3204 <Vec<u8>>::from_hex(hex).unwrap()[..]
3205 );
3206
3207 let hex = "a1f2dadd184eb1627049673f18c6325814384facdee5bfd935d9cb031a1698a5";
3208 assert_eq!(onion_keys[2].blinding_factor[..], <Vec<u8>>::from_hex(hex).unwrap()[..]);
3209
3210 let hex = "03bfd8225241ea71cd0843db7709f4c222f62ff2d4516fd38b39914ab6b83e0da0";
3211 assert_eq!(
3212 onion_keys[2].ephemeral_pubkey.serialize()[..],
3213 <Vec<u8>>::from_hex(hex).unwrap()[..]
3214 );
3215
3216 let hex = "11bf5c4f960239cb37833936aa3d02cea82c0f39fd35f566109c41f9eac8deea";
3217 assert_eq!(onion_keys[2].rho, <Vec<u8>>::from_hex(hex).unwrap()[..]);
3218
3219 let hex = "caafe2820fa00eb2eeb78695ae452eba38f5a53ed6d53518c5c6edf76f3f5b78";
3220 assert_eq!(onion_keys[2].mu, <Vec<u8>>::from_hex(hex).unwrap()[..]);
3221
3222 let hex = "21e13c2d7cfe7e18836df50872466117a295783ab8aab0e7ecc8c725503ad02d";
3223 assert_eq!(
3224 onion_keys[3].shared_secret.secret_bytes(),
3225 <Vec<u8>>::from_hex(hex).unwrap()[..]
3226 );
3227
3228 let hex = "7cfe0b699f35525029ae0fa437c69d0f20f7ed4e3916133f9cacbb13c82ff262";
3229 assert_eq!(onion_keys[3].blinding_factor[..], <Vec<u8>>::from_hex(hex).unwrap()[..]);
3230
3231 let hex = "031dde6926381289671300239ea8e57ffaf9bebd05b9a5b95beaf07af05cd43595";
3232 assert_eq!(
3233 onion_keys[3].ephemeral_pubkey.serialize()[..],
3234 <Vec<u8>>::from_hex(hex).unwrap()[..]
3235 );
3236
3237 let hex = "cbe784ab745c13ff5cffc2fbe3e84424aa0fd669b8ead4ee562901a4a4e89e9e";
3238 assert_eq!(onion_keys[3].rho, <Vec<u8>>::from_hex(hex).unwrap()[..]);
3239
3240 let hex = "5052aa1b3d9f0655a0932e50d42f0c9ba0705142c25d225515c45f47c0036ee9";
3241 assert_eq!(onion_keys[3].mu, <Vec<u8>>::from_hex(hex).unwrap()[..]);
3242
3243 let hex = "b5756b9b542727dbafc6765a49488b023a725d631af688fc031217e90770c328";
3244 assert_eq!(
3245 onion_keys[4].shared_secret.secret_bytes(),
3246 <Vec<u8>>::from_hex(hex).unwrap()[..]
3247 );
3248
3249 let hex = "c96e00dddaf57e7edcd4fb5954be5b65b09f17cb6d20651b4e90315be5779205";
3250 assert_eq!(onion_keys[4].blinding_factor[..], <Vec<u8>>::from_hex(hex).unwrap()[..]);
3251
3252 let hex = "03a214ebd875aab6ddfd77f22c5e7311d7f77f17a169e599f157bbcdae8bf071f4";
3253 assert_eq!(
3254 onion_keys[4].ephemeral_pubkey.serialize()[..],
3255 <Vec<u8>>::from_hex(hex).unwrap()[..]
3256 );
3257
3258 let hex = "034e18b8cc718e8af6339106e706c52d8df89e2b1f7e9142d996acf88df8799b";
3259 assert_eq!(onion_keys[4].rho, <Vec<u8>>::from_hex(hex).unwrap()[..]);
3260
3261 let hex = "8e45e5c61c2b24cb6382444db6698727afb063adecd72aada233d4bf273d975a";
3262 assert_eq!(onion_keys[4].mu, <Vec<u8>>::from_hex(hex).unwrap()[..]);
3263
3264 let payloads = vec!(
3270 RawOnionHopData::new(msgs::OutboundOnionPayload::Forward {
3271 short_channel_id: 1,
3272 amt_to_forward: 15000,
3273 outgoing_cltv_value: 1500,
3274 }),
3275 RawOnionHopData {
3291 data: <Vec<u8>>::from_hex("52020236b00402057806080000000000000002fd02013c0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f0102030405060708090a0b0c0d0e0f").unwrap(),
3292 },
3293 RawOnionHopData::new(msgs::OutboundOnionPayload::Forward {
3294 short_channel_id: 3,
3295 amt_to_forward: 12500,
3296 outgoing_cltv_value: 1250,
3297 }),
3298 RawOnionHopData::new(msgs::OutboundOnionPayload::Forward {
3299 short_channel_id: 4,
3300 amt_to_forward: 10000,
3301 outgoing_cltv_value: 1000,
3302 }),
3303 RawOnionHopData {
3319 data: <Vec<u8>>::from_hex("fd011002022710040203e8082224a33562c54507a9334e79f0dc4f17d407e6d7c61f0e2f3d0d38599502f617042710fd012de02a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a2a").unwrap(),
3320 },
3321 );
3322
3323 let mut w = VecWriter(Vec::new());
3325 payloads[0].write(&mut w).unwrap();
3326 let hop_1_serialized_payload = w.0;
3327 let hex = "1202023a98040205dc06080000000000000001";
3328 let expected_serialized_hop_1_payload = &<Vec<u8>>::from_hex(hex).unwrap()[..];
3329 assert_eq!(hop_1_serialized_payload, expected_serialized_hop_1_payload);
3330
3331 w = VecWriter(Vec::new());
3332 payloads[2].write(&mut w).unwrap();
3333 let hop_3_serialized_payload = w.0;
3334 let hex = "12020230d4040204e206080000000000000003";
3335 let expected_serialized_hop_3_payload = &<Vec<u8>>::from_hex(hex).unwrap()[..];
3336 assert_eq!(hop_3_serialized_payload, expected_serialized_hop_3_payload);
3337
3338 w = VecWriter(Vec::new());
3339 payloads[3].write(&mut w).unwrap();
3340 let hop_4_serialized_payload = w.0;
3341 let hex = "1202022710040203e806080000000000000004";
3342 let expected_serialized_hop_4_payload = &<Vec<u8>>::from_hex(hex).unwrap()[..];
3343 assert_eq!(hop_4_serialized_payload, expected_serialized_hop_4_payload);
3344
3345 let pad_keytype_seed =
3346 super::gen_pad_from_shared_secret(&get_test_session_key().secret_bytes());
3347
3348 let packet: msgs::OnionPacket = super::construct_onion_packet_with_writable_hopdata::<_>(
3349 payloads,
3350 onion_keys,
3351 pad_keytype_seed,
3352 &PaymentHash([0x42; 32]),
3353 )
3354 .unwrap();
3355
3356 let hex = "0002EEC7245D6B7D2CCB30380BFBE2A3648CD7A942653F5AA340EDCEA1F283686619F7F3416A5AA36DC7EEB3EC6D421E9615471AB870A33AC07FA5D5A51DF0A8823AABE3FEA3F90D387529D4F72837F9E687230371CCD8D263072206DBED0234F6505E21E282ABD8C0E4F5B9FF8042800BBAB065036EADD0149B37F27DDE664725A49866E052E809D2B0198AB9610FAA656BBF4EC516763A59F8F42C171B179166BA38958D4F51B39B3E98706E2D14A2DAFD6A5DF808093ABFCA5AEAACA16EDED5DB7D21FB0294DD1A163EDF0FB445D5C8D7D688D6DD9C541762BF5A5123BF9939D957FE648416E88F1B0928BFA034982B22548E1A4D922690EECF546275AFB233ACF4323974680779F1A964CFE687456035CC0FBA8A5428430B390F0057B6D1FE9A8875BFA89693EEB838CE59F09D207A503EE6F6299C92D6361BC335FCBF9B5CD44747AADCE2CE6069CFDC3D671DAEF9F8AE590CF93D957C9E873E9A1BC62D9640DC8FC39C14902D49A1C80239B6C5B7FD91D05878CBF5FFC7DB2569F47C43D6C0D27C438ABFF276E87364DEB8858A37E5A62C446AF95D8B786EAF0B5FCF78D98B41496794F8DCAAC4EEF34B2ACFB94C7E8C32A9E9866A8FA0B6F2A06F00A1CCDE569F97EEC05C803BA7500ACC96691D8898D73D8E6A47B8F43C3D5DE74458D20EDA61474C426359677001FBD75A74D7D5DB6CB4FEB83122F133206203E4E2D293F838BF8C8B3A29ACB321315100B87E80E0EDB272EE80FDA944E3FB6084ED4D7F7C7D21C69D9DA43D31A90B70693F9B0CC3EAC74C11AB8FF655905688916CFA4EF0BD04135F2E50B7C689A21D04E8E981E74C6058188B9B1F9DFC3EEC6838E9FFBCF22CE738D8A177C19318DFFEF090CEE67E12DE1A3E2A39F61247547BA5257489CBC11D7D91ED34617FCC42F7A9DA2E3CF31A94A210A1018143173913C38F60E62B24BF0D7518F38B5BAB3E6A1F8AEB35E31D6442C8ABB5178EFC892D2E787D79C6AD9E2FC271792983FA9955AC4D1D84A36C024071BC6E431B625519D556AF38185601F70E29035EA6A09C8B676C9D88CF7E05E0F17098B584C4168735940263F940033A220F40BE4C85344128B14BEB9E75696DB37014107801A59B13E89CD9D2258C169D523BE6D31552C44C82FF4BB18EC9F099F3BF0E5B1BB2BA9A87D7E26F98D294927B600B5529C47E04D98956677CBCEE8FA2B60F49776D8B8C367465B7C626DA53700684FB6C918EAD0EAB8360E4F60EDD25B4F43816A75ECF70F909301825B512469F8389D79402311D8AECB7B3EF8599E79485A4388D87744D899F7C47EE644361E17040A7958C8911BE6F463AB6A9B2AFACD688EC55EF517B38F1339EFC54487232798BB25522FF4572FF68567FE830F92F7B8113EFCE3E98C3FFFBAEDCE4FD8B50E41DA97C0C08E423A72689CC68E68F752A5E3A9003E64E35C957CA2E1C48BB6F64B05F56B70B575AD2F278D57850A7AD568C24A4D32A3D74B29F03DC125488BC7C637DA582357F40B0A52D16B3B40BB2C2315D03360BC24209E20972C200566BCF3BBE5C5B0AEDD83132A8A4D5B4242BA370B6D67D9B67EB01052D132C7866B9CB502E44796D9D356E4E3CB47CC527322CD24976FE7C9257A2864151A38E568EF7A79F10D6EF27CC04CE382347A2488B1F404FDBF407FE1CA1C9D0D5649E34800E25E18951C98CAE9F43555EEF65FEE1EA8F15828807366C3B612CD5753BF9FB8FCED08855F742CDDD6F765F74254F03186683D646E6F09AC2805586C7CF11998357CAFC5DF3F285329366F475130C928B2DCEBA4AA383758E7A9D20705C4BB9DB619E2992F608A1BA65DB254BB389468741D0502E2588AEB54390AC600C19AF5C8E61383FC1BEBE0029E4474051E4EF908828DB9CCA13277EF65DB3FD47CCC2179126AAEFB627719F421E20";
3357 assert_eq!(packet.encode(), <Vec<u8>>::from_hex(hex).unwrap());
3358 }
3359
3360 #[test]
3361 fn test_attributable_failure_packet_onion_mutations() {
3362 const FAILURE_MESSAGE_LEN: usize = 1060;
3364
3365 for mutating_node in 0..5 {
3366 let attribution_data_mutations = (0..HOLD_TIME_LEN * MAX_HOPS)
3367 .map(AttributionDataMutationType::HoldTimes)
3368 .chain((0..HMAC_LEN * HMAC_COUNT).map(AttributionDataMutationType::Hmacs));
3369
3370 let failure_mutations = (0..FAILURE_MESSAGE_LEN).map(MutationType::FailureMessage);
3371
3372 for mutation_type in failure_mutations
3373 .chain(attribution_data_mutations.map(MutationType::AttributionData))
3374 .chain(iter::once(MutationType::DropAttributionData))
3375 {
3376 let failure_ok = matches!(mutation_type, MutationType::DropAttributionData)
3379 || matches!(mutation_type, MutationType::AttributionData(_));
3380
3381 let mutation = Mutation { node: mutating_node, mutation_type };
3382 let decrypted_failure =
3383 test_attributable_failure_packet_onion_with_mutation(Some(mutation));
3384
3385 if failure_ok {
3386 assert_eq!(
3387 decrypted_failure.onion_error_code,
3388 Some(LocalHTLCFailureReason::IncorrectPaymentDetails)
3389 );
3390 continue;
3391 }
3392
3393 assert!(decrypted_failure.short_channel_id.is_none());
3396
3397 assert!(decrypted_failure.attribution_failed_channel == Some(mutating_node as u64));
3399
3400 assert_eq!(decrypted_failure.hold_times, [5, 4, 3, 2, 1][..mutating_node]);
3401 }
3402 }
3403 }
3404
3405 #[test]
3406 fn test_attributable_failure_packet_onion_happy() {
3407 let decrypted_failure = test_attributable_failure_packet_onion_with_mutation(None);
3408 assert_eq!(
3409 decrypted_failure.onion_error_code,
3410 Some(LocalHTLCFailureReason::IncorrectPaymentDetails)
3411 );
3412 assert_eq!(decrypted_failure.hold_times, [5, 4, 3, 2, 1]);
3413 }
3414
3415 enum AttributionDataMutationType {
3416 HoldTimes(usize),
3417 Hmacs(usize),
3418 }
3419
3420 enum MutationType {
3421 FailureMessage(usize),
3422 AttributionData(AttributionDataMutationType),
3423 DropAttributionData,
3424 }
3425
3426 struct Mutation {
3427 node: usize,
3428 mutation_type: MutationType,
3429 }
3430
3431 fn test_attributable_failure_packet_onion_with_mutation(
3432 mutation: Option<Mutation>,
3433 ) -> DecodedOnionFailure {
3434 struct ExpectedMessage<'a> {
3435 message: &'a str,
3436 attribution_data: &'a str,
3437 }
3438
3439 impl<'a> ExpectedMessage<'a> {
3440 fn assert_eq(&self, actual: &OnionErrorPacket) {
3441 assert_eq!(actual.data.to_lower_hex_string(), self.message);
3442
3443 let (expected_hold_times, expected_hmacs) =
3444 self.attribution_data.split_at(MAX_HOPS * HOLD_TIME_LEN * 2);
3445 assert_eq!(
3446 actual.attribution_data.as_ref().unwrap().hold_times.to_lower_hex_string(),
3447 expected_hold_times
3448 );
3449 assert_eq!(
3450 actual.attribution_data.as_ref().unwrap().hmacs.to_lower_hex_string(),
3451 expected_hmacs
3452 );
3453 }
3454 }
3455
3456 const FAILURE_DATA: &str = "0000000000000064000c3500fd84d1fd012c808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080808080";
3457 const EXPECTED_MESSAGES: [ExpectedMessage; 5] = [
3458 ExpectedMessage {
3459 message: "146e94a9086dbbed6a0ab6932d00c118a7195dbf69b7d7a12b0e6956fc54b5e0a989f165b5f12fd45edd73a5b0c48630ff5be69500d3d82a29c0803f0a0679a6a073c33a6fb8250090a3152eba3f11a85184fa87b67f1b0354d6f48e3b342e332a17b7710f342f342a87cf32eccdf0afc2160808d58abb5e5840d2c760c538e63a6f841970f97d2e6fe5b8739dc45e2f7f5f532f227bcc2988ab0f9cc6d3f12909cd5842c37bc8c7608475a5ebbe10626d5ecc1f3388ad5f645167b44a4d166f87863fe34918cea25c18059b4c4d9cb414b59f6bc50c1cea749c80c43e2344f5d23159122ed4ab9722503b212016470d9610b46c35dbeebaf2e342e09770b38392a803bc9d2e7c8d6d384ffcbeb74943fe3f64afb2a543a6683c7db3088441c531eeb4647518cb41992f8954f1269fb969630944928c2d2b45593731b5da0c4e70d04a0a57afe4af42e99912fbb4f8883a5ecb9cb29b883cb6bfa0f4db2279ff8c6d2b56a232f55ba28fe7dfa70a9ab0433a085388f25cce8d53de6a2fbd7546377d6ede9027ad173ba1f95767461a3689ef405ab608a21086165c64b02c1782b04a6dba2361a7784603069124e12f2f6dcb1ec7612a4fbf94c0e14631a2bef6190c3d5f35e0c4b32aa85201f449d830fd8f782ec758b0910428e3ec3ca1dba3b6c7d89f69e1ee1b9df3dfbbf6d361e1463886b38d52e8f43b73a3bd48c6f36f5897f514b93364a31d49d1d506340b1315883d425cb36f4ea553430d538fd6f3596d4afc518db2f317dd051abc0d4bfb0a7870c3db70f19fe78d6604bbf088fcb4613f54e67b038277fedcd9680eb97bdffc3be1ab2cbcbafd625b8a7ac34d8c190f98d3064ecd3b95b8895157c6a37f31ef4de094b2cb9dbf8ff1f419ba0ecacb1bb13df0253b826bec2ccca1e745dd3b3e7cc6277ce284d649e7b8285727735ff4ef6cca6c18e2714f4e2a1ac67b25213d3bb49763b3b94e7ebf72507b71fb2fe0329666477ee7cb7ebd6b88ad5add8b217188b1ca0fa13de1ec09cc674346875105be6e0e0d6c8928eb0df23c39a639e04e4aedf535c4e093f08b2c905a14f25c0c0fe47a5a1535ab9eae0d9d67bdd79de13a08d59ee05385c7ea4af1ad3248e61dd22f8990e9e99897d653dd7b1b1433a6d464ea9f74e377f2d8ce99ba7dbc753297644234d25ecb5bd528e2e2082824681299ac30c05354baaa9c3967d86d7c07736f87fc0f63e5036d47235d7ae12178ced3ae36ee5919c093a02579e4fc9edad2c446c656c790704bfc8e2c491a42500aa1d75c8d4921ce29b753f883e17c79b09ea324f1f32ddf1f3284cd70e847b09d90f6718c42e5c94484cc9cbb0df659d255630a3f5a27e7d5dd14fa6b974d1719aa98f01a20fb4b7b1c77b42d57fab3c724339d459ee4a1c6b5d3bd4e08624c786a257872acc9ad3ff62222f2265a658d9f2a007229a5293b67ec91c84c4b4407c228434bad8a815ca9b256c776bd2c9f",
3460 attribution_data: "d77d0711b5f71d1d1be56bd88b3bb7ebc1792bb739ea7ebc1bc3b031b8bc2df3a50e25aeb99f47d7f7ab39e24187d3f4df9c4333463b053832ee9ac07274a5261b8b2a01fc09ce9ea7cd04d7b585dfb8cf5958e3f3f2a4365d1ec0df1d83c6a6221b5b7d1ff30156a2289a1d3ee559e7c7256bda444bb8e046f860e00b3a59a85e1e1a43de215fd5e6bf646a5deab97b1912c934e31b1cfd344764d6ca7e14ea7b3f2a951aba907c964c0f5d19a44e6d1d7279637321fa598adde927b3087d238f8b426ecde500d318617cdb7a56e6ce3520fc95be41a549973764e4dc483853ecc313947709f1b5199cb077d46e701fa633e11d3e13b03e9212c115ca6fa004b2f3dd912814693b705a561a06da54cdf603677a3abecdc22c7358c2de3cef771b366a568150aeecc86ad1990bb0f4e2865933b03ea0df87901bff467908273dc6cea31cbab0e2b8d398d10b001058c259ed221b7b55762f4c7e49c8c11a45a107b7a2c605c26dc5b0b10d719b1c844670102b2b6a36c43fe4753a78a483fc39166ae28420f112d50c10ee64ca69569a2f690712905236b7c2cb7ac8954f02922d2d918c56d42649261593c47b14b324a65038c3c5be8d3c403ce0c8f19299b1664bf077d7cf1636c4fb9685a8e58b7029fd0939fa07925a60bed339b23f973293598f595e75c8f9d455d7cebe4b5e23357c8bd47d66d6628b39427e37e0aecbabf46c11be6771f7136e108a143ae9bafba0fc47a51b6c7deef4cba54bae906398ee3162a41f2191ca386b628bde7e1dd63d1611aa01a95c456df337c763cb8c3a81a6013aa633739d8cd554c688102211725e6adad165adc1bcd429d020c51b4b25d2117e8bb27eb0cc7020f9070d4ad19ac31a76ebdf5f9246646aeadbfb9a3f1d75bd8237961e786302516a1a781780e8b73f58dc06f307e58bd0eb1d8f5c9111f01312974c1dc777a6a2d3834d8a2a40014e9818d0685cb3919f6b3b788ddc640b0ff9b1854d7098c7dd6f35196e902b26709640bc87935a3914869a807e8339281e9cedaaca99474c3e7bdd35050bb998ab4546f9900904e0e39135e861ff7862049269701081ebce32e4cca992c6967ff0fd239e38233eaf614af31e186635e9439ec5884d798f9174da6ff569d68ed5c092b78bd3f880f5e88a7a8ab36789e1b57b035fb6c32a6358f51f83e4e5f46220bcad072943df8bd9541a61b7dae8f30fa3dd5fb39b1fd9a0b8e802552b78d4ec306ecee15bfe6da14b29ba6d19ce5be4dd478bca74a52429cd5309d404655c3dec85c252"
3461 },
3462 ExpectedMessage {
3463 message: "7512354d6a26781d25e65539772ba049b7ed7c530bf75ab7ef80cf974b978a07a1c3dabc61940011585323f70fa98cfa1d4c868da30b1f751e44a72d9b3f79809c8c51c9f0843daa8fe83587844fedeacb7348362003b31922cbb4d6169b2087b6f8d192d9cfe5363254cd1fde24641bde9e422f170c3eb146f194c48a459ae2889d706dc654235fa9dd20307ea54091d09970bf956c067a3bcc05af03c41e01af949a131533778bf6ee3b546caf2eabe9d53d0fb2e8cc952b7e0f5326a69ed2e58e088729a1d85971c6b2e129a5643f3ac43da031e655b27081f10543262cf9d72d6f64d5d96387ac0d43da3e3a03da0c309af121dcf3e99192efa754eab6960c256ffd4c546208e292e0ab9894e3605db098dc16b40f17c320aa4a0e42fc8b105c22f08c9bc6537182c24e32062c6cd6d7ec7062a0c2c2ecdae1588c82185cdc61d874ee916a7873ac54cddf929354f307e870011704a0e9fbc5c7802d6140134028aca0e78a7e2f3d9e5c7e49e20c3a56b624bfea51196ec9e88e4e56be38ff56031369f45f1e03be826d44a182f270c153ee0d9f8cf9f1f4132f33974e37c7887d5b857365c873cb218cbf20d4be3abdb2a2011b14add0a5672e01e5845421cf6dd6faca1f2f443757aae575c53ab797c2227ecdab03882bbbf4599318cefafa72fa0c9a0f5a51d13c9d0e5d25bfcfb0154ed25895260a9df8743ac188714a3f16960e6e2ff663c08bffda41743d50960ea2f28cda0bc3bd4a180e297b5b41c700b674cb31d99c7f2a1445e121e772984abff2bbe3f42d757ceeda3d03fb1ffe710aecabda21d738b1f4620e757e57b123dbc3c4aa5d9617dfa72f4a12d788ca596af14bea583f502f16fdc13a5e739afb0715424af2767049f6b9aa107f69c5da0e85f6d8c5e46507e14616d5d0b797c3dea8b74a1b12d4e47ba7f57f09d515f6c7314543f78b5e85329d50c5f96ee2f55bbe0df742b4003b24ccbd4598a64413ee4807dc7f2a9c0b92424e4ae1b418a3cdf02ea4da5c3b12139348aa7022cc8272a3a1714ee3e4ae111cffd1bdfd62c503c80bdf27b2feaea0d5ab8fe00f9cec66e570b00fd24b4a2ed9a5f6384f148a4d6325110a41ca5659ebc5b98721d298a52819b6fb150f273383f1c5754d320be428941922da790e17f482989c365c078f7f3ae100965e1b38c052041165295157e1a7c5b7a57671b842d4d85a7d971323ad1f45e17a16c4656d889fc75c12fc3d8033f598306196e29571e414281c5da19c12605f48347ad5b4648e371757cbe1c40adb93052af1d6110cfbf611af5c8fc682b7e2ade3bfca8b5c7717d19fc9f97964ba6025aebbc91a6671e259949dcf40984342118de1f6b514a7786bd4f6598ffbe1604cef476b2a4cb1343db608aca09d1d38fc23e98ee9c65e7f6023a8d1e61fd4f34f753454bd8e858c8ad6be6403edc599c220e03ca917db765980ac781e758179cd93983e9c1e769e4241d47c",
3464 attribution_data: "1571e10db7f8aa9f8e7e99caaf9c892e106c817df1d8e3b7b0e39d1c48f631e473e17e205489dd7b3c634cac3be0825cbf01418cd46e83c24b8d9c207742db9a0f0e5bcd888086498159f08080ba7bf36dee297079eb841391ccd3096da76461e314863b6412efe0ffe228d51c6097db10d3edb2e50ea679820613bfe9db11ba02920ab4c1f2a79890d997f1fc022f3ab78f0029cc6de0c90be74d55f4a99bf77a50e20f8d076fe61776190a61d2f41c408871c0279309cba3b60fcdc7efc4a0e90b47cb4a418fc78f362ecc7f15ebbce9f854c09c7be300ebc1a40a69d4c7cb7a19779b6905e82bec221a709c1dab8cbdcde7b527aca3f54bde651aa9f3f2178829cee3f1c0b9292758a40cc63bd998fcd0d3ed4bdcaf1023267b8f8e44130a63ad15f76145936552381eabb6d684c0a3af6ba8efcf207cebaea5b7acdbb63f8e7221102409d10c23f0514dc9f4d0efb2264161a193a999a23e992632710580a0d320f676d367b9190721194514457761af05207cdab2b6328b1b3767eacb36a7ef4f7bd2e16762d13df188e0898b7410f62459458712a44bf594ae662fd89eb300abb6952ff8ad40164f2bcd7f86db5c7650b654b79046de55d51aa8061ce35f867a3e8f5bf98ad920be827101c64fb871d86e53a4b3c0455bfac5784168218aa72cbee86d9c750a9fa63c363a8b43d7bf4b2762516706a306f0aa3be1ec788b5e13f8b24837e53ac414f211e11c7a093cd9653dfa5fba4e377c79adfa5e841e2ddb6afc054fc715c05ddc6c8fc3e1ee3406e1ffceb2df77dc2f02652614d1bfcfaddebaa53ba919c7051034e2c7b7cfaabdf89f26e7f8e3f956d205dfab747ad0cb505b85b54a68439621b25832cbc2898919d0cd7c0a64cfd235388982dd4dd68240cb668f57e1d2619a656ed326f8c92357ee0d9acead3c20008bc5f04ca8059b55d77861c6d04dfc57cfba57315075acbe1451c96cf28e1e328e142890248d18f53b5d3513ce574dea7156cf596fdb3d909095ec287651f9cf1bcdc791c5938a5dd9b47e84c004d24ab3ae74492c7e8dcc1da15f65324be2672947ec82074cac8ce2b925bc555facbbf1b55d63ea6fbea6a785c97d4caf2e1dad9551b7f66c31caae5ebc7c0047e892f201308fcf452c588be0e63d89152113d87bf0dbd01603b4cdc7f0b724b0714a9851887a01f709408882e18230fe810b9fafa58a666654576d8eba3005f07221f55a6193815a672e5db56204053bc4286fa3db38250396309fd28011b5708a26a2d76c4a333b69b6bfd272fb"
3465 },
3466 ExpectedMessage {
3467 message: "145bc1c63058f7204abbd2320d422e69fb1b3801a14312f81e5e29e6b5f4774cfed8a25241d3dfb7466e749c1b3261559e49090853612e07bd669dfb5f4c54162fa504138dabd6ebcf0db8017840c35f12a2cfb84f89cc7c8959a6d51815b1d2c5136cedec2e4106bb5f2af9a21bd0a02c40b44ded6e6a90a145850614fb1b0eef2a03389f3f2693bc8a755630fc81fff1d87a147052863a71ad5aebe8770537f333e07d841761ec448257f948540d8f26b1d5b66f86e073746106dfdbb86ac9475acf59d95ece037fba360670d924dce53aaa74262711e62a8fc9eb70cd8618fbedae22853d3053c7f10b1a6f75369d7f73c419baa7dbf9f1fc5895362dcc8b6bd60cca4943ef7143956c91992119bccbe1666a20b7de8a2ff30a46112b53a6bb79b763903ecbd1f1f74952fb1d8eb0950c504df31fe702679c23b463f82a921a2c931500ab08e686cffb2d87258d254fb17843959cccd265a57ba26c740f0f231bb76df932b50c12c10be90174b37d454a3f8b284c849e86578a6182c4a7b2e47dd57d44730a1be9fec4ad07287a397e28dce4fda57e9cdfdb2eb5afdf0d38ef19d982341d18d07a556bb16c1416f480a396f278373b8fd9897023a4ac506e65cf4c306377730f9c8ca63cf47565240b59c4861e52f1dab84d938e96fb31820064d534aca05fd3d2600834fe4caea98f2a748eb8f200af77bd9fbf46141952b9ddda66ef0ebea17ea1e7bb5bce65b6e71554c56dd0d4e14f4cf74c77a150776bf31e7419756c71e7421dc22efe9cf01de9e19fc8808d5b525431b944400db121a77994518d6025711cb25a18774068bba7faaa16d8f65c91bec8768848333156dcb4a08dfbbd9fef392da3e4de13d4d74e83a7d6e46cfe530ee7a6f711e2caf8ad5461ba8177b2ef0a518baf9058ff9156e6aa7b08d938bd8d1485a787809d7b4c8aed97be880708470cd2b2cdf8e2f13428cc4b04ef1f2acbc9562f3693b948d0aa94b0e6113cafa684f8e4a67dc431dfb835726874bef1de36f273f52ee694ec46b0700f77f8538067642a552968e866a72a3f2031ad116663ac17b172b446c5bc705b84777363a9a3fdc6443c07b2f4ef58858122168d4ebbaee920cefc312e1cea870ed6e15eec046ab2073bbf08b0a3366f55cfc6ad4681a12ab0946534e7b6f90ea8992d530ec3daa6b523b3cf03101c60cadd914f30dec932c1ef4341b5a8efac3c921e203574cfe0f1f83433fddb8ccfd273f7c3cab7bc27efe3bb61fdccd5146f1185364b9b621e7fb2b74b51f5ee6be72ab6ff46a6359dc2c855e61469724c1dbeb273df9d2e1c1fb74891239c0019dc12d5c7535f7238f963b761d7102b585372cf021b64c4fc85bfb3161e59d2e298bba44cfd34d6859d9dba9dc6271e5047d525468c814f2ae438474b0a977273036da1a2292f88fcfb89574a6bdca1185b40f8aa54026d5926725f99ef028da1be892e3586361efe15f4a148ff1bc9",
3468 attribution_data: "34e34397b8621ec2f2b54dbe6c14073e267324cd60b152bce76aec8729a6ddefb61bc263be4b57bd592aae604a32bea69afe6ef4a6b573c26b17d69381ec1fc9b5aa769d148f2f1f8b5377a73840bb6dc641f68e356323d766fff0aaca5039fe7fc27038195844951a97d5a5b26698a4ca1e9cd4bca1fcca0aac5fee91b18977d2ad0e399ba159733fc98f6e96898ebc39bf0028c9c81619233bab6fad0328aa183a635fac20437fa6e00e899b2527c3697a8ab7342e42d55a679b176ab76671fcd480a9894cb897fa6af0a45b917a162bed6c491972403185df7235502f7ada65769d1bfb12d29f10e25b0d3cc08bbf6de8481ac5c04df32b4533b4f764c2aefb7333202645a629fb16e4a208e9045dc36830759c852b31dd613d8b2b10bbead1ed4eb60c85e8a4517deba5ab53e39867c83c26802beee2ee545bdd713208751added5fc0eb2bc89a5aa2decb18ee37dac39f22a33b60cc1a369d24de9f3d2d8b63c039e248806de4e36a47c7a0aed30edd30c3d62debdf1ad82bf7aedd7edec413850d91c261e12beec7ad1586a9ad25b2db62c58ca17119d61dcc4f3e5c4520c42a8e384a45d8659b338b3a08f9e123a1d3781f5fc97564ccff2c1d97f06fa0150cfa1e20eacabefb0c339ec109336d207cc63d9170752fc58314c43e6d4a528fd0975afa85f3aa186ff1b6b8cb12c97ed4ace295b0ef5f075f0217665b8bb180246b87982d10f43c9866b22878106f5214e99188781180478b07764a5e12876ddcb709e0a0a8dd42cf004c695c6fc1669a6fd0e4a1ca54b024d0d80eac492a9e5036501f36fb25b72a054189294955830e43c18e55668337c8c6733abb09fc2d4ade18d5a853a2b82f7b4d77151a64985004f1d9218f2945b63c56fdebd1e96a2a7e49fa70acb4c39873947b83c191c10e9a8f40f60f3ad5a2be47145c22ea59ed3f5f4e61cb069e875fb67142d281d784bf925cc286eacc2c43e94d08da4924b83e58dbf2e43fa625bdd620eba6d9ce960ff17d14ed1f2dbee7d08eceb540fdc75ff06dabc767267658fad8ce99e2a3236e46d2deedcb51c3c6f81589357edebac9772a70b3d910d83cd1b9ce6534a011e9fa557b891a23b5d88afcc0d9856c6dabeab25eea55e9a248182229e4927f268fe5431672fcce52f434ca3d27d1a2136bae5770bb36920df12fbc01d0e8165610efa04794f414c1417f1d4059435c5385bfe2de83ce0e238d6fd2dbd3c0487c69843298577bfa480fe2a16ab2a0e4bc712cd8b5a14871cda61c993b6835303d9043d7689a"
3469 },
3470 ExpectedMessage {
3471 message: "1b4b09a935ce7af95b336baae307f2b400e3a7e808d9b4cf421cc4b3955620acb69dcdb656128dae8857adbd4e6b37fbb1be9c1f2f02e61e9e59a630c4c77cf383cb37b07413aa4de2f2fbf5b40ae40a91a8f4c6d74aeacef1bb1be4ecbc26ec2c824d2bc45db4b9098e732a769788f1cff3f5b41b0d25c132d40dc5ad045ef0043b15332ca3c5a09de2cdb17455a0f82a8f20da08346282823dab062cdbd2111e238528141d69de13de6d83994fbc711e3e269df63a12d3a4177c5c149150eb4dc2f589cd8acabcddba14dec3b0dada12d663b36176cd3c257c5460bab93981ad99f58660efa9b31d7e63b39915329695b3fa60e0a3bdb93e7e29a54ca6a8f360d3848866198f9c3da3ba958e7730847fe1e6478ce8597848d3412b4ae48b06e05ba9a104e648f6eaf183226b5f63ed2e68f77f7e38711b393766a6fab7921b03eba82b5d7cb78e34dc961948d6161eadd7cf5d95d9c56df2ff5faa6ccf85eacdc9ff2fc3abafe41c365a5bd14fd486d6b5e2f24199319e7813e02e798877ffe31a70ae2398d9e31b9e3727e6c1a3c0d995c67d37bb6e72e9660aaaa9232670f382add2edd468927e3303b6142672546997fe105583e7c5a3c4c2b599731308b5416e6c9a3f3ba55b181ad0439d3535356108b059f2cb8742eed7a58d4eba9fe79eaa77c34b12aff1abdaea93197aabd0e74cb271269ca464b3b06aef1d6573df5e1224179616036b368677f26479376681b772d3760e871d99efd34cca5cd6beca95190d967da820b21e5bec60082ea46d776b0517488c84f26d12873912d1f68fafd67bcf4c298e43cfa754959780682a2db0f75f95f0598c0d04fd014c50e4beb86a9e37d95f2bba7e5065ae052dc306555bca203d104c44a538b438c9762de299e1c4ad30d5b4a6460a76484661fc907682af202cd69b9a4473813b2fdc1142f1403a49b7e69a650b7cde9ff133997dcc6d43f049ecac5fce097a21e2bce49c810346426585e3a5a18569b4cddd5ff6bdec66d0b69fcbc5ab3b137b34cc8aefb8b850a764df0e685c81c326611d901c392a519866e132bbb73234f6a358ba284fbafb21aa3605cacbaf9d0c901390a98b7a7dac9d4f0b405f7291c88b2ff45874241c90ac6c5fc895a440453c344d3a365cb929f9c91b9e39cb98b142444aae03a6ae8284c77eb04b0a163813d4c21883df3c0f398f47bf127b5525f222107a2d8fe55289f0cfd3f4bbad6c5387b0594ef8a966afc9e804ccaf75fe39f35c6446f7ee076d433f2f8a44dba1515acc78e589fa8c71b0a006fe14feebd51d0e0aa4e51110d16759eee86192eee90b34432130f387e0ccd2ee71023f1f641cddb571c690107e08f592039fe36d81336a421e89378f351e633932a2f5f697d25b620ffb8e84bb6478e9bd229bf3b164b48d754ae97bd23f319e3c56b3bcdaaeb3bd7fc02ec02066b324cb72a09b6b43dec1097f49d69d3c138ce6f1a6402898baf7568c",
3472 attribution_data: "74a4ea61339463642a2182758871b2ea724f31f531aa98d80f1c3043febca41d5ee52e8b1e127e61719a0d078db8909748d57839e58424b91f063c4fbc8a221bef261140e66a9b596ca6d420a973ad54fef30646ae53ccf0855b61f291a81e0ec6dc0f6bf69f0ca0e5889b7e23f577ba67d2a7d6a2aa91264ab9b20630ed52f8ed56cc10a869807cd1a4c2cd802d8433fee5685d6a04edb0bff248a480b93b01904bed3bb31705d1ecb7332004290cc0cd9cc2f7907cf9db28eec02985301668f53fbc28c3e095c8f3a6cd8cab28e5e442fd9ba608b8b12e098731bbfda755393bd403c62289093b40390b2bae337fc87d2606ca028311d73a9ffbdffef56020c735ada30f54e577c6a9ec515ae2739290609503404b118d7494499ecf0457d75015bb60a16288a4959d74cf5ac5d8d6c113de39f748a418d2a7083b90c9c0a09a49149fd1f2d2cde4412e5aa2421eca6fd4f6fe6b2c362ff37d1a0608c931c7ca3b8fefcfd4c44ef9c38357a0767b14f83cb49bd1989fb3f8e2ab202ac98bd8439790764a40bf309ea2205c1632610956495720030a25dc7118e0c868fdfa78c3e9ecce58215579a0581b3bafdb7dbbe53be9e904567fdc0ce1236aab5d22f1ebc18997e3ea83d362d891e04c5785fd5238326f767bce499209f8db211a50e1402160486e98e7235cf397dbb9ae19fd9b79ef589c821c6f99f28be33452405a003b33f4540fe0a41dfcc286f4d7cc10b70552ba7850869abadcd4bb7f256823face853633d6e2a999ac9fcd259c71d08e266db5d744e1909a62c0db673745ad9585949d108ab96640d2bc27fb4acac7fa8b170a30055a5ede90e004df9a44bdc29aeb4a6bec1e85dde1de6aaf01c6a5d12405d0bec22f49026cb23264f8c04b8401d3c2ab6f2e109948b6193b3bec27adfe19fb8afb8a92364d6fc5b219e8737d583e7ff3a4bcb75d53edda3bf3f52896ac36d8a877ad9f296ea6c045603fc62ac4ae41272bde85ef7c3b3fd3538aacfd5b025fefbe277c2906821ecb20e6f75ea479fa3280f9100fb0089203455c56b6bc775e5c2f0f58c63edd63fa3eec0b40da4b276d0d41da2ec0ead865a98d12bc694e23d8eaadd2b4d0ee88e9570c88fb878930f492e036d27998d593e47763927ff7eb80b188864a3846dd2238f7f95f4090ed399ae95deaeb37abca1cf37c397cc12189affb42dca46b4ff6988eb8c060691d155302d448f50ff70a794d97c0408f8cee9385d6a71fa412e36edcb22dbf433db9db4779f27b682ee17fc05e70c8e794b9f7f6d1"
3473 },
3474 ExpectedMessage {
3475 message: "2dd2f49c1f5af0fcad371d96e8cddbdcd5096dc309c1d4e110f955926506b3c03b44c192896f45610741c85ed4074212537e0c118d472ff3a559ae244acd9d783c65977765c5d4e00b723d00f12475aafaafff7b31c1be5a589e6e25f8da2959107206dd42bbcb43438129ce6cce2b6b4ae63edc76b876136ca5ea6cd1c6a04ca86eca143d15e53ccdc9e23953e49dc2f87bb11e5238cd6536e57387225b8fff3bf5f3e686fd08458ffe0211b87d64770db9353500af9b122828a006da754cf979738b4374e146ea79dd93656170b89c98c5f2299d6e9c0410c826c721950c780486cd6d5b7130380d7eaff994a8503a8fef3270ce94889fe996da66ed121741987010f785494415ca991b2e8b39ef2df6bde98efd2aec7d251b2772485194c8368451ad49c2354f9d30d95367bde316fec6cbdddc7dc0d25e99d3075e13d3de0822669861dafcd29de74eac48b64411987285491f98d78584d0c2a163b7221ea796f9e8671b2bb91e38ef5e18aaf32c6c02f2fb690358872a1ed28166172631a82c2568d23238017188ebbd48944a147f6cdb3690d5f88e51371cb70adf1fa02afe4ed8b581afc8bcc5104922843a55d52acde09bc9d2b71a663e178788280f3c3eae127d21b0b95777976b3eb17be40a702c244d0e5f833ff49dae6403ff44b131e66df8b88e33ab0a58e379f2c34bf5113c66b9ea8241fc7aa2b1fa53cf4ed3cdd91d407730c66fb039ef3a36d4050dde37d34e80bcfe02a48a6b14ae28227b1627b5ad07608a7763a531f2ffc96dff850e8c583461831b19feffc783bc1beab6301f647e9617d14c92c4b1d63f5147ccda56a35df8ca4806b8884c4aa3c3cc6a174fdc2232404822569c01aba686c1df5eecc059ba97e9688c8b16b70f0d24eacfdba15db1c71f72af1b2af85bd168f0b0800483f115eeccd9b02adf03bdd4a88eab03e43ce342877af2b61f9d3d85497cd1c6b96674f3d4f07f635bb26add1e36835e321d70263b1c04234e222124dad30ffb9f2a138e3ef453442df1af7e566890aedee568093aa922dd62db188aa8361c55503f8e2c2e6ba93de744b55c15260f15ec8e69bb01048ca1fa7bbbd26975bde80930a5b95054688a0ea73af0353cc84b997626a987cc06a517e18f91e02908829d4f4efc011b9867bd9bfe04c5f94e4b9261d30cc39982eb7b250f12aee2a4cce0484ff34eebba89bc6e35bd48d3968e4ca2d77527212017e202141900152f2fd8af0ac3aa456aae13276a13b9b9492a9a636e18244654b3245f07b20eb76b8e1cea8c55e5427f08a63a16b0a633af67c8e48ef8e53519041c9138176eb14b8782c6c2ee76146b8490b97978ee73cd0104e12f483be5a4af414404618e9f6633c55dda6f22252cb793d3d16fae4f0e1431434e7acc8fa2c009d4f6e345ade172313d558a4e61b4377e31b8ed4e28f7cd13a7fe3f72a409bc3bdabfe0ba47a6d861e21f64d2fac706dab18b3e546df4",
3476 attribution_data: "84986c936d26bfd3bb2d34d3ec62cfdb63e0032fdb3d9d75f3e5d456f73dffa7e35aab1db4f1bd3b98ff585caf004f656c51037a3f4e810d275f3f6aea0c8e3a125ebee5f374b6440bcb9bb2955ebf706f42be9999a62ed49c7a81fc73c0b4a16419fd6d334532f40bf179dd19afec21bd8519d5e6ebc3802501ef373bc378eee1f14a6fc5fab5b697c91ce31d5922199d1b0ad5ee12176aacafc7c81d54bc5b8fb7e63f3bfd40a3b6e21f985340cbd1c124c7f85f0369d1aa86ebc66def417107a7861131c8bcd73e8946f4fb54bfac87a2dc15bd7af642f32ae583646141e8875ef81ec9083d7e32d5f135131eab7a43803360434100ff67087762bbe3d6afe2034f5746b8c50e0c3c20dd62a4c174c38b1df7365dccebc7f24f19406649fbf48981448abe5c858bbd4bef6eb983ae7a23e9309fb33b5e7c0522554e88ca04b1d65fc190947dead8c0ccd32932976537d869b5ca53ed4945bccafab2a014ea4cbdc6b0250b25be66ba0afff2ff19c0058c68344fd1b9c472567147525b13b1bc27563e61310110935cf89fda0e34d0575e2389d57bdf2869398ca2965f64a6f04e1d1c2edf2082b97054264a47824dd1a9691c27902b39d57ae4a94dd6481954a9bd1b5cff4ab29ca221fa2bf9b28a362c9661206f896fc7cec563fb80aa5eaccb26c09fa4ef7a981e63028a9c4dac12f82ccb5bea090d56bbb1a4c431e315d9a169299224a8dbd099fb67ea61dfc604edf8a18ee742550b636836bb552dabb28820221bf8546331f32b0c143c1c89310c4fa2e1e0e895ce1a1eb0f43278fdb528131a3e32bfffe0c6de9006418f5309cba773ca38b6ad8507cc59445ccc0257506ebc16a4c01d4cd97e03fcf7a2049fea0db28447858f73b8e9fe98b391b136c9dc510288630a1f0af93b26a8891b857bfe4b818af99a1e011e6dbaa53982d29cf74ae7dffef45545279f19931708ed3eede5e82280eab908e8eb80abff3f1f023ab66869297b40da8496861dc455ac3abe1efa8a6f9e2c4eda48025d43a486a3f26f269743eaa30d6f0e1f48db6287751358a41f5b07aee0f098862e3493731fe2697acce734f004907c6f11eef189424fee52cd30ad708707eaf2e441f52bcf3d0c5440c1742458653c0c8a27b5ade784d9e09c8b47f1671901a29360e7e5e94946b9c75752a1a8d599d2a3e14ac81b84d42115cd688c8383a64fc6e7e1dc5568bb4837358ebe63207a4067af66b2027ad2ce8fb7ae3a452d40723a51fdf9f9c9913e8029a222cf81d12ad41e58860d75deb6de30ad"
3477 }
3478 ];
3479
3480 let failure_data = <Vec<u8>>::from_hex(FAILURE_DATA).unwrap();
3481
3482 let onion_keys = build_test_onion_keys();
3483 let mut onion_error = super::build_unencrypted_failure_packet(
3484 onion_keys[4].shared_secret.as_ref(),
3485 LocalHTLCFailureReason::IncorrectPaymentDetails,
3486 &failure_data,
3487 1,
3488 1024,
3489 );
3490
3491 let logger: Arc<TestLogger> = Arc::new(TestLogger::new());
3492
3493 super::crypt_failure_packet(onion_keys[4].shared_secret.as_ref(), &mut onion_error);
3494 EXPECTED_MESSAGES[0].assert_eq(&onion_error);
3495
3496 let mut mutated = false;
3497 let mutate_packet = |packet: &mut OnionErrorPacket, mutation_type: &MutationType| {
3498 match mutation_type {
3499 MutationType::FailureMessage(i) => {
3500 packet.data[*i] ^= 1;
3502 },
3503 MutationType::AttributionData(AttributionDataMutationType::HoldTimes(i)) => {
3504 packet.attribution_data.as_mut().unwrap().hold_times[*i] ^= 1;
3506 },
3507 MutationType::AttributionData(AttributionDataMutationType::Hmacs(i)) => {
3508 packet.attribution_data.as_mut().unwrap().hmacs[*i] ^= 1;
3510 },
3511 MutationType::DropAttributionData => {
3512 packet.attribution_data = None;
3514 },
3515 }
3516 };
3517
3518 if let Some(Mutation { node, ref mutation_type }) = mutation {
3519 if node == 4 {
3520 mutate_packet(&mut onion_error, mutation_type);
3521 mutated = true;
3522 }
3523 }
3524
3525 for idx in (0..4).rev() {
3526 let shared_secret = onion_keys[idx].shared_secret.as_ref();
3527 let hold_time = (5 - idx) as u32;
3528 process_failure_packet(&mut onion_error, shared_secret, hold_time);
3529 super::crypt_failure_packet(shared_secret, &mut onion_error);
3530
3531 if let Some(Mutation { node, ref mutation_type }) = mutation {
3532 if node == idx {
3533 mutate_packet(&mut onion_error, mutation_type);
3534 mutated = true;
3535 }
3536 }
3537
3538 if !mutated {
3539 let expected_messages = &EXPECTED_MESSAGES[4 - idx];
3540 expected_messages.assert_eq(&onion_error);
3541 }
3542 }
3543
3544 let ctx_full = Secp256k1::new();
3545 let path = build_test_path();
3546 let htlc_source = HTLCSource::OutboundRoute {
3547 path,
3548 session_priv: get_test_session_key(),
3549 first_hop_htlc_msat: 0,
3550 payment_id: PaymentId([1; 32]),
3551 bolt12_invoice: None,
3552 };
3553
3554 process_onion_failure(&ctx_full, &logger, &htlc_source, onion_error)
3555 }
3556
3557 #[test]
3560 fn test_success_hold_times() {
3561 fn assert_data(actual: &AttributionData, expected: &str) {
3562 let (expected_hold_times, expected_hmacs) =
3563 expected.split_at(MAX_HOPS * HOLD_TIME_LEN * 2);
3564
3565 println!(
3566 "{}{}",
3567 actual.hold_times.to_lower_hex_string(),
3568 actual.hmacs.to_lower_hex_string()
3569 );
3570
3571 assert_eq!(actual.hold_times.to_lower_hex_string(), expected_hold_times);
3572 assert_eq!(actual.hmacs.to_lower_hex_string(), expected_hmacs);
3573 }
3574
3575 const EXPECTED_MESSAGES: [&str; 5] = [
3577 "d77d0711b5f71d1d1be56bd88b3bb7ebc1792bb739ea7ebc1bc3b031b8bc2df3a50e25aeb99f47d7f7ab39e24187d3f4df9c4333463b053832ee9ac07274a5261b8b2a01fc09ce9ea7cd04d7b585dfb83299fb6570d71f793c1fcac0ef498766952c8c6840efa02a567d558a3cf6822b12476324b9b9efa03e5f8f26f81fa93daac46cbf00c98e69b6747cf69caaa2a71b025bd18830c4c54cd08f598cfde6197b3f2a951aba907c964c0f5d19a44e6d1d7279637321fa598adde927b3087d238f8b426ecde500d318617cdb7a56e6ce3520fc95be41a549973764e4dc483853ecc313947709f1b5199cb077d46e701fa633e11d3e13b03e9212c115ca6fa004b2f3dd912814693b705a561a06da54cdf603677a3abecdc22c7358c2de3cef771b366a568150aeecc86ad1990bb0f4e2865933b03ea0df87901bff467908273dc6cea31cbab0e2b8d398d10b001058c259ed221b7b55762f4c7e49c8c11a45a107b7a2c605c26dc5b0b10d719b1c844670102b2b6a36c43fe4753a78a483fc39166ae28420f112d50c10ee64ca69569a2f690712905236b7c2cb7ac8954f02922d2d918c56d42649261593c47b14b324a65038c3c5be8d3c403ce0c8f19299b1664bf077d7cf1636c4fb9685a8e58b7029fd0939fa07925a60bed339b23f973293598f595e75c8f9d455d7cebe4b5e23357c8bd47d66d6628b39427e37e0aecbabf46c11be6771f7136e108a143ae9bafba0fc47a51b6c7deef4cba54bae906398ee3162a41f2191ca386b628bde7e1dd63d1611aa01a95c456df337c763cb8c3a81a6013aa633739d8cd554c688102211725e6adad165adc1bcd429d020c51b4b25d2117e8bb27eb0cc7020f9070d4ad19ac31a76ebdf5f9246646aeadbfb9a3f1d75bd8237961e786302516a1a781780e8b73f58dc06f307e58bd0eb1d8f5c9111f01312974c1dc777a6a2d3834d8a2a40014e9818d0685cb3919f6b3b788ddc640b0ff9b1854d7098c7dd6f35196e902b26709640bc87935a3914869a807e8339281e9cedaaca99474c3e7bdd35050bb998ab4546f9900904e0e39135e861ff7862049269701081ebce32e4cca992c6967ff0fd239e38233eaf614af31e186635e9439ec5884d798f9174da6ff569d68ed5c092b78bd3f880f5e88a7a8ab36789e1b57b035fb6c32a6358f51f83e4e5f46220bcad072943df8bd9541a61b7dae8f30fa3dd5fb39b1fd9a0b8e802552b78d4ec306ecee15bfe6da14b29ba6d19ce5be4dd478bca74a52429cd5309d404655c3dec85c252",
3578 "1571e10db7f8aa9f8e7e99caaf9c892e106c817df1d8e3b7b0e39d1c48f631e473e17e205489dd7b3c634cac3be0825cbf01418cd46e83c24b8d9c207742db9a0f0e5bcd888086498159f08080ba7bf3ea029c0b493227c4e75a90f70340d9e21f00979fc7e4fb2078477c1a457ba242ed54b313e590b13a2a13bfeed753dab133c78059f460075b2594b4c31c50f31076f8f1a0f7ad0530d0fadaf2d86e505ff9755940ec0665f9e5bc58cad6e523091f94d0bcd3c6c65ca1a5d401128dcc5e14f9108b32e660017c13de598bcf9d403710857cccb0fb9c2a81bfd66bc4552e1132afa3119203a4aaa1e8839c1dab8cbdcde7b527aca3f54bde651aa9f3f2178829cee3f1c0b9292758a40cc63bd998fcd0d3ed4bdcaf1023267b8f8e44130a63ad15f76145936552381eabb6d684c0a3af6ba8efcf207cebaea5b7acdbb63f8e7221102409d10c23f0514dc9f4d0efb2264161a193a999a23e992632710580a0d320f676d367b9190721194514457761af05207cdab2b6328b1b3767eacb36a7ef4f7bd2e16762d13df188e0898b7410f62459458712a44bf594ae662fd89eb300abb6952ff8ad40164f2bcd7f86db5c7650b654b79046de55d51aa8061ce35f867a3e8f5bf98ad920be827101c64fb871d86e53a4b3c0455bfac5784168218aa72cbee86d9c750a9fa63c363a8b43d7bf4b2762516706a306f0aa3be1ec788b5e13f8b24837e53ac414f211e11c7a093cd9653dfa5fba4e377c79adfa5e841e2ddb6afc054fc715c05ddc6c8fc3e1ee3406e1ffceb2df77dc2f02652614d1bfcfaddebaa53ba919c7051034e2c7b7cfaabdf89f26e7f8e3f956d205dfab747ad0cb505b85b54a68439621b25832cbc2898919d0cd7c0a64cfd235388982dd4dd68240cb668f57e1d2619a656ed326f8c92357ee0d9acead3c20008bc5f04ca8059b55d77861c6d04dfc57cfba57315075acbe1451c96cf28e1e328e142890248d18f53b5d3513ce574dea7156cf596fdb3d909095ec287651f9cf1bcdc791c5938a5dd9b47e84c004d24ab3ae74492c7e8dcc1da15f65324be2672947ec82074cac8ce2b925bc555facbbf1b55d63ea6fbea6a785c97d4caf2e1dad9551b7f66c31caae5ebc7c0047e892f201308fcf452c588be0e63d89152113d87bf0dbd01603b4cdc7f0b724b0714a9851887a01f709408882e18230fe810b9fafa58a666654576d8eba3005f07221f55a6193815a672e5db56204053bc4286fa3db38250396309fd28011b5708a26a2d76c4a333b69b6bfd272fb",
3579 "34e34397b8621ec2f2b54dbe6c14073e267324cd60b152bce76aec8729a6ddefb61bc263be4b57bd592aae604a32bea69afe6ef4a6b573c26b17d69381ec1fc9b5aa769d148f2f1f8b5377a73840bb6dffc324ded0d1c00dc0c99e3dbc13273b2f89510af6410b525dd8836208abbbaae12753ae2276fa0ca49950374f94e187bf65cefcdd9dd9142074edc4bd0052d0eb027cb1ab6182497f9a10f9fe800b3228e3c088dab60081c807b30a67313667ca8c9e77b38b161a037cae8e973038d0fc4a97ea215914c6c4e23baf6ac4f0fb1e7fcc8aac3f6303658dae1f91588b535eb678e2200f45383c2590a55dc181a09f2209da72f79ae6745992c803310d39f960e8ecf327aed706e4b3e2704eeb9b304dc0e0685f5dcd0389ec377bdba37610ad556a0e957a413a56339dd3c40817214bced5802beee2ee545bdd713208751added5fc0eb2bc89a5aa2decb18ee37dac39f22a33b60cc1a369d24de9f3d2d8b63c039e248806de4e36a47c7a0aed30edd30c3d62debdf1ad82bf7aedd7edec413850d91c261e12beec7ad1586a9ad25b2db62c58ca17119d61dcc4f3e5c4520c42a8e384a45d8659b338b3a08f9e123a1d3781f5fc97564ccff2c1d97f06fa0150cfa1e20eacabefb0c339ec109336d207cc63d9170752fc58314c43e6d4a528fd0975afa85f3aa186ff1b6b8cb12c97ed4ace295b0ef5f075f0217665b8bb180246b87982d10f43c9866b22878106f5214e99188781180478b07764a5e12876ddcb709e0a0a8dd42cf004c695c6fc1669a6fd0e4a1ca54b024d0d80eac492a9e5036501f36fb25b72a054189294955830e43c18e55668337c8c6733abb09fc2d4ade18d5a853a2b82f7b4d77151a64985004f1d9218f2945b63c56fdebd1e96a2a7e49fa70acb4c39873947b83c191c10e9a8f40f60f3ad5a2be47145c22ea59ed3f5f4e61cb069e875fb67142d281d784bf925cc286eacc2c43e94d08da4924b83e58dbf2e43fa625bdd620eba6d9ce960ff17d14ed1f2dbee7d08eceb540fdc75ff06dabc767267658fad8ce99e2a3236e46d2deedcb51c3c6f81589357edebac9772a70b3d910d83cd1b9ce6534a011e9fa557b891a23b5d88afcc0d9856c6dabeab25eea55e9a248182229e4927f268fe5431672fcce52f434ca3d27d1a2136bae5770bb36920df12fbc01d0e8165610efa04794f414c1417f1d4059435c5385bfe2de83ce0e238d6fd2dbd3c0487c69843298577bfa480fe2a16ab2a0e4bc712cd8b5a14871cda61c993b6835303d9043d7689a",
3580 "74a4ea61339463642a2182758871b2ea724f31f531aa98d80f1c3043febca41d5ee52e8b1e127e61719a0d078db8909748d57839e58424b91f063c4fbc8a221bef261140e66a9b596ca6d420a973ad5431adfa8280a7355462fe50d4cac15cdfbd7a535c4b72a0b6d7d8a64cff3f719ff9b8be28036826342dc3bf3781efc70063d1e6fc79dff86334ae0564a5ab87bd61f8446465ef6713f8c4ef9d0200ebb375f90ee115216b469af42de554622df222858d30d733af1c9223e327ae09d9126be8baee6dd59a112d83a57cc6e0252104c11bc11705d384220eedd72f1a29a0597d97967e28b2ad13ba28b3d8a53c3613c1bb49fe9700739969ef1f795034ef9e2e983af2d3bbd6c637fb12f2f7dfc3aee85e08711e9b604106e95d7a4974e5b047674a6015792dae5d913681d84f71edd415910582e5d86590df2ecfd561dc6e1cdb08d3e10901312326a45fb0498a177319389809c6ba07a76cfad621e07b9af097730e94df92fbd311b2cb5da32c80ab5f14971b6d40f8e2ab202ac98bd8439790764a40bf309ea2205c1632610956495720030a25dc7118e0c868fdfa78c3e9ecce58215579a0581b3bafdb7dbbe53be9e904567fdc0ce1236aab5d22f1ebc18997e3ea83d362d891e04c5785fd5238326f767bce499209f8db211a50e1402160486e98e7235cf397dbb9ae19fd9b79ef589c821c6f99f28be33452405a003b33f4540fe0a41dfcc286f4d7cc10b70552ba7850869abadcd4bb7f256823face853633d6e2a999ac9fcd259c71d08e266db5d744e1909a62c0db673745ad9585949d108ab96640d2bc27fb4acac7fa8b170a30055a5ede90e004df9a44bdc29aeb4a6bec1e85dde1de6aaf01c6a5d12405d0bec22f49026cb23264f8c04b8401d3c2ab6f2e109948b6193b3bec27adfe19fb8afb8a92364d6fc5b219e8737d583e7ff3a4bcb75d53edda3bf3f52896ac36d8a877ad9f296ea6c045603fc62ac4ae41272bde85ef7c3b3fd3538aacfd5b025fefbe277c2906821ecb20e6f75ea479fa3280f9100fb0089203455c56b6bc775e5c2f0f58c63edd63fa3eec0b40da4b276d0d41da2ec0ead865a98d12bc694e23d8eaadd2b4d0ee88e9570c88fb878930f492e036d27998d593e47763927ff7eb80b188864a3846dd2238f7f95f4090ed399ae95deaeb37abca1cf37c397cc12189affb42dca46b4ff6988eb8c060691d155302d448f50ff70a794d97c0408f8cee9385d6a71fa412e36edcb22dbf433db9db4779f27b682ee17fc05e70c8e794b9f7f6d1",
3581 "84986c936d26bfd3bb2d34d3ec62cfdb63e0032fdb3d9d75f3e5d456f73dffa7e35aab1db4f1bd3b98ff585caf004f656c51037a3f4e810d275f3f6aea0c8e3a125ebee5f374b6440bcb9bb2955ebf70c06d64090f9f6cf098200305f7f4305ba9e1350a0c3f7dab4ccf35b8399b9650d8e363bf83d3a0a09706433f0adae6562eb338b21ea6f21329b3775905e59187c325c9cbf589f5da5e915d9e5ad1d21aa1431f9bdc587185ed8b5d4928e697e67cc96bee6d5354e3764cede3f385588fa665310356b2b1e68f8bd30c75d395405614a40a587031ebd6ace60dfb7c6dd188b572bd8e3e9a47b06c2187b528c5ed35c32da5130a21cd881138a5fcac806858ce6c596d810a7492eb261bcc91cead1dae75075b950c2e81cecf7e5fdb2b51df005d285803201ce914dfbf3218383829a0caa8f15486dd801133f1ed7edec436730b0ec98f48732547927229ac80269fcdc5e4f4db264274e940178732b429f9f0e582c559f994a7cdfb76c93ffc39de91ff936316726cc561a6520d47b2cd487299a96322dadc463ef06127fc63902ff9cc4f265e2fbd9de3fa5e48b7b51aa0850580ef9f3b5ebb60c6c3216c5a75a93e82936113d9cad57ae4a94dd6481954a9bd1b5cff4ab29ca221fa2bf9b28a362c9661206f896fc7cec563fb80aa5eaccb26c09fa4ef7a981e63028a9c4dac12f82ccb5bea090d56bbb1a4c431e315d9a169299224a8dbd099fb67ea61dfc604edf8a18ee742550b636836bb552dabb28820221bf8546331f32b0c143c1c89310c4fa2e1e0e895ce1a1eb0f43278fdb528131a3e32bfffe0c6de9006418f5309cba773ca38b6ad8507cc59445ccc0257506ebc16a4c01d4cd97e03fcf7a2049fea0db28447858f73b8e9fe98b391b136c9dc510288630a1f0af93b26a8891b857bfe4b818af99a1e011e6dbaa53982d29cf74ae7dffef45545279f19931708ed3eede5e82280eab908e8eb80abff3f1f023ab66869297b40da8496861dc455ac3abe1efa8a6f9e2c4eda48025d43a486a3f26f269743eaa30d6f0e1f48db6287751358a41f5b07aee0f098862e3493731fe2697acce734f004907c6f11eef189424fee52cd30ad708707eaf2e441f52bcf3d0c5440c1742458653c0c8a27b5ade784d9e09c8b47f1671901a29360e7e5e94946b9c75752a1a8d599d2a3e14ac81b84d42115cd688c8383a64fc6e7e1dc5568bb4837358ebe63207a4067af66b2027ad2ce8fb7ae3a452d40723a51fdf9f9c9913e8029a222cf81d12ad41e58860d75deb6de30ad",
3582 ];
3583
3584 let onion_keys = build_test_onion_keys();
3585
3586 let mut attribution_data = AttributionData::new();
3587 attribution_data.update(&[], onion_keys[4].shared_secret.as_ref(), 1);
3588
3589 let logger: Arc<TestLogger> = Arc::new(TestLogger::new());
3590
3591 attribution_data.crypt(onion_keys[4].shared_secret.as_ref());
3592
3593 assert_data(&attribution_data, EXPECTED_MESSAGES[0]);
3594
3595 for idx in (0..4).rev() {
3596 let shared_secret = onion_keys[idx].shared_secret.as_ref();
3597 let hold_time = (5 - idx) as u32;
3598
3599 attribution_data.shift_right();
3600 attribution_data.update(&[], shared_secret, hold_time);
3601 attribution_data.crypt(shared_secret);
3602
3603 assert_data(&attribution_data, EXPECTED_MESSAGES[4 - idx]);
3604 }
3605
3606 let ctx_full = Secp256k1::new();
3607 let path = build_test_path();
3608 let hold_times = decode_fulfill_attribution_data(
3609 &ctx_full,
3610 &logger,
3611 &path,
3612 &get_test_session_key(),
3613 attribution_data.clone(),
3614 );
3615
3616 assert_eq!(hold_times, [5, 4, 3, 2, 1])
3617 }
3618
3619 fn build_trampoline_test_path() -> Path {
3620 Path {
3621 hops: vec![
3622 RouteHop {
3624 pubkey: PublicKey::from_slice(&<Vec<u8>>::from_hex("0324653eac434488002cc06bbfb7f10fe18991e35f9fe4302dbea6d2353dc0ab1c").unwrap()).unwrap(),
3625 node_features: NodeFeatures::empty(),
3626 short_channel_id: 0,
3627 channel_features: ChannelFeatures::empty(),
3628 fee_msat: 3_000,
3629 cltv_expiry_delta: 24,
3630 maybe_announced_channel: false,
3631 },
3632
3633 RouteHop {
3635 pubkey: PublicKey::from_slice(&<Vec<u8>>::from_hex("027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007").unwrap()).unwrap(),
3636 node_features: NodeFeatures::empty(),
3637 short_channel_id: (572330 << 40) + (42 << 16) + 2821,
3638 channel_features: ChannelFeatures::empty(),
3639 fee_msat: 153_000,
3640 cltv_expiry_delta: 0,
3641 maybe_announced_channel: false,
3642 },
3643 ],
3644 blinded_tail: Some(BlindedTail {
3645 trampoline_hops: vec![
3646 TrampolineHop {
3648 pubkey: PublicKey::from_slice(&<Vec<u8>>::from_hex("027f31ebc5462c1fdce1b737ecff52d37d75dea43ce11c74d25aa297165faa2007").unwrap()).unwrap(),
3649 node_features: Features::empty(),
3650 fee_msat: 2_500,
3651 cltv_expiry_delta: 24,
3652 },
3653
3654 TrampolineHop {
3656 pubkey: PublicKey::from_slice(&<Vec<u8>>::from_hex("02edabbd16b41c8371b92ef2f04c1185b4f03b6dcd52ba9b78d9d7c89c8f221145").unwrap()).unwrap(),
3657 node_features: Features::empty(),
3658 fee_msat: 2_500,
3659 cltv_expiry_delta: 24,
3660 },
3661
3662 TrampolineHop {
3664 pubkey: PublicKey::from_slice(&<Vec<u8>>::from_hex("032c0b7cf95324a07d05398b240174dc0c2be444d96b159aa6c7f7b1e668680991").unwrap()).unwrap(),
3665 node_features: Features::empty(),
3666 fee_msat: 150_500,
3667 cltv_expiry_delta: 36,
3668 },
3669 ],
3670
3671 hops: vec![
3673 BlindedHop {
3675 blinded_node_id: PublicKey::from_slice(&<Vec<u8>>::from_hex("0295d40514096a8be54859e7dfe947b376eaafea8afe5cb4eb2c13ff857ed0b4be").unwrap()).unwrap(),
3676 encrypted_payload: vec![],
3677 }
3678 ],
3679 blinding_point: PublicKey::from_slice(&<Vec<u8>>::from_hex("02988face71e92c345a068f740191fd8e53be14f0bb957ef730d3c5f76087b960e").unwrap()).unwrap(),
3680 excess_final_cltv_expiry_delta: 0,
3681 final_value_msat: 150_000_000,
3682 }),
3683 }
3684 }
3685
3686 #[test]
3687 fn test_trampoline_onion_error_cryptography() {
3688 let secp_ctx = Secp256k1::new();
3691 let logger: Arc<TestLogger> = Arc::new(TestLogger::new());
3692 let dummy_amt_msat = 150_000_000;
3693
3694 {
3695 let trampoline_session_priv = SecretKey::from_slice(&[3; 32]).unwrap();
3698 let outer_session_priv = SecretKey::from_slice(&[4; 32]).unwrap();
3699
3700 let error_packet_hex = "f8941a320b8fde4ad7b9b920c69cbf334114737497d93059d77e591eaa78d6334d3e2aeefcb0cc83402eaaf91d07d695cd895d9cad1018abdaf7d2a49d7657b1612729db7f393f0bb62b25afaaaa326d72a9214666025385033f2ec4605dcf1507467b5726d806da180ea224a7d8631cd31b0bdd08eead8bfe14fc8c7475e17768b1321b54dd4294aecc96da391efe0ca5bd267a45ee085c85a60cf9a9ac152fa4795fff8700a3ea4f848817f5e6943e855ab2e86f6929c9e885d8b20c49b14d2512c59ed21f10bd38691110b0d82c00d9fa48a20f10c7550358724c6e8e2b966e56a0aadf458695b273768062fa7c6e60eb72d4cdc67bf525c194e4a17fdcaa0e9d80480b586bf113f14eea530b6728a1c53fe5cee092e24a90f21f4b764015e7ed5e23";
3701 let error_packet = OnionErrorPacket {
3702 data: <Vec<u8>>::from_hex(error_packet_hex).unwrap(),
3703 attribution_data: None,
3704 };
3705 let decrypted_failure = process_onion_failure_inner(
3706 &secp_ctx,
3707 &logger,
3708 &build_trampoline_test_path(),
3709 &outer_session_priv,
3710 Some(trampoline_session_priv),
3711 error_packet,
3712 );
3713 assert_eq!(
3714 decrypted_failure.onion_error_code,
3715 Some(LocalHTLCFailureReason::IncorrectPaymentDetails),
3716 );
3717 }
3718
3719 {
3720 let session_priv = get_test_session_key();
3722 let path = build_trampoline_test_path();
3723 let outer_onion_keys = construct_onion_keys(&Secp256k1::new(), &path, &session_priv);
3724
3725 let trampoline_session_priv = compute_trampoline_session_priv(&session_priv);
3726 let trampoline_onion_keys = construct_trampoline_onion_keys(
3727 &secp_ctx,
3728 &path.blinded_tail.as_ref().unwrap(),
3729 &trampoline_session_priv,
3730 );
3731
3732 let htlc_source = HTLCSource::OutboundRoute {
3733 path,
3734 session_priv,
3735 first_hop_htlc_msat: dummy_amt_msat,
3736 payment_id: PaymentId([1; 32]),
3737 bolt12_invoice: None,
3738 };
3739
3740 {
3741 let error_code = LocalHTLCFailureReason::TemporaryNodeFailure;
3743 let mut first_hop_error_packet = build_unencrypted_failure_packet(
3744 outer_onion_keys[0].shared_secret.as_ref(),
3745 error_code,
3746 &[0; 0],
3747 0,
3748 DEFAULT_MIN_FAILURE_PACKET_LEN,
3749 );
3750
3751 crypt_failure_packet(
3752 outer_onion_keys[0].shared_secret.as_ref(),
3753 &mut first_hop_error_packet,
3754 );
3755
3756 let decrypted_failure =
3757 process_onion_failure(&secp_ctx, &logger, &htlc_source, first_hop_error_packet);
3758 assert_eq!(decrypted_failure.onion_error_code, Some(error_code));
3759 };
3760
3761 {
3762 let error_code = 0x2003.into();
3764 let mut trampoline_outer_hop_error_packet = build_unencrypted_failure_packet(
3765 outer_onion_keys[1].shared_secret.as_ref(),
3766 error_code,
3767 &[0; 0],
3768 0,
3769 DEFAULT_MIN_FAILURE_PACKET_LEN,
3770 );
3771 trampoline_outer_hop_error_packet.attribution_data = None;
3772
3773 crypt_failure_packet(
3774 outer_onion_keys[1].shared_secret.as_ref(),
3775 &mut trampoline_outer_hop_error_packet,
3776 );
3777
3778 crypt_failure_packet(
3779 outer_onion_keys[0].shared_secret.as_ref(),
3780 &mut trampoline_outer_hop_error_packet,
3781 );
3782
3783 let decrypted_failure = process_onion_failure(
3784 &secp_ctx,
3785 &logger,
3786 &htlc_source,
3787 trampoline_outer_hop_error_packet,
3788 );
3789 assert_eq!(decrypted_failure.onion_error_code, Some(error_code));
3790 };
3791
3792 {
3793 let error_code = 0x2004.into();
3795 let mut trampoline_inner_hop_error_packet = build_unencrypted_failure_packet(
3796 trampoline_onion_keys[0].shared_secret.as_ref(),
3797 error_code,
3798 &[0; 0],
3799 0,
3800 DEFAULT_MIN_FAILURE_PACKET_LEN,
3801 );
3802 trampoline_inner_hop_error_packet.attribution_data = None;
3803
3804 crypt_failure_packet(
3805 trampoline_onion_keys[0].shared_secret.as_ref(),
3806 &mut trampoline_inner_hop_error_packet,
3807 );
3808
3809 crypt_failure_packet(
3810 outer_onion_keys[1].shared_secret.as_ref(),
3811 &mut trampoline_inner_hop_error_packet,
3812 );
3813
3814 crypt_failure_packet(
3815 outer_onion_keys[0].shared_secret.as_ref(),
3816 &mut trampoline_inner_hop_error_packet,
3817 );
3818
3819 let decrypted_failure = process_onion_failure(
3820 &secp_ctx,
3821 &logger,
3822 &htlc_source,
3823 trampoline_inner_hop_error_packet,
3824 );
3825 assert_eq!(decrypted_failure.onion_error_code, Some(error_code));
3826 }
3827
3828 {
3829 let error_code = 0x2005.into();
3831 let mut trampoline_second_hop_error_packet = build_unencrypted_failure_packet(
3832 trampoline_onion_keys[1].shared_secret.as_ref(),
3833 error_code,
3834 &[0; 0],
3835 0,
3836 DEFAULT_MIN_FAILURE_PACKET_LEN,
3837 );
3838 trampoline_second_hop_error_packet.attribution_data = None;
3839
3840 crypt_failure_packet(
3841 trampoline_onion_keys[1].shared_secret.as_ref(),
3842 &mut trampoline_second_hop_error_packet,
3843 );
3844
3845 crypt_failure_packet(
3846 trampoline_onion_keys[0].shared_secret.as_ref(),
3847 &mut trampoline_second_hop_error_packet,
3848 );
3849
3850 crypt_failure_packet(
3851 outer_onion_keys[1].shared_secret.as_ref(),
3852 &mut trampoline_second_hop_error_packet,
3853 );
3854
3855 crypt_failure_packet(
3856 outer_onion_keys[0].shared_secret.as_ref(),
3857 &mut trampoline_second_hop_error_packet,
3858 );
3859
3860 let decrypted_failure = process_onion_failure(
3861 &secp_ctx,
3862 &logger,
3863 &htlc_source,
3864 trampoline_second_hop_error_packet,
3865 );
3866 assert_eq!(decrypted_failure.onion_error_code, Some(error_code));
3867 }
3868 }
3869 }
3870
3871 #[test]
3872 fn test_non_attributable_failure_packet_onion() {
3873 let packet = vec![1u8; 292];
3875 let onion_error_packet =
3876 OnionErrorPacket { data: packet, attribution_data: Some(AttributionData::new()) };
3877
3878 let logger: TestLogger = TestLogger::new();
3880 let decrypted_failure = test_failure_attribution(&logger, onion_error_packet);
3881 assert_eq!(decrypted_failure.attribution_failed_channel, Some(0));
3882 }
3883
3884 #[test]
3885 fn test_long_route_attributable_failure() {
3886 let secp_ctx = Secp256k1::new();
3889 const LEGACY_MAX_HOPS: usize = 27;
3890
3891 let mut hops = Vec::new();
3893 for i in 0..LEGACY_MAX_HOPS {
3894 let mut secret_bytes = [0; 32];
3895 secret_bytes[0] = (i + 1) as u8;
3896 let secret_key = SecretKey::from_slice(&secret_bytes).unwrap();
3897 let pubkey = secret_key.public_key(&secp_ctx);
3898
3899 hops.push(RouteHop {
3900 pubkey,
3901 channel_features: ChannelFeatures::empty(),
3902 node_features: NodeFeatures::empty(),
3903 short_channel_id: i as u64,
3904 fee_msat: 0,
3905 cltv_expiry_delta: 0,
3906 maybe_announced_channel: true,
3907 });
3908 }
3909 let path = Path { hops, blinded_tail: None };
3910
3911 let session_key = get_test_session_key();
3913 let onion_keys: Vec<_> =
3914 construct_onion_keys_generic(&secp_ctx, &path.hops, None, &session_key)
3915 .map(|(key, ..)| key)
3916 .collect();
3917
3918 let logger = TestLogger::new();
3920 let htlc_source = HTLCSource::OutboundRoute {
3921 path,
3922 session_priv: session_key,
3923 first_hop_htlc_msat: 0,
3924 payment_id: PaymentId([1; 32]),
3925 bolt12_invoice: None,
3926 };
3927
3928 for failure_pos in 0..LEGACY_MAX_HOPS {
3930 let packet = vec![1u8; 292];
3932 let mut onion_error =
3933 OnionErrorPacket { data: packet, attribution_data: Some(AttributionData::new()) };
3934
3935 for i in (0..failure_pos).rev() {
3937 let shared_secret = onion_keys[i].secret_bytes();
3938 process_failure_packet(&mut onion_error, &shared_secret, 0);
3939 super::crypt_failure_packet(&shared_secret, &mut onion_error);
3940 }
3941
3942 let decrypted_failure =
3944 process_onion_failure(&secp_ctx, &&logger, &htlc_source, onion_error);
3945
3946 let expected_failed_chan =
3948 if failure_pos < MAX_HOPS { Some(failure_pos as u64) } else { None };
3949 assert_eq!(decrypted_failure.attribution_failed_channel, expected_failed_chan);
3950 }
3951 }
3952
3953 #[test]
3954 fn test_unreadable_failure_packet_onion() {
3955 let onion_keys: Vec<OnionKeys> = build_test_onion_keys();
3957 let shared_secret = onion_keys[0].shared_secret.as_ref();
3958 let um = gen_um_from_shared_secret(&shared_secret);
3959
3960 let mut packet = [0u8; 33];
3962
3963 let mut hmac = HmacEngine::<Sha256>::new(&um);
3964 hmac.input(&packet[32..]);
3965 let hmac = Hmac::from_engine(hmac).to_byte_array();
3966 packet[..32].copy_from_slice(&hmac);
3967
3968 let mut onion_error_packet = OnionErrorPacket {
3969 data: packet.to_vec(),
3970 attribution_data: Some(AttributionData::new()),
3971 };
3972 onion_error_packet
3973 .attribution_data
3974 .as_mut()
3975 .unwrap()
3976 .add_hmacs(shared_secret, &onion_error_packet.data);
3977 crypt_failure_packet(shared_secret, &mut onion_error_packet);
3978
3979 let logger: TestLogger = TestLogger::new();
3981 let decrypted_failure = test_failure_attribution(&logger, onion_error_packet);
3982 assert_eq!(decrypted_failure.short_channel_id, Some(0));
3983
3984 logger.assert_log_contains("lightning::ln::onion_utils", "Unreadable failure", 1);
3985 }
3986
3987 #[test]
3988 fn test_missing_error_code() {
3989 let onion_keys: Vec<OnionKeys> = build_test_onion_keys();
3991 let shared_secret = onion_keys[0].shared_secret.as_ref();
3992 let um = gen_um_from_shared_secret(&shared_secret);
3993
3994 let failuremsg = vec![1];
3995 let pad = Vec::new();
3996 let mut packet = msgs::DecodedOnionErrorPacket { hmac: [0; 32], failuremsg, pad };
3997
3998 let mut hmac = HmacEngine::<Sha256>::new(&um);
3999 hmac.input(&packet.encode()[32..]);
4000 packet.hmac = Hmac::from_engine(hmac).to_byte_array();
4001
4002 let mut onion_error_packet = OnionErrorPacket {
4003 data: packet.encode(),
4004 attribution_data: Some(AttributionData::new()),
4005 };
4006 onion_error_packet
4007 .attribution_data
4008 .as_mut()
4009 .unwrap()
4010 .add_hmacs(shared_secret, &onion_error_packet.data);
4011 crypt_failure_packet(shared_secret, &mut onion_error_packet);
4012
4013 let logger = TestLogger::new();
4014 let decrypted_failure = test_failure_attribution(&logger, onion_error_packet);
4015 assert_eq!(decrypted_failure.short_channel_id, Some(0));
4016
4017 logger.assert_log_contains(
4018 "lightning::ln::onion_utils",
4019 "Missing error code in failure",
4020 1,
4021 );
4022 }
4023
4024 fn test_failure_attribution(
4025 logger: &TestLogger, packet: OnionErrorPacket,
4026 ) -> DecodedOnionFailure {
4027 let ctx_full = Secp256k1::new();
4028 let path = build_test_path();
4029 let htlc_source = HTLCSource::OutboundRoute {
4030 path,
4031 session_priv: get_test_session_key(),
4032 first_hop_htlc_msat: 0,
4033 payment_id: PaymentId([1; 32]),
4034 bolt12_invoice: None,
4035 };
4036
4037 let decrypted_failure = process_onion_failure(&ctx_full, &logger, &htlc_source, packet);
4038
4039 decrypted_failure
4040 }
4041
4042 struct RawOnionHopData {
4043 data: Vec<u8>,
4044 }
4045 impl RawOnionHopData {
4046 fn new(orig: msgs::OutboundOnionPayload) -> Self {
4047 Self { data: orig.encode() }
4048 }
4049 }
4050 impl Writeable for RawOnionHopData {
4051 fn write<W: Writer>(&self, writer: &mut W) -> Result<(), io::Error> {
4052 writer.write_all(&self.data[..])
4053 }
4054 }
4055
4056 #[test]
4057 fn max_length_with_no_cltv_limit() {
4058 let recipient = PublicKey::from_slice(&[2; 33]).unwrap();
4061 let mut route_params = RouteParameters {
4062 payment_params: PaymentParameters::for_keysend(recipient, u32::MAX, true),
4063 final_value_msat: u64::MAX,
4064 max_total_routing_fee_msat: Some(u64::MAX),
4065 };
4066 route_params.payment_params.max_total_cltv_expiry_delta = u32::MAX;
4067 let recipient_onion = RecipientOnionFields::spontaneous_empty(u64::MAX);
4068 set_max_path_length(&mut route_params, &recipient_onion, None, None, 42).unwrap();
4069 }
4070
4071 #[test]
4072 fn test_failure_packet_max_size() {
4073 let failure_data = vec![0; 64531];
4087
4088 let shared_secret = [0; 32];
4089 let onion_error = super::build_unencrypted_failure_packet(
4090 &shared_secret,
4091 LocalHTLCFailureReason::TemporaryNodeFailure,
4092 &failure_data,
4093 0,
4094 DEFAULT_MIN_FAILURE_PACKET_LEN,
4095 );
4096
4097 let msg = UpdateFailHTLC {
4098 channel_id: ChannelId([0; 32]),
4099 htlc_id: 0,
4100 reason: onion_error.data,
4101 attribution_data: onion_error.attribution_data,
4102 };
4103
4104 let mut buffer = Vec::new();
4105 msg.write(&mut buffer).unwrap();
4106
4107 assert_eq!(buffer.len(), 65535);
4108 }
4109
4110 #[test]
4111 fn create_payment_onion_fails_for_empty_route() {
4112 let secp_ctx = Secp256k1::new();
4113 let session_priv = get_test_session_key();
4114 let recipient_onion = RecipientOnionFields::spontaneous_empty(1000);
4115 let payment_hash = PaymentHash([0; 32]);
4116 let empty_path = Path { hops: vec![], blinded_tail: None };
4117
4118 let err = super::create_payment_onion(
4119 &secp_ctx,
4120 &empty_path,
4121 &session_priv,
4122 &recipient_onion,
4123 100,
4124 &payment_hash,
4125 &None,
4126 None,
4127 [0; 32],
4128 )
4129 .unwrap_err();
4130
4131 match err {
4132 APIError::InvalidRoute { err } => {
4133 assert_eq!(err, "Route size too large (or empty) considering onion data");
4134 },
4135 _ => panic!("Expected InvalidRoute error, got {:?}", err),
4136 }
4137 }
4138}