Script To Limit Transactions To Specific Wallets I am trying to write a script that will allow the receiver of my coins to only spend them on two wallets I specify. After that check has been done I want to perform the usual verification that the current client does to verify a transaction. This is where I am at, but I am not sure if things are in the right order, if OP_EQUAL pushes to the stack, and if OP_BOOLOR reads from it. 

scriptPubKey: OP_EQUAL Wallet1_Value [Wallet] 
              OP_EQUAL Wallet2_Value [Wallet] 
              OP_BOOLOR 
              OP_VERIFY OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG

scriptSig: [Wallet] [Wallet] [sig] [pubKey]
How to use OP_BOOLOR and OP_EQUAL?

You can see the actual implementation for script opcodes in Bitcoin's script.cpp.

OP_BOOLOR does this:

[...]
CBigNum bn1 = CastToBigNum(stacktop(-2));
CBigNum bn2 = CastToBigNum(stacktop(-1));
CBigNum bn;
[...]
case OP_BOOLOR:              bn = (bn1 != bnZero || bn2 != bnZero); break;
[...]
popstack(stack);
popstack(stack);
stack.push_back(bn.getvch());
[...]


So it's effectively reading from the stack, popping the values and pushing the result.

OP_EQUAL is pretty much the same:

[...]
popstack(stack);
popstack(stack);
stack.push_back(fEqual ? vchTrue : vchFalse);
[...]


It's popping two values from the top and pushing the result of the comparison.



Is the script correct?

Let's run the scripts and see what happens! scriptSig is executed first:

scriptSig: [Wallet] [Wallet] [sig] [pubKey]


This code is just pushing into the stack, so after the scriptSig runs the stack looks like this:

[pubKey] &lt;- TOP OF THE STACK
[sig]
[Wallet]
[Wallet]


Notice the elements are reversed. The first thing pushed goes to the bottom of the stack.

Now scriptPubKey is run keeping the contents of the stack resulting from running scriptSig. If we do that with your script...

scriptPubKey: OP_EQUAL Wallet1_Value [Wallet] 
              OP_EQUAL Wallet2_Value [Wallet] 
              OP_BOOLOR 
              OP_VERIFY OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG


...the first thing that gets executed is OP_EQUAL, which compares the top two elements of the stack [pubKey]  [sig] which are obviously not equal so 0 (false) is pushed. I'll just stop here since it won't make sense at all to continue.



Building the correct script

I guessed what you actually meant to do, and this are my proposed scripts.

First, I guess the spending user supplies [sig], [pubKey] and [Wallet] where [Wallet] is either Wallet1_Value or Wallet2_Value to be able to spend the funds:

scriptSig: [sig] [pubKey] [Wallet]

Final stack after running:
    [Wallet] &lt;- TOP OF THE STACK
    [pubKey]
    [sig]


That's scriptSig, and it's what a user supplies when he wants to spend the funds. We're done! Let's build the next step, i.e. the scriptPubKey that checks if the supplied values are fine.

The first thing you want to do is to check whether [Wallet] is one of Wallet1_Value or Wallet2_Value. First let's duplicate [Wallet] so we can check it twice. The first step in scriptPubKey is OP_DUP. Let's run both scriptSig first and the the new scriptPubKey:

scriptSig: [sig] [pubKey] [Wallet]
scriptPubKey: OP_DUP 

Final stack:
    [Wallet] &lt;- TOP OF THE STACK
    [Wallet]
    [pubKey]
    [sig]


Of course we want to check it against Wallet1_Value first:

scriptSig: [sig] [pubKey] [Wallet]
scriptPubKey: OP_DUP [Wallet1_value]

Final stack:
    Wallet1_Value &lt;- TOP OF THE STACK
    [Wallet]
    [Wallet]
    [pubKey]
    [sig]


And now check the top two items for equality:

scriptSig: [sig] [pubKey] [Wallet]
scriptPubKey: OP_DUP [Wallet1_value] OP_EQUAL

Final stack:
    (== Wallet1, either TRUE or FALSE) &lt;- TOP OF THE STACK
    [Wallet]
    [pubKey]
    [sig]


