Verifying a digital signature that a transaction is going to an output with value X inside a script

0

Edit; after writing this post i have found that OP_CHECKDATASIG is basically this in a nutshell. It is implemented on Bitcoin Cash and may soon be on Bitcoin Core as well.

Someone has even written this post into a Bitcoin Cash smart contract: https://honest.cash/pein_sama/spending-constraints-with-op_checkdatasig-172

nick carraway

Posted 2019-03-30T03:13:17.690

Reputation: 215

Answers

0

Yes, this is possible in the Bitcoin Cash blockchain only. It would also be possible in OP_CODES, but much harder.

Here's how it works:

In the script signature, we check both OP_CHECKSIG and OP_CHECKDATASIG. First, OP_CHECKSIG goes "outside" and checks that the signature validates the transaction outputs. Thus, the signature variable has now been externally-verified to contain information from the transaction outputs.

In OP_CHECKDATASIG, we then verify that an input variable called "preimage" is the precursor to this exact "signature". Since digital signatures are unique, this pre-image must be the transaction itself. So, we now have a variable called preimage, that, transitively, is externally-verified to the transaction outputs. Coincidentally, this is also the raw transaction data containing the outputs.

Finally, we step through the preimage to determine the contents of the transaction before allowing spending. Very cool. (edited)

nick carraway

Posted 2019-03-30T03:13:17.690

Reputation: 215

1

but in bitcoin usually the message is a hash of the previous transaction and the 'to' pubkey-hash and/or transaction? Unless i am missing something, the SIGHASH_SINGLE parameter specifically signs only the input and output of the new transaction. So, if you could create this input and output, and sign it inside an OP_CODE with a privatekey, you could verify that an output was going to a particular person inside a bitcoin script sig. Of course, the private key holding that UTXO would be unusable except for returning BTC to the user, or perhaps another pubkey could be used to spend the UTXO.

This is incorrect. Transaction signing works by:

for every input i in inputs:
    Start with a transaction skeleton that matches the transaction for non-input/output fields like tx version
    Add the input i
    Add other inputs and outputs based on the sighash flag
    Hash this update tx skeleton
    Sign the hash

The SIGHASH flags simplify specify which inputs and outputs are covered by the signature. For SIGHASH_ALL, the entire input and output set is signed. For SIGHASH_SINGLE, only the output corresponding to the index of the input is signed (for the first input in a tx, the first output will be signed). You also have additional options such as ANYONE_CAN_PAY which allow addition inputs to be added later, by only signing your input (for use with coinjoins).

By using SIGHASH_ALL | SIGHASH_ANYONECANPAY or SIGHASH_SINGLE | SIGHASH_ANYONECANPAY flags, if you already control an output, you can specify something such as:

If this output is used as an input, at least X BTC must be sent to {these|this} new output(s).

However, this restriction only applies if the final transaction uses this specific signed input - nothing prevents you from creating another signed tx that spends that same output to a different destination and broadcasting it first.

Your example fails since within the signature, you have no information about the output. The data that is signed is that of an augmented tx skeleton as a whole - you cannot use Bitcoin Script to inspect a subset of that data and validate the signature.

To take the example another way, let us say we construct a bitcoin script equivalent to:

Accept a signature and a public key
Verify that the signature is over the data (input,hash160(public_key)
Verify the signature is performed by the same key that unlocks the input being spent

This would seem to imply that we can sign the destination public key using the same private key that owns the input, and then have a script that validates both the tx signature, and the signature over the public key we claim to send to.

However, in this case, nothing prevents you from feeding a valid signature and destination public key to the script, but specifying a completely different output in the actual tx - This is because there is simply no way for the Bitcoin Script program to read and check where the tx output(s) are actually going.

Raghav Sood

Posted 2019-03-30T03:13:17.690

Reputation: 10 897

Wait, really? I can sign a group of inputs, and a group of outputs. Where the inputs provides only 0.1 BTC from my accounts. And the outputs provide 10.0 BTC as output. (invalid tx) And If i sign it with "SIGHASH_ALL | SIGHASH_ANYONE_CAN_PAY", then the transaction will go through if someone adds inputs totaling 9.9 BTC? (And I understand that it would only apply to this signed input; I could rebroadcast if i wanted)nick carraway 2019-03-30T04:17:22.537

Or can you still only sign valid TX like this?nick carraway 2019-03-30T04:18:37.830

1

Yes, that's correct. You can construct a partial tx, with insufficient inputs or outputs and wait for other people to complete it. I wrote a blog post on this some time ago with more detail/examples, if you are interested: http://raghavsood.com/blog/2018/06/10/bitcoin-signature-types-sighash

Raghav Sood 2019-03-30T04:19:12.877

Thanks. I have been studying your blog post. It seems if I want people to be able to add outputs, the SIGHASH_SINGLE is the only way to do it. But this limits to a single output. I wish that I could sign multiple outputs and still have someone else add outputs.nick carraway 2019-03-30T05:00:40.193

You can, in a round about way. If you own n utxos, you can create a tx with n inputs, each signed with SIGHASH_SINGLE for their corresponding output (1 through n). Then, anyone else can add more outputs after the fifth oneRaghav Sood 2019-03-30T05:49:44.570

But wouldn't someone be able to degroup these transactions? I need to ensure that if one utxo is broadcasted, so is the othernick carraway 2019-03-30T12:47:51.627

This is exact stack exchange post is implemented in bitcoin cash https://honest.cash/pein_sama/spending-constraints-with-op_checkdatasig-172

nick carraway 2019-03-30T22:11:46.807

But I think your explanation still holdsnick carraway 2019-03-30T23:23:45.747

@nickcarraway OP_CHECKDATASIG is not available in Bitcoin, from what I recall. You might be able to use it on one of the forks, though.Raghav Sood 2019-03-31T03:14:49.103

I think it's coming to lightning. Also, doesn't your explanation still hold? It's still just an unlocking script that takes information from the input stack and unlocks the coin. Just want to be surenick carraway 2019-03-31T16:49:54.970

Someone could still provide a fake signature that says the coins are going one place, where in the actual transaction they are going to the wrong place right?nick carraway 2019-03-31T16:55:35.650

????????????????nick carraway 2019-04-01T04:02:16.067

are you alive sirnick carraway 2019-04-01T04:22:28.500