1 // This file is Copyright its original authors, visible in version control
4 // This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
5 // or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
6 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
7 // You may not use this file except in accordance with one or both of these
10 //! Structs and enums useful for constructing and reading an onion message packet.
12 use bitcoin::secp256k1::PublicKey;
14 use ln::msgs::DecodeError;
16 use super::blinded_route::{ForwardTlvs, ReceiveTlvs};
17 use util::chacha20poly1305rfc::ChaChaPolyWriteAdapter;
18 use util::ser::{LengthRead, LengthReadable, Readable, Writeable, Writer};
24 // Per the spec, an onion message packet's `hop_data` field length should be
25 // SMALL_PACKET_HOP_DATA_LEN if it fits, else BIG_PACKET_HOP_DATA_LEN if it fits.
26 pub(super) const SMALL_PACKET_HOP_DATA_LEN: usize = 1300;
27 pub(super) const BIG_PACKET_HOP_DATA_LEN: usize = 32768;
29 #[derive(Clone, Debug, PartialEq)]
30 pub(crate) struct Packet {
32 public_key: PublicKey,
33 // Unlike the onion packets used for payments, onion message packets can have payloads greater
35 // TODO: if 1300 ends up being the most common size, optimize this to be:
36 // enum { ThirteenHundred([u8; 1300]), VarLen(Vec<u8>) }
41 impl onion_utils::Packet for Packet {
43 fn new(public_key: PublicKey, hop_data: Vec<u8>, hmac: [u8; 32]) -> Packet {
53 impl Writeable for Packet {
54 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
55 self.version.write(w)?;
56 self.public_key.write(w)?;
57 w.write_all(&self.hop_data)?;
63 impl LengthReadable for Packet {
64 fn read<R: LengthRead>(r: &mut R) -> Result<Self, DecodeError> {
65 const READ_BUFFER_SIZE: usize = 4096;
67 let version = Readable::read(r)?;
68 let public_key = Readable::read(r)?;
70 let mut hop_data = Vec::new();
71 let hop_data_len = r.total_bytes() as usize - 66; // 1 (version) + 33 (pubkey) + 32 (HMAC) = 66
73 while read_idx < hop_data_len {
74 let mut read_buffer = [0; READ_BUFFER_SIZE];
75 let read_amt = cmp::min(hop_data_len - read_idx, READ_BUFFER_SIZE);
76 r.read_exact(&mut read_buffer[..read_amt]);
77 hop_data.extend_from_slice(&read_buffer[..read_amt]);
81 let hmac = Readable::read(r)?;
91 /// Onion message payloads contain "control" TLVs and "data" TLVs. Control TLVs are used to route
92 /// the onion message from hop to hop and for path verification, whereas data TLVs contain the onion
93 /// message content itself, such as an invoice request.
94 pub(super) enum Payload {
95 /// This payload is for an intermediate hop.
96 Forward(ForwardControlTlvs),
97 /// This payload is for the final hop.
99 control_tlvs: ReceiveControlTlvs,
101 // reply_path: Option<BlindedRoute>,
108 // InvoiceRequest(InvoiceRequest),
110 // InvoiceError(InvoiceError),
114 /// Forward control TLVs in their blinded and unblinded form.
115 pub(super) enum ForwardControlTlvs {
116 /// If we're sending to a blinded route, the node that constructed the blinded route has provided
117 /// this hop's control TLVs, already encrypted into bytes.
119 /// If we're constructing an onion message hop through an intermediate unblinded node, we'll need
120 /// to construct the intermediate hop's control TLVs in their unblinded state to avoid encoding
121 /// them into an intermediate Vec. See [`super::blinded_route::ForwardTlvs`] for more info.
122 Unblinded(ForwardTlvs),
125 /// Receive control TLVs in their blinded and unblinded form.
126 pub(super) enum ReceiveControlTlvs {
127 /// See [`ForwardControlTlvs::Blinded`].
129 /// See [`ForwardControlTlvs::Unblinded`] and [`super::blinded_route::ReceiveTlvs`].
130 Unblinded(ReceiveTlvs),
133 // Uses the provided secret to simultaneously encode and encrypt the unblinded control TLVs.
134 impl Writeable for (Payload, [u8; 32]) {
135 fn write<W: Writer>(&self, w: &mut W) -> Result<(), io::Error> {
137 Payload::Forward(ForwardControlTlvs::Blinded(encrypted_bytes)) |
138 Payload::Receive { control_tlvs: ReceiveControlTlvs::Blinded(encrypted_bytes)} => {
139 encode_varint_length_prefixed_tlv!(w, {
140 (4, encrypted_bytes, vec_type)
143 Payload::Forward(ForwardControlTlvs::Unblinded(control_tlvs)) => {
144 let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
145 encode_varint_length_prefixed_tlv!(w, {
146 (4, write_adapter, required)
149 Payload::Receive { control_tlvs: ReceiveControlTlvs::Unblinded(control_tlvs)} => {
150 let write_adapter = ChaChaPolyWriteAdapter::new(self.1, &control_tlvs);
151 encode_varint_length_prefixed_tlv!(w, {
152 (4, write_adapter, required)