1

Stewart, I., et. al. (2018). "Committing to quantum resistance: A slow defence for Bitcoin against a fast quantum computing attack" described a method by which funds could be safely moved from vulnerable locking scripts that use elliptic curve signatures:

We then propose a simple but slow commit–delay–reveal protocol, which allows users to securely move their funds from old (non-quantum-resistant) outputs to those adhering to a quantum-resistant digital signature scheme. The transition protocol functions even if ECDSA has already been com- promised. While our scheme requires modifications to the Bitcoin proto- col, these can be implemented as a soft fork.

I wonder, is it possible, using Bitcoin Script, to implement something similar: a smart-contract that would implement a commit-delay-reveal protocol?

1 Answer 1

1

With current version of Bitcoin Script, that is not possible. However, with some upgrades to Bitcoin's ScriptVM it would become possible, the prerequisites are:

  • A way to commit to transaction's outputs (e.g. OP_CHECKTEMPLATEVERIFY or TX introspection opcodes + OP_CAT)
  • A way to split & concatenate stack items (OP_CAT & OP_SPLIT)
  • A way for inputs to "see" each other (introspection opcodes)

With that, one could code a hash-lock but with an additional requirement: another input must reveal an aged commitment to (prevout + output contents of the TX). This is something only the person who knows the secret would be able to produce ahead of revealing the secret. Once he spends from the contract he will reveal it, but he'll already have the aged commitment and others won't be able to steal his funds. Once posted to mempool, security would rely on the spending TX getting mined before an attacker would be able to age an alternative commitment and post an alternative spending TX.

A proof-of-concept for such a contract exists for Bitcoin Cash (BCH), a blockchain fork of Bitcoin (BTC) which upgraded the ScriptVM with the required L1 primitives in '18 (OP_CAT & OP_SPLIT) and '22 (introspection opcodes) network upgrades.

The "lock" redeem script, placed on the UTXO which would hold the balance

(note: there's no unlocking data, the input's unlocking script is just the redeem script push)

// sha256(one_time_secret + commit_script_tail)
<93168bb98087a29aeb40733ef301f907c3e4125568dd0ddf851f304b43438a14>

// slice associated input's script
OP_INPUTINDEX OP_1ADD
OP_INPUTBYTECODE
<1> OP_SPLIT
OP_SWAP OP_SPLIT
<2> OP_SPLIT
<1> OP_SPLIT
<32> OP_SPLIT
<1> OP_SPLIT
<1> OP_SPLIT

// verify sha256(one_time_secret + commit_script_tail)
<6> OP_ROLL OP_SWAP OP_CAT OP_SHA256
<6> OP_ROLL OP_EQUALVERIFY

// verify input script head format
<0x51> <0x61> OP_WITHIN OP_VERIFY
<0x51> <0x61> OP_WITHIN OP_VERIFY
OP_SIZE <32> OP_EQUALVERIFY
OP_DROP <32> OP_EQUALVERIFY
<0x4c72> OP_EQUAL

The "commit" redeem script, placed on the UTXO which would reveal the aged commitment

(note: the unlocking data is just the one_time_secret)

// sha256(associated_outpoint + one_time_secret + {first 3 outputs})
<0x8bda8c89d438b6da3fd9d289da59532736bfb23d93bba1e2e8da41c194ea43e9>
// age_reveal
<2>
// age_cleanup
<4>

OP_DEPTH <4> OP_LESSTHAN
// if no secret is provided then this is a cleanup spend
OP_IF
    // once redeem script is revealed and utxo aged beyond age_cleanup,
    // any miner can claim the dust to himself

    // verify age_cleanup
    OP_CHECKSEQUENCEVERIFY OP_DROP
    OP_2DROP
// else it is a reveal spend
OP_ELSE
    // drop age_cleanup, not needed here
    OP_DROP
    // verify age_spend
    OP_CHECKSEQUENCEVERIFY OP_DROP
    // get associated outpoint on top of stack
    OP_INPUTINDEX OP_1SUB OP_DUP
    OP_OUTPOINTTXHASH
    OP_SWAP OP_OUTPOINTINDEX OP_CAT
    // get one_time_secret on top of stack and concatenate
    OP_ROT OP_CAT
    // concatenate outputs 00 [& 01 [& 02]]
    <0> OP_OUTPUTVALUE OP_CAT
    <0> OP_OUTPUTTOKENCATEGORY OP_CAT
    <0> OP_OUTPUTTOKENCOMMITMENT OP_CAT
    <0> OP_OUTPUTTOKENAMOUNT OP_CAT
    <0> OP_OUTPUTBYTECODE OP_CAT
    OP_TXOUTPUTCOUNT <2> OP_GREATERTHANOREQUAL
    OP_IF
        <1> OP_OUTPUTVALUE OP_CAT
        <1> OP_OUTPUTTOKENCATEGORY OP_CAT
        <1> OP_OUTPUTTOKENCOMMITMENT OP_CAT
        <1> OP_OUTPUTTOKENAMOUNT OP_CAT
        <1> OP_OUTPUTBYTECODE OP_CAT
    OP_ENDIF
    OP_TXOUTPUTCOUNT <3> OP_GREATERTHANOREQUAL
    OP_IF
        <2> OP_OUTPUTVALUE OP_CAT
        <2> OP_OUTPUTTOKENCATEGORY OP_CAT
        <2> OP_OUTPUTTOKENCOMMITMENT OP_CAT
        <2> OP_OUTPUTTOKENAMOUNT OP_CAT
        <2> OP_OUTPUTBYTECODE OP_CAT
    OP_ENDIF
    OP_SHA256
    // verify against embedded pre-commitment
    OP_EQUALVERIFY
OP_ENDIF
OP_1

The contracts can be loaded into BitAuthIDE debugger using this link.

The contracts have been successfully spent from on BCH mainnet:

This proof-of-concept was first published here

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.