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  }