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