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 }