Skip to content

Encrypted descriptor#1846

Merged
edouardparis merged 13 commits intowizardsardine:masterfrom
pythcoiner:encrypted_descriptor
Sep 18, 2025
Merged

Encrypted descriptor#1846
edouardparis merged 13 commits intowizardsardine:masterfrom
pythcoiner:encrypted_descriptor

Conversation

@pythcoiner
Copy link
Copy Markdown
Collaborator

@pythcoiner pythcoiner commented Sep 8, 2025

This is a lightweight version of #1807, where we do not encrypt for a backup export.
(I just dropped the commit that enable encryption on backup export)

@jp1ac4
Copy link
Copy Markdown
Collaborator

jp1ac4 commented Sep 9, 2025

Should the encrypted descriptor option be listed here?

image

@nondiremanuel
Copy link
Copy Markdown
Collaborator

Should the encrypted descriptor option be listed here?
image

I inserted it only in the "Wallet" section of the settings to distinguish between the concept of backup and import/exports material. So my idea is that it shouldn't be added here, but open to discuss. At the same time we have the plain text descriptor file among the exports, which seems to contradict this concept, but I don't think it should be in the wallet section since we should incentivize to use the encrypted version.

@pythcoiner
Copy link
Copy Markdown
Collaborator Author

I inserted it only in the "Wallet" section of the settings to distinguish between the concept of backup and import/exports material. So my idea is that it shouldn't be added here, but open to discuss. At the same time we have the plain text descriptor file among the exports, which seems to contradict this concept, but I don't think it should be in the wallet section since we should incentivize to use the encrypted version.

the plaintext descriptor option must be kept for register descriptor on airgap devices

Copy link
Copy Markdown
Collaborator

@jp1ac4 jp1ac4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've successfully tested importing an encrypted backup using a signing device, a manually pasted xpub and the corresponding mnemonic.

