1 /*
2 	This file is part of solidity.
3 
4 	solidity is free software: you can redistribute it and/or modify
5 	it under the terms of the GNU General Public License as published by
6 	the Free Software Foundation, either version 3 of the License, or
7 	(at your option) any later version.
8 
9 	solidity is distributed in the hope that it will be useful,
10 	but WITHOUT ANY WARRANTY; without even the implied warranty of
11 	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12 	GNU General Public License for more details.
13 
14 	You should have received a copy of the GNU General Public License
15 	along with solidity.  If not, see <http://www.gnu.org/licenses/>.
16 */
17 // SPDX-License-Identifier: GPL-3.0
18 /**
19  * Definition of u256 and similar types and helper functions.
20  */
21 
22 #pragma once
23 
24 #include <libsolutil/Common.h>
25 #include <libsolutil/CommonData.h>
26 
27 #include <boost/version.hpp>
28 #if (BOOST_VERSION < 106500)
29 #error "Unsupported Boost version. At least 1.65 required."
30 #endif
31 
32 #include <boost/multiprecision/cpp_int.hpp>
33 
34 #include <limits>
35 
36 namespace solidity
37 {
38 
39 // Numeric types.
40 using bigint = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<>>;
41 using u256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::unsigned_magnitude, boost::multiprecision::unchecked, void>>;
42 using s256 = boost::multiprecision::number<boost::multiprecision::cpp_int_backend<256, 256, boost::multiprecision::signed_magnitude, boost::multiprecision::unchecked, void>>;
43 
44 /// Interprets @a _u as a two's complement signed number and returns the resulting s256.
u2s(u256 _u)45 inline s256 u2s(u256 _u)
46 {
47 	static bigint const c_end = bigint(1) << 256;
48 	if (boost::multiprecision::bit_test(_u, 255))
49 		return s256(-(c_end - _u));
50 	else
51 		return s256(_u);
52 }
53 
54 /// @returns the two's complement signed representation of the signed number _u.
s2u(s256 _u)55 inline u256 s2u(s256 _u)
56 {
57 	static bigint const c_end = bigint(1) << 256;
58 	if (_u >= 0)
59 		return u256(_u);
60 	else
61 		return u256(c_end + _u);
62 }
63 
exp256(u256 _base,u256 _exponent)64 inline u256 exp256(u256 _base, u256 _exponent)
65 {
66 	using boost::multiprecision::limb_type;
67 	u256 result = 1;
68 	while (_exponent)
69 	{
70 		if (boost::multiprecision::bit_test(_exponent, 0))
71 			result *= _base;
72 		_base *= _base;
73 		_exponent >>= 1;
74 	}
75 	return result;
76 }
77 
78 /// Checks whether _mantissa * (X ** _exp) fits into 4096 bits,
79 /// where X is given indirectly via _log2OfBase = log2(X).
80 bool fitsPrecisionBaseX(bigint const& _mantissa, double _log2OfBase, uint32_t _exp);
81 
82 
83 // Big-endian to/from host endian conversion functions.
84 
85 /// Converts a templated integer value to the big-endian byte-stream represented on a templated collection.
86 /// The size of the collection object will be unchanged. If it is too small, it will not represent the
87 /// value properly, if too big then the additional elements will be zeroed out.
88 /// @a Out will typically be either std::string or bytes.
89 /// @a T will typically by unsigned, u160, u256 or bigint.
90 template <class T, class Out>
toBigEndian(T _val,Out & o_out)91 inline void toBigEndian(T _val, Out& o_out)
92 {
93 	static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift
94 	for (auto i = o_out.size(); i != 0; _val >>= 8, i--)
95 	{
96 		T v = _val & (T)0xff;
97 		o_out[i - 1] = (typename Out::value_type)(uint8_t)v;
98 	}
99 }
100 
101 /// Converts a big-endian byte-stream represented on a templated collection to a templated integer value.
102 /// @a In will typically be either std::string or bytes.
103 /// @a T will typically by unsigned, u256 or bigint.
104 template <class T, class In>
fromBigEndian(In const & _bytes)105 inline T fromBigEndian(In const& _bytes)
106 {
107 	T ret = (T)0;
108 	for (auto i: _bytes)
109 		ret = (T)((ret << 8) | (uint8_t)(typename std::make_unsigned<typename In::value_type>::type)i);
110 	return ret;
111 }
toBigEndian(u256 _val)112 inline bytes toBigEndian(u256 _val) { bytes ret(32); toBigEndian(_val, ret); return ret; }
113 
114 /// Convenience function for toBigEndian.
115 /// @returns a byte array just big enough to represent @a _val.
116 template <class T>
117 inline bytes toCompactBigEndian(T _val, unsigned _min = 0)
118 {
119 	static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift
120 	unsigned i = 0;
121 	for (T v = _val; v; ++i, v >>= 8) {}
122 	bytes ret(std::max<unsigned>(_min, i), 0);
123 	toBigEndian(_val, ret);
124 	return ret;
125 }
126 
127 /// Convenience function for conversion of a u256 to hex
toHex(u256 val)128 inline std::string toHex(u256 val)
129 {
130 	return util::toHex(toBigEndian(val));
131 }
132 
133 template <class T>
toCompactHexWithPrefix(T _value)134 inline std::string toCompactHexWithPrefix(T _value)
135 {
136 	return "0x" + util::toHex(toCompactBigEndian(_value, 1));
137 }
138 
139 /// Returns decimal representation for small numbers and hex for large numbers.
formatNumber(bigint const & _value)140 inline std::string formatNumber(bigint const& _value)
141 {
142 	if (_value < 0)
143 		return "-" + formatNumber(-_value);
144 	if (_value > 0x1000000)
145 		return "0x" + util::toHex(toCompactBigEndian(_value, 1));
146 	else
147 		return _value.str();
148 }
149 
formatNumber(u256 const & _value)150 inline std::string formatNumber(u256 const& _value)
151 {
152 	if (_value > 0x1000000)
153 		return toCompactHexWithPrefix(_value);
154 	else
155 		return _value.str();
156 }
157 
158 
159 // Algorithms for string and string-like collections.
160 
161 /// Determine bytes required to encode the given integer value. @returns 0 if @a _i is zero.
162 template <class T>
numberEncodingSize(T _i)163 inline unsigned numberEncodingSize(T _i)
164 {
165 	static_assert(std::is_same<bigint, T>::value || !std::numeric_limits<T>::is_signed, "only unsigned types or bigint supported"); //bigint does not carry sign bit on shift
166 	unsigned i = 0;
167 	for (; _i != 0; ++i, _i >>= 8) {}
168 	return i;
169 }
170 
171 }
172