ed0206a2adbd2c2f883902c215a94872a1a6116e
[rust-lightning] / lightning / src / onion_message / packet.rs
1 // This file is Copyright its original authors, visible in version control
2 // history.
3 //
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
8 // licenses.
9
10 //! Structs and enums useful for constructing and reading an onion message packet.
11
12 use bitcoin::secp256k1::PublicKey;
13
14 use ln::msgs::DecodeError;
15 use ln::onion_utils;
16 use super::blinded_route::{ForwardTlvs, ReceiveTlvs};
17 use util::chacha20poly1305rfc::ChaChaPolyWriteAdapter;
18 use util::ser::{LengthRead, LengthReadable, Readable, Writeable, Writer};
19
20 use core::cmp;
21 use io;
22 use prelude::*;
23
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;
28
29 #[derive(Clone, Debug, PartialEq)]
30 pub(crate) struct Packet {
31         version: u8,
32         public_key: PublicKey,
33         // Unlike the onion packets used for payments, onion message packets can have payloads greater
34         // than 1300 bytes.
35         // TODO: if 1300 ends up being the most common size, optimize this to be:
36         // enum { ThirteenHundred([u8; 1300]), VarLen(Vec<u8>) }
37         hop_data: Vec<u8>,
38         hmac: [u8; 32],
39 }
40
41 impl onion_utils::Packet for Packet {
42         type Data = Vec<u8>;
43         fn new(public_key: PublicKey, hop_data: Vec<u8>, hmac: [u8; 32]) -> Packet {
44                 Self {
45                         version: 0,
46                         public_key,
47                         hop_data,
48                         hmac,
49                 }
50         }
51 }
52
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)?;
58                 self.hmac.write(w)?;
59                 Ok(())
60         }
61 }
62
63 impl LengthReadable for Packet {
64         fn read<R: LengthRead>(r: &mut R) -> Result<Self, DecodeError> {
65                 const READ_BUFFER_SIZE: usize = 4096;
66
67                 let version = Readable::read(r)?;
68                 let public_key = Readable::read(r)?;
69
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
72                 let mut read_idx = 0;
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]);
78                         read_idx += read_amt;
79                 }
80
81                 let hmac = Readable::read(r)?;
82                 Ok(Packet {
83                         version,
84                         public_key,
85                         hop_data,
86                         hmac,
87                 })
88         }
89 }
90
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.
98         Receive {
99                 control_tlvs: ReceiveControlTlvs,
100                 // Coming soon:
101                 // reply_path: Option<BlindedRoute>,
102                 // message: Message,
103         }
104 }
105
106 // Coming soon:
107 // enum Message {
108 //      InvoiceRequest(InvoiceRequest),
109 //      Invoice(Invoice),
110 //      InvoiceError(InvoiceError),
111 //      CustomMessage<T>,
112 // }
113
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.
118         Blinded(Vec<u8>),
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),
123 }
124
125 /// Receive control TLVs in their blinded and unblinded form.
126 pub(super) enum ReceiveControlTlvs {
127         /// See [`ForwardControlTlvs::Blinded`].
128         Blinded(Vec<u8>),
129         /// See [`ForwardControlTlvs::Unblinded`] and [`super::blinded_route::ReceiveTlvs`].
130         Unblinded(ReceiveTlvs),
131 }
132
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> {
136                 match &self.0 {
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)
141                                 })
142                         },
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)
147                                 })
148                         },
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)
153                                 })
154                         },
155                 }
156                 Ok(())
157         }
158 }