+/// Since onion message packets and onion payment packets have different lengths but are otherwise
+/// identical, we use this trait to allow `construct_onion_packet_with_init_noise` to return either
+/// type.
+pub(crate) trait Packet {
+ type Data: AsMut<[u8]>;
+ fn new(pubkey: PublicKey, hop_data: Self::Data, hmac: [u8; 32]) -> Self;
+}
+
+// Needed for rustc versions older than 1.47 to avoid E0277: "arrays only have std trait
+// implementations for lengths 0..=32".
+pub(crate) struct FixedSizeOnionPacket(pub(crate) [u8; ONION_DATA_LEN]);
+
+impl AsMut<[u8]> for FixedSizeOnionPacket {
+ fn as_mut(&mut self) -> &mut [u8] {
+ &mut self.0
+ }
+}
+
+pub(crate) fn payloads_serialized_length<HD: Writeable>(payloads: &Vec<HD>) -> usize {
+ payloads.iter().map(|p| p.serialized_length() + 32 /* HMAC */).sum()
+}
+
+/// panics if payloads_serialized_length(payloads) > packet_data_len
+pub(crate) fn construct_onion_message_packet<HD: Writeable, P: Packet<Data = Vec<u8>>>(
+ payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, prng_seed: [u8; 32], packet_data_len: usize) -> P
+{
+ let mut packet_data = vec![0; packet_data_len];
+
+ let mut chacha = ChaCha20::new(&prng_seed, &[0; 8]);
+ chacha.process_in_place(&mut packet_data);
+
+ construct_onion_packet_with_init_noise::<_, _>(payloads, onion_keys, packet_data, None)
+}
+
+/// panics if payloads_serialized_length(payloads) > packet_data.len()
+fn construct_onion_packet_with_init_noise<HD: Writeable, P: Packet>(
+ mut payloads: Vec<HD>, onion_keys: Vec<OnionKeys>, mut packet_data: P::Data, associated_data: Option<&PaymentHash>) -> P
+{