Now we want to check the duplicate [Wallet] against Wallet2_value but the previous result is at the top of the stack. We must swap it first using OP_SWAP:

scriptSig: [sig] [pubKey] [Wallet]
scriptPubKey: OP_DUP [Wallet1_value] OP_EQUAL OP_SWAP

Final stack:
    [Wallet] &lt;- TOP OF THE STACK
    (== Wallet1)
    [pubKey]
    [sig]


Again, we push the value we want to check, and OP_EQUAL it:

scriptSig: [sig] [pubKey] [Wallet]
scriptPubKey: OP_DUP [Wallet1_value] OP_EQUAL OP_SWAP [Wallet2_value] OP_EQUAL

Final stack:
    (== Wallet2) &lt;- TOP OF THE STACK
    (== Wallet1)
    [pubKey]
    [sig]


The script is pretty much done. Now just OP_BOOLOR OP_VERIFY:

scriptSig: [sig] [pubKey] [Wallet]
scriptPubKey: OP_DUP [Wallet1_value] OP_EQUAL OP_SWAP [Wallet2_value] OP_EQUAL OP_BOOLOR OP_VERIFY


If OP_VERIFY finds FALSE at the top of the stack it will reject the transaction. If it finds TRUE the script continues and the stack looks like this:

Final stack if correct [Wallet] was provided:
    [pubKey]
    [sig]


Which is what the stack looks like after a regular scriptSig! So the rest of the scriptPubKey is just a regular pay-to-pubkey-hash script. The final scriptPubKey is:

OP_DUP [Wallet1_value] OP_EQUAL OP_SWAP [Wallet2_value] OP_EQUAL OP_BOOLOR OP_VERIFY
OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG




Actual security

Now, regardless of the order, the script is not very secure. I get this might just be an exercise in understanding scripts or is not meant to be secure (it might be only a check to avoid spending from unwanted wallets) but I think it's important to show how this is actually not secure at all.

Whenever you publish a transaction using this scheme, the output scriptPubKey is publicly available and looks like this:

OP_DUP [Wallet1_value] OP_EQUAL OP_SWAP [Wallet2_value] OP_EQUAL OP_BOOLOR OP_VERIFY
OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG


Both Wallet1_value and Wallet2_value are public for anyone to see in the blockchain! The security still depends ONLY on [sig] [pubKey] since I know exactly what's required to spend the transaction, i.e. the script security is equivalent to a regular pay-to-pubkey-hash transaction!



EDIT: A little bit safer (response to comment)


  Could you require Wallet1_value and Wallet2_value be hashes instead? Then the scriptsig would have to supply a hash of one of the two wallets.


Yes. Actually it's very easy (changes shown in bold face):

OP_HASH256 OP_DUP [Wallet1_hash] OP_EQUAL OP_SWAP [Wallet2_hash] OP_EQUAL OP_BOOLOR OP_VERIFY OP_DUP OP_HASH160 [pubKeyHash] OP_EQUALVERIFY OP_CHECKSIG

As you can see the top of the stack is hashed (OP_HASH160 or OP_HASH256, whichever you prefer) before duplication, so now you can compare the provided data to match with one of two hashes instead of values.

This is a bit better since the data is not there in plain sight. You would have to brute-force to find one of WalletN_hash. The problem is as soon as you spend it, the WalletN_value becomes public in the spending transaction, so WalletN_hash can't be used in a transaction again! It would be one-use only. If you published several transactions with the same WalletN_hash, you'd have to spend all outputs at the same time or else the unspent ones might be hijacked.

Bear in mind the scheme is still secure because there are signatures involved. If the scriptPubKey lacked the standard signatue verification it would just be:

OP_HASH256 OP_DUP Wallet1_hash OP_EQUAL OP_SWAP Wallet2_hash OP_EQUAL OP_BOOLOR OP_VERIFY


Any miner could listen for this type of transactions and, as soon as anyone tried to spend one with scriptSig = [WalletN_value], the transaction could be modified (even the outputs!) instead of relaying it since the transaction is not signed at all, so the miner could redeem the outputs himself.