github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/btc/script.go (about) 1 package btc 2 3 import ( 4 "bytes" 5 "encoding/binary" 6 "encoding/hex" 7 "errors" 8 "fmt" 9 "math/big" 10 "strconv" 11 "strings" 12 ) 13 14 func RawToStack(sig []byte) []byte { 15 if len(sig) == 1 { 16 if sig[0] == 0x81 { 17 return []byte{OP_1NEGATE} 18 } 19 if sig[0] == 0x80 || sig[0] == 0x00 { 20 return []byte{OP_0} 21 } 22 if sig[0] <= 16 { 23 return []byte{OP_1 - 1 + sig[0]} 24 } 25 } 26 bb := new(bytes.Buffer) 27 if len(sig) < OP_PUSHDATA1 { 28 bb.Write([]byte{byte(len(sig))}) 29 } else if len(sig) <= 0xff { 30 bb.Write([]byte{OP_PUSHDATA1}) 31 bb.Write([]byte{byte(len(sig))}) 32 } else if len(sig) <= 0xffff { 33 bb.Write([]byte{OP_PUSHDATA2}) 34 binary.Write(bb, binary.LittleEndian, uint16(len(sig))) 35 } else { 36 bb.Write([]byte{OP_PUSHDATA4}) 37 binary.Write(bb, binary.LittleEndian, uint32(len(sig))) 38 } 39 bb.Write(sig) 40 return bb.Bytes() 41 } 42 43 func int2scr(v int64) []byte { 44 if v == -1 || v >= 1 && v <= 16 { 45 return []byte{byte(v + OP_1 - 1)} 46 } 47 48 neg := v < 0 49 if neg { 50 v = -v 51 } 52 bn := big.NewInt(v) 53 bts := bn.Bytes() 54 if (bts[0] & 0x80) != 0 { 55 if neg { 56 bts = append([]byte{0x80}, bts...) 57 } else { 58 bts = append([]byte{0x00}, bts...) 59 } 60 } else if neg { 61 bts[0] |= 0x80 62 } 63 64 sig := make([]byte, len(bts)) 65 for i := range bts { 66 sig[len(bts)-i-1] = bts[i] 67 } 68 69 return RawToStack(sig) 70 } 71 72 func DecodeScript(pk string) (out []byte, e error) { 73 xx := strings.Split(pk, " ") 74 for i := range xx { 75 v, er := strconv.ParseInt(xx[i], 10, 64) 76 if er == nil { 77 switch { 78 case v == -1: 79 out = append(out, 0x4f) 80 case v == 0: 81 out = append(out, 0x0) 82 case v > 0 && v <= 16: 83 out = append(out, 0x50+byte(v)) 84 default: 85 out = append(out, int2scr(v)...) 86 } 87 } else if len(xx[i]) > 2 && xx[i][:2] == "0x" { 88 d, _ := hex.DecodeString(xx[i][2:]) 89 out = append(out, d...) 90 } else { 91 if len(xx[i]) >= 2 && xx[i][0] == '\'' && xx[i][len(xx[i])-1] == '\'' { 92 out = append(out, RawToStack([]byte(xx[i][1:len(xx[i])-1]))...) 93 } else { 94 if len(xx[i]) > 3 && xx[i][:3] == "OP_" { 95 xx[i] = xx[i][3:] 96 } 97 switch xx[i] { 98 case "RESERVED": 99 out = append(out, 0x50) 100 case "NOP": 101 out = append(out, 0x61) 102 case "VER": 103 out = append(out, 0x62) 104 case "IF": 105 out = append(out, 0x63) 106 case "NOTIF": 107 out = append(out, 0x64) 108 case "VERIF": 109 out = append(out, 0x65) 110 case "VERNOTIF": 111 out = append(out, 0x66) 112 case "ELSE": 113 out = append(out, 0x67) 114 case "ENDIF": 115 out = append(out, 0x68) 116 case "VERIFY": 117 out = append(out, 0x69) 118 case "RETURN": 119 out = append(out, 0x6a) 120 case "TOALTSTACK": 121 out = append(out, 0x6b) 122 case "FROMALTSTACK": 123 out = append(out, 0x6c) 124 case "2DROP": 125 out = append(out, 0x6d) 126 case "2DUP": 127 out = append(out, 0x6e) 128 case "3DUP": 129 out = append(out, 0x6f) 130 case "2OVER": 131 out = append(out, 0x70) 132 case "2ROT": 133 out = append(out, 0x71) 134 case "2SWAP": 135 out = append(out, 0x72) 136 case "IFDUP": 137 out = append(out, 0x73) 138 case "DEPTH": 139 out = append(out, 0x74) 140 case "DROP": 141 out = append(out, 0x75) 142 case "DUP": 143 out = append(out, 0x76) 144 case "NIP": 145 out = append(out, 0x77) 146 case "OVER": 147 out = append(out, 0x78) 148 case "PICK": 149 out = append(out, 0x79) 150 case "ROLL": 151 out = append(out, 0x7a) 152 case "ROT": 153 out = append(out, 0x7b) 154 case "SWAP": 155 out = append(out, 0x7c) 156 case "TUCK": 157 out = append(out, 0x7d) 158 case "CAT": 159 out = append(out, 0x7e) 160 case "SUBSTR": 161 out = append(out, 0x7f) 162 case "LEFT": 163 out = append(out, 0x80) 164 case "RIGHT": 165 out = append(out, 0x81) 166 case "SIZE": 167 out = append(out, 0x82) 168 case "INVERT": 169 out = append(out, 0x83) 170 case "AND": 171 out = append(out, 0x84) 172 case "OR": 173 out = append(out, 0x85) 174 case "XOR": 175 out = append(out, 0x86) 176 case "EQUAL": 177 out = append(out, 0x87) 178 case "EQUALVERIFY": 179 out = append(out, 0x88) 180 case "RESERVED1": 181 out = append(out, 0x89) 182 case "RESERVED2": 183 out = append(out, 0x8a) 184 case "1ADD": 185 out = append(out, 0x8b) 186 case "1SUB": 187 out = append(out, 0x8c) 188 case "2MUL": 189 out = append(out, 0x8d) 190 case "2DIV": 191 out = append(out, 0x8e) 192 case "NEGATE": 193 out = append(out, 0x8f) 194 case "ABS": 195 out = append(out, 0x90) 196 case "NOT": 197 out = append(out, 0x91) 198 case "0NOTEQUAL": 199 out = append(out, 0x92) 200 case "ADD": 201 out = append(out, 0x93) 202 case "SUB": 203 out = append(out, 0x94) 204 case "MUL": 205 out = append(out, 0x95) 206 case "DIV": 207 out = append(out, 0x96) 208 case "MOD": 209 out = append(out, 0x97) 210 case "LSHIFT": 211 out = append(out, 0x98) 212 case "RSHIFT": 213 out = append(out, 0x99) 214 case "BOOLAND": 215 out = append(out, 0x9a) 216 case "BOOLOR": 217 out = append(out, 0x9b) 218 case "NUMEQUAL": 219 out = append(out, 0x9c) 220 case "NUMEQUALVERIFY": 221 out = append(out, 0x9d) 222 case "NUMNOTEQUAL": 223 out = append(out, 0x9e) 224 case "LESSTHAN": 225 out = append(out, 0x9f) 226 case "GREATERTHAN": 227 out = append(out, 0xa0) 228 case "LESSTHANOREQUAL": 229 out = append(out, 0xa1) 230 case "GREATERTHANOREQUAL": 231 out = append(out, 0xa2) 232 case "MIN": 233 out = append(out, 0xa3) 234 case "MAX": 235 out = append(out, 0xa4) 236 case "WITHIN": 237 out = append(out, 0xa5) 238 case "RIPEMD160": 239 out = append(out, 0xa6) 240 case "SHA1": 241 out = append(out, 0xa7) 242 case "SHA256": 243 out = append(out, 0xa8) 244 case "HASH160": 245 out = append(out, 0xa9) 246 case "HASH256": 247 out = append(out, 0xaa) 248 case "CODESEPARATOR": 249 out = append(out, 0xab) 250 case "CHECKSIG": 251 out = append(out, 0xac) 252 case "CHECKSIGVERIFY": 253 out = append(out, 0xad) 254 case "CHECKMULTISIG": 255 out = append(out, 0xae) 256 case "CHECKMULTISIGVERIFY": 257 out = append(out, 0xaf) 258 case "NOP1": 259 out = append(out, 0xb0) 260 case "NOP2": 261 out = append(out, 0xb1) 262 case "CHECKLOCKTIMEVERIFY": 263 out = append(out, 0xb1) 264 case "NOP3": 265 out = append(out, 0xb2) 266 case "CHECKSEQUENCEVERIFY": 267 out = append(out, 0xb2) 268 case "NOP4": 269 out = append(out, 0xb3) 270 case "NOP5": 271 out = append(out, 0xb4) 272 case "NOP6": 273 out = append(out, 0xb5) 274 case "NOP7": 275 out = append(out, 0xb6) 276 case "NOP8": 277 out = append(out, 0xb7) 278 case "NOP9": 279 out = append(out, 0xb8) 280 case "NOP10": 281 out = append(out, 0xb9) 282 case "CHECKSIGADD": 283 out = append(out, 0xba) 284 case "": 285 out = append(out, []byte{}...) 286 default: 287 dat, _ := hex.DecodeString(xx[i]) 288 if dat == nil { 289 return nil, errors.New("Syntax error: " + xx[i]) 290 } 291 out = append(out, RawToStack(dat)...) 292 } 293 } 294 } 295 } 296 return 297 } 298 299 func ScriptToText(p []byte) (out []string, e error) { 300 var opcnt, idx int 301 for idx < len(p) { 302 opcode, vchPushValue, n, er := GetOpcode(p[idx:]) 303 304 if er != nil { 305 e = errors.New("ScriptToText: " + er.Error()) 306 println("C", idx, hex.EncodeToString(p)) 307 return 308 } 309 idx += n 310 311 if vchPushValue != nil && len(vchPushValue) > MAX_SCRIPT_ELEMENT_SIZE { 312 e = errors.New(fmt.Sprint("ScriptToText: vchPushValue too long ", len(vchPushValue))) 313 return 314 } 315 316 if opcode > 0x60 { 317 opcnt++ 318 if opcnt > 201 { 319 e = errors.New("ScriptToText: evalScript has too many opcodes") 320 return 321 } 322 } 323 324 if opcode == 0x7e /*OP_CAT*/ || 325 opcode == 0x7f /*OP_SUBSTR*/ || 326 opcode == 0x80 /*OP_LEFT*/ || 327 opcode == 0x81 /*OP_RIGHT*/ || 328 opcode == 0x83 /*OP_INVERT*/ || 329 opcode == 0x84 /*OP_AND*/ || 330 opcode == 0x85 /*OP_OR*/ || 331 opcode == 0x86 /*OP_XOR*/ || 332 opcode == 0x8d /*OP_2MUL*/ || 333 opcode == 0x8e /*OP_2DIV*/ || 334 opcode == 0x95 /*OP_MUL*/ || 335 opcode == 0x96 /*OP_DIV*/ || 336 opcode == 0x97 /*OP_MOD*/ || 337 opcode == 0x98 /*OP_LSHIFT*/ || 338 opcode == 0x99 /*OP_RSHIFT*/ { 339 e = errors.New(fmt.Sprint("ScriptToText: Unsupported opcode ", opcode)) 340 return 341 } 342 343 var sel string 344 if 0 <= opcode && opcode <= OP_PUSHDATA4 { 345 if len(vchPushValue) == 0 { 346 sel = "OP_FALSE" 347 } else { 348 sel = hex.EncodeToString(vchPushValue) 349 } 350 } else { 351 switch { 352 case opcode == 0x4f: 353 sel = "1NEGATE" 354 case opcode >= 0x50 && opcode <= 0x60: 355 sel = fmt.Sprint(opcode - 0x50) 356 case opcode == 0x61: 357 sel = "NOP" 358 case opcode == 0x63: 359 sel = "IF" 360 case opcode == 0x64: 361 sel = "NOTIF" 362 case opcode == 0x67: 363 sel = "ELSE" 364 case opcode == 0x68: 365 sel = "ENDIF" 366 case opcode == 0x69: 367 sel = "VERIFY" 368 case opcode == 0x6a: 369 sel = "RETURN" 370 case opcode == 0x74: 371 sel = "DEPTH" 372 case opcode == 0x75: 373 sel = "DROP" 374 case opcode == 0x76: 375 sel = "DUP" 376 case opcode == 0x87: 377 sel = "EQUAL" 378 case opcode == 0x88: 379 sel = "EQUALVERIFY" 380 case opcode == 0xa9: 381 sel = "HASH160" 382 case opcode == 0xac: 383 sel = "CHECKSIG" 384 case opcode == 0xad: 385 sel = "CHECKSIGVERIFY" 386 case opcode == 0xae: 387 sel = "CHECKMULTISIG" 388 case opcode == 0xb2: 389 sel = "CHECKSEQUENCEVERIFY" 390 default: 391 sel = fmt.Sprintf("0x%02X", opcode) 392 } 393 sel = "OP_" + sel 394 } 395 out = append(out, sel) 396 } 397 return 398 }