github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/script/misc.go (about) 1 package script 2 3 import ( 4 "encoding/hex" 5 "fmt" 6 7 "github.com/piotrnar/gocoin/lib/btc" 8 "github.com/piotrnar/gocoin/lib/secp256k1" 9 ) 10 11 func IsP2KH(scr []byte) bool { 12 return len(scr) == 25 && scr[0] == 0x76 && scr[1] == 0xa9 && 13 scr[2] == 0x14 && scr[23] == 0x88 && scr[24] == 0xac 14 } 15 16 func IsP2SH(scr []byte) bool { 17 return len(scr) == 23 && scr[0] == 0xa9 && scr[1] == 0x14 && scr[22] == 0x87 18 } 19 20 func IsP2WPKH(scr []byte) bool { 21 return len(scr) == 22 && scr[0] == 0 && scr[1] == 20 22 } 23 24 func IsP2WSH(scr []byte) bool { 25 return len(scr) == 34 && scr[0] == 0 && scr[1] == 32 26 } 27 28 func IsP2TAP(scr []byte) bool { 29 return len(scr) == 34 && scr[0] == btc.OP_1 && scr[1] == 32 30 } 31 32 func IsP2PK(scr []byte) (bool, []byte) { 33 if len(scr) == 35 && scr[0] == 33 && scr[34] == 0xac && (scr[1] == 0x02 || scr[1] == 0x03) { 34 return true, scr[1:34] 35 } 36 if len(scr) == 67 && scr[0] == 65 && scr[66] == 0xac && scr[1] == 0x04 { 37 var pk secp256k1.XY 38 if pk.ParsePubkey(scr[1:66]) && pk.IsValid() { 39 return true, scr[1:66] 40 } 41 //println("invalid uncompressed pubkey") 42 } 43 return false, nil 44 } 45 46 func IsUnspendable(scr []byte) bool { 47 if len(scr) > 0 && scr[0] == 0x6a { 48 return true 49 } 50 if len(scr) > MAX_SCRIPT_SIZE { 51 return true 52 } 53 if len(scr) == 67 && scr[0] == 65 && scr[66] == 0xac && scr[1] == 0x04 { 54 var pk secp256k1.XY 55 if !pk.ParsePubkey(scr[1:66]) || !pk.IsValid() { 56 return true // pay to public key script with invalid (uncompressed) key 57 } 58 } 59 return false 60 } 61 62 func IsValidSignatureEncoding(sig []byte) bool { 63 // Minimum and maximum size constraints. 64 if len(sig) < 9 { 65 return false 66 } 67 if len(sig) > 73 { 68 return false 69 } 70 71 // A signature is of type 0x30 (compound). 72 if sig[0] != 0x30 { 73 return false 74 } 75 76 // Make sure the length covers the entire signature. 77 if int(sig[1]) != len(sig)-3 { 78 return false 79 } 80 81 // Extract the length of the R element. 82 lenR := uint(sig[3]) 83 84 // Make sure the length of the S element is still inside the signature. 85 if 5+lenR >= uint(len(sig)) { 86 return false 87 } 88 89 // Extract the length of the S element. 90 lenS := uint(sig[5+lenR]) 91 92 // Verify that the length of the signature matches the sum of the length 93 // of the elements. 94 if lenR+lenS+7 != uint(len(sig)) { 95 return false 96 } 97 98 // Check whether the R element is an integer. 99 if sig[2] != 0x02 { 100 return false 101 } 102 103 // Zero-length integers are not allowed for R. 104 if lenR == 0 { 105 return false 106 } 107 108 // Negative numbers are not allowed for R. 109 if (sig[4] & 0x80) != 0 { 110 return false 111 } 112 113 // Null bytes at the start of R are not allowed, unless R would 114 // otherwise be interpreted as a negative number. 115 if lenR > 1 && sig[4] == 0x00 && (sig[5]&0x80) == 0 { 116 return false 117 } 118 119 // Check whether the S element is an integer. 120 if sig[lenR+4] != 0x02 { 121 return false 122 } 123 124 // Zero-length integers are not allowed for S. 125 if lenS == 0 { 126 return false 127 } 128 129 // Negative numbers are not allowed for S. 130 if (sig[lenR+6] & 0x80) != 0 { 131 return false 132 } 133 134 // Null bytes at the start of S are not allowed, unless S would otherwise be 135 // interpreted as a negative number. 136 if lenS > 1 && (sig[lenR+6] == 0x00) && (sig[lenR+7]&0x80) == 0 { 137 return false 138 } 139 140 return true 141 } 142 143 func IsDefinedHashtypeSignature(sig []byte) bool { 144 if len(sig) == 0 { 145 return false 146 } 147 htype := sig[len(sig)-1] & (btc.SIGHASH_ANYONECANPAY ^ 0xff) 148 if htype < btc.SIGHASH_ALL || htype > btc.SIGHASH_SINGLE { 149 return false 150 } 151 return true 152 } 153 154 func IsLowS(sig []byte) bool { 155 if !IsValidSignatureEncoding(sig) { 156 return false 157 } 158 159 ss, e := btc.NewSignature(sig) 160 if e != nil { 161 return false 162 } 163 164 return ss.IsLowS() 165 } 166 167 func CheckSignatureEncoding(sig []byte, flags uint32) bool { 168 if len(sig) == 0 { 169 return true 170 } 171 if (flags&(VER_DERSIG|VER_STRICTENC)) != 0 && !IsValidSignatureEncoding(sig) { 172 return false 173 } else if (flags&VER_LOW_S) != 0 && !IsLowS(sig) { 174 return false 175 } else if (flags&VER_STRICTENC) != 0 && !IsDefinedHashtypeSignature(sig) { 176 return false 177 } 178 return true 179 } 180 181 func IsCompressedOrUncompressedPubKey(pk []byte) bool { 182 if len(pk) < 33 { 183 return false 184 } 185 if pk[0] == 0x04 { 186 if len(pk) != 65 { 187 return false 188 } 189 } else if pk[0] == 0x02 || pk[0] == 0x03 { 190 if len(pk) != 33 { 191 return false 192 } 193 } else { 194 return false 195 } 196 return true 197 } 198 199 func IsCompressedPubKey(pk []byte) bool { 200 if len(pk) != 33 { 201 return false 202 } 203 if pk[0] == 0x02 || pk[0] == 0x03 { 204 return true 205 } 206 return false 207 } 208 209 func CheckPubKeyEncoding(pk []byte, flags uint32, sigversion int) bool { 210 if (flags&VER_STRICTENC) != 0 && !IsCompressedOrUncompressedPubKey(pk) { 211 return false 212 } 213 // Only compressed keys are accepted in segwit 214 if (flags&VER_WITNESS_PUBKEY) != 0 && sigversion == SIGVERSION_WITNESS_V0 && !IsCompressedPubKey(pk) { 215 return false 216 } 217 return true 218 } 219 220 // https://bitcointalk.org/index.php?topic=1240385.0 221 func checkMinimalPush(d []byte, opcode int) bool { 222 if DBG_SCR { 223 fmt.Printf("checkMinimalPush %02x %s\n", opcode, hex.EncodeToString(d)) 224 } 225 if len(d) == 0 { 226 // Could have used OP_0. 227 if DBG_SCR { 228 fmt.Println("Could have used OP_0.") 229 } 230 return opcode == 0x00 231 } else if len(d) == 1 && d[0] >= 1 && d[0] <= 16 { 232 // Could have used OP_1 .. OP_16. 233 if DBG_SCR { 234 fmt.Println("Could have used OP_1 .. OP_16.", 0x01+int(d[0]-1), 0x01, int(d[0]-1)) 235 } 236 return opcode == 0x51+int(d[0])-1 237 } else if len(d) == 1 && d[0] == 0x81 { 238 // Could have used OP_1NEGATE. 239 if DBG_SCR { 240 fmt.Println("Could have used OP_1NEGATE.") 241 } 242 return opcode == 0x4f 243 } else if len(d) <= 75 { 244 // Could have used a direct push (opcode indicating number of bytes pushed + those bytes). 245 if DBG_SCR { 246 fmt.Println("Could have used a direct push (opcode indicating number of bytes pushed + those bytes).") 247 } 248 return opcode == len(d) 249 } else if len(d) <= 255 { 250 // Could have used OP_PUSHDATA. 251 if DBG_SCR { 252 fmt.Println("Could have used OP_PUSHDATA.") 253 } 254 return opcode == 0x4c 255 } else if len(d) <= 65535 { 256 // Could have used OP_PUSHDATA2. 257 if DBG_SCR { 258 fmt.Println("Could have used OP_PUSHDATA2.") 259 } 260 return opcode == 0x4d 261 } 262 fmt.Println("All checks passed") 263 return true 264 } 265 266 func CheckSequence(tx *btc.Tx, inp int, seq int64) bool { 267 if tx.Version < 2 { 268 return false 269 } 270 271 toseq := int64(tx.TxIn[inp].Sequence) 272 273 if (toseq & SEQUENCE_LOCKTIME_DISABLE_FLAG) != 0 { 274 return false 275 } 276 277 // Mask off any bits that do not have consensus-enforced meaning 278 // before doing the integer comparisons 279 const nLockTimeMask = SEQUENCE_LOCKTIME_TYPE_FLAG | SEQUENCE_LOCKTIME_MASK 280 txToSequenceMasked := toseq & nLockTimeMask 281 nSequenceMasked := seq & nLockTimeMask 282 283 if !((txToSequenceMasked < SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked < SEQUENCE_LOCKTIME_TYPE_FLAG) || 284 (txToSequenceMasked >= SEQUENCE_LOCKTIME_TYPE_FLAG && nSequenceMasked >= SEQUENCE_LOCKTIME_TYPE_FLAG)) { 285 return false 286 } 287 288 // Now that we know we're comparing apples-to-apples, the 289 // comparison is a simple numeric one. 290 if nSequenceMasked > txToSequenceMasked { 291 return false 292 } 293 294 return true 295 } 296 297 func CompressScript(scr []byte) (out []byte) { 298 if IsP2KH(scr) { 299 out = make([]byte, 21) 300 //out[0] = 0x00 301 copy(out[1:], scr[3:23]) 302 return 303 } 304 if IsP2SH(scr) { 305 out = make([]byte, 21) 306 out[0] = 0x01 307 copy(out[1:], scr[2:22]) 308 return 309 } 310 311 if ok, pk := IsP2PK(scr); ok { 312 out = make([]byte, 33) 313 copy(out[1:], pk[1:33]) 314 out[0] = pk[0] 315 if pk[0] == 0x04 { 316 out[0] |= pk[64] & 0x01 317 } 318 } 319 return 320 } 321 322 func DecompressScript(data []byte) (script []byte) { 323 switch data[0] { 324 case 0x00: 325 script = make([]byte, 25) 326 script[0] = 0x76 327 script[1] = 0xa9 328 script[2] = 20 329 copy(script[3:23], data[1:21]) 330 script[23] = 0x88 331 script[24] = 0xac 332 333 case 0x01: 334 script = make([]byte, 23) 335 script[0] = 0xa9 336 script[1] = 20 337 copy(script[2:22], data[1:]) 338 script[22] = 0x87 339 340 case 0x02, 0x03: 341 script = make([]byte, 35) 342 script[0] = 33 343 copy(script[1:34], data) 344 script[34] = 0xac 345 346 case 0x04, 0x05: 347 var vch [33]byte 348 var pk secp256k1.XY 349 vch[0] = data[0] - 2 350 copy(vch[1:], data[1:]) 351 pk.ParsePubkey(vch[:]) 352 script = make([]byte, 67) 353 script[0] = 65 354 pk.GetPublicKey(script[1:66]) 355 script[66] = 0xac 356 } 357 return 358 }