read.cash Log in
@rinexc more from that month

Covenants without OP_CHECKDATASIG

On November 2018, Tendo Pein published a brilliant article on spending constraints with `OP_CHECKDATASIG` (updated version). By using `OP_CHECKDATASIG` (`OP_CDS`) and `OP_CHECKSIG` a script can verify it has received a subset of the content of the spending transaction (a sighash preimage). This enables an output script to apply rules to the spending transaction, effectively creating a covenant. https://read.cash/@pein/bch-covenants-with-spedn-c1170a02 Recently I've seen claims that `OP_CDS` is not required to have this capability, like in this tweet from @sinoTrinity. I asked around and u/-mr-word- briefly explained to me what he calls "the checksig trick". https://twitter.com/sinoTrinity/status/1225323514632138753 Then I found a solution that could have been used on BCH since May 2018, as it doesn't require any bignum operation. Here's an example on mainnet. https://explorer.bitcoin.com/bch/tx/870436f83226134e0808cee8c13d107da83e3a6aeb62e2a4bd9869da0e506f0c Covenants using bignum To simulate `OP_CDS` in script (i.e. to verify a signature), we need bignum math and complex elliptic curve operations. However, @sinoTrinity's solution on BSV is completely different: instead of checking one user-provided signature twice, it actually **creates** the signature in script and check it with `OP_CHECKSIG`. A successful signature check means the user provided the right sighash preimage, just like we have with `OP_CDS` on BCH. This approach requires bignum operations, but can be made to completely avoid elliptic curve operations. An ECDSA signature is a pair (r,s) calculated as: https://en.wikipedia.org/wiki/Elliptic_Curve_Digital_Signature_Algorithm#Signature_generation_algorithm `r=x coordinate of (k \times G)`, where `k` is a nonce, `G` is the generator point, `\times` is the EC point multiplication operation. `s=k^(-1)*(sighash + r*d) mod n`, where `d` is the private key and `n` is the order of `G`. The solution on BSV uses bignum operations. It basically follows these steps: https://test.whatsonchain.com/tx/8795194ca00c59e1f6c8cd02f65130e7dbaba7f936d8626836624c2aad8f3555 Calculate sighash i.e. hash the sighash preimage. Convert it to little-endian. Calculate `s=k^(-1)*(sighash + r*d) mod n`. `k^(-1)`, `r`, `d` and `n` are constants in the contract. Adjust `s` to guarantee a low-s (a consensus rule on BCH and BSV). https://github.com/bitcoin/bips/blob/master/bip-0062.mediawiki#low-s-values-in-signatures Convert it to big-endian. Concatenate `r` and `s` to create a valid DER encoded signature. `OP_CHECKSIG` it with a pre-computed public key derived from `d`. A user spending from this contract has to provide only the sighash preimage in the scriptSig and it executes only one signature verification (SigOp). In contrast, on BCH using `OP_CDS` the user is required to provide the sighash preimage, a signature and a public key and it uses 2 SigOps. The choice of parameters (`k` and `d`) used in this contract seemed random. Since any valid choice suffices, why not choose numbers that facilitates the computation? Covenants without bignum By choosing `k=1` and `d=r^(-1)`, step 3 becomes `s=(sighash + 1) mod n`. We can safely ignore the `mod n` operation, since the low-s restriction on step 4 automatically covers it. Because we are avoiding bignum operations, we just skip step 4 and restrict sighash so that `sighash<n/2`. Fortunately, it's quite easy to malleate the spending transaction to generate a new sighash, for instance by changing `nSequence`or `nLockTime`. Any sighash has a probability close to 50% to become a low-s signature, so this shouldn't be much work. The computation is now reduced to `s=sighash + 1`. It's not as easy as it seems, because we must convert endianness twice and potentially have to propagate a carry over many bytes. We could avoid the carry part by including another restriction on sighash, but there's an easier way: choosing `d=r^(-1)*0x01...00 (256bit scalar)`. This avoids the endianness conversions and carry propagation by simply restricting the said sighash constraint a little more: now sighash's MSB must be `<0x7e`. We need to malleate the transaction ~2 times, in expected value, to find an adequate sighash to spend this covenant contract. The unlocking script then becomes: `OP_HASH256 OP_1 OP_SPLIT OP_SWAP OP_BIN2NUM OP_1ADD OP_SWAP OP_CAT [3044022079be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f817980220] OP_SWAP OP_CAT [c1] OP_CAT [02b405d7f0322a89d0f9f3a98e6f938fdc1c969a8d1382a2bf66a71ae74a1e83b0] OP_CHECKSIG[VERIFY]` It uses 87 bytes and only one SigOp. It can be used anywhere one needs to verify that the correct sighash preimage was provided. This solution makes it really easy to trigger smart contracts: no ecdsa or even hash code needed! If it fails to broadcast with a "Non-canonical DER signature" error, just malleate the transaction and try again. I tested it on mainnet with no extra spending restrictions. https://explorer.bitcoin.com/bch/tx/870436f83226134e0808cee8c13d107da83e3a6aeb62e2a4bd9869da0e506f0c Can we use schnorr? Choose `k=x=1` and this 63-bytes script also does the trick: https://gitlab.com/bitcoin-cash-node/bitcoin-cash-node/-/blob/master/src/secp256k1/src/modules/schnorr/schnorr_impl.h#L23 `OP_HASH256 [79be667ef9dcbbac55a06295ce870b07029bfcdb2dce28d959f2815b16f81798] OP_2 OP_OVER OP_CAT OP_2DUP OP_CAT OP_3 OP_ROLL OP_CAT OP_SHA256 [1f] OP_SPLIT [00] OP_CAT OP_BIN2NUM OP_1ADD OP_1 OP_SPLIT OP_DROP OP_CAT OP_SWAP OP_TOALTSTACK OP_CAT [c1] OP_CAT OP_FROMALTSTACK OP_CHECKSIG[VERIFY]` The good news is that we need to malleate the transaction only once every 256 spends, in average. Also, add an `OP_CODESEPARATOR` and this script can be useful for covenants optimizing for smaller scriptSigs, even smaller than using `OP_CDS`. Here's a sample transaction on mainnet. https://explorer.bitcoin.com/bch/tx/c9b679aae236f4d9cde9e982a392d8125d045ff26b459560681488d57a4aa654 So, it seems we could have had covenants smart contracts since May 2018. Is this approach useful? What are your thoughts? Lead image by edar from Pixabay. https://pixabay.com/users/edar-609103/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=962359 https://pixabay.com/?utm_source=link-attribution&utm_medium=referral&utm_campaign=image&utm_content=962359

2 comments

Log in to join in Reading is open to everyone. Replying needs an account.