# descriptor-encrypt
## Overview
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.
## Features
`descriptor-encrypt` provides a robust mechanism for encrypting Bitcoin wallet descriptors with a security model that maps directly to the spending conditions of the descriptor itself. Here's what it does in detail:
### Threshold-Based Security Model
- **Threshold Authentication**: The descriptor's access control policy (e.g., m-of-n multisig) automatically determines the decryption threshold
- **Policy Mirroring**: Encryption security policy directly mirrors the descriptor's spending policy - if a wallet requires 2-of-3 keys to spend, it will also require 2-of-3 keys to decrypt
### Cryptographic Implementation
- **Deterministic Key Derivation**: Master encryption keys are derived deterministically from the descriptor's structure and content
- **Shamir Secret Sharing**: Implements recursive Shamir's Secret Sharing to split the master encryption key according to the descriptor's threshold requirements
- **Public Key-Based Access Control**: Each share is encrypted with the corresponding public key from the descriptor
- **ChaCha20-Poly1305 Encryption**: Uses modern, efficient encryption for both the payload (ChaCha20) and the key shares (ChaCha20Poly1305)
### Complex Descriptor Support
- **Full Descriptor Coverage**: Supports all Bitcoin descriptor types including:
- Single-sig (wpkh, pkh)
- Multi-sig (sorted, unsorted)
- Complex scripts (Miniscript expressions)
- Taproot descriptors with internal keys and script paths
- **Nested Threshold Handling**: Properly handles nested threshold conditions (e.g., an OR with AND conditions inside it)
- **Time and Hash Lock Support**: Maintains time locks and hash locks in the template while encrypting the specific values
### Template and Path Extraction
- **Origin Path Extraction**: Can extract derivation paths from encrypted descriptors without full decryption
- **Template Generation**: Can reveal the structure of an encrypted descriptor (with dummy values) without revealing the actual keys
### Compact Encoding
- **Tag-Based Encoding**: Uses tag-based encoding to minimize the size of the descriptor template
- **Variable-Length Encoding**: Uses LEB128 variable-length integers to minimize the size of the encrypted data
This ensures that a descriptor can only be decrypted by the same keys needed to spend from it, creating a direct correspondence between fund access and descriptor recovery.
## Installation
To build the project, use the following command:
```bash
cargo build --release
```
The executable will be located at `target/release/descriptor-encrypt`.
## CLI Usage
`descriptor-encrypt` is a command-line tool for encrypting and decrypting Bitcoin descriptors.
### Commands
* #### Encrypt a Descriptor
Encrypts a Bitcoin descriptor and outputs the result as hex.
```bash
./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.
* #### Decrypt a Descriptor
Decrypts hex-encoded encrypted descriptor data using a set of public keys.
```bash
./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.
* #### Get Template Descriptor
Retrieves a template descriptor (with dummy keys, hashes, and timelocks) from hex-encoded encrypted data.
```bash
./target/release/descriptor-encrypt get-template <DATA>
```
**Arguments**:
* `<DATA>`: hex-encoded encrypted data.
* #### Get Origin Derivation Paths
Retrieves the origin derivation paths from hex-encoded encrypted data.
```bash
./target/release/descriptor-encrypt get-derivation-paths <DATA>
```
**Arguments**:
* `<DATA>`: hex-encoded encrypted data.
## Library Usage
The core logic of `descriptor-encrypt` can also be used as a library in other Rust projects.
### Key Functions
**`encrypt(desc: Descriptor<DescriptorPublicKey>) -> Result<Vec<u8>>`**
* Encrypts a descriptor such that it can only be recovered by a set of keys with access to the funds.
**`encrypt_with_full_secrecy(desc: Descriptor<DescriptorPublicKey>) -> Result<Vec<u8>>`**
* Identical to `encrypt` except it leaks no information about key inclusion without full decryption.
* Provides maximum privacy but slower to decrypt, as we must try all possible combinations of shares and keys. This has a running time of $O((N+1)^K)$, where $N$ is the number of provided keys and $K$ is the number of shares.
**`decrypt(data: &[u8], pks: Vec<DescriptorPublicKey>) -> Result<Descriptor<DescriptorPublicKey>>`**
* Decrypts an encrypted descriptor using a set of public keys with access to the funds.
**`get_template(data: &[u8]) -> Result<Descriptor<DescriptorPublicKey>>`**
* Returns a template descriptor with dummy keys, hashes, and timelocks from the encrypted data.
**`get_origin_derivation_paths(data: &[u8]) -> Result<Vec<DerivationPath>>`**
* Returns the origin derivation paths found in the encrypted descriptor.
## Demo
<div align="center">
<a href="https://www.youtube.com/watch?v=ankTi65Y-EA" target="_blank">
<img src="https://img.youtube.com/vi/ankTi65Y-EA/maxresdefault.jpg" alt="descriptor-encrypt Demo" style="max-width: 100%; box-shadow: 0 0 10px rgba(0,0,0,0.4); border-radius: 5px;">
</a>
</div>
## License
This project is licensed under the CC0-1.0 License.
## Author
Joshua Doman <joshsdoman@gmail.com>