In-depth study of OP_PUSH_TX of Bitcoin script (1)

Anyone who knows Bitcoin Script knows that it is composed of a series of calculation instructions (ie Opcode) and data. Script execution is the process of using instructions to perform operations on data. In other words, the input of this program is determined before it is executed. It is precisely because of this setting that many people subconsciously think that its range of capabilities is also very limited, because it is not "flexible" enough.

What I want to introduce to you today actually breaks through this stereotype and allows us to have a deeper understanding of the power and interest of the script.

We have designed an algorithm so that the script can access the current transaction data where the script is being executed. We call it OP_PUSH_TX , which can put the current transaction on the stack like a pseudo opcode. We implemented it with sCrypt , which is a high-level language that can be compiled into Bitcoin's native script. We will use an example to demonstrate the usage of OP_PUSH_TX.

OP_CHECKSIG

OP_CHECKSIG is the operation code used to verify the ECDSA signature . In theory, it includes two steps:

  1. The current transaction calculate a hash value.
  2. Perform signature verification on this hash value.

Note that the hash value in step 1 can only be the hash value of the current transaction, so OP_CHECKSIG will work normally only when the signed data is the hash value of the current transaction. Signing any other data will not work properly.

OP_PUSH_TX

Overview

Usually, the signature used in OP_CHECKSIG is generated off-chain and passed into the unlocking script as a parameter. In order to access the current transaction, we instead use the script to directly calculate the signature on the chain . For this reason, what is passed into the unlock script as a parameter is no longer the signature, but the current transaction. The ECDMA public-private key pair used to calculate the signature is also passed into the unlocking script as a parameter. Through the current transaction parameters and private key parameters, an ECDMA signature can be calculated, and OP_CHECKSIG can use the public key parameters to verify the calculated signature. If the verification passes, we can be sure that the current transaction parameter passed in the unlock script is the real current transaction, because OP_CHECKSIG will only pass when the signed data is the hash value of the current transaction .

Details

The algorithm to implement OP_PUSH_TX with script is as follows:

  1. Put the current transaction on the top of the stack;
  2. Put the private key on the top of the stack (the private key is published in the script and is only used to calculate the signature and does not control any bitcoin);
  3. Run the ECDSA signature algorithm in the script, and use the transaction and private key put in the stack in steps 1 and 2 to calculate the signature;
  4. Put the public key corresponding to the private key in step 2 on the top of the stack;
  5. Run OP_CHECKSIG;

Steps 1, 2, and 4 are in the unlocking script, and steps 3 and 5 are in the locking script.

If the first step 5 OP_CHECKSIG verify signatures through, then we can confirm that the transaction parameters placed on the stack in step 1 of the current transaction is indeed true, because only the current transaction will be OP_CHECKSIG signature verification by 1 . OP_CHECKSIG does not care whether the signature is generated by an external program off the chain (as in the case of P2PKH) or in a script on the chain (as in the case of OP_PUSH_TX).

It is worth noting that the private key in step 2. Usually the private key is kept secret, but it is public in the script. This is no problem, because this private key does not control Bitcoin, but only participates in the signature calculation to prove that the parameters in step 1 are indeed the current transaction. In fact, this private key can even be reused.

Sighash Preimage

More precisely, the transaction in step 1 is not the complete current transaction data, but the preimage generated from the complete data. In the subsequent calculations, two SHA256 operations will be performed. The preimage format predetermined as follows:

sighashPreimage
Note that the input script is not included.

achieve

sCrypt implements the OP_PUSH_TX algorithm and encapsulates it into a standard contract function Tx.checkPreimageto verify whether the incoming parameter is the preimage of the current transaction. The following demonstrates an example. We use it to develop a contract called CheckLockTimeVerify , which can ensure that the coins in it cannot be spent before a certain time, similar to OP_CLTV . After passing the verification (ie require(Tx.checkPreimage(sighashPreimage))), you can access the data in the current transaction.

contract CheckLockTimeVerify {
    
    
    int matureTime;

    public function spend(bytes sighashPreimage) {
    
    
        // this ensures the preimage is for the current tx
        require(Tx.checkPreimage(sighashPreimage));

        // parse nLocktime
        int len = length(sighashPreimage);
        int nLocktime = this.fromLEUnsigned(sighashPreimage[len - 8 : len - 4]);

        require(nLocktime >= this.matureTime);
    }

    function fromLEUnsigned(bytes b) returns (int) {
    
    
        // append positive sign byte. This does not hurt even when sign bit is already positive
        return unpack(b + b'00');
    }
}

Extend

Using OP_PUSH_TX allows the contract code to access the entire transaction data, including all input and output. We can set any constraints on these data in the contract. This opens up endless possibilities for running various smart contracts on the Bitcoin network, and we will show more examples in the future.

This article is the first in a series of articles that will tell you what Bitcoin smart contracts can do and how to do it.

Thanks

Special thanks to nChain for the original ideas.



  1. Unless there is a hash collision (two pieces of different information have the same hash value), this collision is considered almost impossible. In digital signatures, the signed data is the hash value of the information, not the information itself. ↩︎

Guess you like

Origin blog.csdn.net/freedomhero/article/details/107306604