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