github.com/BlockABC/godash@v0.0.0-20191112120524-f4aa3a32c566/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 }