<p>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:</p>
<ul>
<li>A way to commit to transaction's outputs (e.g. OP_CHECKTEMPLATEVERIFY or TX introspection opcodes + OP_CAT)</li>
<li>A way to split &amp; concatenate stack items (OP_CAT &amp; OP_SPLIT)</li>
<li>A way for inputs to &quot;see&quot; each other (introspection opcodes)</li>
</ul>
<p>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.</p>
<p>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 <a href="https://documentation.cash/protocol/forks/may-2018-reenabled-opcodes" rel="nofollow noreferrer">'18 (OP_CAT &amp; OP_SPLIT)</a> and <a href="https://documentation.cash/protocol/forks/chips/2022-05-native-introspection-opcodes" rel="nofollow noreferrer">'22 (introspection opcodes)</a> network upgrades.</p>
<p><strong>The &quot;lock&quot; redeem script, placed on the UTXO which would hold the balance</strong></p>
<p>(note: there's no unlocking data, the input's unlocking script is just the redeem script push)</p>
<pre><code>// sha256(one_time_secret + commit_script_tail)
&lt;93168bb98087a29aeb40733ef301f907c3e4125568dd0ddf851f304b43438a14&gt;

// slice associated input's script
OP_INPUTINDEX OP_1ADD
OP_INPUTBYTECODE
&lt;1&gt; OP_SPLIT
OP_SWAP OP_SPLIT
&lt;2&gt; OP_SPLIT
&lt;1&gt; OP_SPLIT
&lt;32&gt; OP_SPLIT
&lt;1&gt; OP_SPLIT
&lt;1&gt; OP_SPLIT

// verify sha256(one_time_secret + commit_script_tail)
&lt;6&gt; OP_ROLL OP_SWAP OP_CAT OP_SHA256
&lt;6&gt; OP_ROLL OP_EQUALVERIFY

// verify input script head format
&lt;0x51&gt; &lt;0x61&gt; OP_WITHIN OP_VERIFY
&lt;0x51&gt; &lt;0x61&gt; OP_WITHIN OP_VERIFY
OP_SIZE &lt;32&gt; OP_EQUALVERIFY
OP_DROP &lt;32&gt; OP_EQUALVERIFY
&lt;0x4c72&gt; OP_EQUAL
</code></pre>
<p><strong>The &quot;commit&quot; redeem script, placed on the UTXO which would reveal the aged commitment</strong></p>
<p>(note: the unlocking data is just the <code>one_time_secret</code>)</p>
<pre><code>// sha256(associated_outpoint + one_time_secret + {first 3 outputs})
&lt;0x8bda8c89d438b6da3fd9d289da59532736bfb23d93bba1e2e8da41c194ea43e9&gt;
// age_reveal
&lt;2&gt;
// age_cleanup
&lt;4&gt;

OP_DEPTH &lt;4&gt; 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 [&amp; 01 [&amp; 02]]
    &lt;0&gt; OP_OUTPUTVALUE OP_CAT
    &lt;0&gt; OP_OUTPUTTOKENCATEGORY OP_CAT
    &lt;0&gt; OP_OUTPUTTOKENCOMMITMENT OP_CAT
    &lt;0&gt; OP_OUTPUTTOKENAMOUNT OP_CAT
    &lt;0&gt; OP_OUTPUTBYTECODE OP_CAT
    OP_TXOUTPUTCOUNT &lt;2&gt; OP_GREATERTHANOREQUAL
    OP_IF
        &lt;1&gt; OP_OUTPUTVALUE OP_CAT
        &lt;1&gt; OP_OUTPUTTOKENCATEGORY OP_CAT
        &lt;1&gt; OP_OUTPUTTOKENCOMMITMENT OP_CAT
        &lt;1&gt; OP_OUTPUTTOKENAMOUNT OP_CAT
        &lt;1&gt; OP_OUTPUTBYTECODE OP_CAT
    OP_ENDIF
    OP_TXOUTPUTCOUNT &lt;3&gt; OP_GREATERTHANOREQUAL
    OP_IF
        &lt;2&gt; OP_OUTPUTVALUE OP_CAT
        &lt;2&gt; OP_OUTPUTTOKENCATEGORY OP_CAT
        &lt;2&gt; OP_OUTPUTTOKENCOMMITMENT OP_CAT
        &lt;2&gt; OP_OUTPUTTOKENAMOUNT OP_CAT
        &lt;2&gt; OP_OUTPUTBYTECODE OP_CAT
    OP_ENDIF
    OP_SHA256
    // verify against embedded pre-commitment
    OP_EQUALVERIFY
