Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Helpers for constructing standard HD wallet descriptors #513

Open
casey opened this issue Jan 4, 2023 · 2 comments
Open

Helpers for constructing standard HD wallet descriptors #513

casey opened this issue Jan 4, 2023 · 2 comments

Comments

@casey
Copy link

casey commented Jan 4, 2023

Constructing standard HD wallet descriptors takes a fair bit of code. For example, to construct a BIP-86 single-key taproot HD wallet descriptor:

let master_xkey = ExtendedPrivKey::new_master(network, &seed)?;

let fingerprint = master_xkey.fingerprint(&secp);

let derivation_path = DerivationPath::master()
  .child(ChildNumber::Hardened { index: 86 })
  .child(ChildNumber::Hardened { index: 0 })
  .child(ChildNumber::Hardened { index: 0 });

let derived_xkey = master_xkey.derive_priv(&secp, &derivation_path)?;

let secret_key = DescriptorSecretKey::XPrv(DescriptorXKey {
  origin: Some((fingerprint, derivation_path.clone())),
  xkey: derived_xkey,
  derivation_path: DerivationPath::master().child(ChildNumber::Normal { index: 0 }),
  wildcard: Wildcard::Unhardened,
});

let public_key = secret_key.to_public(&secp)?;

let mut key_map = std::collections::HashMap::new();
key_map.insert(public_key.clone(), secret_key);

let receive_desc = Descriptor::new_tr(public_key, None)?;

It could be nice to provide helpers that would create standard HD wallet descriptors from seeds, in this case something like:

impl Descriptor {
  fn new_bip_86(secp: &Secp256k1, network: Network, seed: [u8; 32], change: bool) -> Result<(Self, DescriptorSecretKey)> {
    let master_xkey = ExtendedPrivKey::new_master(network, &seed)?;

    let fingerprint = master_xkey.fingerprint(&secp);

    let derivation_path = DerivationPath::master()
      .child(ChildNumber::Hardened { index: 86 })
      .child(ChildNumber::Hardened { index: 0 })
      .child(ChildNumber::Hardened { index: 0 });

    let derived_xkey = master_xkey.derive_priv(&secp, &derivation_path)?;

    let secret_key = DescriptorSecretKey::XPrv(DescriptorXKey {
      origin: Some((fingerprint, derivation_path.clone())),
      xkey: derived_xkey,
      derivation_path: DerivationPath::master().child(ChildNumber::Normal { index: 0 }),
      wildcard: Wildcard::Unhardened,
    });

    let public_key = secret_key.to_public(&secp)?;

    (Descriptor::new_tr(public_key, None), secret_key)
  }
}
@apoelstra
Copy link
Member

concept ACK. I'm not sure how we ought to organize this, since probably we want to support BIP 48, 84, 86, etc. (I'm not sure if I'm remembering all the numbers right :)), as well as generic BIP-49.

I'm not really thrilled with any of these BIPs, exactly because they're supposed to be supplanted by descriptors, where you don't need a "standard" as long as you've written out the descriptor. And because the BIP86-style standards don't scale well, as evidenced by the large number of them. (One could make the argument that descriptors suffer from the same problem :) but descriptors are much more general.) So I don't want to make them a first-class thing, but I definitely agree that we should support them.

Maybe have a standard or bips module and put everything in there?

@casey
Copy link
Author

casey commented Jan 6, 2023

Maybe standard would be a good name, in case there are ever standard derivation paths that aren't documented in BIPs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants