github.com/btcsuite/btcd@v0.24.0/txscript/scriptnum.go (about)

     1  // Copyright (c) 2015-2017 The btcsuite developers
     2  // Use of this source code is governed by an ISC
     3  // license that can be found in the LICENSE file.
     4  
     5  package txscript
     6  
     7  import (
     8  	"fmt"
     9  )
    10  
    11  const (
    12  	maxInt32 = 1<<31 - 1
    13  	minInt32 = -1 << 31
    14  
    15  	// maxScriptNumLen is the maximum number of bytes data being interpreted
    16  	// as an integer may be for the majority of op codes.
    17  	maxScriptNumLen = 4
    18  
    19  	// cltvMaxScriptNumLen is the maximum number of bytes data being interpreted
    20  	// as an integer may be for by-time and by-height locks as interpreted by
    21  	// CHECKLOCKTIMEVERIFY.
    22  	//
    23  	// The value comes from the fact that the current transaction locktime
    24  	// is a uint32 resulting in a maximum locktime of 2^32-1 (the year
    25  	// 2106).  However, scriptNums are signed and therefore a standard
    26  	// 4-byte scriptNum would only support up to a maximum of 2^31-1 (the
    27  	// year 2038).  Thus, a 5-byte scriptNum is needed since it will support
    28  	// up to 2^39-1 which allows dates beyond the current locktime limit.
    29  	cltvMaxScriptNumLen = 5
    30  )
    31  
    32  // scriptNum represents a numeric value used in the scripting engine with
    33  // special handling to deal with the subtle semantics required by consensus.
    34  //
    35  // All numbers are stored on the data and alternate stacks encoded as little
    36  // endian with a sign bit.  All numeric opcodes such as OP_ADD, OP_SUB,
    37  // and OP_MUL, are only allowed to operate on 4-byte integers in the range
    38  // [-2^31 + 1, 2^31 - 1], however the results of numeric operations may overflow
    39  // and remain valid so long as they are not used as inputs to other numeric
    40  // operations or otherwise interpreted as an integer.
    41  //
    42  // For example, it is possible for OP_ADD to have 2^31 - 1 for its two operands
    43  // resulting 2^32 - 2, which overflows, but is still pushed to the stack as the
    44  // result of the addition.  That value can then be used as input to OP_VERIFY
    45  // which will succeed because the data is being interpreted as a boolean.
    46  // However, if that same value were to be used as input to another numeric
    47  // opcode, such as OP_SUB, it must fail.
    48  //
    49  // This type handles the aforementioned requirements by storing all numeric
    50  // operation results as an int64 to handle overflow and provides the Bytes
    51  // method to get the serialized representation (including values that overflow).
    52  //
    53  // Then, whenever data is interpreted as an integer, it is converted to this
    54  // type by using the MakeScriptNum function which will return an error if the
    55  // number is out of range or not minimally encoded depending on parameters.
    56  // Since all numeric opcodes involve pulling data from the stack and
    57  // interpreting it as an integer, it provides the required behavior.
    58  type scriptNum int64
    59  
    60  // checkMinimalDataEncoding returns whether or not the passed byte array adheres
    61  // to the minimal encoding requirements.
    62  func checkMinimalDataEncoding(v []byte) error {
    63  	if len(v) == 0 {
    64  		return nil
    65  	}
    66  
    67  	// Check that the number is encoded with the minimum possible
    68  	// number of bytes.
    69  	//
    70  	// If the most-significant-byte - excluding the sign bit - is zero
    71  	// then we're not minimal.  Note how this test also rejects the
    72  	// negative-zero encoding, [0x80].
    73  	if v[len(v)-1]&0x7f == 0 {
    74  		// One exception: if there's more than one byte and the most
    75  		// significant bit of the second-most-significant-byte is set
    76  		// it would conflict with the sign bit.  An example of this case
    77  		// is +-255, which encode to 0xff00 and 0xff80 respectively.
    78  		// (big-endian).
    79  		if len(v) == 1 || v[len(v)-2]&0x80 == 0 {
    80  			str := fmt.Sprintf("numeric value encoded as %x is "+
    81  				"not minimally encoded", v)
    82  			return scriptError(ErrMinimalData, str)
    83  		}
    84  	}
    85  
    86  	return nil
    87  }
    88  
    89  // Bytes returns the number serialized as a little endian with a sign bit.
    90  //
    91  // Example encodings:
    92  //
    93  //	   127 -> [0x7f]
    94  //	  -127 -> [0xff]
    95  //	   128 -> [0x80 0x00]
    96  //	  -128 -> [0x80 0x80]
    97  //	   129 -> [0x81 0x00]
    98  //	  -129 -> [0x81 0x80]
    99  //	   256 -> [0x00 0x01]
   100  //	  -256 -> [0x00 0x81]
   101  //	 32767 -> [0xff 0x7f]
   102  //	-32767 -> [0xff 0xff]
   103  //	 32768 -> [0x00 0x80 0x00]
   104  //	-32768 -> [0x00 0x80 0x80]
   105  func (n scriptNum) Bytes() []byte {
   106  	// Zero encodes as an empty byte slice.
   107  	if n == 0 {
   108  		return nil
   109  	}
   110  
   111  	// Take the absolute value and keep track of whether it was originally
   112  	// negative.
   113  	isNegative := n < 0
   114  	if isNegative {
   115  		n = -n
   116  	}
   117  
   118  	// Encode to little endian.  The maximum number of encoded bytes is 9
   119  	// (8 bytes for max int64 plus a potential byte for sign extension).
   120  	result := make([]byte, 0, 9)
   121  	for n > 0 {
   122  		result = append(result, byte(n&0xff))
   123  		n >>= 8
   124  	}
   125  
   126  	// When the most significant byte already has the high bit set, an
   127  	// additional high byte is required to indicate whether the number is
   128  	// negative or positive.  The additional byte is removed when converting
   129  	// back to an integral and its high bit is used to denote the sign.
   130  	//
   131  	// Otherwise, when the most significant byte does not already have the
   132  	// high bit set, use it to indicate the value is negative, if needed.
   133  	if result[len(result)-1]&0x80 != 0 {
   134  		extraByte := byte(0x00)
   135  		if isNegative {
   136  			extraByte = 0x80
   137  		}
   138  		result = append(result, extraByte)
   139  
   140  	} else if isNegative {
   141  		result[len(result)-1] |= 0x80
   142  	}
   143  
   144  	return result
   145  }
   146  
   147  // Int32 returns the script number clamped to a valid int32.  That is to say
   148  // when the script number is higher than the max allowed int32, the max int32
   149  // value is returned and vice versa for the minimum value.  Note that this
   150  // behavior is different from a simple int32 cast because that truncates
   151  // and the consensus rules dictate numbers which are directly cast to ints
   152  // provide this behavior.
   153  //
   154  // In practice, for most opcodes, the number should never be out of range since
   155  // it will have been created with MakeScriptNum using the defaultScriptLen
   156  // value, which rejects them.  In case something in the future ends up calling
   157  // this function against the result of some arithmetic, which IS allowed to be
   158  // out of range before being reinterpreted as an integer, this will provide the
   159  // correct behavior.
   160  func (n scriptNum) Int32() int32 {
   161  	if n > maxInt32 {
   162  		return maxInt32
   163  	}
   164  
   165  	if n < minInt32 {
   166  		return minInt32
   167  	}
   168  
   169  	return int32(n)
   170  }
   171  
   172  // MakeScriptNum interprets the passed serialized bytes as an encoded integer
   173  // and returns the result as a script number.
   174  //
   175  // Since the consensus rules dictate that serialized bytes interpreted as ints
   176  // are only allowed to be in the range determined by a maximum number of bytes,
   177  // on a per opcode basis, an error will be returned when the provided bytes
   178  // would result in a number outside of that range.  In particular, the range for
   179  // the vast majority of opcodes dealing with numeric values are limited to 4
   180  // bytes and therefore will pass that value to this function resulting in an
   181  // allowed range of [-2^31 + 1, 2^31 - 1].
   182  //
   183  // The requireMinimal flag causes an error to be returned if additional checks
   184  // on the encoding determine it is not represented with the smallest possible
   185  // number of bytes or is the negative 0 encoding, [0x80].  For example, consider
   186  // the number 127.  It could be encoded as [0x7f], [0x7f 0x00],
   187  // [0x7f 0x00 0x00 ...], etc.  All forms except [0x7f] will return an error with
   188  // requireMinimal enabled.
   189  //
   190  // The scriptNumLen is the maximum number of bytes the encoded value can be
   191  // before an ErrStackNumberTooBig is returned.  This effectively limits the
   192  // range of allowed values.
   193  // WARNING:  Great care should be taken if passing a value larger than
   194  // maxScriptNumLen, which could lead to addition and multiplication
   195  // overflows.
   196  //
   197  // See the Bytes function documentation for example encodings.
   198  func MakeScriptNum(v []byte, requireMinimal bool, scriptNumLen int) (scriptNum, error) {
   199  	// Interpreting data requires that it is not larger than
   200  	// the passed scriptNumLen value.
   201  	if len(v) > scriptNumLen {
   202  		str := fmt.Sprintf("numeric value encoded as %x is %d bytes "+
   203  			"which exceeds the max allowed of %d", v, len(v),
   204  			scriptNumLen)
   205  		return 0, scriptError(ErrNumberTooBig, str)
   206  	}
   207  
   208  	// Enforce minimal encoded if requested.
   209  	if requireMinimal {
   210  		if err := checkMinimalDataEncoding(v); err != nil {
   211  			return 0, err
   212  		}
   213  	}
   214  
   215  	// Zero is encoded as an empty byte slice.
   216  	if len(v) == 0 {
   217  		return 0, nil
   218  	}
   219  
   220  	// Decode from little endian.
   221  	var result int64
   222  	for i, val := range v {
   223  		result |= int64(val) << uint8(8*i)
   224  	}
   225  
   226  	// When the most significant byte of the input bytes has the sign bit
   227  	// set, the result is negative.  So, remove the sign bit from the result
   228  	// and make it negative.
   229  	if v[len(v)-1]&0x80 != 0 {
   230  		// The maximum length of v has already been determined to be 4
   231  		// above, so uint8 is enough to cover the max possible shift
   232  		// value of 24.
   233  		result &= ^(int64(0x80) << uint8(8*(len(v)-1)))
   234  		return scriptNum(-result), nil
   235  	}
   236  
   237  	return scriptNum(result), nil
   238  }