1use std::str::FromStr;
2
3use descriptor::descr_to_dpks;
4
5pub use ll::Content;
6use miniscript::{
7 bitcoin::{bip32::DerivationPath, secp256k1},
8 Descriptor, DescriptorPublicKey,
9};
10
11#[cfg(all(feature = "miniscript_12_0", feature = "miniscript_12_3_5"))]
12compile_error!("A single miniscript version must be selected");
13
14#[cfg(not(any(feature = "miniscript_12_0", feature = "miniscript_12_3_5")))]
15compile_error!("A miniscript version must be selected with feature flag");
16#[cfg(feature = "tokio")]
17pub use tokio;
18
19#[cfg(feature = "miniscript_12_0")]
20pub use mscript_12_0 as miniscript;
21#[cfg(feature = "miniscript_12_3_5")]
22pub use mscript_12_3_5 as miniscript;
23
24use num_enum::{FromPrimitive, IntoPrimitive};
25
26pub mod descriptor;
27pub mod ll;
28#[cfg(feature = "devices")]
29pub mod signing_devices;
30
31pub trait ToPayload {
32 fn to_payload(&self) -> Result<Vec<u8>, Error>;
33 fn content_type(&self) -> Content;
34 fn derivation_paths(&self) -> Result<Vec<DerivationPath>, Error>;
35 fn keys(&self) -> Result<Vec<secp256k1::PublicKey>, Error>;
36}
37
38impl ToPayload for Vec<u8> {
39 fn to_payload(&self) -> Result<Vec<u8>, Error> {
40 Ok(self.clone())
41 }
42 fn content_type(&self) -> Content {
43 Content::Unknown
44 }
45 fn derivation_paths(&self) -> Result<Vec<DerivationPath>, Error> {
46 Ok(vec![])
47 }
48 fn keys(&self) -> Result<Vec<secp256k1::PublicKey>, Error> {
49 Ok(vec![])
50 }
51}
52
53impl ToPayload for Descriptor<DescriptorPublicKey> {
54 fn to_payload(&self) -> Result<Vec<u8>, Error> {
55 Ok(self.to_string().as_bytes().to_vec())
56 }
57
58 fn content_type(&self) -> Content {
59 Content::Bip380
60 }
61
62 fn derivation_paths(&self) -> Result<Vec<DerivationPath>, Error> {
63 let dpks = descr_to_dpks(self)?;
64 let (_, p) = descriptor::dpks_to_derivation_keys_paths(&dpks);
65 Ok(p)
66 }
67
68 fn keys(&self) -> Result<Vec<secp256k1::PublicKey>, Error> {
69 let dpks = descr_to_dpks(self)?;
70 let (k, _) = descriptor::dpks_to_derivation_keys_paths(&dpks);
71 Ok(k)
72 }
73}
74
75#[derive(Debug, Clone, PartialEq, Eq)]
76pub enum Decrypted {
77 Descriptor(Descriptor<DescriptorPublicKey>),
78 Policy,
79 Labels,
80 WalletBackup(Vec<u8>),
81 Raw(Vec<u8>),
82}
83
84#[derive(Debug, Clone)]
85pub enum Payload {
86 None,
87 Encrypt {
88 payload: Vec<u8>,
89 },
90 DecryptV1 {
91 cyphertext: Vec<u8>,
92 individual_secrets: Vec<[u8; 32]>,
93 nonce: [u8; 12],
94 },
95}
96
97impl Payload {
98 pub fn is_none(&self) -> bool {
99 matches!(self, Payload::None)
100 }
101}
102
103#[derive(Debug, Clone)]
104pub struct EncryptedBackup {
105 version: Version,
106 content: Content,
107 encryption: Encryption,
108 derivation_paths: Vec<DerivationPath>,
109 keys: Vec<secp256k1::PublicKey>,
110 payload: Payload,
111}
112
113impl Default for EncryptedBackup {
114 fn default() -> Self {
115 Self {
116 version: Version::V0,
117 content: Content::Unknown,
118 encryption: Encryption::AesGcm256,
119 derivation_paths: vec![],
120 keys: vec![],
121 payload: Payload::None,
122 }
123 }
124}
125
126impl EncryptedBackup {
127 pub fn new() -> Self {
128 Default::default()
129 }
130 pub fn get_derivation_paths(&self) -> Vec<DerivationPath> {
131 self.derivation_paths.clone()
132 }
133 pub fn get_keys(&self) -> Vec<secp256k1::PublicKey> {
134 self.keys.clone()
135 }
136 pub fn get_content(&self) -> Content {
137 self.content.clone()
138 }
139 pub fn get_version(&self) -> Version {
140 self.version
141 }
142 pub fn get_encryption(&self) -> Encryption {
143 self.encryption
144 }
145 pub fn set_keys(mut self, keys: Vec<secp256k1::PublicKey>) -> Self {
146 self.keys = keys;
147 self
148 }
149 pub fn set_version(mut self, version: Version) -> Self {
150 self.version = version;
151 self
152 }
153 pub fn set_content_type(mut self, content_type: Content) -> Self {
154 self.content = content_type;
155 self
156 }
157 pub fn set_encryption(mut self, encryption: Encryption) -> Self {
158 self.encryption = encryption;
159 self
160 }
161 pub fn set_derivation_paths(mut self, derivation_paths: Vec<DerivationPath>) -> Self {
162 self.derivation_paths = derivation_paths;
163 self
164 }
165 pub fn set_payload<T: ToPayload>(mut self, payload: &T) -> Result<Self, Error> {
166 self.payload = Payload::Encrypt {
167 payload: payload.to_payload()?,
168 };
169 if payload.content_type().is_known() {
170 self.content = payload.content_type();
171 };
172 self.derivation_paths
173 .append(&mut payload.derivation_paths()?);
174 self.keys.append(&mut payload.keys()?);
175 Ok(self)
176 }
177 pub fn encrypt(self) -> Result<Vec<u8>, Error> {
178 if self.content == Content::Unknown {
179 return Err(Error::UnknownContent);
180 }
181 if !self.encryption.is_defined() {
182 return Err(Error::EncryptionUndefined);
183 }
184 if !self.version.is_valid() {
185 return Err(Error::InvalidVersion);
186 }
187 let bytes = if let Payload::Encrypt { payload } = &self.payload {
188 payload.clone()
189 } else {
190 return Err(Error::WrongPayload);
191 };
192
193 match (self.encryption, self.version) {
194 (Encryption::AesGcm256, Version::V0 | Version::V1) => Ok(ll::encrypt_aes_gcm_256_v1(
195 self.derivation_paths,
196 self.content.clone(),
197 self.keys,
198 &bytes,
199 )?),
200 _ => Err(Error::NotImplemented),
201 }
202 }
203 pub fn set_encrypted_payload(mut self, bytes: &[u8]) -> Result<Self, Error> {
204 let version: Version = ll::decode_version(bytes).map(|v| v.into())?;
205 match version {
206 Version::V0 | Version::V1 => {
207 let (derivation_paths, individual_secrets, encryption_type, nonce, cyphertext) =
208 ll::decode_v1(bytes)?;
209 self.derivation_paths = derivation_paths;
210 self.encryption = encryption_type.into();
211 self.payload = Payload::DecryptV1 {
212 cyphertext,
213 individual_secrets,
214 nonce,
215 }
216 }
217 _ => return Err(Error::NotImplemented),
218 }
219 Ok(self)
220 }
221 pub fn extract(content: Content, bytes: Vec<u8>) -> Result<Decrypted, Error> {
222 match content {
223 Content::None | Content::Unknown => Ok(Decrypted::Raw(bytes)),
224 Content::Bip380 => {
225 let descr_str = String::from_utf8(bytes).map_err(|_| Error::Utf8)?;
226 let descriptor = Descriptor::<DescriptorPublicKey>::from_str(&descr_str)
227 .map_err(|_| Error::Descriptor)?;
228 Ok(Decrypted::Descriptor(descriptor))
229 }
230 Content::BIP(_) | Content::Proprietary(_) | Content::Bip329 | Content::Bip388 => {
231 Err(Error::NotImplemented)
232 }
233 }
234 }
235 pub fn decrypt(&self) -> Result<Decrypted, Error> {
236 if self.keys.is_empty() {
237 return Err(Error::NoKey);
238 }
239 match self.version {
240 Version::V0 | Version::V1 => match &self.payload {
241 Payload::None | Payload::Encrypt { .. } => Err(Error::WrongPayload),
242 Payload::DecryptV1 {
243 cyphertext,
244 individual_secrets,
245 nonce,
246 } => {
247 for key in &self.keys {
248 if let Ok((content, bytes)) = ll::decrypt_aes_gcm_256_v1(
249 *key,
250 &individual_secrets.clone(),
251 cyphertext.clone(),
252 *nonce,
253 ) {
254 return Self::extract(content, bytes);
255 }
256 }
257 Err(Error::WrongKey)
258 }
259 },
260 Version::Unknown => Err(Error::UnknownVersion),
261 }
262 }
263}
264
265#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive, PartialEq, Eq)]
266#[repr(u8)]
267pub enum Encryption {
268 Undefined,
269 AesGcm256,
270 #[num_enum(default)]
271 Unknown = 0xFF,
272}
273
274impl Encryption {
275 pub fn is_defined(&self) -> bool {
276 match self {
277 Encryption::Undefined | Encryption::Unknown => false,
278 Encryption::AesGcm256 => true,
279 }
280 }
281}
282
283#[derive(Debug, Clone, Copy, FromPrimitive, IntoPrimitive, PartialEq, Eq)]
284#[repr(u8)]
285pub enum Version {
286 V0,
287 V1,
288 #[num_enum(default)]
289 Unknown = 0xFF,
290}
291
292impl Version {
293 fn max() -> Self {
294 Version::V1
295 }
296 pub fn is_valid(&self) -> bool {
297 match self {
298 Version::Unknown => false,
299 Version::V0 | Version::V1 => true,
300 }
301 }
302}
303
304#[derive(Debug, Clone, PartialEq, Eq)]
305pub enum Error {
306 Ll(ll::Error),
307 Utf8,
308 Descriptor,
309 NotImplemented,
310 UnknownContent,
311 EncryptionUndefined,
312 InvalidVersion,
313 WrongPayload,
314 UnknownVersion,
315 NoKey,
316 WrongKey,
317 DescriptorHasNoKeys,
318 String(Box<String>),
319}
320
321impl From<ll::Error> for Error {
322 fn from(value: ll::Error) -> Self {
323 Error::Ll(value)
324 }
325}
326
327#[cfg(test)]
328mod tests {
329 use miniscript::bitcoin;
330
331 use crate::descriptor::dpk_to_pk;
332
333 use super::*;
334
335 #[test]
336 fn test_simple_encrypted_descriptor() {
337 let descriptor = descriptor::tests::descr_1();
338 let backp = EncryptedBackup::new().set_payload(&descriptor).unwrap();
339 let keys = backp.get_keys();
340 let bytes = backp.encrypt().unwrap();
341 let restored = EncryptedBackup::new()
342 .set_encrypted_payload(&bytes)
343 .unwrap()
344 .set_keys(keys)
345 .decrypt()
346 .unwrap();
347 assert_eq!(restored, Decrypted::Descriptor(descriptor));
348 }
349
350 #[test]
351 fn test_encrypt_bytes() {
352 let payload = vec![0x00u8, 0x00, 0x00];
353 let mut backp = EncryptedBackup::new().set_payload(&payload).unwrap();
354 assert!(!backp.payload.is_none());
355
356 assert!(backp.get_keys().is_empty());
357 let pk1 = dpk_to_pk(&descriptor::tests::dpk_1());
358 backp = backp.set_keys(vec![pk1]);
359 let pks = backp.get_keys();
360 assert_eq!(pks.len(), 1);
361 assert_eq!(*pks.first().unwrap(), pk1);
362
363 assert!(backp.get_derivation_paths().is_empty());
364 let deriv = DerivationPath::from_str("0/0").unwrap();
365 backp = backp.set_derivation_paths(vec![deriv.clone()]);
366 assert_eq!(backp.get_derivation_paths(), vec![deriv]);
367
368 assert_eq!(backp.get_content(), Content::Unknown);
369 let fail = backp.clone().encrypt().unwrap_err();
370 assert_eq!(fail, Error::UnknownContent);
371 backp = backp.set_content_type(Content::None);
372 assert_eq!(backp.get_content(), Content::None);
373
374 assert_eq!(backp.get_encryption(), Encryption::AesGcm256);
375 backp = backp.set_encryption(Encryption::Undefined);
376 assert_eq!(backp.get_encryption(), Encryption::Undefined);
377 let fail = backp.clone().encrypt().unwrap_err();
378 assert_eq!(fail, Error::EncryptionUndefined);
379 backp = backp.set_encryption(Encryption::AesGcm256);
380 assert_eq!(backp.get_encryption(), Encryption::AesGcm256);
381
382 backp = backp.set_version(Version::Unknown);
383 let fail = backp.clone().encrypt().unwrap_err();
384 assert_eq!(fail, Error::InvalidVersion);
385 backp = backp.set_version(Version::V0);
386 assert_eq!(backp.get_version(), Version::V0);
387 backp = backp.set_version(Version::V1);
388 assert_eq!(backp.get_version(), Version::V1);
389
390 let bytes = backp.encrypt().unwrap();
391
392 let fail = EncryptedBackup::new()
393 .set_encrypted_payload(&bytes)
394 .unwrap()
395 .decrypt()
396 .unwrap_err();
397 assert_eq!(fail, Error::NoKey);
398
399 let w_key = bitcoin::secp256k1::PublicKey::from_slice(&[
400 4, 54, 57, 149, 239, 162, 148, 175, 246, 254, 239, 75, 154, 152, 10, 82, 234, 224, 85,
401 220, 40, 100, 57, 121, 30, 162, 94, 156, 135, 67, 74, 49, 179, 57, 236, 53, 162, 124,
402 149, 144, 168, 77, 74, 30, 72, 211, 229, 110, 111, 55, 96, 193, 86, 227, 183, 152, 195,
403 155, 51, 247, 123, 113, 60, 228, 188,
404 ])
405 .unwrap();
406 let fail = EncryptedBackup::new()
407 .set_encrypted_payload(&bytes)
408 .unwrap()
409 .set_keys(vec![w_key])
410 .decrypt()
411 .unwrap_err();
412 assert_eq!(fail, Error::WrongKey);
413
414 let restored = EncryptedBackup::new()
415 .set_encrypted_payload(&bytes)
416 .unwrap()
417 .set_keys(vec![pk1])
418 .decrypt()
419 .unwrap();
420 assert_eq!(restored, Decrypted::Raw(vec![0x00u8, 0x00, 0x00]));
421 }
422
423 pub fn dummy_encrypted_payload() -> Vec<u8> {
424 let key = dpk_to_pk(&descriptor::tests::dpk_1());
425 EncryptedBackup::new()
426 .set_payload(&vec![0x00])
427 .unwrap()
428 .set_keys(vec![key])
429 .set_content_type(Content::None)
430 .encrypt()
431 .unwrap()
432 }
433
434 #[test]
435 fn test_encrypt_wrong_payload() {
436 let fail = EncryptedBackup::new()
438 .set_content_type(Content::None)
439 .encrypt()
440 .unwrap_err();
441 assert_eq!(fail, Error::WrongPayload);
442
443 let dummy_payload = dummy_encrypted_payload();
444
445 let fail = EncryptedBackup::new()
447 .set_encrypted_payload(&dummy_payload)
448 .unwrap()
449 .set_content_type(Content::None)
450 .encrypt()
451 .unwrap_err();
452 assert_eq!(fail, Error::WrongPayload);
453 }
454
455 #[test]
456 fn test_decrypt_wrong_payload() {
457 let key = dpk_to_pk(&descriptor::tests::dpk_1());
458 let fail = EncryptedBackup::new()
460 .set_keys(vec![key])
461 .decrypt()
462 .unwrap_err();
463 assert_eq!(fail, Error::WrongPayload);
464
465 let fail = EncryptedBackup::new()
467 .set_keys(vec![key])
468 .set_payload(&vec![0x00])
469 .unwrap()
470 .decrypt()
471 .unwrap_err();
472 assert_eq!(fail, Error::WrongPayload);
473
474 let dummy = dummy_encrypted_payload();
475
476 let fail = EncryptedBackup::new()
478 .set_keys(vec![key])
479 .set_encrypted_payload(&dummy)
480 .unwrap()
481 .set_version(Version::Unknown)
482 .decrypt()
483 .unwrap_err();
484 assert_eq!(fail, Error::UnknownVersion);
485 }
486
487 #[test]
488 fn test_encryption_to_u8() {
489 let mut u: u8 = Encryption::AesGcm256.into();
490 assert_eq!(0x01, u);
491 u = Encryption::Undefined.into();
492 assert_eq!(0x00, u);
493 u = Encryption::Unknown.into();
494 assert_eq!(0xFF, u);
495 }
496
497 #[test]
498 fn test_u8_to_encryption() {
499 let mut e: Encryption = 0x00u8.into();
500 assert_eq!(e, Encryption::Undefined);
501 e = 0x01u8.into();
502 assert_eq!(e, Encryption::AesGcm256);
503
504 for i in 0x02..0xFFu8 {
505 e = i.into();
506 assert_eq!(e, Encryption::Unknown);
507 }
508 }
509
510 #[test]
511 fn test_version_to_u8() {
512 let mut u: u8 = Version::V0.into();
513 assert_eq!(0x00, u);
514 u = Version::V0.into();
515 assert_eq!(0x00, u);
516 u = Version::Unknown.into();
517 assert_eq!(0xFF, u);
518 }
519
520 #[test]
521 fn test_u8_to_version() {
522 let mut v: Version = 0x00u8.into();
523 assert_eq!(v, Version::V0);
524 v = 0x01u8.into();
525 assert_eq!(v, Version::V1);
526
527 for i in 0x02..0xFFu8 {
528 v = i.into();
529 assert_eq!(v, Version::Unknown);
530 }
531 }
532}