Pages:
Author

Topic: Is there any useful place where OP_CODESEPARATOR is used? (Read 478 times)

legendary
Activity: 3472
Merit: 10611
I found some clue, why OP_CODESEPARATOR is still in Taproot: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-February/021448.html
Quote
Code:
[2] In Taproot, if you want to prevent signatures migrating to another
    branch or within a branch, you can use the CODESEPARATOR opcode
    which was redisegned in Taproot for exactly this purpose... we
    really did about witness malleation in its design!
Thanks for the update.
I need to investigate the implementation again but I don't think it works the way that is explained here because of how Taproot scripts were designed so that the leaf hash is covered by the signature.
copper member
Activity: 909
Merit: 2301
I found some clue, why OP_CODESEPARATOR is still in Taproot: https://lists.linuxfoundation.org/pipermail/bitcoin-dev/2023-February/021448.html
Quote
Code:
[2] In Taproot, if you want to prevent signatures migrating to another
    branch or within a branch, you can use the CODESEPARATOR opcode
    which was redisegned in Taproot for exactly this purpose... we
    really did about witness malleation in its design!
copper member
Activity: 821
Merit: 1992
Quote
By anything I meant literary anything not just another signature. For example it could be replaced by an arbitrary message like OP_CODESEPARATOR
Well, any miner can do that today on any legacy address, just because it is possible.

Quote
If it can be discarded that means it is pointless and is not solving anything.
It can be discarded in the current consensus. But OP_CODESEPARATOR can decide, what is signed, and what is not, so by introducing new sighashes, the signed parts of the input script can be controlled by signatures.

Quote
you can't use someone else's public key or use a different script to spend that output
You can always use a different script, because you can always extend it, if you are a miner. In Segwit, it just does not matter, because txid is not affected.
legendary
Activity: 3472
Merit: 10611
Quote
or be replaced by anything else
Any signature can be replaced by anything else, because we don't have deterministic signatures, so "" can be also replaced. Anyone using legacy addresses should be aware of that.
By anything I meant literary anything not just another signature. For example it could be replaced by an arbitrary message like OP_CODESEPARATOR

Quote
Quote
The bold part of the signature script can be discarded
It can be discarded in the same way, as any pushes in P2SH before the script itself can be discarded, and in the same way, as all Segwit inputs can be.
If it can be discarded that means it is pointless and is not solving anything.
You see, the locking script should be designed in a way that it mandates all the unlocking script parts. For example in a P2PKH locking script, it requires 2 items: a signature and a public key and neither one can change meaning you can't use someone else's public key or use a different script to spend that output.
copper member
Activity: 821
Merit: 1992
Quote
or be replaced by anything else
Any signature can be replaced by anything else, because we don't have deterministic signatures, so "" can be also replaced. Anyone using legacy addresses should be aware of that.

Quote
The bold part of the signature script can be discarded
It can be discarded in the same way, as any pushes in P2SH before the script itself can be discarded, and in the same way, as all Segwit inputs can be. So, they can be discarded, because there is no soft-fork preventing people from doing so. But I can imagine a Taproot implementation, where some part of the input is committed to the public key, then that system would be safe.

So, historically, P2SH could be introduced as a OP_CODESEPARATOR commitment to the public key, instead of creating a new address type. It is all about privacy, where you can hide anything behind some output that looks the same. But yes, in Taproot, we can currently reach the same thing.
legendary
Activity: 3472
Merit: 10611
The output script is: " OP_CHECKSIG". And then, the whole magic is in using OP_CODESEPARATOR inside the input script.
The input script is: " OP_CHECKSIGVERIFY OP_CODESEPARATOR ".
The bold part of the signature script can be discarded or be replaced by anything else and the transaction would still be valid. In other words your scripts are examples of the malleability attack.
copper member
Activity: 821
Merit: 1992
What about conditional multisig? It is non-standard, but it is possible with OP_CODESEPARATOR.

In a non-segwit transaction, any change in the signature can change the transaction ID. It is usually not desired, but it can be useful in some cases, for example: it is possible to make a conditional multisig, where coins will be signed by one key, or by two keys, and when they will be signed only by one key, the second key will be entirely hidden.

The output script is: " OP_CHECKSIG". And then, the whole magic is in using OP_CODESEPARATOR inside the input script.
The input script is: " OP_CHECKSIGVERIFY OP_CODESEPARATOR ".

Then, both parties can make their signatures upfront, so the next transaction could use the previous transaction hash as an input. And that transaction could trigger something, and will be valid only if both parties will sign everything with their upfront-prepared, deterministic signatures. But if anyone will refuse to sign, or use another signature, then this transaction will not be confirmed, because of no matching txid.

The benefit is that if Alice will use any signature on such output, it will be perfectly valid and standard, so nobody will notice that any multisig was even planned.
legendary
Activity: 3472
Merit: 10611
In exactly the same way, how you don't have to provide a public key in your output. You don't have to use " OP_CHECKSIG" as your output and "" as your input, you can also use "OP_CHECKSIG" as your output, and " " as your input.
True, but the problem is that such scripts make no sense since anybody could spend a OP_CHECKSIG output script.

