Skip to content

Commit 797d86a

Browse files
committed
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 e77c694 commit 797d86a

File tree

2 files changed

+154
-0
lines changed

2 files changed

+154
-0
lines changed

lightning/src/ln/mod.rs

+1
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ pub mod chan_utils;
2424
mod features;
2525
pub mod script;
2626
pub mod types;
27+
pub mod our_peer_storage;
2728

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

lightning/src/ln/our_peer_storage.rs

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

0 commit comments

Comments
 (0)