Skip to content

Conversation

@brandonblack
Copy link
Contributor

These clarifications would each have prevented an error in our initial implementation of these BIPs.

*** ''sha_prevouts'' (32): the SHA256 of the serialization of all input outpoints.
*** ''sha_amounts'' (32): the SHA256 of the serialization of all spent output amounts.
*** ''sha_scriptpubkeys'' (32): the SHA256 of the serialization of all spent output ''scriptPubKey''s.
*** ''sha_scriptpubkeys'' (32): the SHA256 of the serialization of all spent output ''(compact_size(size of scriptPubKey) || scriptPubKey)''s.

Choose a reason for hiding this comment

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

sha_scriptpubkeys is the hash of the serializations of all spent scriptPubKeys. The serialization of a scriptPubKey is already (compact_size(size of scriptPubKey) || scriptPubKey). I know it may not be super clear but I don't think we should modify it. If it is necessary we should rather put a note somewhere to remember what the serialization of a scriptPubKey

Copy link
Contributor Author

Choose a reason for hiding this comment

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

True, I'll adjust the wording to be correct. The reason this part was confusing as written is that later in the description of SigMsg the annex is specifically called out as having its compact_size prepended to it. I think there should be consistency between this and that.

Copy link
Contributor

Choose a reason for hiding this comment

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

In the description below for scriptPubKey it says "serialized as script inside CTxOut". This is identical to your suggestion but it would be better to be consistent.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks. Changed to use the common wording.

The total length of ''SigMsg()'' is at most ''206'' bytes<ref>'''What is the output length of ''SigMsg()''?''' The total length of ''SigMsg()'' can be computed using the following formula: ''174 - is_anyonecanpay * 49 - is_none * 32 + has_annex * 32''.</ref>. Note that this does not include the size of sub-hashes such as ''sha_prevouts'', which may be cached across signatures of the same transaction.
The total length of ''SigMsg()'' (without extensions) is at most ''206'' bytes<ref>'''What is the output length of ''SigMsg()''?''' The total length of ''SigMsg()'' can be computed using the following formula: ''174 - is_anyonecanpay * 49 - is_none * 32 + has_annex * 32''.</ref>. Note that this does not include the size of sub-hashes such as ''sha_prevouts'', which may be cached across signatures of the same transaction.

Copy link

@giacomocaironi giacomocaironi Oct 30, 2021

Choose a reason for hiding this comment

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

This is false. The total length of SigMsg is in fact at most 206 bytes. The message extension is appended to the output of SigMsg but it is not in itself part of SigMsg. In BIP 341 and 342 is clearly specified that what is hashed is not the output of SigMsg but rather 0x00 || SigMsg() || ext (if ext is present)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't think what you've said and this addition are at odds. As someone who is not a core developer reading this BIP, I would be inclined to allocate exactly 206 bytes for the data to be hashed as input to my signing function. Adding the parenthetical puts me on notice that there may be cases where I need a larger buffer.

Choose a reason for hiding this comment

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

Ok I understand your point. But the wording of the BIP is very precise, 206 bytes is the maximum total length of SigMsg(). We may clarify that what is signed is not the output SigMsg() but its output plus additional data; so the maximum total length of what is signed is not 206 bytes but 1 (version) + 206(SigMsg()) + 37(ext) = 244 bytes

Copy link
Contributor

Choose a reason for hiding this comment

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

I agree with @giacomocaironi on this one. This change makes me thing "if extensions are included, SigMsg() can exceed 206 bytes."

Copy link
Contributor

Choose a reason for hiding this comment

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

The message extension is appended to the output of SigMsg but it is not in itself part of SigMsg.

Agree. It's simpler if SigMsg remains independent of extensions. Your suggested change could be misunderstood as appending ext twice. First as an Extension inside SigMsg and then again due to the || operator.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I've changed the commit relating to SigMsg / extensions to avoid this confusion by adding a Taproot script path spending signature validation section.

@giacomocaironi
Copy link

giacomocaironi commented Oct 30, 2021

Hi @brandonblack. I am working on some test vectors for these two BIP's because I too spent a lot of time trying to implement them. I think if the tests would have prevented your errors. The pull request is #1191. Your feedback is very welcome!
UPDATE: pull request is now superseded by #1225

@brandonblack brandonblack force-pushed the master branch 2 times, most recently from a81124f to 869b6a0 Compare October 31, 2021 03:40
@brandonblack
Copy link
Contributor Author

Yes, those test vectors would have been helpful (although we generated our own by patching bitcoin-core, probably similar to how you did).

Copy link
Contributor

@jonasnick jonasnick left a comment

Choose a reason for hiding this comment

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

Thanks @brandonblack for your valuable feedback.

The function ''SigMsg(hash_type, ext_flag)'' computes the message being signed as a byte array. It is implicitly also a function of the spending transaction and the outputs it spends, but these are not listed to keep notation simple.

