1

I want to construct a 1-of-2 multisig script and I don't know one of the keys, I only know its address. Question is, is that possible?

So I was thinking if it is possible to construct a script that would have 2 branches, first branch would be allowing the first public key which I now to spend the money. And the 2nd branch would need a spending script to provide the public key which would then be duplicated on the stack, then hashed in order to get the address from it, this address would be compared to the address I know and if that matched, it would allow spending the coins.

  • 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: 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 Feb 4 '18 at 22:04
  • I 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 Feb 5 '18 at 12:16
1

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:

  1. <signature1> OP_DUP OP_TOALTSTACK <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  2. <signature1> <signature1> OP_TOALTSTACK <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  3. <signature1> <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  4. 0x01 OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  5. <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:

  1. <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>
  2. <signature2> <pubKey2> <pubKey2> OP_TOALTSTACK <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  3. <signature2> <pubKey2> <pubKey1> OP_CHECKSIG OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  4. <signature2> 0x00 OP_NOTIF OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  5. <signature2> OP_FROMALTSTACK OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  6. <signature2> <pubKey2> OP_DUP OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  7. <signature2> <pubKey2> <pubKey2> OP_HASH <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  8. <signature2> <pubKey2> <pubKeyHash2> <pubKeyHash2> OP_EQUALVERIFY OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  9. <signature2> <pubKey2> OP_CHECKSIGVERIFY OP_ENDIF <0x01>
  10. <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 ;)

  • Interesting, thank you. One question though, in the first case you have put something on alternative stack and you left it there, is that okay? – Wapac Feb 15 '18 at 10:35
  • @Wapac Yes, I think so. There does not seem to be any code checking if there is anything left in the alt stack in the script evaluation function (github.com/bitcoin/bitcoin/blob/master/src/script/…). – cpsola Feb 22 '18 at 12:29

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.