buidl-bitcoin / buidl-python

python3 bitcoin library with no dependencies and extensive test coverage
https://pypi.org/project/buidl/
MIT License
83 stars 26 forks source link

Bug: Not possible to spend a MuSig Address without TapTree #155

Open wip-abramson opened 11 months ago

wip-abramson commented 11 months ago

I have been attempting to construct bitcoin address that is a 2-2 MuSig address only. No taproot tree.

Something like this

points = [alice_public_key, bob_public_key]
musig = MuSigTapScript(points)
internal_pubkey = musig.point
// The address for the ScriptPubKey
p2tr_musig = internal_pubkey.p2tr_address(network="signet")

The p2tr_musig address is always tweaked. see cecc.py L200

I think this is correct per BIP86.

But, when I construct MuSig using the get_signature function. If there is no merkle_root, then no tweak is applied.

So I get back a valid signature from the untweaked public key. However, when I try to verify I transaction with an input that has a p2tr_musig value as ScriptPubKey it verifies as false. Because the pubkey used for the ScriptPubKey is tweaked, but the sig has not been.

Basically

// Returns valid, but untweaked schnorr sig
schnorr = musig.get_signature(s_sum, r, sig_hash)
// Adds sig to tx input witness
tx_in.finalize_p2tr_keypath(schnorr.serialize())
// Is false
btc_update_tx.verify_input(input_index)

I believe a simple fix would be to remove the if/else in the get_signature function so that the tweak is always applied.

Happy to submit a P.R if I am on the right lines

jimmysong commented 10 months ago

Hey Will, I'm looking at the BIP327 spec and realizing that it's different than what I've implemented (over a year ago). Thus, I would hold off until the updates to the library for making it BIP327 compliant are done. Sorry for the hassle!

wip-abramson commented 10 months ago

Sure, no worries.

What are the differences out of interest?

jimmysong commented 10 months ago

Very specific ways to generate the nonce, ways to add more than one tweak and so on. I've got all the tests passing, it's just a matter of getting it ready as a PR.

wip-abramson commented 3 weeks ago

Any updates on this issue.

It seems per BIP341 all taproot addresses should include a tweak, and in the case where a TapScript is not required this the tweak should commit to an unspendable TapScript. I had a look in the code, but couldn't find it in there.

If the spending conditions do not require a script path, the output key should commit to an unspendable script path instead of having no script path. This can be achieved by computing the output key point as Q = P + int(hashTapTweak(bytes(P)))G. [23] https://github.com/bitcoin/bips/blob/master/bip-0341.mediawiki