github.com/dashpay/godash@v0.0.0-20160726055534-e038a21e0e3d/txscript/scriptnum.go (about)

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