OP_ENDIF
OP_1
</code></pre>
<p>The contracts can be loaded into BitAuthIDE debugger using <a href="https://alpha.ide.bitauth.com/import-template/eJztWAtv4kgS_ista3U7o0uIX4AdjSIR8AxoGciC2Zm5EEVtuxy8BzbnbmcTjfLft9pvA2GSlfZ00gUlYHdXV331VXVX2d-ln5i7gg2VzqUV51t2fnYWeNByAk4Tvmq50eZMXEDIA5fyIApPOWy2a8rh9F5uZWtbv7MolE4kD5gbB1shheoGsI1YwM-XodIis2i9JpSE8AeJaehFG8LAjYG3lqHaIh9jHEAj-eAJuYMQYrRBltI6cv-9lIjzyMGNPCC4GsXw67I_JDwigdCxDOdbHAvCu8zcAFz0gkQhSbZCSCNRwrcJZ5m9T5V6dHAT8IMGonD9SFi0gdSUlzBe2tNa5AsNOEmQljUOEXoHjKjEEWiFEb1FUkSVA_-sG1vYX6cMtd0Beh2nDowDF0IG4vL688gmk4j0OI8DJxF83ryLUB2LktiFVhTfna0z8TPUdyqfvW8h_SHdAPL-a0JDnmxOY2AB43hNpiGc8mADpwkDMkY4KCwCygNg0vl3KfoD6RAXzQBWKjOBE-mexgF11vmqEG6F1tssaMfW4xV_3IqrnuchLjagnEpP-DmRGPqBaqNUJwNeVyek8LcIzUGrkvzgAPjH_iVhp4ltDjxPNoIBAIxWDkOE2AEShDgccPAwL0gkgkRKoDWuJeEAYs6za58DYSef_GuG4IFjGqHmOjcNYnE_Mepm9pCfAsn19zTzcEtclvRJ3Q41Fd3xwQRPB2q6XUOTXRXA7LhKl2qO1_b9dkdzFdVXHcOgbhr1dQJzyiO2ClCxaZqy_HRySH0Hg3ojyObA-G0SComDedH0qsBcumXjcrLIlu95GISlg5mFBoZria0jLt2cpExEQcjtavmQshWqp1TxTdpVjK4PstmR24qvK6DLvqlomgOOY-iaoqmO6TuCEpe6nY7apo4hCzmNSpXyUejBg3Se8nEADWZ06jgajeEe6FokzPPAulrbNWWvA5rW1k0FDENDi47X8VzT6ELbMVUNwHAd2Xc9anS7akfzZAWXmJppdg4BE_n5nwRCFybJxhHbXMUQ4Wh6lEyPZUtB5cFY1zzLTjXcZDdF5HNf_2rkZ9nyV0a-hijPvKNc__eS4CUp-b8V-RqVGZEHU6DMjzLu7hpomGyPlYI0wP1c7m_Y264GmtF2DdPX27ILnqLrjk7bpquYDlBV94226radDpWNrqJ5bb3r6x4Gtksd06W--iIi9accw99-0oqzVn71hr3JCqvgP61J1X7cUsZE-b5ubNSbMjxxsfXKBDg7Izs1dxl-2Bm5wAVZvFjtPDiRavmwY7iYqSy7ZU6Upp_RWtWVHaX5RKUzKUrIYZXFIZGrPi8ptbNmZauylSpXuZvLNclhK6q2O-8QSeQG2FN6t0X-YMu3wxOOfPeDGHdA2ZA-vUc65QfDwV2NWevpmuF0PKr5numpeI-p29bUrtZxfEfVcLc7DlVABcOjuoJJjbmla2BeLEPEgl1oHlJUqlZjObc4qF-IBnN6dTuwruwhwXuCN2NrPreHvUm6IPBJGBXNUcDINo7usZn2RIMe4hcO4R8luVLCRJ-b6hx9XIYEP2nKuEBi8ACw00_ZEosybKhK9NgJf4gEOux84DHCgRrSk1IRDR_JJsD2k7g0RJs0yJ4UinZ8FWwYrH3hVb7iHvsp_7Hpt5hCgP2h1f9lbv26sCZ96zdrNvr4TQwPZtOrUkbN7lARrLFdDnjmbQa95qw1nlulTS-Otg38SCHHpx0QvIm-r1Rf2WpCzRW_FCguxmcHUmUdKbMOH3o4ool8gt0_PnoUOkeTq4U9mgysr-JOmS8uU5WLyvXpwr6ajia2_XXYmw_L4fmX3lV9utTR79kNNLvZvoMkjbqLmYF4Q_wvDcym9q66mljZP8syuf4HkZX0W725yYQ_yBcFuIX9W2-8sBq6GtP29BcktGdbn6azbz8Sm37Gx7DP1sT-gWDv83RxTOjym231p4MmLLzGR8B0vp8ux-0qBj_NLIQ3E5txOsP498ZV_PLdlRpQjjq9J_K848-IHnb-sPABAvYEnyPBmgwKv_Yp0V5FifpjStSXU7IveoSSPeHnKFFfTcl82MPysn9i0CDEAxCwH_HEGbON4TQrTxt8sq90Cbqy8yM7tDLdYv8vQ1H6ikp6vPDtVtGq7O0XuAzFbSZ7y2mwFhXup3d7PQP5sC96kZNRef4-LVjCoHjjUT_w0l7xZ5aXl6wANY-43mBQDRd0I5gsMedX45GdzhcHXD6SR6m4a0h_0I5NNu5S1Hm8XslW5yI7Fsfj-vnb4GVPqhHquu2Up6IIr4B6xI_iDeVp39FGyPjTyZB_GdnD0URcFYpeICIgjf5lkYKa3ZwTRevwJGrV3W5tomrG6oyI_Gx0YI3JWlq-tTVvbc1bW_PW1ry1Nf-_bU36rp8l220U4_EhXg1c9odYkq2-eC-Adlj6qkl--hNOKZL4" rel="nofollow noreferrer">this link</a>.</p>
<p>The contracts have been successfully spent from on BCH mainnet:</p>
<ul>
<li>Fund the lock: <a href="https://bch.loping.net/tx/aa1f9a7187fe096051f41e40f9133bebb843132b9fba3bdcac6625ab80f41e3a" rel="nofollow noreferrer">aa1f9a7187fe096051f41e40f9133bebb843132b9fba3bdcac6625ab80f41e3a</a></li>
<li>Commit: <a href="https://bch.loping.net/tx/735c90d6e335491e883f41bd6dc987e5b923ee8cb0fcda877263d0190d93996a" rel="nofollow noreferrer">735c90d6e335491e883f41bd6dc987e5b923ee8cb0fcda877263d0190d93996a</a></li>
<li>Reveal &amp; unlock: <a href="https://bch.loping.net/tx/9938671a934a85ef9877ab7df5468559966789d3eb8a1fa41463ebc9514919ce" rel="nofollow noreferrer">9938671a934a85ef9877ab7df5468559966789d3eb8a1fa41463ebc9514919ce</a></li>
<li>Unusable commitment (committed to wrong output amount, scripts would still validate but such TX would violate general consensus rules): <a href="https://bch.loping.net/tx/c3e385c89f450ced144b4a59c19bea24f852c5b6a08713d547f4d6257ab9caf2" rel="nofollow noreferrer">c3e385c89f450ced144b4a59c19bea24f852c5b6a08713d547f4d6257ab9caf2</a></li>
<li>Clean-up unusable commitment: <a href="https://bch.loping.net/tx/44667265d6203b1b9485635cfbf430d29bf18a4313cedf6431d435ad56febd63" rel="nofollow noreferrer">44667265d6203b1b9485635cfbf430d29bf18a4313cedf6431d435ad56febd63</a></li>
</ul>
<p>This proof-of-concept was first published here</p>
<ul>
<li><a href="https://bitcoincashresearch.org/t/quantum-resistant-one-time-use-lock/1197" rel="nofollow noreferrer">https://bitcoincashresearch.org/t/quantum-resistant-one-time-use-lock/1197</a></li>
</ul>

