1use anyhow::{anyhow, Context, Error};
3use bytes::{Buf, Bytes, BytesMut};
4use chacha20poly1305::{AeadInPlace, ChaCha20Poly1305, KeyInit};
5use lightning_signer::bitcoin::{
6 secp256k1::{ecdh::SharedSecret, PublicKey, Secp256k1, SecretKey},
7 Network,
8};
9use std::io::Read;
10
11const VERSION: u8 = 0x01;
12const HEADER_LEN: usize = 1 + 33 + 12 + 16;
14
15pub fn decrypt_with_seed(enc: BytesMut, seed: &SecretKey) -> Result<Bytes, Error> {
16 use lightning_signer::signer::derive::{key_derive, KeyDerivationStyle};
18
19 let secp = Secp256k1::default();
20 let d = key_derive(KeyDerivationStyle::Native, Network::Bitcoin);
21 let (_, node_secret) = d.node_keys(&seed.secret_bytes(), &secp);
22
23 decrypt(enc, &node_secret)
24}
25
26pub fn decrypt(mut enc: BytesMut, privkey: &SecretKey) -> Result<Bytes, Error> {
27 let mut r = enc.clone().reader();
28 let mut version = [0u8; 1];
30 r.read_exact(&mut version)?;
31
32 if VERSION != version[0] {
33 return Err(anyhow!(
34 "Backup version {} is not supported by this client version {}",
35 version[0],
36 VERSION
37 ));
38 }
39
40 let mut ephkey = [0u8; 33];
41 r.read_exact(&mut ephkey)?;
42
43 let mut nonce = [0u8; 12];
44 r.read_exact(&mut nonce)?;
45
46 let mut tag = [0u8; 16];
47 r.read_exact(&mut tag)?;
48
49 let secp = Secp256k1::default();
50 let ephkey = PublicKey::from_slice(&ephkey).context("loading ephemeral key")?;
51 let node_id = privkey.public_key(&secp);
52
53 let shared_secret = SharedSecret::new(&ephkey, &privkey);
54 enc.advance(HEADER_LEN);
55
56 let cipher = ChaCha20Poly1305::new(&shared_secret.secret_bytes().into());
57
58 cipher
59 .decrypt_in_place_detached(&nonce.into(), &node_id.serialize(), &mut enc, &tag.into())
60 .map_err(|e| anyhow!("Error decrypting: {}", e))?;
61
62 Ok(enc.clone().into())
63}