github.com/piotrnar/gocoin@v0.0.0-20240512203912-faa0448c5e96/lib/btc/funcs.go (about) 1 package btc 2 3 import ( 4 "bytes" 5 "crypto/sha256" 6 "encoding/base64" 7 "encoding/binary" 8 "errors" 9 "fmt" 10 "io" 11 "os" 12 "strconv" 13 "strings" 14 ) 15 16 func allzeros(b []byte) bool { 17 for i := range b { 18 if b[i] != 0 { 19 return false 20 } 21 } 22 return true 23 } 24 25 // PutVlen puts var_length field into the given buffer. 26 func PutVlen(b []byte, vl int) uint32 { 27 uvl := uint32(vl) 28 if uvl < 0xfd { 29 b[0] = byte(uvl) 30 return 1 31 } 32 if uvl < 0x10000 { 33 b[0] = 0xfd 34 b[1] = byte(uvl) 35 b[2] = byte(uvl >> 8) 36 return 3 37 } 38 b[0] = 0xfe 39 b[1] = byte(uvl) 40 b[2] = byte(uvl >> 8) 41 b[3] = byte(uvl >> 16) 42 b[4] = byte(uvl >> 24) 43 return 5 44 } 45 46 func PutULe(b []byte, uvl uint64) int { 47 if uvl < 0xfd { 48 b[0] = byte(uvl) 49 return 1 50 } 51 if uvl < 0x10000 { 52 b[0] = 0xfd 53 binary.LittleEndian.PutUint16(b[1:3], uint16(uvl)) 54 return 3 55 } 56 if uvl < 0x100000000 { 57 b[0] = 0xfe 58 binary.LittleEndian.PutUint32(b[1:5], uint32(uvl)) 59 return 5 60 } 61 b[0] = 0xff 62 binary.LittleEndian.PutUint64(b[1:9], uvl) 63 return 9 64 } 65 66 // VLenSize returns how many bytes it would take to write this VLen. 67 func VLenSize(uvl uint64) int { 68 if uvl < 0xfd { 69 return 1 70 } 71 if uvl < 0x10000 { 72 return 3 73 } 74 if uvl < 0x100000000 { 75 return 5 76 } 77 return 9 78 } 79 80 // VLen returns var_int and number of bytes that the var_int took. 81 // If there is not enough bytes in the buffer, it returns 0, 0. 82 func VLen(b []byte) (le int, var_int_siz int) { 83 if len(b) > 0 { 84 switch b[0] { 85 case 0xfd: 86 if len(b) >= 3 { 87 return int(binary.LittleEndian.Uint16(b[1:3])), 3 88 } 89 case 0xfe: 90 if len(b) >= 5 { 91 return int(binary.LittleEndian.Uint32(b[1:5])), 5 92 } 93 case 0xff: 94 if len(b) >= 9 { 95 return int(binary.LittleEndian.Uint64(b[1:9])), 9 96 } 97 default: 98 return int(b[0]), 1 99 } 100 } 101 return 102 } 103 104 // VULe returns var_uint and number of bytes that the var_uint took. 105 // If there is not enough bytes in the buffer, it returns 0, 0. 106 func VULe(b []byte) (le uint64, var_int_siz int) { 107 if len(b) > 0 { 108 switch b[0] { 109 case 0xfd: 110 if len(b) >= 3 { 111 return uint64(binary.LittleEndian.Uint16(b[1:3])), 3 112 } 113 case 0xfe: 114 if len(b) >= 5 { 115 return uint64(binary.LittleEndian.Uint32(b[1:5])), 5 116 } 117 case 0xff: 118 if len(b) >= 9 { 119 return uint64(binary.LittleEndian.Uint64(b[1:9])), 9 120 } 121 default: 122 return uint64(b[0]), 1 123 } 124 } 125 return 126 } 127 128 func CalcMerkle(mtr [][32]byte) (res []byte, mutated bool) { 129 var j, i2 int 130 for siz := len(mtr); siz > 1; siz = (siz + 1) / 2 { 131 for i := 0; i < siz; i += 2 { 132 if i+1 < siz-1 { 133 i2 = i + 1 134 } else { 135 i2 = siz - 1 136 } 137 if i != i2 && bytes.Equal(mtr[j+i][:], mtr[j+i2][:]) { 138 mutated = true 139 } 140 s := sha256.New() 141 s.Write(mtr[j+i][:]) 142 s.Write(mtr[j+i2][:]) 143 tmp := s.Sum(nil) 144 s.Reset() 145 s.Write(tmp) 146 147 var sum [32]byte 148 copy(sum[:], s.Sum(nil)) 149 mtr = append(mtr, sum) 150 } 151 j += siz 152 } 153 res = mtr[len(mtr)-1][:] 154 return 155 } 156 157 func GetWitnessMerkle(txs []*Tx) (res []byte, mutated bool) { 158 mtr := make([][32]byte, len(txs), 3*len(txs)) // make the buffer 3 times longer as we use append() inside CalcMerkle 159 //mtr[0] = make([]byte, 32) // null 160 for i := 1; i < len(txs); i++ { 161 mtr[i] = txs[i].WTxID().Hash 162 } 163 res, mutated = CalcMerkle(mtr) 164 return 165 } 166 167 // ReadVLen reads var_len from the given reader. 168 func ReadVLen(b io.Reader) (res uint64, e error) { 169 var buf [8]byte 170 171 if _, e = io.ReadFull(b, buf[:1]); e != nil { 172 //println("ReadVLen1 error:", e.Error()) 173 return 174 } 175 176 if buf[0] < 0xfd { 177 res = uint64(buf[0]) 178 return 179 } 180 181 c := 2 << (2 - (0xff - buf[0])) 182 183 if _, e = io.ReadFull(b, buf[:c]); e != nil { 184 println("ReadVLen1 error:", e.Error()) 185 return 186 } 187 for i := 0; i < c; i++ { 188 res |= (uint64(buf[i]) << uint64(8*i)) 189 } 190 return 191 } 192 193 // WriteVlen writes var_length field into the given writer. 194 func WriteVlen(b io.Writer, var_len uint64) { 195 if var_len < 0xfd { 196 b.Write([]byte{byte(var_len)}) 197 return 198 } 199 if var_len < 0x10000 { 200 b.Write([]byte{0xfd}) 201 binary.Write(b, binary.LittleEndian, uint16(var_len)) 202 return 203 } 204 if var_len < 0x100000000 { 205 b.Write([]byte{0xfe}) 206 binary.Write(b, binary.LittleEndian, uint32(var_len)) 207 return 208 } 209 b.Write([]byte{0xff}) 210 binary.Write(b, binary.LittleEndian, var_len) 211 } 212 213 // WritePutLen writes opcode to put a specific number of bytes to stack. 214 func WritePutLen(b io.Writer, data_len uint32) { 215 switch { 216 case data_len <= OP_PUSHDATA1: 217 b.Write([]byte{byte(data_len)}) 218 219 case data_len < 0x100: 220 b.Write([]byte{OP_PUSHDATA1, byte(data_len)}) 221 222 case data_len < 0x10000: 223 b.Write([]byte{OP_PUSHDATA2}) 224 binary.Write(b, binary.LittleEndian, uint16(data_len)) 225 226 default: 227 b.Write([]byte{OP_PUSHDATA4}) 228 binary.Write(b, binary.LittleEndian, uint32(data_len)) 229 } 230 } 231 232 // ReadString reads bitcoin protocol string. 233 func ReadString(rd io.Reader) (s string, e error) { 234 var le uint64 235 le, e = ReadVLen(rd) 236 if e != nil { 237 return 238 } 239 bu := make([]byte, le) 240 _, e = rd.Read(bu) 241 if e == nil { 242 s = string(bu) 243 } 244 return 245 } 246 247 // ParseMessageSignature takes a Base64 encoded Bitcoin generated signature and decodes it. 248 func ParseMessageSignature(encsig string) (nv byte, sig *Signature, er error) { 249 var sd []byte 250 251 sd, er = base64.StdEncoding.DecodeString(encsig) 252 if er != nil { 253 return 254 } 255 256 if len(sd) != 65 { 257 er = errors.New("The decoded signature is not 65 bytes long") 258 return 259 } 260 261 nv = sd[0] 262 263 sig = new(Signature) 264 sig.R.SetBytes(sd[1:33]) 265 sig.S.SetBytes(sd[33:65]) 266 267 if nv < 27 || nv > 34 { 268 er = errors.New("nv out of range") 269 } 270 271 return 272 } 273 274 func IsPayToScript(scr []byte) bool { 275 return len(scr) == 23 && scr[0] == OP_HASH160 && scr[1] == 0x14 && scr[22] == OP_EQUAL 276 } 277 278 // StringToSatoshis parses a floating number string to return uint64 value expressed in Satoshis. 279 // Using strconv.ParseFloat followed by uint64(val*1e8) is not precise enough. 280 func StringToSatoshis(s string) (val uint64, er error) { 281 var big, small uint64 282 283 ss := strings.Split(s, ".") 284 if len(ss) == 1 { 285 val, er = strconv.ParseUint(ss[0], 10, 64) 286 if er != nil { 287 return 288 } 289 val *= 1e8 290 return 291 } 292 if len(ss) != 2 { 293 println("Incorrect amount", s) 294 os.Exit(1) 295 } 296 297 if len(ss[1]) > 8 { 298 er = errors.New("Too many decimal points") 299 return 300 } 301 if len(ss[1]) < 8 { 302 ss[1] += strings.Repeat("0", 8-len(ss[1])) 303 } 304 305 small, er = strconv.ParseUint(ss[1], 10, 64) 306 if er != nil { 307 return 308 } 309 310 big, er = strconv.ParseUint(ss[0], 10, 64) 311 if er == nil { 312 val = 1e8*big + small 313 } 314 315 return 316 } 317 318 // UintToBtc converts value of satoshis to a BTC-value string (with 8 decimal points). 319 func UintToBtc(val uint64) string { 320 return fmt.Sprintf("%d.%08d", val/1e8, val%1e8) 321 } 322 323 // IsP2SH returns true if the given PK_script is a standard P2SH. 324 func IsP2SH(d []byte) bool { 325 return len(d) == 23 && d[0] == 0xa9 && d[1] == 20 && d[22] == 0x87 326 } 327 328 func GetOpcode(b []byte) (opcode int, ret []byte, pc int, e error) { 329 // Read instruction 330 if pc+1 > len(b) { 331 e = errors.New("GetOpcode error 1") 332 return 333 } 334 opcode = int(b[pc]) 335 pc++ 336 337 if opcode <= OP_PUSHDATA4 { 338 size := 0 339 if opcode < OP_PUSHDATA1 { 340 size = opcode 341 } 342 if opcode == OP_PUSHDATA1 { 343 if pc+1 > len(b) { 344 e = errors.New("GetOpcode error 2") 345 return 346 } 347 size = int(b[pc]) 348 pc++ 349 } else if opcode == OP_PUSHDATA2 { 350 if pc+2 > len(b) { 351 e = errors.New("GetOpcode error 3") 352 return 353 } 354 size = int(binary.LittleEndian.Uint16(b[pc : pc+2])) 355 pc += 2 356 } else if opcode == OP_PUSHDATA4 { 357 if pc+4 > len(b) { 358 e = errors.New("GetOpcode error 4") 359 return 360 } 361 size = int(binary.LittleEndian.Uint16(b[pc : pc+4])) 362 pc += 4 363 } 364 if pc+size > len(b) { 365 e = errors.New(fmt.Sprint("GetOpcode size to fetch exceeds remainig data left: ", pc+size, "/", len(b))) 366 return 367 } 368 ret = b[pc : pc+size] 369 pc += size 370 } 371 372 return 373 } 374 375 func GetSigOpCount(scr []byte, fAccurate bool) (n uint) { 376 var pc int 377 var lastOpcode byte = 0xff 378 for pc < len(scr) { 379 opcode, _, le, e := GetOpcode(scr[pc:]) 380 if e != nil || opcode == 0x6a /* Break on OP_RETURN - Fix for testnet block #1971687/Txs[30] (too many sigops) */ { 381 break 382 } 383 pc += le 384 if opcode == 0xac /*OP_CHECKSIG*/ || opcode == 0xad /*OP_CHECKSIGVERIFY*/ { 385 n++ 386 } else if opcode == 0xae /*OP_CHECKMULTISIG*/ || opcode == 0xaf /*OP_CHECKMULTISIGVERIFY*/ { 387 if fAccurate && lastOpcode >= 0x51 /*OP_1*/ && lastOpcode <= 0x60 /*OP_16*/ { 388 n += uint(DecodeOP_N(lastOpcode)) 389 } else { 390 n += MAX_PUBKEYS_PER_MULTISIG 391 } 392 } 393 lastOpcode = byte(opcode) 394 } 395 return 396 } 397 398 func DecodeOP_N(opcode byte) int { 399 if opcode == 0x00 /*OP_0*/ { 400 return 0 401 } 402 return int(opcode) - 0x50 /*OP_1-1*/ 403 } 404 405 func GetP2SHSigOpCount(scr []byte) uint { 406 // This is a pay-to-script-hash scriptPubKey; 407 // get the last item that the scr 408 // pushes onto the stack: 409 var pc, opcode, le int 410 var e error 411 var data []byte 412 for pc < len(scr) { 413 opcode, data, le, e = GetOpcode(scr[pc:]) 414 if e != nil { 415 return 0 416 } 417 pc += le 418 if opcode > 0x60 /*OP_16*/ { 419 return 0 420 } 421 } 422 423 return GetSigOpCount(data, true) 424 } 425 426 func IsWitnessProgram(scr []byte) (version int, program []byte) { 427 if len(scr) < 4 || len(scr) > 42 { 428 return 429 } 430 if scr[0] != OP_0 && (scr[0] < OP_1 || scr[0] > OP_16) { 431 return 432 } 433 if int(scr[1])+2 == len(scr) { 434 version = DecodeOP_N(scr[0]) 435 program = scr[2:] 436 } 437 return 438 } 439 440 func WitnessSigOps(witversion int, witprogram []byte, witness [][]byte) uint { 441 if witversion == 0 { 442 if len(witprogram) == 20 { 443 return 1 444 } 445 446 if len(witprogram) == 32 && len(witness) > 0 { 447 subscript := witness[len(witness)-1] 448 return GetSigOpCount(subscript, true) 449 } 450 } 451 return 0 452 } 453 454 func IsPushOnly(scr []byte) bool { 455 idx := 0 456 for idx < len(scr) { 457 op, _, n, e := GetOpcode(scr[idx:]) 458 if e != nil { 459 return false 460 } 461 if op > OP_16 { 462 return false 463 } 464 idx += n 465 } 466 return true 467 } 468 469 // Amount compression: 470 // * If the amount is 0, output 0 471 // * first, divide the amount (in base units) by the largest power of 10 possible; call the exponent e (e is max 9) 472 // * if e<9, the last digit of the resulting number cannot be 0; store it as d, and drop it (divide by 10) 473 // * call the result n 474 // * output 1 + 10*(9*n + d - 1) + e 475 // * if e==9, we only know the resulting number is not zero, so output 1 + 10*(n - 1) + 9 476 // (this is decodable, as d is in [1-9] and e is in [0-9]) 477 func CompressAmount(n uint64) uint64 { 478 if n == 0 { 479 return 0 480 } 481 var e uint64 482 for (n%10) == 0 && e < 9 { 483 n /= 10 484 e++ 485 } 486 if e < 9 { 487 d := n % 10 488 n /= 10 489 return 1 + (n*9+d-1)*10 + e 490 } else { 491 return 1 + (n-1)*10 + 9 492 } 493 } 494 495 func DecompressAmount(x uint64) uint64 { 496 // x = 0 OR x = 1+10*(9*n + d - 1) + e OR x = 1+10*(n - 1) + 9 497 if x == 0 { 498 return 0 499 } 500 x-- 501 // x = 10*(9*n + d - 1) + e 502 e := x % 10 503 x /= 10 504 var n uint64 505 if e < 9 { 506 // x = 9*n + d - 1 507 d := (x % 9) + 1 508 x /= 9 509 // x = n 510 n = x*10 + d 511 } else { 512 n = x + 1 513 } 514 for e != 0 { 515 n *= 10 516 e-- 517 } 518 return n 519 }