-
Notifications
You must be signed in to change notification settings - Fork 65
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
extended bdk-cli key derive to output xprv #25
Conversation
Sorry, this is wrong. Please ignore. Will push an update. |
src/lib.rs
Outdated
@@ -894,7 +894,7 @@ pub fn handle_key_subcommand( | |||
|
|||
if let Secret(secret_key, _, _) = xprv_desc_key { | |||
let desc_pubkey = secret_key.as_public(&secp).unwrap(); | |||
Ok(json!({"xpub": desc_pubkey.to_string()})) | |||
Ok(json!({"xpub": desc_pubkey.to_string(), "xprv": secret_key.to_string()})) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
secret_key.to_string()
here gives the parent xprv provided.
I was able to calculate the child xprv using the following
let _child = xprv.derive_priv(&secp, &deriv_path).unwrap();
However, this does not contain the path for the descriptor and requires some additional sting concatenation. Is there a better way of going about doing this?
I looked into the DescriptorKey and DescriptorSecretKey Enums, was unable to find a way.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think what we need to do is below. It doesn't split the derivation path into hardended/unhardened parts but I think this is probably better behavior since it gives the user more control. The test_key_derive
test will also need to be updated with this change.
let deriv_path: DerivationPath = DerivationPath::from_str(path.as_str())?;
let derived_xprv = &xprv.derive_priv(&secp, &deriv_path)?;
let origin:KeySource = (xprv.fingerprint(&secp), deriv_path);
let derived_xprv_desc_key: DescriptorKey<Segwitv0> =
derived_xprv.into_descriptor_key(Some(origin), DerivationPath::default())?;
if let Secret(desc_seckey, _, _) = derived_xprv_desc_key {
let desc_pubkey = desc_seckey.as_public(&secp).unwrap();
Ok(json!({"xpub": desc_pubkey.to_string(), "xprv": desc_seckey.to_string()}))
} else {
Err(Error::Key(Message("Invalid key variant".to_string())))
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
yeah, that looks more clear with the child xprv being explicitly derived at the path.
As you said, the derivation path isnt being separated now, so the the resulting outputs now show the entire path within the prefix [ ] as below:
|
Ya I'm not sure if this is a bug or a feature. Is this OK for your use case? Here's a way to fix it (borrowed some code from rust-miniscript) , may be what most users would expect: let deriv_path = DerivationPath::from_str(path.as_str())?;
let deriv_path_len = (&deriv_path).as_ref().len();
let normal_suffix_len = (&deriv_path)
.into_iter()
.rev()
.take_while(|c| c.is_normal())
.count();
let deriv_path_hardened = DerivationPath::from(&deriv_path[..(deriv_path_len - normal_suffix_len)]);
let deriv_path_normal = DerivationPath::from(&deriv_path[(deriv_path_len - normal_suffix_len)..]);
let derived_xprv = &xprv.derive_priv(&secp, &deriv_path_hardened)?;
let origin:KeySource = (xprv.fingerprint(&secp), deriv_path_hardened);
let derived_xprv_desc_key: DescriptorKey<Segwitv0> =
derived_xprv.into_descriptor_key(Some(origin), deriv_path_normal)?;
if let Secret(desc_seckey, _, _) = derived_xprv_desc_key {
let desc_pubkey = desc_seckey.as_public(&secp).unwrap();
Ok(json!({"xpub": desc_pubkey.to_string(), "xprv": desc_seckey.to_string()}))
} else {
Err(Error::Key(Message("Invalid key variant".to_string())))
} |
One final thing, when you're all done be sure to run |
I think it should be fine for now. I tried running the code you shared and changed the tests but they are failing. I'll spend a little more time with it and get back. Might be better to display it the most commonly expected format. |
I think it is better to split the path and then the original test should pass without any changes except to also verify the xprv. |
@vmenond can you also setup gpg signing for your commits? It's not a big deal but it is best practice and good thing to have for other projects you're working on. Github provides good instructions for signing commits. And there's also a blog post on how to retroactively sign git commits. I'm happy to help if you run into any problems. |
@notmandatory surely! I will get on this next session and push a final commit with a signature. been a bit caught up with work, hence the delayed responses. |
GOT IT! Small typo. let derived_xprv = &xprv.derive_priv(&secp, &deriv_path_hardened)?; TO let derived_xprv = &xprv.derive_priv(&secp, &deriv_path)?; All tests passing. Also double checked at https://bip32jp.github.io/english/ |
30f5320
to
ef63021
Compare
Sorry about the messy commit history. Had a few issues getting a valid signature. Commit 078b75d should be all good now. |
I'm trying to understand the workflow for this. Does the user provide the path as a new argument? Could you post an example of the use of the command? Cheers! Edit: Oh wait. I might have misunderstood the PR. Is this only about the format of the returned json-ish object printed by |
the command used to originally only output the child xpub. If you run
Which also needs an update For the given input:
Old output:
This part of the PR was discussed over Discord. Then, after making the change to output the xprv as well, this thread started with the first post - unable to get the child key pair to output in the same descriptor format. New output:
|
Oh nice! The new Great stuff. 🔥 |
Hi thanks for getting everything signed! I'm traveling but will be able to re-review when I'm back in a few days. |
I took a look and would like to discuss pro/con of not splitting the hardened/non-hardened path. Looks like you went with just deriving from the whole path including any non-hardened parts at the end. But I think most users would expect to just derive up to the last hardened part of the path with the unhardened part of the path added after the derived key part. This way also the test remains the same for the xpub with the addition of an assert for the xprv. I have a code suggestion #25 (comment) for how to do it. Also I'd like to help you do an interactive rebase to cleanup your commit history. We can chat on Discord about how to do it if you like. |
@notmandatory Made changes based on your suggestions. Should be good to go now. |
Output:
I've been using the same format for xprv as xpub [fingerprint/hardened/path]xprv/*, not sure how to get the xprv in that format - or if it is required.