I present a proof of concept for a quantum-resistant BCH contract.
This is similar to Stewart, I., et. al. (2018). “Committing to quantum resistance: A slow defence for Bitcoin against a fast quantum computing attack”, but it is implemented using smart contract capabilities specific to Bitcoin Cash (TX introspection opcodes, OP_CAT & OP_SPLIT). The outline of the contract was given at end of section here:
We can outline the contract here: require a valid signature from a key, and also require spending another input alongside - one that spends a prevout which reveals a pre-commitment to the signature and such that it is time-locked.
This way, even if the key is revealed, the adversary could not immediately produce an alternative transaction since he would not have a matured pre-commitment output in his possession.
He could produce one and wait, but by the time it matures, the real owner’s transaction will be buried under some blocks, and stealing the funds would require a chain re-org.
We don’t even need a signature! The contract is essentially a hash-lock contract (labeled “lock”) with an additional requirement in that an aged commitment to the particular “lock” UTXO + desired outputs must be revealed in the same transaction.
The commitment is done by using another contract (labeled “commit”) to which only BCH dust is sent when the user wants to spend from the “lock”.
The “lock” only commits to the secret + invariant part of the “commit” redeem script (sha256(one_time_secret + commit_script_tail)
), meaning the owner can later decide to which outputs he wants to send the funds locked.
Once decided, he generates the commitment for the “commit” script, which commits to prevout ref. of the particular “lock” UTXO, the secret, and the outputs: sha256(associated_outpoint + one_time_secret + {first 3 outputs})
and sends some dust to the “commit” script.
To spend, both “lock” and matching “commit” must be spent together.
The “lock” contract will verify the contents of the “commit” reveal script, and the “commit” contract will verify the outputs of the TX and that it’s being spent with the correct “lock” UTXO.
Example transactions:
- Fund the lock: aa1f9a7187fe096051f41e40f9133bebb843132b9fba3bdcac6625ab80f41e3a
- Commit: 735c90d6e335491e883f41bd6dc987e5b923ee8cb0fcda877263d0190d93996a
- Reveal & unlock: 9938671a934a85ef9877ab7df5468559966789d3eb8a1fa41463ebc9514919ce
- Unusuable commitment (I committed to wrong output amount, scripts would still validate but such TX would violate general consensus rules): c3e385c89f450ced144b4a59c19bea24f852c5b6a08713d547f4d6257ab9caf2
- Clean-up unusable commitment: 44667265d6203b1b9485635cfbf430d29bf18a4313cedf6431d435ad56febd63
Notes:
- Main trade-off is that we lose the 0-conf UX, because each spend requires waiting for the commitment UTXO to age.
- If you give the “lock” address to some sender, he could later send you once more, not knowing that the secret is revealed and anyone can race to spend from it. We can work around this with a more complex scheme - one that would use a pay-to-token address so senders are never given the quantum-lock address. The owner would keep only the NFT in the quantum-lock address, and use it to collect BCH sent to associated pay-to-token address. This would hide the quantum-lock address from senders.
- The 2 contracts use relative +1 & -1 offsets from “this” input index to “look” at each other, meaning any number of the pairs can be spent in the same TX.
- The pair of contracts is limited to up to 3 outputs (more can be added but it would increase size of the contract).
- So, N-to-1, N-to-2, and N-to-3 spends are possible.
- Once a secret is revealed, anyone can learn it and start watching the “lock” address for deposits and race to steal the funds. Users should take great care in managing their secrets.
- The commitment UTXO could be commiting to invalid outputs (like an output with 22M BCH), meaning user would be unable to spend not because scripts would fail evaluation but because the TX would fail to validate against general consensus rules (I made that mistake, then I had to generate a correct commitment and clean up the unusable one). This means that users could accidentally reveal the secret by trying to broadcast an invalid TX, and then some attacker could front-run their later, valid, spend by generating a commitment as soon as he learns the secret.
- Adversarial hash-rate could in theory collude to delay confiriming the spending TX, while allowing their own commit UTXO to age and then they’d allow their own spend through, while censoring the original. Unless they could execute a 51%, users could just set a longer
age_spend
. - If blocks would get clogged, it could happen that the spending TX is not confirmed for a long time, allowing a miner to age an alternative commitment and post an alternative spending TX.
Contract’s BitauthIDE Template
License: MIT No Attribution.