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 }