bip-325: change signature scheme to be tx-based #947

pull ajtowns wants to merge 1 commits into bitcoin:master from ajtowns:202007-signet-tx changing 1 files +42 −30
  1. ajtowns commented at 2:59 AM on July 20, 2020: contributor

    This changes the block signing algorithm for signet to be based on tx validation instead of a custom method. In particular, this allows the generalises the scheme so that new signets can make use of new signature/scripting methods (such as schnorr or musig) when they are added.

    Note: this is incompatible with existing signets and requires a chain restart.

  2. ajtowns commented at 3:02 AM on July 20, 2020: contributor

    Sample implementation is at https://github.com/ajtowns/bitcoin/commits/202007-signet

    The approach is to support two headers for the signature data; one for filling in scriptSig, one for filling in scriptWitness. In general, it only (currently) ever makes sense to use one or the other, though you could use both if you wanted/needed. Likewise, at present, it only really makes sense to use scriptSig -- scriptWitness offers no benefits for block signing today, though perhaps it will with schnorr signatures only available via scriptWitness signing.

    Reviewers may want to ensure that this does not introduce additional block malleability -- eg, that a signature does not remain valid if the scriptSig/scriptWitness headers are reordered, or empty/dummy headers are added/removed.

  3. ajtowns cross-referenced this on Jul 20, 2020 from issue BIP-325: Signet [consensus] by kallewoof
  4. ajtowns force-pushed on Jul 20, 2020
  5. in bip-0325.mediawiki:47 in 5b1ca5603e outdated
      70 | +
      71 | +To sign the block or verify a block signature, a virtual transaction with a single input and output is constructed from the block as follows:
      72 | +
      73 | +    nVersion = 1
      74 | +    nLockTime = block.nTime
      75 | +    vin[0].prevout.hash = block.hashPrevBlock
    


    sipa commented at 4:01 AM on July 20, 2020:

    I'm not sure if there were perhaps reasons not to do this, but maybe it is desirable to exactly structure it like transaction spending, as that would mean PSBT infrastructure can be reused for block signing.

    One possibility would be, construct 2 virtual transactions. The first is a coinbase tx (perhaps intentionally BIP34-invalid), with a single output, whose scriptPubKey is the signet's challenge script. The second tx spends that output, referring to it using its txid, and its scriptSig/witness is what is put in the block. The first tx could even be cached and constant for all blocks.


    kallewoof commented at 4:24 AM on July 20, 2020:

    PSBT compatibility would be great, yeah!


    ajtowns commented at 4:38 AM on July 22, 2020:

    I've updated the text and the sample implementation to use this approach, it seems much better!

    One reason we might not have thought of it, is that an idea had been to allow signet users to opt-in to reorgs by allowing a different challenge: ie, normally signet might be checked against "2 KEY_A KEY_B 2 CHECKMULTISIG" and the solution is "0 SIG_A SIG_B"; but if you were to use "DROP 1 KEY_A 1 CHECKMULTISIG" as your script, and KEY_A alone was used to sign short reorgs as well as the main chain, you'd be able to test how well your software handled reorgs, while people who used the normal signet challenge wouldn't see any of the reorgs. By actually constructing a tx to spend that includes the challenge, this doesn't work so well anymore.

    On the other hand, it probably doesn't work anyway, because at the p2p layer, the peer doing the reorgs would try forwarding the to-be-reorged blocks to its peers, who would see them as consensus-invalid and ban the peer. So I think it's fine to drop this idea in favour of PSBT support.


    instagibbs commented at 12:57 PM on July 27, 2020:

    aside: I think it's kind of awesome you could get a ColdCard, put it into HSM mode, and have it blocksign!


    MarcoFalke commented at 6:00 PM on August 22, 2020:

    On the other hand, it probably doesn't work anyway, because at the p2p layer, the peer doing the reorgs would try forwarding the to-be-reorged blocks to its peers, who would see them as consensus-invalid and ban the peer. So I think it's fine to drop this idea in favour of PSBT support.

    Even if the different signet policies are run on different p2p networks, it would be nice if the actual blockchain was identical. This would allow to restart the node and select a different signet reorg policy without a reindex/redownload (or selecting a different datadir).


    MarcoFalke commented at 6:32 PM on August 22, 2020:

    A really dumb way to keep the psbt nature, but allow node operators to choose the signet reorg policy is to ask them to supply multiple challenges. Then try all and continue with the first one that matches.


    kallewoof commented at 4:56 AM on August 24, 2020:

    I never thought of actually having multiple networks with the same underlying blockchain. That should totally work -- unfortunately signet now derives the magic from the block challenge, so you can't tweak that easily (well, you can, but it becomes a little messy). Perhaps add a -signet_magic flag that lets you override the derived one..


    ajtowns commented at 7:33 AM on August 24, 2020:

    I think you have to have a reindex if you're applying a different reorg policy -- otherwise, suppose your chain goes 100a 101a 102a 103a 104b 105b (for height 100-105) but the "b" blocks will eventually be reorged out and replaced by 104a 105a 106a but you've only seen 104a so far and that's a less-work tip. Switching to "no reorgs" means you want to move to 104a as your tip immediately. I guess you could do that with a specialised rewind instead of a reindex?


    MarcoFalke commented at 2:50 PM on August 24, 2020:

    As the challenge can only be changed at startup, simply disconnecting blocks until the just removed block can be connected again should suffice.

  6. in bip-0325.mediawiki:41 in 5b1ca5603e outdated
      64 | +
      65 | +    1-4 bytes - Push the following (x + 4) bytes
      66 | +    4 bytes - Signet scriptWitness header (0xecc7daa3)
      67 | +    x bytes - Solution (scriptWitness)
      68 | +
      69 | +Any push operations that do not start with either of the 4 byte signet header are ignored. Multiple push operations with either 4 byte signet header are ignored except for the first instance of each header.
    


    jonatack commented at 5:06 AM on July 20, 2020:
    Any push operations that do not start with either of the 4-byte signet headers are ignored. Multiple push operations with either 4-byte signet header are ignored except for the first instance of each header.
    
  7. in bip-0325.mediawiki:55 in 5b1ca5603e outdated
      78 | +    vout[0].nValue = block.nVersion
      79 | +    vout[0].scriptPubKey = signet_merkle_root
      80 | +
      81 | +The scriptSig and/or scriptWitness for <code>vin[0]</code> are filled in from the secondary commitment push above.
      82 | +
      83 | +The <code>signet_merkle_root</code> hash is obtained by generating the merkle root of the block transactions, with the coinbase witness commitment as is, without the signet solution (that is the secondary commitment includes a four byte push of the Signet scriptSig header or scriptWitness header, with not additional solution data). This means the merkle root of the block is different from the merkle root in the signet commitment. This is needed, because the signature can never be included in the very message (in this case, a block) that is being signed. Apart from the signature, to facilitate block generation (mining), the block nonce value is the only other component of the block that the signet signature does not commit to. When grinding proof of work, the extended nonce cannot be used as it would invalidate the signature. Instead, simply resigning the same (or an updated) block will give a new search space.
    


    jonatack commented at 5:09 AM on July 20, 2020:
    The <code>signet_merkle_root</code> hash is obtained by generating the merkle root of the block transactions, with the coinbase witness commitment as-is, without the signet solution (that is, the secondary commitment includes a 4-byte push of the Signet scriptSig header or scriptWitness header, without additional solution data). This means the merkle root of the block is different from the merkle root in the signet commitment. This is needed, because the signature can never be included in the very message (in this case, a block) that is being signed. Apart from the signature, to facilitate block generation (mining), the block nonce value is the only other component of the block that the signet signature does not commit to. When grinding proof of work, the extended nonce cannot be used as it would invalidate the signature. Instead, simply resigning the same (or an updated) block will give a new search space.
    
  8. in bip-0325.mediawiki:59 in 5b1ca5603e outdated
      82 | +
      83 | +The <code>signet_merkle_root</code> hash is obtained by generating the merkle root of the block transactions, with the coinbase witness commitment as is, without the signet solution (that is the secondary commitment includes a four byte push of the Signet scriptSig header or scriptWitness header, with not additional solution data). This means the merkle root of the block is different from the merkle root in the signet commitment. This is needed, because the signature can never be included in the very message (in this case, a block) that is being signed. Apart from the signature, to facilitate block generation (mining), the block nonce value is the only other component of the block that the signet signature does not commit to. When grinding proof of work, the extended nonce cannot be used as it would invalidate the signature. Instead, simply resigning the same (or an updated) block will give a new search space.
      84 | +
      85 | +This virtual transaction is validated against a virtual UTXO being output 0 of txid <code>block.hashPrevBlock</code>, with scriptPubKey as the signet challenge, and amount as 20,999,999.99999999 (ie 1 satoshi less than 21 million).
      86 | +
      87 | +A block is considered fully validated only if the solution is valid. It is recommended that this verification is done directly before or after the witness commitment verification, as the data required to do both is approximately the same.
    


    jonatack commented at 5:10 AM on July 20, 2020:
    A block is considered fully validated only if the solution is valid. It is recommended that this verification be done directly before or after the witness commitment verification, as the data required to do both is approximately the same.
    

    kallewoof commented at 7:16 AM on July 21, 2020:

    I slightly prefer the original here.

  9. in bip-0325.mediawiki:57 in 5b1ca5603e outdated
      80 | +
      81 | +The scriptSig and/or scriptWitness for <code>vin[0]</code> are filled in from the secondary commitment push above.
      82 | +
      83 | +The <code>signet_merkle_root</code> hash is obtained by generating the merkle root of the block transactions, with the coinbase witness commitment as is, without the signet solution (that is the secondary commitment includes a four byte push of the Signet scriptSig header or scriptWitness header, with not additional solution data). This means the merkle root of the block is different from the merkle root in the signet commitment. This is needed, because the signature can never be included in the very message (in this case, a block) that is being signed. Apart from the signature, to facilitate block generation (mining), the block nonce value is the only other component of the block that the signet signature does not commit to. When grinding proof of work, the extended nonce cannot be used as it would invalidate the signature. Instead, simply resigning the same (or an updated) block will give a new search space.
      84 | +
      85 | +This virtual transaction is validated against a virtual UTXO being output 0 of txid <code>block.hashPrevBlock</code>, with scriptPubKey as the signet challenge, and amount as 20,999,999.99999999 (ie 1 satoshi less than 21 million).
    


    jonatack commented at 5:10 AM on July 20, 2020:
    This virtual transaction is validated against a virtual UTXO being output 0 of txid <code>block.hashPrevBlock</code>, with scriptPubKey as the signet challenge, and amount as 20,999,999.99999999 (i.e. 1 satoshi less than 21 million).
    
  10. jonatack commented at 5:15 AM on July 20, 2020: contributor

    Some nits while reading the changes, feel free to ignore.

  11. ajtowns force-pushed on Jul 22, 2020
  12. bip-325: change signature scheme to be tx-based 3cf239eef3
  13. in bip-0325.mediawiki:34 in ef5480ba6c outdated
      59 | +The witness commitment of the coinbase transaction is extended to include a secondary commitment (the signature/solution) of either:
      60 | +
      61 | +    1-4 bytes - Push the following (4 + x + y) bytes
      62 | +    4 bytes - Signet scriptSig header (0xecc7daa2)
      63 | +    x bytes - scriptSig
      64 | +    y bytes - scriptWitness
    


    kallewoof commented at 4:41 AM on July 22, 2020:

    I'm starting to wonder if we even need the scriptSig part at all. It seems that the scriptWitness is a superset of the features we get from scriptSig, and any systems incorporating block sig validation will still need to handle segwit stuff, since that's a possibility now.


    ajtowns commented at 4:45 AM on July 22, 2020:

    Could do that, but the scriptWitness would be more data. With scriptSig, you can make the signet challenge be the actual script; but with scriptWitness, the challenge has to be p2wpkh or p2wsh and you have to then include either the pubkey or the script that matches the hash in every block solution.


    kallewoof commented at 4:52 AM on July 22, 2020:

    That seems really backwards. It should be possible to put the pubkey/script into the challenge directly, IMO, but we can sort that out later.


    maaku commented at 5:52 AM on July 22, 2020:

    Just make the witness pubkey/script implicit. The client knows it and can insert it where it belongs.


    instagibbs commented at 12:56 PM on July 27, 2020:

    Wallets do this all the time(fill out preimage details), now that the block is a "signable transaction" this is even more the case.


    pinheadmz commented at 2:49 PM on July 30, 2020:

    Out of curiosity @ajtowns why use the witness commitment for this and not an additional OP_RETURN with a different magic header?

  14. ajtowns force-pushed on Jul 22, 2020
  15. ajtowns commented at 4:49 AM on July 22, 2020: contributor

    Updated with @sipa's suggested approach, some of @jonatack's suggested nits

  16. instagibbs commented at 12:54 PM on July 27, 2020: member

    concept ACK! It fixes the biggest downside I felt of the current BIP(the lack of extensibility to taproot/script).

  17. kallewoof commented at 12:25 AM on July 30, 2020: member

    ACK - please merge at your convenience, @luke-jr.

  18. luke-jr merged this on Jul 30, 2020
  19. luke-jr closed this on Jul 30, 2020

  20. JeremyRubin commented at 4:56 AM on August 12, 2020: contributor

    concept ack -- this fixes my concerns with signet I believe!

  21. MarcoFalke cross-referenced this on Aug 24, 2020 from issue RFC: Signet meta discussion by michaelfolkson
  22. in bip-0325.mediawiki:29 in 3cf239eef3
      54 | -|}
      55 | -
      56 | -The <code>modifiedMerkleRoot</code> hash is obtained by generating the merkle root of the block transactions, with the coinbase witness commitment as is, without the signet extension. This means the merkle root of the block is different from the merkle root in the signet commitment. This is needed, because the signature can never be included in the very message (in this case, a block) that is being signed. Apart from the signature, to facilitate block generation (mining), the block nonce value is the only other component of the block that the signet signature does not commit to. When grinding proof of work, the extended nonce cannot be used as it would invalidate the signature. Instead, simply resigning the same (or an updated) block will give a new search space.
      57 | -
      58 | -A block is considered fully validated if the above commitment is found, and its solution is valid. It is recommended that this verification is done directly before or after the witness commitment verification, as the data required to do both is approximately the same.
      59 | +The witness commitment of the coinbase transaction is extended to include a secondary commitment (the signature/solution) of either:
    


    narula commented at 11:51 PM on September 7, 2020:

    What are the choices this "either" is referring to?


    ajtowns commented at 7:52 AM on September 8, 2020:

    An earlier draft had two different secondary commitments, one for scriptSig and a different one for scriptWitness. When they were combined the "either" wasn't removed.

  23. instagibbs commented at 11:53 PM on September 7, 2020: member

    Neha check the open PRs(on phone no link sorry) I change this because it's old leftover language.

    On Mon, Sep 7, 2020, 7:52 PM Neha Narula notifications@github.com wrote:

    @narula commented on this pull request.

    In bip-0325.mediawiki https://github.com/bitcoin/bips/pull/947#discussion_r484588354:

    -|- -|Int32||4||nVersion -|- -|Uint256||32||hashPrevBlock -|- -|Uint256||32||modifiedMerkleRoot -|- -|Uint32||4||nTime -|- -|Uint32||4||nBits -|}

    • -The <code>modifiedMerkleRoot</code> hash is obtained by generating the merkle root of the block transactions, with the coinbase witness commitment as is, without the signet extension. This means the merkle root of the block is different from the merkle root in the signet commitment. This is needed, because the signature can never be included in the very message (in this case, a block) that is being signed. Apart from the signature, to facilitate block generation (mining), the block nonce value is the only other component of the block that the signet signature does not commit to. When grinding proof of work, the extended nonce cannot be used as it would invalidate the signature. Instead, simply resigning the same (or an updated) block will give a new search space.
    • -A block is considered fully validated if the above commitment is found, and its solution is valid. It is recommended that this verification is done directly before or after the witness commitment verification, as the data required to do both is approximately the same. +The witness commitment of the coinbase transaction is extended to include a secondary commitment (the signature/solution) of either:

    What is the choices this "either" is referring to?

    — You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/bitcoin/bips/pull/947#pullrequestreview-483728568, or unsubscribe https://github.com/notifications/unsubscribe-auth/ABMAFU5FUMTS5JSJT2S7CETSEVW2PANCNFSM4PBZBT5Q .

  24. narula commented at 12:02 AM on September 8, 2020: none

github-metadata-mirror

This is a metadata mirror of the GitHub repository bitcoin/bips. This site is not affiliated with GitHub. Content is generated from a GitHub metadata backup.
generated: 2026-04-19 07:10 UTC

This site is hosted by @0xB10C
More mirrored repositories can be found on mirror.b10c.me