Quote
So, in the same way, you can use "OP_CHECKLOCKTIMEVERIFY OP_DROP OP_TRUE" as your output, and "" as your input.
Similarly it won't make sense to use OP_CHECKLOCKTIMEVERIFY in first place if the spender is setting it and it can be changed specially if you add OP_CODESEPERATOR which would mean it would also make the transaction malleable.

Quote
So, what about that script?
Code:
OP_DUP   OP_WITHIN OP_VERIFY OP_CHECKLOCKTIMEVERIFY OP_DROP OP_TRUE
That would work fine since the locking script is defining a strict condition of the locktime so it can't be arbitrary. Although I'm not sure you need the final OP_TRUE though.
copper member
Activity: 909
Merit: 2301
Quote
I don't see how.
In exactly the same way, how you don't have to provide a public key in your output. You don't have to use " OP_CHECKSIG" as your output and "" as your input, you can also use "OP_CHECKSIG" as your output, and " " as your input. So, in the same way, you can use "OP_CHECKLOCKTIMEVERIFY OP_DROP OP_TRUE" as your output, and "" as your input. So yes, the hash of the previous transaction is now fixed, so you always commit to the whole script, but on the other hand, that script can be flexible enough to allow you to change the locktime.

So, what about that script?
Code:
OP_DUP   OP_WITHIN OP_VERIFY OP_CHECKLOCKTIMEVERIFY OP_DROP OP_TRUE
Also note that there are only N possible valid input scripts, that means there are only N possible transaction hashes, that you can reach. You can imagine, how it could affect the next transaction, if it will be used as an input, and if there is no Segwit, so the input script affects the transaction hash (other inputs can use Segwit, only this input can be non-Segwit on purpose, just to reach N possible options, another option could require deterministic signatures, but it is hard to enforce in the current script).
legendary
Activity: 3472
Merit: 10611
You can still change it, if it will be a part of the input script.
I don't see how.
If for example you are spending a P2SH or P2WSH output, the hash of the entire script is already locked in the previous transaction being spent and can not change without changing that transaction also.
hero member
Activity: 1008
Merit: 629
They only need a previous transaction hash and a previous index

 Which in this case is the pre-image hash? Because Bob will not be able to access the funds without them. Now for the case of "txid:vout", you will have to provide a script as proof that it was committed to by the output.
sr. member
Activity: 966
Merit: 421
Bitcoindata.science
You can still change it, if it will be a part of the input script. And note you have opcodes like OP_MIN, OP_MAX or OP_WITHIN.
Input script that validates the spending signature i guess?. How about in cases of Op_Hash160 where the input is encoded twice how would this change get into the input script will there be room for this time lock to get an OP_MIN, OP_MAX or OP_WITHIN

Quote
Edit: Also, there is another thing planned, called SIGHASH_ANYPREVOUT. Or rather, it could be a little more complex: "txid:vout" can be used to select the output, and then tweaked accordingly, by changing the previous transaction:

SIGHASH_PREVOUT_ALL (default, no change),
SIGHASH_PREVOUT_SINGLE (sign only one corresponding input, selected by vout),
SIGHASH_PREVOUT_NONE (sign no inputs of the previous transaction),
SIGHASH_PREVOUT_ANYONECANPAY (sign only this "txid:vout", all other outputs cleared, can be combined with other sighashes).

Then, it could be possible to create a chain of transaction, that would allow "flow control", because you could use SIGHASH_PREVOUT_NONE|SIGHASH_PREVOUT_ANYONECANPAY, and make it resistant to any changes of the previous transaction inputs and outputs (but still, fields like version and locktime will still be signed in that case).
I thought this hashes are scrambled using the timelock how then will it be recalculated so as to make changes on the previous transaction
copper member
Activity: 909
Merit: 2301
Quote
P.S. Now that I look at it again, only the part where I said "locktime value can be changed" was wrong since the script is protected by the hash of the it found in the output script that is being spent.
You can still change it, if it will be a part of the input script. And note you have opcodes like OP_MIN, OP_MAX or OP_WITHIN.

Edit: Also, there is another thing planned, called SIGHASH_ANYPREVOUT. Or rather, it could be a little more complex: "txid:vout" can be used to select the output, and then tweaked accordingly, by changing the previous transaction:

SIGHASH_PREVOUT_ALL (default, no change),
SIGHASH_PREVOUT_SINGLE (sign only one corresponding input, selected by vout),
SIGHASH_PREVOUT_NONE (sign no inputs of the previous transaction),
SIGHASH_PREVOUT_ANYONECANPAY (sign only this "txid:vout", all other outputs cleared, can be combined with other sighashes).

