github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/script/checker.go (about)

     1  package script
     2  
     3  import (
     4  	"encoding/hex"
     5  	"fmt"
     6  
     7  	"github.com/piotrnar/gocoin/lib/btc"
     8  )
     9  
    10  type SigChecker struct {
    11  	Tx     *btc.Tx
    12  	Idx    int
    13  	Amount uint64
    14  }
    15  
    16  func (c *SigChecker) evalChecksig(vchSig, vchPubKey, p []byte, pbegincodehash int, execdata *btc.ScriptExecutionData, ver_flags uint32, sigversion int) (ok, fSuccess bool) {
    17  	if sigversion == SIGVERSION_BASE || sigversion == SIGVERSION_WITNESS_V0 {
    18  		return c.evalChecksigPreTapscript(vchSig, vchPubKey, p, pbegincodehash, ver_flags, sigversion)
    19  	}
    20  	if sigversion == SIGVERSION_TAPSCRIPT {
    21  		return c.evalChecksigTapscript(vchSig, vchPubKey, execdata, ver_flags, sigversion)
    22  	}
    23  	panic("should not get here")
    24  }
    25  
    26  func (c *SigChecker) evalChecksigTapscript(sig, pubkey []byte, execdata *btc.ScriptExecutionData, flags uint32, sigversion int) (ok, success bool) {
    27  	/*
    28  	 *  The following validation sequence is consensus critical. Please note how --
    29  	 *    upgradable public key versions precede other rules;
    30  	 *    the script execution fails when using empty signature with invalid public key;
    31  	 *    the script execution fails when using non-empty invalid signature.
    32  	 */
    33  	success = len(sig) > 0
    34  	if success {
    35  		// Implement the sigops/witnesssize ratio test.
    36  		// Passing with an upgradable public key version is also counted.
    37  		execdata.M_validation_weight_left -= VALIDATION_WEIGHT_PER_SIGOP_PASSED
    38  		if execdata.M_validation_weight_left < 0 {
    39  			if DBG_ERR {
    40  				fmt.Println("SCRIPT_ERR_TAPSCRIPT_VALIDATION_WEIGHT")
    41  			}
    42  			return
    43  		}
    44  	}
    45  	if len(pubkey) == 0 {
    46  		if DBG_ERR {
    47  			fmt.Println("SCRIPT_ERR_PUBKEYTYPE")
    48  		}
    49  		return
    50  	} else if len(pubkey) == 32 {
    51  		if success && !c.CheckSchnorrSignature(sig, pubkey, sigversion, execdata) {
    52  			if DBG_ERR {
    53  				fmt.Println("evalChecksigTapscript: CheckSchnorrSignature failed")
    54  			}
    55  			return
    56  		}
    57  	} else {
    58  		/*
    59  		 *  New public key version softforks should be defined before this `else` block.
    60  		 *  Generally, the new code should not do anything but failing the script execution. To avoid
    61  		 *  consensus bugs, it should not modify any existing values (including `success`).
    62  		 */
    63  		if (flags & VER_DIS_PUBKEYTYPE) != 0 {
    64  			fmt.Println("SCRIPT_ERR_DISCOURAGE_UPGRADABLE_PUBKEYTYPE")
    65  			return
    66  		}
    67  	}
    68  
    69  	ok = true
    70  	return
    71  }
    72  
    73  func (c *SigChecker) evalChecksigPreTapscript(vchSig, vchPubKey, p []byte, pbegincodehash int, ver_flags uint32, sigversion int) (ok, fSuccess bool) {
    74  	scriptCode := p[pbegincodehash:]
    75  
    76  	// Drop the signature in pre-segwit scripts but not segwit scripts
    77  	if sigversion == SIGVERSION_BASE {
    78  		var found int
    79  		scriptCode, found = delSig(scriptCode, vchSig)
    80  		if found > 0 && (ver_flags&VER_CONST_SCRIPTCODE) != 0 {
    81  			if DBG_ERR {
    82  				fmt.Println("SCRIPT_ERR_SIG_FINDANDDELETE SIN")
    83  			}
    84  			return
    85  		}
    86  	}
    87  
    88  	// BIP-0066
    89  	if !CheckSignatureEncoding(vchSig, ver_flags) || !CheckPubKeyEncoding(vchPubKey, ver_flags, sigversion) {
    90  		if DBG_ERR {
    91  			fmt.Println("Invalid Signature Encoding A")
    92  		}
    93  		return
    94  	}
    95  
    96  	if len(vchSig) > 0 {
    97  		var sh []byte
    98  		if sigversion == SIGVERSION_WITNESS_V0 {
    99  			if DBG_SCR {
   100  				fmt.Println("getting WitnessSigHash error")
   101  			}
   102  			sh = c.Tx.WitnessSigHash(scriptCode, c.Amount, c.Idx, int32(vchSig[len(vchSig)-1]))
   103  		} else {
   104  			sh = c.Tx.SignatureHash(scriptCode, c.Idx, int32(vchSig[len(vchSig)-1]))
   105  		}
   106  		if DBG_SCR {
   107  			fmt.Println("EcdsaVerify", hex.EncodeToString(sh))
   108  			fmt.Println(" key:", hex.EncodeToString(vchPubKey))
   109  			fmt.Println(" sig:", hex.EncodeToString(vchSig))
   110  		}
   111  		fSuccess = btc.EcdsaVerify(vchPubKey, vchSig, sh)
   112  		if DBG_SCR {
   113  			fmt.Println(" ->", fSuccess)
   114  		}
   115  	}
   116  	if !fSuccess && DBG_SCR {
   117  		fmt.Println("EcdsaVerify fail 1", c.Tx.Hash.String())
   118  	}
   119  
   120  	if !fSuccess && (ver_flags&VER_NULLFAIL) != 0 && len(vchSig) > 0 {
   121  		if DBG_ERR {
   122  			fmt.Println("SCRIPT_ERR_SIG_NULLFAIL-1")
   123  		}
   124  		return
   125  	}
   126  	ok = true
   127  	return
   128  }
   129  
   130  func (c *SigChecker) verifyECDSA(data, sig, pubkey []byte, sigversion int) bool {
   131  	if len(sig) == 0 {
   132  		return false
   133  	}
   134  
   135  	nHashType := int32(sig[len(sig)-1])
   136  
   137  	var sh []byte
   138  
   139  	if sigversion == SIGVERSION_WITNESS_V0 {
   140  		sh = c.Tx.WitnessSigHash(data, c.Amount, c.Idx, nHashType)
   141  	} else {
   142  		sh = c.Tx.SignatureHash(data, c.Idx, nHashType)
   143  	}
   144  	return btc.EcdsaVerify(pubkey, sig, sh)
   145  }
   146  
   147  func (c *SigChecker) CheckSchnorrSignature(sig, pubkey []byte, sigversion int, execdata *btc.ScriptExecutionData) bool {
   148  	if len(sig) != 64 && len(sig) != 65 {
   149  		if DBG_ERR {
   150  			fmt.Println("SCRIPT_ERR_SCHNORR_SIG_SIZE")
   151  		}
   152  		return false
   153  	}
   154  	hashtype := byte(btc.SIGHASH_DEFAULT)
   155  	if len(sig) == 65 {
   156  		hashtype = sig[64]
   157  		if hashtype == btc.SIGHASH_DEFAULT {
   158  			if DBG_ERR {
   159  				fmt.Println("SCRIPT_ERR_SCHNORR_SIG_HASHTYPE")
   160  			}
   161  			return false
   162  		}
   163  		sig = sig[:64]
   164  	}
   165  	sh := c.Tx.TaprootSigHash(execdata, c.Idx, hashtype, sigversion == SIGVERSION_TAPSCRIPT)
   166  	return btc.SchnorrVerify(pubkey, sig, sh)
   167  }