The parameter ''hash_type'' is an 8-bit unsigned value. The <code>SIGHASH</code> encodings from the legacy script system are reused, including <code>SIGHASH_ALL</code>, <code>SIGHASH_NONE</code>, <code>SIGHASH_SINGLE</code>, and <code>SIGHASH_ANYONECANPAY</code>, plus the default ''hash_type'' value ''0x00'' which results in signing over the whole transaction just as for <code>SIGHASH_ALL</code>. The following restrictions apply, which cause validation failure if violated:
The parameter ''hash_type'' is an 8-bit unsigned value. The <code>SIGHASH</code> encodings from the legacy script system are reused, including <code>SIGHASH_ALL</code>, <code>SIGHASH_NONE</code>, <code>SIGHASH_SINGLE</code>, and <code>SIGHASH_ANYONECANPAY</code>, plus <code>SIGHASH_DEFAULT</code> (value ''0x00'') which results in signing over the whole transaction just as for <code>SIGHASH_ALL</code>. The following restrictions apply, which cause validation failure if violated:
Copy link
Contributor

Choose a reason for hiding this comment

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

Since Core apparently gives this a name, it seems like a good idea to have a standardized name for this. How about rephrasing this so it's more clear that this is a new hashtype?

The SIGHASH encodings from the legacy script system are reused, including SIGHASH_ALL, SIGHASH_NONE, SIGHASH_SINGLE, and SIGHASH_ANYONECANPAY.
We define a new ''hashtype'' SIGHASH_DEFAULT (value ''0x00'') which results in signing over the whole transaction just as for SIGHASH_ALL.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks, changed the wording.

The total length of ''SigMsg()'' is at most ''206'' bytes<ref>'''What is the output length of ''SigMsg()''?''' The total length of ''SigMsg()'' can be computed using the following formula: ''174 - is_anyonecanpay * 49 - is_none * 32 + has_annex * 32''.</ref>. Note that this does not include the size of sub-hashes such as ''sha_prevouts'', which may be cached across signatures of the same transaction.
The total length of ''SigMsg()'' (without extensions) is at most ''206'' bytes<ref>'''What is the output length of ''SigMsg()''?''' The total length of ''SigMsg()'' can be computed using the following formula: ''174 - is_anyonecanpay * 49 - is_none * 32 + has_annex * 32''.</ref>. Note that this does not include the size of sub-hashes such as ''sha_prevouts'', which may be cached across signatures of the same transaction.

Copy link
Contributor

Choose a reason for hiding this comment

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

The message extension is appended to the output of SigMsg but it is not in itself part of SigMsg.

Agree. It's simpler if SigMsg remains independent of extensions. Your suggested change could be misunderstood as appending ext twice. First as an Extension inside SigMsg and then again due to the || operator.

In order to allow spending with the key path, we define <code>taproot_tweak_seckey</code> to compute the secret key for a tweaked public key.
For any byte string <code>h</code> it holds that <code>taproot_tweak_pubkey(pubkey_gen(seckey), h)[1] == pubkey_gen(taproot_tweak_seckey(seckey, h))</code>.

Note that the secret key must be negated, if necessary, to produce an even-y pubkey before applying the tweak.
Copy link
Contributor

Choose a reason for hiding this comment

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

This could be misunderstood as an instruction to negate the secret key before calling taproot_tweak_seckey. Also, public keys are 32 byte arrays and therefore don't have even- or odd-Y (and the corresponding points are always even-Y).

How about something like this:
"Note that because tweaks are applied to 32-byte public keys, taproot_tweak_seckey may need to negate the secret key before applying the tweak."

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thank you. Changed the wording.

@brandonblack
Copy link
Contributor Author

Thanks for all the quick feedback! I don't seem to be able to re-request review, but I think I've addressed them.

Comment on lines 144 to 149
==== Taproot script path spending signature validation ====

Validation is identical to ''key path validation'' except that the input to hash<sub>TapSighash</sub> is ''(0x00 || SigMsg(hash_type, ext_flag) || ext)''.

The value of ''ext'' is computed as specified in the BIP corresponding a particular value of ''ext_flag''.

Copy link
Contributor

Choose a reason for hiding this comment

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

That's a semantic change of the BIP and precludes new leaf versions from computing the signature message hash differently. There's no reason to do that.

Also the beginning of the section Signature validation rules mentions that it only applies to key spending.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Mmm. Right, will remove.

* Pull the definition of the extension in BIP342 to its own section
* Add a section to BIP341 on validating script path signatures
* Clarify that SigMsg does not produce the message being signed, but
a common portion of it
@luke-jr
Copy link
Member

luke-jr commented Nov 4, 2021

@sipa @jonasnick @ajtowns

@sipa
Copy link
Member

sipa commented Nov 5, 2021

ACK 6222dc4, conditional on @jonasnick feeling his comments have been addressed.

Copy link
Contributor

@jonasnick jonasnick left a comment

Choose a reason for hiding this comment

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

ACK 6222dc4

@ajtowns
Copy link
Contributor

ajtowns commented Nov 7, 2021

ACK 6222dc4

@kallewoof kallewoof merged commit b155143 into bitcoin:master Nov 11, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

9 participants