Bitcoin scripts that force disclosure of the private key Context: I am creating an example code that would demonstrate an atomic swap between Elements and Bitcoin, with the aim that the swap transactions cannot be trivially linked, as it would be with simple HTLC, where you can look for the same hash/preimage in both chains. This is because the key to disclose is actually a sum of keys, (A+B), and to claim the other side of the swap, another sum key, (A+C) is used. A, B, and C are only known to (one or both) participants.

I use CHECKSIGFROMSTACK on Elements side to force the counterparty to create a signature with fixed R value (the k would be known, and thus the other party can recover the key)

I was pointed to https://bitcointalk.org/index.php?topic=321228.msg13072047#msg13072047, where gmaxwell tells that you can achieve the same effect of forcing privkey disclosure on unmodified Bitcoin.

He says that he is aware of two ways to achieve this on unmodified Bitcoin, one of them is:

OP_SIZE 57 OP_LESSTHANOREQUAL OP_VERIFY &lt;P&gt; OP_CHECKSIGVERIFY

My questions:


in the script listed above, the signature is forced to be of the length less than or equal 57. This seems to rely on known small R value, and assumption that other R values of equal or smaller size for some known k is not computationally possible to find.

in this post https://crypto.stackexchange.com/questions/60420/what-does-the-special-form-of-the-base-point-of-secp256k1-allow an R value with 90 leading zero bits is given. S would need to be &lt;= 29 bytes in size with R length of 21 bytes (166 bit), for signature to fit into 57 byte limit (29+21+6+1=57). To satisfy this script using this known small R, the creator of the signature would need to search for the message to sign that would result in a signature with len(S) &lt;= 29. Is this tight limit chosen to reduce 'wiggle room' for bruteforcing R ?
What is the second method to achieve this on unmodified Bitcoin ?
If these methods work, why they have not been widely used instead of HTLC constructs, given that these methods (or at least the presented one) are not much more complex implementation-wise, but are more private (because there is no public shared hash/preimage) ? What are the downsides of these methods, versus HTLC ?


(Note: The questions above are more out of intellectual curiosity  than for concrete practical purpose, because when Schnorr signatures will be enabled on Bitcoin (I hope that won't be too long), adaptor signatures https://github.com/apoelstra/scriptless-scripts/blob/master/md/atomic-swap.md would be much better way to create atomic swaps without trivial link between transactions)
I've done some searches and research, and I also got input on #elements channel on bitcoincore slack, so I feel that I can answer these now (EDIT: At first I got confused about CODESEPARATOR method, but after some more time, I asked Anthony Towns and he provided the links to his messages in lighting-dev list explaining it.)


I think that the size 57 is chosen for increased guarantee against the possibility that other small-size R value would be found, that is larger than 21 bytes, but small enough that grinding for smaller S could enable to overcome the size limit. I've also seen other example of how this technique might be used (https://gist.github.com/nothingmuch/683042343c48a4ef07efd3d438e7ee56), but it sets 60 for the size limit. It might be assuming that R value that starts with 72 zero bits is not feasible to be found either. It also may be that 57 byte limit is unnecessary small. Note that grinding for len(S) &lt;= 29 is feasible on general-purpose computer. This could be done by changing other inputs/outputs of the transaction so that sighash changes. Relevant: https://lists.linuxfoundation.org/pipermail/lightning-dev/2015-November/000344.html
The second way to achieve this on unmodified bitcoin may somehow involve the use of OP_CODESEPARATOR. There would be two signatures of one pubkey, but the second signature would use different sighash because this signature is checked after CODESEPARATOR is executed, and sighash will be calculated using only the part of the script after CODESEPARATOR. But while you can have two different signatures (on different messages) for one pubkey, it is not clear to me how to force nonce reuse here, if not with the same size-trick as described before, or using the disabled opcodes.

EDIT: Asked Anthony Towns about this, got reply. There is a tecnique using two codeseparators and three checkmultisigs, in such a way that forces reuse of R. See https://lists.linuxfoundation.org/pipermail/lightning-dev/2015-November/000344.html and https://lists.linuxfoundation.org/pipermail/lightning-dev/2015-November/000363.html

Other relevant links: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-December/016594.html https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2018-December/016592.html My experimental scripts: https://gist.github.com/dgpv/7818a4009f4e90868c0920cc1e238653

Note that CODESEPARATOR is non-standard for non-segwit inputs in Bitcoin, but should be OK for segwit inputs. But still not without some controvesy: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2019-March/016732.html (there was a proposal to remove CODESEPARATOR altogether, or to calculate sighash always using initial script, disregarding effects of CODESEPARATOR)
HTLC is simpler to implement, and the program that creates HTLCs does not need to be able to work with bignums, along with having the function that implements modular inverse on bignums. HTLCs would also generally be smaller in size. They are also more 'known' and thus popular.