Skip to content

Commit f6f5585

Browse files
Aditya SharmaAditya Sharma
authored andcommitted
Add OurPeerStorage for serialized Peer Storage backups
Introduce the OurPeerStorage struct to manage serialized channel data for peer storage backups. This struct facilitates the distribution of peer storage to channel partners and includes versioning and timestamping for comparison between retrieved peer storage instances. - Add the OurPeerStorage struct with fields for version, timestamp, and serialized channel data (ser_channels). - Implement methods to encrypt and decrypt peer storage securely. - Add functionality to update channel data within OurPeerStorage.
1 parent 612d964 commit f6f5585

File tree

2 files changed

+168
-0
lines changed

2 files changed

+168
-0
lines changed

lightning/src/ln/mod.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ pub mod chan_utils;
3030
pub mod features;
3131
pub mod script;
3232
pub mod types;
33+
pub mod our_peer_storage;
3334

3435
// TODO: These modules were moved from lightning-invoice and need to be better integrated into this
3536
// crate now:

lightning/src/ln/our_peer_storage.rs

Lines changed: 167 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,167 @@
1+
use crate::ln::types::ChannelId;
2+
use bitcoin::secp256k1::PublicKey;
3+
use std::collections::HashMap;
4+
5+
use crate::chain::channelmonitor::get_stub_channel_info_from_ser_channel;
6+
use crate::crypto::chacha20poly1305rfc::ChaCha20Poly1305RFC;
7+
8+
use crate::util::ser::{ Writeable, VecWriter, Writer, Readable };
9+
10+
use crate::prelude::*;
11+
use crate::io::{self, Error};
12+
13+
use crate::ln::msgs::DecodeError;
14+
15+
/// [`OurPeerStorage`] is used to store channel information that allows for the creation of a
16+
/// PeerStorage backup. It includes versioning and timestamping for comparison between
17+
/// instances of [`OurPeerStorage`].
18+
///
19+
/// This structure is designed to serialize channel data for backup and supports encryption
20+
/// and decryption to ensure data integrity and security during exchange or storage.
21+
///
22+
/// # Fields
23+
/// - `version`: Defines the structure's version for backward compatibility.
24+
/// - `timestamp`: UNIX timestamp indicating the creation or modification time of the instance.
25+
/// - `ser_channels`: Serialized channel data.
26+
///
27+
/// # Key Methods
28+
/// - `new`: Creates a new [`OurPeerStorage`] instance with the current timestamp.
29+
/// - `stub_channels`: Updates the serialized channel data.
30+
/// - `get_ser_channels`: Retrieves the serialized channel data.
31+
/// - `encrypt_our_peer_storage`: Encrypts the storage using a given key and returns the ciphertext.
32+
/// - `decrypt_our_peer_storage`: Decrypts the ciphertext using the key and updates the result buffer.
33+
/// - `get_cid_and_min_seen_secret`: Extracts channel IDs and their corresponding minimum seen
34+
/// secrets from the serialized data.
35+
///
36+
/// # Usage
37+
/// This structure can be used for securely managing and exchanging peer storage backups. It
38+
/// includes methods for encryption and decryption using `ChaCha20Poly1305RFC`, making it
39+
/// suitable for on-the-wire transmission.
40+
///
41+
/// ## Example
42+
/// ```
43+
/// let mut our_peer_storage = OurPeerStorage::new();
44+
/// our_peer_storage.stub_channels(vec![1, 2, 3]);
45+
/// let key = [0u8; 32];
46+
/// let encrypted = our_peer_storage.encrypt_our_peer_storage(key);
47+
/// let mut decrypted = vec![0u8; encrypted.len()];
48+
/// OurPeerStorage::decrypt_our_peer_storage(&mut decrypted, &encrypted).unwrap();
49+
/// ```
50+
#[derive(PartialEq)]
51+
pub struct OurPeerStorage {
52+
version: u8,
53+
timestamp: u32,
54+
ser_channels: Vec<u8>,
55+
}
56+
57+
impl OurPeerStorage {
58+
/// Returns a [`OurPeerStorage`] with version 1 and current timestamp.
59+
pub fn new() -> Self {
60+
let duration_since_epoch = std::time::SystemTime::now()
61+
.duration_since(std::time::SystemTime::UNIX_EPOCH)
62+
.expect("Time must be > 1970");
63+
64+
Self {
65+
version: 1,
66+
timestamp: duration_since_epoch.as_secs() as u32,
67+
ser_channels: Vec::new(),
68+
}
69+
}
70+
71+
/// Stubs a channel inside [`OurPeerStorage`]
72+
pub fn stub_channels(&mut self, ser_chan: Vec<u8>) {
73+
self.ser_channels = ser_chan;
74+
}
75+
76+
/// Get `ser_channels` field from [`OurPeerStorage`]
77+
pub fn get_ser_channels(&self) -> Vec<u8> {
78+
self.ser_channels.clone()
79+
}
80+
81+
/// Encrypt [`OurPeerStorage`] using the `key` and return a Vec<u8> containing the result.
82+
pub fn encrypt_our_peer_storage(&self, key: [u8; 32]) -> Vec<u8> {
83+
let n = 0u64;
84+
let mut peer_storage = VecWriter(Vec::new());
85+
self.write(&mut peer_storage).unwrap();
86+
let mut res = vec![0;peer_storage.0.len() + 16];
87+
88+
let plaintext = &peer_storage.0[..];
89+
let mut nonce = [0; 12];
90+
nonce[4..].copy_from_slice(&n.to_le_bytes()[..]);
91+
92+
let mut chacha = ChaCha20Poly1305RFC::new(&key, &nonce, b"");
93+
let mut tag = [0; 16];
94+
chacha.encrypt(plaintext, &mut res[0..plaintext.len()], &mut tag);
95+
res[plaintext.len()..].copy_from_slice(&tag);
96+
res
97+
}
98+
99+
/// Decrypt `OurPeerStorage` using the `key`, result is stored inside the `res`.
100+
/// Returns an error if the the `cyphertext` is not correct.
101+
pub fn decrypt_our_peer_storage(res: &mut[u8], cyphertext_with_key: &[u8]) -> Result<(), ()> {
102+
const KEY_SIZE: usize = 32;
103+
104+
// Ensure the combined data is at least as large as the key size
105+
if cyphertext_with_key.len() <= KEY_SIZE {
106+
return Err(());
107+
}
108+
109+
let (cyphertext, key) = cyphertext_with_key.split_at(cyphertext_with_key.len() - KEY_SIZE);
110+
let n = 0u64;
111+
let mut nonce = [0; 12];
112+
nonce[4..].copy_from_slice(&n.to_le_bytes()[..]);
113+
114+
let mut chacha = ChaCha20Poly1305RFC::new(&key, &nonce, b"");
115+
if chacha.variable_time_decrypt(&cyphertext[0..cyphertext.len() - 16], res, &cyphertext[cyphertext.len() - 16..]).is_err() {
116+
return Err(());
117+
}
118+
Ok(())
119+
}
120+
/// We store some channel information before the serialized channel, so that we can get data required to identify stale or missing channelmonitors.
121+
pub fn get_cid_and_min_seen_secret (&self) -> Result<HashMap<(PublicKey, ChannelId), u64>, DecodeError> {
122+
let mut cid_min_secret_map = HashMap::new();
123+
let chan_reader = &mut ::bitcoin::io::Cursor::new(self.ser_channels.clone());
124+
let num_chan: u64 = Readable::read(chan_reader)?;
125+
for _ in 0..num_chan {
126+
let len: u64 = Readable::read(chan_reader)?;
127+
let mut chan_bytes: Vec<u8> = Vec::with_capacity(len as usize);
128+
for _ in 0..len {
129+
chan_bytes.push(Readable::read(chan_reader)?);
130+
}
131+
let mut chan_reader = ::bitcoin::io::Cursor::new(chan_bytes);
132+
match get_stub_channel_info_from_ser_channel(&mut chan_reader) {
133+
Ok(p) => {
134+
cid_min_secret_map.insert((p.counterparty_node_id, p.cid), p.min_seen_secret);
135+
}
136+
Err(_) => {
137+
panic!("Could not get Peer Storage");
138+
}
139+
}
140+
}
141+
Ok(cid_min_secret_map)
142+
}
143+
}
144+
145+
impl Writeable for OurPeerStorage {
146+
fn write<W: Writer>(&self, writer: &mut W) -> Result<(), Error> {
147+
write_ver_prefix!(writer, self.version, 1);
148+
self.timestamp.write(writer)?;
149+
self.ser_channels.write(writer)?;
150+
Ok(())
151+
}
152+
}
153+
154+
impl Readable for OurPeerStorage {
155+
fn read<R: io::Read>(reader: &mut R) -> Result<Self, DecodeError> {
156+
let ver = read_ver_prefix!(reader, 1u8);
157+
let timestamp: u32 = Readable::read(reader)?;
158+
let ser_channels = <Vec<u8> as Readable>::read(reader)?;
159+
160+
let ps = OurPeerStorage {
161+
version: ver,
162+
timestamp,
163+
ser_channels,
164+
};
165+
Ok(ps)
166+
}
167+
}

0 commit comments

Comments
 (0)