CC BY-SA 4.0
2023-11-29T11:31:28.487Z
2023-11-29T11:31:28.487Z
bca-0353f40e
<p><a href="https://eprint.iacr.org/2018/213.pdf" rel="nofollow noreferrer">Stewart, I., et. al. (2018). &quot;Committing to quantum resistance: A slow defence for Bitcoin against a fast quantum computing attack&quot;</a> described a method by which funds could be safely moved from vulnerable locking scripts that use elliptic curve signatures:</p>
<blockquote>
<p>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.</p>
</blockquote>
<p>I wonder, is it possible, using Bitcoin Script, to implement something similar: a smart-contract that would implement a commit-delay-reveal protocol?</p>

<script><quantum-computing>
Is it possible to use Bitcoin Script to implement a quantum-resistant locking script that would be safe to spend from?
bca-0353f40e
# Is it possible to use Bitcoin Script to implement a quantum-resistant locking script that would be safe to spend from?

(Asked by: username_0 on 2023-11-29)

[Stewart, I., et. al. (2018). "Committing to quantum resistance: A slow defence for Bitcoin against a fast quantum computing attack"](https://eprint.iacr.org/2018/213.pdf) 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?

**Tags:** script, quantum-computing


---

## 1 answers

### Answer by username_0 on 2023-11-29. Score: 1 | Accepted answer

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:

Fund the lock: aa1f9a7187fe096051f41e40f9133bebb843132b9fba3bdcac6625ab80f41e3a
Commit: 735c90d6e335491e883f41bd6dc987e5b923ee8cb0fcda877263d0190d93996a
Reveal & unlock: 9938671a934a85ef9877ab7df5468559966789d3eb8a1fa41463ebc9514919ce
Unusable commitment (committed to wrong output amount, scripts would still validate but such TX would violate general consensus rules): c3e385c89f450ced144b4a59c19bea24f852c5b6a08713d547f4d6257ab9caf2
Clean-up unusable commitment: 44667265d6203b1b9485635cfbf430d29bf18a4313cedf6431d435ad56febd63

This proof-of-concept was first published here

https://bitcoincashresearch.org/t/quantum-resistant-one-time-use-lock/1197


---