modal: None,
}
}
pub fn update(&mut self, msg: Decrypt) -> Task<installer::Message> {
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be useful to return something more general that doesn't depend on installer here?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

for now only uses cases are with installer::Message, if needed we can later make it more generic

pub const BACKUP_DESCRIPTOR_MESSAGE: &str = "A backup of your wallet configuration is necessary to recover your funds. Please make sure to store your Wallet backup file (or alternatively to copy and paste the descriptor string) in one or more secure and accessible locations. You still need to back up your seed phrases too, since they are not included in the file.";
pub const BACKUP_DESCRIPTOR_HELP: &str = "In Bitcoin, the coins are locked using a Script (related to the 'address'). In order to recover your funds you need to know both the Scripts you have participated in (your 'addresses'), and be able to sign a transaction that spends from those. For the ability to sign, you back up your private key, this is your mnemonic ('seed words'). For finding the coins that belong to you, you back up a template of your Script (your 'addresses'), this is your descriptor, included in your wallet backup file. However, note the descriptor need not be stored as securely as the private key. A thief who steals your descriptor but not your private key cannot steal your funds.";
pub const BACKUP_DESCRIPTOR_MESSAGE: &str = "This backup is required to recover your funds.
Click “Back Up Descriptor” to download an encrypted file of your wallet configuration and store it in safe, accessible places.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should this be changed to "encrypted file of your wallet descriptor"?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@pythcoiner pythcoiner force-pushed the encrypted_descriptor branch 6 times, most recently from 6c49810 to af661b5 Compare September 12, 2025 14:20
@pythcoiner
Copy link
Copy Markdown
Collaborator Author

bump encrypted_backup to last changes & rebased

@pythcoiner pythcoiner force-pushed the encrypted_descriptor branch 2 times, most recently from 44bee47 to 8ca0b13 Compare September 16, 2025 12:19
@pythcoiner
Copy link
Copy Markdown
Collaborator Author

added sanity checks before write encrypted descriptor to disk

if let DescriptorPublicKey::MultiXPub(multixkey) = k {
let key = DescriptorPublicKey::XPub(DescriptorXKey {
origin: multixkey.origin.clone(),
xkey: multixkey.xkey,
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than adding dummy values, which could misleadingly suggest these are the values present in the descriptor itself, wouldn't it be clearer to return the multikey.xkey and then let the caller add these dummy values as required?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

those are not dummies values, It's just about having a DescriptorPublicKey that contains Xpub + Origin, Xpub is not enough as it does not contains the origin and I expect we use the result of this function to list xpubs of the Bip388 Policy

this way I think we can directly call .to_string()

  • DescriptorPublicKey::Single is not suitable as it will not output a xpub
  • DescriptorPublicKey::MultiXpub is not suitable as DerivPaths cannot be empty

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I am fine with it, maybe add a comment to say that is a vessel for the xkey.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

well it's not a vessel, it's litteraly how it's intended to be used:

this

let key_str = "[abcdef01/0/0/0]xpub6Eze7yAT3Y1wGrnzedCNVYDXUqa9NmHVWck5emBaTbXtURbe1NWZbK9bsz1TiVE7Cz341PMTfYgFw1KdLWdzcM1UMFTcdQfCYhhXZ2HJvTW";
let key = DescriptorPublicKey::from_str(key_str).unwrap();

will yield

XPub(
    DescriptorXKey {
        origin: Some(
            (
                0xabcdef01,
                0/0/0,
            ),
        ),
        xkey: Xpub {
            network: Main,
            depth: 4,
            parent_fingerprint: 0xc6c45ae6,
            child_number: Normal {
                index: 0,
            },
            public_key: PublicKey(
                4fcda97320d37e42ddd2c9adf5c5c5edf7ff9decb550c50ad2ace5ae3a16abb3b780ec63e8766dbaa3e323148cc0e6ee760e3a41b5a0b1229f5d69b59ce3a0a3,
            ),
            chain_code: 0xf98f1f14305e50df1ff23883210e9020e212bc62a790eff034e9f5036af844a1,
        },
        derivation_path: ,
        wildcard: None,
    },
)

I'm fine to add a comment, but from my POV make it more confusing

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry I understand better now. I think a name like definite_keys_without_deriv_path() would make it clearer what is being returned (rust-miniscript uses DefiniteDescriptorKey for a DescriptorPublicKey without wildcard).

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, since we require an origin for all user-provided keys when creating a LianaDescriptor (as enforced in the constructors), an alternative check would be to exclude any descriptor keys that don't have an origin. Or simply to return all keys and let the caller check if it has an origin.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

an alternative check would be to exclude any descriptor keys that don't have an origin

in which other case than the unspendable key we can have a key w/o origin?

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(rust-miniscript uses DefiniteDescriptorKey for a DescriptorPublicKey without wildcard)

No in our case it's not a DefiniteDescriptorKey, my understanding of "definite" in rust-miniscript context is that the key is not deriveable anymore, while the key we generating here is the "root" key for derivation

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

in which other case than the unspendable key we can have a key w/o origin?

I meant it would be an equivalent check, since we expect a key not to have an origin if and only if it's unspendable, but I suppose it's more reliable to check for the NUMS directly.

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but I suppose it's more reliable to check for the NUMS directly.

yes especially if in the future we allow importing key w/o origin (watchonly?)

@pythcoiner pythcoiner force-pushed the encrypted_descriptor branch 5 times, most recently from b733b01 to 3f005eb Compare September 17, 2025 11:58
Copy link
Copy Markdown
Collaborator

@jp1ac4 jp1ac4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

tACK b278ef2.

Copy link
Copy Markdown
Collaborator

@jp1ac4 jp1ac4 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ACK bbe75f7.

@edouardparis edouardparis merged commit 1932ada into wizardsardine:master Sep 18, 2025
13 checks passed
@nondiremanuel nondiremanuel moved this from In Review to Done in Liana General Sep 23, 2025
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

4 participants