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 ;)
On 2nd branch: do you really mean bitcoin addresses? When hashing a pub key, this is not the address. To come from a public key to an address would require 9 steps (see e.g. here: http://gobittest.appspot.com/Address). So somehow an address would be difficult, cause the stack operators do not allow for the checksum and base58check encoding.
– pebwindkraft – 2018-02-04T22:04:13.733I am interested in any secure solution, I didn't want to suggest a particular one, so I was more just expressing the way I was thinking about it, which could be wrong. – Wapac – 2018-02-05T12:16:15.403