Then, it could be possible to create a chain of transaction, that would allow "flow control", because you could use SIGHASH_PREVOUT_NONE|SIGHASH_PREVOUT_ANYONECANPAY, and make it resistant to any changes of the previous transaction inputs and outputs (but still, fields like version and locktime will still be signed in that case).
legendary
Activity: 3472
Merit: 10611
That's the point. Imagine that Alice and Bob signed some script that was prepared by Charlie, so they don't have to know the opcodes that were before.
I understood that, my point was that since Alice is seeing and signing OP_CHECKLOCKTIMEVERIFY, she also has to see and sign the locktime value or OP_CODESEPARATOR has to come after OP_CLV so that Alice doesn't even see that OP code to know there is a locktime involved.

P.S. Now that I look at it again, only the part where I said "locktime value can be changed" was wrong since the script is protected by the hash of the it found in the output script that is being spent.
copper member
Activity: 909
Merit: 2301
Quote
The first time value (locktimeAlice) is pointless since it will never be signed by any of the keys so it can be changed to any value by anyone. Apart from that, it was interesting.
That's the point. Imagine that Alice and Bob signed some script that was prepared by Charlie, so they don't have to know the opcodes that were before. They only need a previous transaction hash and a previous index, by having those 36 bytes, they can sign it with any sighashes (also note that Alice can use different sighashes than Bob, that's another interesting part of multisig, that is not widely explored, because you cannot concatenate multisigs with different sighashes into a single signature). Also note what is signed by Bob, so how many opcodes is needed to pass to him. And imagine there are N people, where each of them can know only some part of the script. It could also work with Taproot, but then, there is a need to prove that no OP_SUCCESS is present in any previous opcodes.

Edit: Also note that the previous transaction hash can be used to reveal only some part of the previous transaction. For example, it is possible to reveal the result of the first SHA-256 only. It is possible to reveal that, and the last SHA-256 block (then, it is possible to know some last bytes, the size of the whole transaction, and the hash of the previous part). SHA-256 is executed in 512-bit blocks. That can be used to form very interesting protocols, because you can reveal some parts of the message, and hide the rest, as long as you can set any Initialization Vector and any Exit Hash, and require revealing a matching part in-between, you can cryptographically force another party to cooperate. Unfortunately, the current Script allows only executing hash functions with default IVs (but still, it can be used to compute in-between hashes, and then require revealing some partial messages).
legendary
Activity: 3472
Merit: 10611
Edit: Also, what about this?
Code:
OP_CODESEPARATOR OP_CHECKLOCKTIMEVERIFY OP_DROP OP_CHECKSIGVERIFY OP_CODESEPARATOR OP_CHECKLOCKTIMEVERIFY OP_DROP OP_CHECKSIG
The first time value (locktimeAlice) is pointless since it will never be signed by any of the keys so it can be changed to any value by anyone. Apart from that, it was interesting.
copper member
Activity: 909
Merit: 2301
I think I found some use case for OP_CODESEPARATOR: it allows you to sign some unknown script, chosen by the second party, as long as the transaction will match your signature (including your sighashes, not limited to SIGHASH_ALL). So, if you will have "OP_CODESEPARATOR OP_CHECKSIG", then only that part will be signed. By getting previous transaction hash and index from the second party, as long as you generated a fresh private key that was never used, you can safely provide your public key, then another party will prepare a transaction, and you can sign it. Then, there is no way to cheat, because the other party can only block coins, but not steal them (because there is no OP_SUCCESS outside TapScript).

Edit: Also, what about this?
Code:
OP_CODESEPARATOR OP_CHECKLOCKTIMEVERIFY OP_DROP OP_CHECKSIGVERIFY OP_CODESEPARATOR OP_CHECKLOCKTIMEVERIFY OP_DROP OP_CHECKSIG
copper member
Activity: 821
Merit: 1992
Quote
why use OP_CODESEPARATOR here at all?
Good point, maybe it should be placed between OP_PICK and OP_CHECKLOCKTIMEVERIFY? I am not sure, it needs more testing.
legendary
Activity: 3472
Merit: 10611
Quote
So why not use a nested IF?
Maybe no IF is needed at all if there are many cases. Something like this should solve it:
Code:
scriptPubKey: OP_TOALTSTACK OP_CODESEPARATOR 600300 600200 600100 OP_FROMALTSTACK OP_PICK OP_CHECKLOCKTIMEVERIFY OP_2DROP OP_2DROP 2 2 OP_CHECKMULTISIG
scriptSig: 1
That's an interesting approach for the same script but why use OP_CODESEPARATOR here at all? It doesn't change anything apart from affecting whether or not you hash OP_TOALTSTACK while computing the sighash which seems pointless to me.
copper member
Activity: 821
Merit: 1992
Quote
So why not use a nested IF?
Maybe no IF is needed at all if there are many cases. Something like this should solve it:
Code:
scriptPubKey: OP_TOALTSTACK OP_CODESEPARATOR 600300 600200 600100 OP_FROMALTSTACK OP_PICK OP_CHECKLOCKTIMEVERIFY OP_2DROP OP_2DROP 2 2 OP_CHECKMULTISIG
scriptSig: 1
Pages:
Jump to: