Indeed, if you have a public key and then the hash of another public key, you can build a script that behaves similarly than a 1-of-2 multisig. Something like this would do the trick:
OP_DUP OP_TOALTSTACK <pubKey1> OP_CHECKSIG
OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY
OP_CHECKSIGVERIFY OP_ENDIF
<0x01>
The output script will be unlocked if either a signature validated with pubKey1
is provided or a valid signature and a public key that match pubKeyHash2
are provided.
In the first case, the user with pubKey1
spends with a valid signature:
ScriptSig: <signature1>
Evaluation:
<signature1> OP_DUP OP_TOALTSTACK <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<signature1> <signature1> OP_TOALTSTACK <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<signature1> <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
0x01 OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<0x01>
Note that since the first OP_CHECKSIG
returns True
, the opcodes inside the conditional are not executed, and the script terminates succesfully (leaving 0x01
in the stack).
In the second case, the user with pubKeyHash2
spends with a valid signature and revealing the public key matching the hash:
ScriptSig: <signature2> <pubKey2>
Evaluation:
<signature2> <pubKey2> OP_DUP OP_TOALTSTACK <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<signature2> <pubKey2> <pubKey2> OP_TOALTSTACK <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<signature2> <pubKey2> <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<signature2> 0x00 OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<signature2> OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<signature2> <pubKey2> OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<signature2> <pubKey2> <pubKey2> OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<signature2> <pubKey2> <pubKeyHash2> <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<signature2> <pubKey2> OP_CHECKSIGVERIFY OP_ENDIF <0x01>
<0x01>
In this case, the first OP_CHECKSIG
fails, so the code inside the conditional is executed. This code validates the signature and public key with pubKeyHash2
, and makes the script fail if any of the validations fail. If both validations are passed, then the script pushes 0x01
to the stack, terminating successfully.
PD: Please don't use this script in the mainnet without first having checked that it works as expected ;)