+
+/// Construct onion packet payloads and keys for sending an onion message along the given
+/// `unblinded_path` to the given `destination`.
+fn packet_payloads_and_keys<T: secp256k1::Signing + secp256k1::Verification>(
+ secp_ctx: &Secp256k1<T>, unblinded_path: &[PublicKey], destination: Destination, session_priv: &SecretKey
+) -> Result<(Vec<(Payload, [u8; 32])>, Vec<onion_utils::OnionKeys>), secp256k1::Error> {
+ let num_hops = unblinded_path.len() + destination.num_hops();
+ let mut payloads = Vec::with_capacity(num_hops);
+ let mut onion_packet_keys = Vec::with_capacity(num_hops);
+
+ let (mut intro_node_id_blinding_pt, num_blinded_hops) = if let Destination::BlindedRoute(BlindedRoute {
+ introduction_node_id, blinding_point, blinded_hops }) = &destination {
+ (Some((*introduction_node_id, *blinding_point)), blinded_hops.len()) } else { (None, 0) };
+ let num_unblinded_hops = num_hops - num_blinded_hops;
+
+ let mut unblinded_path_idx = 0;
+ let mut blinded_path_idx = 0;
+ let mut prev_control_tlvs_ss = None;
+ utils::construct_keys_callback(secp_ctx, unblinded_path, Some(destination), session_priv, |_, onion_packet_ss, ephemeral_pubkey, control_tlvs_ss, unblinded_pk_opt, enc_payload_opt| {
+ if num_unblinded_hops != 0 && unblinded_path_idx < num_unblinded_hops {
+ if let Some(ss) = prev_control_tlvs_ss.take() {
+ payloads.push((Payload::Forward(ForwardControlTlvs::Unblinded(
+ ForwardTlvs {
+ next_node_id: unblinded_pk_opt.unwrap(),
+ next_blinding_override: None,
+ }
+ )), ss));
+ }
+ prev_control_tlvs_ss = Some(control_tlvs_ss);
+ unblinded_path_idx += 1;
+ } else if let Some((intro_node_id, blinding_pt)) = intro_node_id_blinding_pt.take() {
+ if let Some(control_tlvs_ss) = prev_control_tlvs_ss.take() {
+ payloads.push((Payload::Forward(ForwardControlTlvs::Unblinded(ForwardTlvs {
+ next_node_id: intro_node_id,
+ next_blinding_override: Some(blinding_pt),
+ })), control_tlvs_ss));
+ }
+ if let Some(encrypted_payload) = enc_payload_opt {
+ payloads.push((Payload::Forward(ForwardControlTlvs::Blinded(encrypted_payload)),
+ control_tlvs_ss));
+ } else { debug_assert!(false); }
+ blinded_path_idx += 1;
+ } else if blinded_path_idx < num_blinded_hops - 1 && enc_payload_opt.is_some() {
+ payloads.push((Payload::Forward(ForwardControlTlvs::Blinded(enc_payload_opt.unwrap())),
+ control_tlvs_ss));
+ blinded_path_idx += 1;
+ } else if let Some(encrypted_payload) = enc_payload_opt {
+ payloads.push((Payload::Receive {
+ control_tlvs: ReceiveControlTlvs::Blinded(encrypted_payload),
+ }, control_tlvs_ss));
+ }
+
+ let (rho, mu) = onion_utils::gen_rho_mu_from_shared_secret(onion_packet_ss.as_ref());
+ onion_packet_keys.push(onion_utils::OnionKeys {
+ #[cfg(test)]
+ shared_secret: onion_packet_ss,
+ #[cfg(test)]
+ blinding_factor: [0; 32],
+ ephemeral_pubkey,
+ rho,
+ mu,
+ });
+ })?;
+
+ if let Some(control_tlvs_ss) = prev_control_tlvs_ss {
+ payloads.push((Payload::Receive {
+ control_tlvs: ReceiveControlTlvs::Unblinded(ReceiveTlvs { path_id: None, })
+ }, control_tlvs_ss));
+ }
+
+ Ok((payloads, onion_packet_keys))
+}
+
+fn construct_onion_message_packet(payloads: Vec<(Payload, [u8; 32])>, onion_keys: Vec<onion_utils::OnionKeys>, prng_seed: [u8; 32]) -> Packet {
+ // Spec rationale:
+ // "`len` allows larger messages to be sent than the standard 1300 bytes allowed for an HTLC
+ // onion, but this should be used sparingly as it is reduces anonymity set, hence the
+ // recommendation that it either look like an HTLC onion, or if larger, be a fixed size."
+ let payloads_ser_len = onion_utils::payloads_serialized_length(&payloads);
+ let hop_data_len = if payloads_ser_len <= SMALL_PACKET_HOP_DATA_LEN {
+ SMALL_PACKET_HOP_DATA_LEN
+ } else if payloads_ser_len <= BIG_PACKET_HOP_DATA_LEN {
+ BIG_PACKET_HOP_DATA_LEN
+ } else { payloads_ser_len };
+
+ onion_utils::construct_onion_message_packet::<_, _>(payloads, onion_keys, prng_seed, hop_data_len)
+}