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

Upstream bdk sighash calculation code #946

Closed

Conversation

tcharding
Copy link
Member

bitcoindevkit's bdk has some code in it for computing the sighash of PSBT inputs during signing (and some nice signing code too). I first came across this code a few years back and wondered why it was not upstream. This last week @DanGould and myself have been working on some PSBT examples/tests and for them I shamelessly stole the code out of bdk for signing.

This PR is an exploration to see if we want this code in rust-bitcoin. I'm no where near fully understanding what goes where in PSBTs, or sighashes even, so this will need a fair bit of review.

I have added a TODO to add attribution and/or the bdk license, not sure if this is enough code to warrant that. @RCasatta can you speak for bdk on this matter?

So far this is just the sighash code, I rekon we could use the PSBT signing code as well possibly but I'll wait to see how this is received.

Thanks

In order to sign a utxo that does a p2wpkh spend we need to create the
script that can be used to create a sighash. In the libbitcoin docs this
is referred to as the 'script code' [0].

The script is the same as a p2pkh script but the pubkey_hash is found in
the scriptPubkey.

Add a `Script` conversion method that checks if `self` is a v0 p2wpkh
script and if so extracts the pubkey_hash and returns the required
script.

[0] https://github.com/libbitcoin/libbitcoin-system/wiki/P2WPKH-Transactions#spending-a-p2wpkh-output
Add methods to get the sighash from a PSBT prior to signing, one for
legacy inputs and one for segwit v0 inputs.

This code is copied directly from bdk, attribution and licensing needs
seeing to.
@RCasatta
Copy link
Collaborator

RCasatta commented Apr 7, 2022

Maybe some/all of this code belong to rust-miniscript? @apoelstra ?

If it's ok here I think an attribution naming bdk is due, I think naming the whole project instead of individual author is fine. @afilini do you agree?

@tcharding
Copy link
Member Author

You definitely deserve attribution, this code is non-trivial to work out! Would you guys like your license on the file too? bdk uses Apache and rust-bicoin uses CC0?

Copy link
Member

@sanket1729 sanket1729 left a comment

Choose a reason for hiding this comment

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

Left a few comments. Please refer to the comment in the second commit before putting in additional effort into sighash message API.

@@ -427,6 +427,23 @@ impl Script {
Script::new_p2sh(&self.script_hash())
}

/// Returns the script code used for spending a P2WPKH output if this script is a script pubkey
/// for a P2WPKH output.
pub fn p2wpkh_script_code(&self) -> Option<Script> {
Copy link
Member

Choose a reason for hiding this comment

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

Yes, please. I had to do this downstream in an ugly way

// Get a script from witness script pubkey hash
fn script_code_wpkh(script: &Script) -> Script {
    assert!(script.is_v0_p2wpkh());
    // ugly segwit stuff https://github.com/bitcoin/bips/blob/master/bip-0143.mediawiki#specification
    let mut script_code = vec![0x76u8, 0xa9, 0x14];
    script_code.extend(&script.as_bytes()[2..]);
    script_code.push(0x88);
    script_code.push(0xac);
    Script::from(script_code)
}

Copy link
Member Author

Choose a reason for hiding this comment

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

Moved to a separate PR since its a discreet change: #954

@@ -427,6 +427,23 @@ impl Script {
Script::new_p2sh(&self.script_hash())
}

/// Returns the script code used for spending a P2WPKH output if this script is a script pubkey
/// for a P2WPKH output.
pub fn p2wpkh_script_code(&self) -> Option<Script> {
Copy link
Member

Choose a reason for hiding this comment

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

This should also link to BIP143.

Copy link
Member Author

@tcharding tcharding Apr 18, 2022

Choose a reason for hiding this comment

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

Added link in #954 as suggested.

@@ -183,6 +185,103 @@ impl PartiallySignedTransaction {

Ok(())
}

// TODO: Work out attribution/license stuff, copied from `impl ComputeSighash for Legacy` in `bdk`.
Copy link
Member

Choose a reason for hiding this comment

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

I think we can ask bdk for relicensing stuff here. They are super-friendly people and (I think) they would not mind doing it. But we should have attribution here.

Copy link
Member Author

Choose a reason for hiding this comment

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

I've raised an issue on bdk repo to get input: bitcoindevkit/bdk#586

// TODO: Work out attribution/license stuff, copied from `impl ComputeSighash for Legacy` in `bdk`.
/// Returns the sighash (and type) for input at `input_index`, caller is
/// responsible for ensuring `input_index` is a legacy input.
pub fn legacy_sighash(&self, input_index: usize) -> Result<(Sighash, EcdsaSighashType), Error> {
Copy link
Member

Choose a reason for hiding this comment

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

I think we can actually do better :) . See https://docs.rs/miniscript/7.0.0-rc.2/miniscript/psbt/trait.PsbtExt.html#tymethod.sighash_msg . This figures out what the type of spent input is and applies the corresponding signature hash algorithm.

I was planning to upstream this but forgot about it.

@sanket1729
Copy link
Member

Please also see the discussion rust-bitcoin/rust-miniscript#305 (comment) and the following comments. I think we should have signer support like @JeremyRubin suggested there. I did not review deeply his suggestion, but I do think we need some form of API to allow the signers to sign the psbt and insert the signature.

/// Note that this should handle all types of spends (legacy, segwitv0, taproot) and both types of signature algorithms(schnorr/ecdsa)
pub fn sign_psbt(&mut self, sk: bitcoin::PrivateKey);

@tcharding
Copy link
Member Author

Thanks for the links @sanket1729, I'm not watching rust-miniscript development (yet :) so I appreciate this info. I raised the bdk issue before reading all the links. Going forward I think I will attempt to better grok the PSBT workflow and how a user would typically best use rust-bitcoin and rust-miniscript and then:

  • Update the new psbt example PR with some docs pointing users to rust-miniscript.
  • Use bdk code and rust-miniscript code to put together some complete sighash functionality (incl. taproot) that fits here in rust-bitcoin

@LLFourn
Copy link

LLFourn commented Apr 19, 2022

+1 for having sighash computation code for PSBTs in rust-bitcoin. This already exists in rust-miniscript though. Have you seen this: https://docs.rs/miniscript/7.0.0-rc.2/miniscript/psbt/trait.PsbtExt.html#tymethod.sighash_msg

Any reason this couldn't be plucked from rust-miniscript into rust-bitcoin @sanket1729?

[EDIT] NVM it can be: #946 (comment)

Note for signing in case I forget: we also made an xkey signer which does on the fly derivation from the master and then signs in gun: https://github.com/GoUpNumber/gun/blob/f71a9a84ed4cf49a0f8534c27595191f4eb8b03b/src/signers.rs#L28

(this can be copied without attribution).

@tcharding
Copy link
Member Author

Cheers @LLFourn, I'm on it.

@tcharding tcharding closed this Apr 19, 2022
@sanket1729
Copy link
Member

(this can be copied without attribution).

I think we should attribute it in a comment. But I don't think we should be copying around license files everywhere.

@LLFourn
Copy link

LLFourn commented Apr 19, 2022

(this can be copied without attribution).

I think we should attribute it in a comment. But I don't think we should be copying around license files everywhere.

Feel free to praise me for my fabulous code. just pointing out the BSD0 LICENSE doesn't require attribution.

@tcharding tcharding deleted the upstream-bdk-signing-code branch April 20, 2022 00:34
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

Successfully merging this pull request may close these issues.

None yet

4 participants