| Crates.io | descriptor-encrypt |
| lib.rs | descriptor-encrypt |
| version | 0.1.2 |
| created_at | 2025-05-22 23:28:40.318867+00 |
| updated_at | 2025-06-09 23:18:59.599463+00 |
| description | Encrypt Bitcoin wallet descriptors such that only authorized spenders can decrypt |
| homepage | https://github.com/joshdoman/descriptor-encrypt |
| repository | https://github.com/joshdoman/descriptor-encrypt |
| max_upload_size | |
| id | 1685711 |
| size | 262,142 |
A rust library and CLI tool that efficiently encrypts a Bitcoin wallet descriptor such that it can only be recovered by a set of keys that can spend the funds.
Bitcoin wallet descriptors encode the spending conditions for Bitcoin outputs, including keys, scripts, and other requirements. While descriptors are powerful tools for representing wallet structures, securely backing them up presents a challenge, especially for multi-signature and complex script setups.
This library encrypts any Bitcoin wallet descriptor in a way that directly mirrors the descriptor's spending conditions:
The encryption mechanism works through several key innovations:
use std::str::FromStr;
use descriptor_encrypt::{encrypt, decrypt, get_template, get_origin_derivation_paths};
use miniscript::descriptor::{Descriptor, DescriptorPublicKey};
// Create a descriptor - a 2-of-3 multisig in this example
let desc_str = "wsh(multi(2,\
03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7,\
036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00,\
02e8445082a72f29b75ca48748a914df60622a609cacfce8ed0e35804560741d29\
))";
let descriptor = Descriptor::<DescriptorPublicKey>::from_str(desc_str).unwrap();
// Encrypt the descriptor
let encrypted_data = encrypt(descriptor.clone()).unwrap();
// Encrypt the descriptor with full secrecy (best for privacy but slower when decrypting large descriptors)
let encrypted_data_with_full_secrecy = encrypt(descriptor.clone()).unwrap();
// Get a template descriptor with dummy keys, hashes, and timelocks
let template = get_template(&encrypted_data).unwrap();
// Extract only the derivation paths (useful for deriving xpubs)
let paths = get_origin_derivation_paths(&encrypted_data).unwrap();
// Later, decrypt with the keys (in this example, only the first two keys are provided,
// which is sufficient for a 2-of-3 multisig)
let pk0 = DescriptorPublicKey::from_str("03a0434d9e47f3c86235477c7b1ae6ae5d3442d49b1943c2b752a68e2a47e247c7").unwrap();
let pk1 = DescriptorPublicKey::from_str("036d2b085e9e382ed10b69fc311a03f8641ccfff21574de0927513a49d9a688a00").unwrap();
let first_two_keys = vec![pk0, pk1];
// Recover the original descriptor
let recovered_descriptor = decrypt(&encrypted_data, first_two_keys).unwrap();
assert_eq!(descriptor.to_string(), recovered_descriptor.to_string());
The library supports all standard Bitcoin descriptor types:
pkh, wpkh, tr with internal key)sh(multi), wsh(multi), sh(wsh(multi)), etc.)tr with script trees)This library ensures:
The security of the system relies on the security of ChaCha20(Poly1305) for encryption and Shamir Secret Sharing for threshold access control.
To build the project, use the following command:
cargo build --release
The executable will be located at target/release/descriptor-encrypt.
descriptor-encrypt is a command-line tool for encrypting and decrypting Bitcoin descriptors.
Encrypts a Bitcoin descriptor and outputs the result as hex.
./target/release/descriptor-encrypt encrypt <DESCRIPTOR_STRING>
Arguments:
<DESCRIPTOR_STRING>: The Bitcoin descriptor string to encrypt.Options:
-w, --with-full-secrecy: Enables full secrecy mode, which leaks no information about key inclusion without full decryption.Decrypts hex-encoded encrypted descriptor data using a set of public keys.
./target/release/descriptor-encrypt decrypt <DATA> -p <PKS>
Arguments:
<DATA>: hex-encoded encrypted data.-p, --pks <PKS>: Comma-separated list of public keys and xpubs (e.g., "pk1,pk2,pk3"). At least one public key must be provided.Retrieves a template descriptor (with dummy keys, hashes, and timelocks) from hex-encoded encrypted data.
./target/release/descriptor-encrypt get-template <DATA>
Arguments:
<DATA>: hex-encoded encrypted data.Retrieves the origin derivation paths from hex-encoded encrypted data.
./target/release/descriptor-encrypt get-derivation-paths <DATA>
Arguments:
<DATA>: hex-encoded encrypted data.The core logic of descriptor-encrypt can also be used as a library in other Rust projects.
encrypt(desc: Descriptor<DescriptorPublicKey>) -> Result<Vec<u8>>
encrypt_with_full_secrecy(desc: Descriptor<DescriptorPublicKey>) -> Result<Vec<u8>>
encrypt except it leaks no information about key inclusion without full decryption.decrypt(data: &[u8], pks: Vec<DescriptorPublicKey>) -> Result<Descriptor<DescriptorPublicKey>>
get_template(data: &[u8]) -> Result<Descriptor<DescriptorPublicKey>>
get_origin_derivation_paths(data: &[u8]) -> Result<Vec<DerivationPath>>
This project is licensed under the CC0-1.0 License.
Joshua Doman joshsdoman@gmail.com