I'm trying to write a scriptPubKey for a transaction which checks that the hash of the top value in the scriptSig is equal to either one of two fixed values and if so will do the normal transaction signature checks to allow the owner of a specific bitcoin address to spend them; if the scriptSig value is not equal to either one of the fixed values then the spending transaction should be marked as invalid.

I'm trying to keep the scriptPubKey as small as possible, i.e. avoiding hard-coded duplications of pubKeyHash and/or duplications of large chunks of scripting.

Here's what I've got so far...



The scriptSig would look like this...


<sig> <pubKey> <A>

The intention is that the transaction would pay out if ( HASH160(A)=B or HASH160(A)=C ) and sig, pubKey and pubKeyHash were all valid in the normal way.

My worry arises from OP_NOTIF; the scripting section of the Bitcoin wiki says that OP_NOTIF removes the top stack value...I assume that it is removed as the OP_NOTIF evaluates it and it is removed regardless of whether it is TRUE or FALSE. Is that correct?

The latter assumption is why I've duplicated the result of the first OP_EQUAL so that I can OP_VERIFY it after the conditional line (assuming that it was TRUE and hasn't otherwise been OP_DROPped by the conditional line).

Would my proposed scriptPubKey have the desired result (without nasty side effects) or is there something smaller/simpler (e.g. using OP_IFDUP instead of an OP_DUP and a conditional OP_DROP) or, if my script is plain wrong, what would a workable script look like?

I should say that the point of this transaction is not to effect a multi-signature transaction; it's to effect a kind of single-signature plus 1-of-2 'passwords' transaction.

  • 1
    Another approach: OP_HASH160 OP_DUP <B> OP_EQUAL OP_NOTIF <C> OP_EQUAL OP_ELSE OP_DROP OP_1 OP_ENDIF OP_VERIFY OP_DUP OP_HASH160 <pubKeyHash> OP_EQUALVERIFY OP_CHECKSIG – ScripterRon Mar 31 '14 at 16:17
  • This one is great. Thanks scripterron. :-) – Phil Dann Ward Mar 31 '14 at 17:49

OP_IF and OP_NOTIF always remove the top stack element.

Note that this is a non-standard transaction and may not be relayed by the network. It would be interesting to see what happens.

  • Using your suggestion I think OP_VERIFY is applied to HASH160(A) for HASH160(A)=B; the duplication of a TRUE result from the first OP_EQUAL is popped by the OP_NOTIF and the original TRUE result of the first OP_EQUAL is then popped by the ELSE OP_DROP before the OP_VERIFY...or am I reading your script incorrectly? Is it OK to do that with OP_VERIFY; the bitcoin wiki seems to suggest that the OP_VERIFY argument is only(?) either '0' (i.e. OP_FALSE) or '1' (i.e. OP_TRUE), rather than being as general as any non-zero argument being treated as TRUE? – Phil Dann Ward Mar 31 '14 at 16:35
  • OP_VERIFY considers any non-zero value to be TRUE. See my comment on your question for a script that I think will also work. – ScripterRon Mar 31 '14 at 17:02
  • I'm still trying to get my newbie brain to understand the subtleties of bitcoin scripting so, out of interest, would your previous version of the script that OP_VERIFYed HASH160(A) have gone wrong if, by some amazing (non?) coincidence, HASH160(A)=B=OP_0? Or is HASH160(A)=OP_0 impossible? – Phil Dann Ward Mar 31 '14 at 20:09
  • I think it would be safe to assume the hash would not be zero. I'm not a mathematician, so I can't tell you if a zero result is impossible. But a zero hash is used in several parts of the bitcoin protocol to indicate no hash value was provided (the 'getblocks' message for example) – ScripterRon Mar 31 '14 at 21:39
  • So, to answer your question, you could remove the OP_ELSE clause in the above script and it would still work. As long as the top stack element is non-zero, OP_VERIFY will succeed. – ScripterRon Mar 31 '14 at 21:48

So your inputs are:

<sig> <pubkey> <a>

And you want to verify that Hash160(a) == Hash1 or Hash2, and that sig is a valid signature by pubkey? Based on your original script, it looks like you also want to verify that pubkey matches a hash in the script.

So, the best way to do this is like this:

// stack now has <sig> <pubkey> <Hash160(a)> <Hash160(a)==Hash1>
// stack now has <sig> <pubkey> <Hash160(a)==Hash1> <Hash160(a)>
<Hash2> OP_EQUAL
// stack now has <sig> <pubkey> <Hash160(a)==Hash1> <Hash160(a)==Hash2>
// stack now has <sig> <pubkey> <Hash160(a)==Hash1 OR Hash160(a)==Hash2>
// stack now contains <sig> <pubkey>, and if <a> didn't pass the test the transaction has already failed
// now just do a norma pay-to-pubkey-hash for the rest of it

(I realize this is an old question, but I didn't see that until I'd already written up the script for it, so I'm posting anyway...)

  • I realize this is an old question Don't worry about it! There's nothing wrong with answering old questions - there's a badge for it, actually. +1 – Nick ODell Oct 27 '14 at 21:17

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.