Skip to content

Commit dfe99e2

Browse files
committed
added math.sol
1 parent dd5f5a8 commit dfe99e2

File tree

1 file changed

+160
-0
lines changed
  • target_chains/ethereum/sdk/solidity

1 file changed

+160
-0
lines changed
Lines changed: 160 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,160 @@
1+
// SPDX-License-Identifier: MIT
2+
// OpenZeppelin Contracts (last updated v5.3.0) (utils/math/Math.sol)
3+
// Source: https://github.com/OpenZeppelin/openzeppelin-contracts/blob/v5.3.0/contracts/utils/math/Math.sol
4+
5+
6+
pragma solidity ^0.8.0;
7+
8+
library Math {
9+
10+
/// @dev division or modulo by zero
11+
uint256 internal constant DIVISION_BY_ZERO = 0x12;
12+
/// @dev arithmetic underflow or overflow
13+
uint256 internal constant UNDER_OVERFLOW = 0x11;
14+
15+
16+
/**
17+
* @dev Return the 512-bit multiplication of two uint256.
18+
*
19+
* The result is stored in two 256 variables such that product = high * 2²⁵⁶ + low.
20+
*/
21+
function mul512(uint256 a, uint256 b) internal pure returns (uint256 high, uint256 low) {
22+
// 512-bit multiply [high low] = x * y. Compute the product mod 2²⁵⁶ and mod 2²⁵⁶ - 1, then use
23+
// the Chinese Remainder Theorem to reconstruct the 512 bit result. The result is stored in two 256
24+
// variables such that product = high * 2²⁵⁶ + low.
25+
/// @solidity memory-safe-assembly
26+
assembly {
27+
let mm := mulmod(a, b, not(0))
28+
low := mul(a, b)
29+
high := sub(sub(mm, low), lt(mm, low))
30+
}
31+
}
32+
33+
/**
34+
* @dev Branchless ternary evaluation for `a ? b : c`. Gas costs are constant.
35+
*
36+
* IMPORTANT: This function may reduce bytecode size and consume less gas when used standalone.
37+
* However, the compiler may optimize Solidity ternary operations (i.e. `a ? b : c`) to only compute
38+
* one branch when needed, making this function more expensive.
39+
*/
40+
function ternary(bool condition, uint256 a, uint256 b) internal pure returns (uint256) {
41+
unchecked {
42+
// branchless ternary works because:
43+
// b ^ (a ^ b) == a
44+
// b ^ 0 == b
45+
return b ^ ((a ^ b) * toUint(condition));
46+
}
47+
}
48+
49+
/**
50+
* @dev Cast a boolean (false or true) to a uint256 (0 or 1) with no jump.
51+
*/
52+
function toUint(bool b) internal pure returns (uint256 u) {
53+
/// @solidity memory-safe-assembly
54+
assembly {
55+
u := iszero(iszero(b))
56+
}
57+
}
58+
59+
/// @dev Reverts with a panic code. Recommended to use with
60+
/// the internal constants with predefined codes.
61+
function panic(uint256 code) internal pure {
62+
/// @solidity memory-safe-assembly
63+
assembly {
64+
mstore(0x00, 0x4e487b71)
65+
mstore(0x20, code)
66+
revert(0x1c, 0x24)
67+
}
68+
}
69+
70+
71+
/**
72+
* @dev Calculates floor(x * y / denominator) with full precision. Throws if result overflows a uint256 or
73+
* denominator == 0.
74+
*
75+
* Original credit to Remco Bloemen under MIT license (https://xn--2-umb.com/21/muldiv) with further edits by
76+
* Uniswap Labs also under MIT license.
77+
*/
78+
function mulDiv(uint256 x, uint256 y, uint256 denominator) internal pure returns (uint256 result) {
79+
unchecked {
80+
(uint256 high, uint256 low) = mul512(x, y);
81+
82+
// Handle non-overflow cases, 256 by 256 division.
83+
if (high == 0) {
84+
// Solidity will revert if denominator == 0, unlike the div opcode on its own.
85+
// The surrounding unchecked block does not change this fact.
86+
// See https://docs.soliditylang.org/en/latest/control-structures.html#checked-or-unchecked-arithmetic.
87+
return low / denominator;
88+
}
89+
90+
// Make sure the result is less than 2²⁵⁶. Also prevents denominator == 0.
91+
if (denominator <= high) {
92+
panic(ternary(denominator == 0, DIVISION_BY_ZERO, UNDER_OVERFLOW));
93+
}
94+
95+
///////////////////////////////////////////////
96+
// 512 by 256 division.
97+
///////////////////////////////////////////////
98+
99+
// Make division exact by subtracting the remainder from [high low].
100+
uint256 remainder;
101+
/// @solidity memory-safe-assembly
102+
assembly {
103+
// Compute remainder using mulmod.
104+
remainder := mulmod(x, y, denominator)
105+
106+
// Subtract 256 bit number from 512 bit number.
107+
high := sub(high, gt(remainder, low))
108+
low := sub(low, remainder)
109+
}
110+
111+
// Factor powers of two out of denominator and compute largest power of two divisor of denominator.
112+
// Always >= 1. See https://cs.stackexchange.com/q/138556/92363.
113+
114+
uint256 twos = denominator & (0 - denominator);
115+
/// @solidity memory-safe-assembly
116+
assembly {
117+
// Divide denominator by twos.
118+
denominator := div(denominator, twos)
119+
120+
// Divide [high low] by twos.
121+
low := div(low, twos)
122+
123+
// Flip twos such that it is 2²⁵⁶ / twos. If twos is zero, then it becomes one.
124+
twos := add(div(sub(0, twos), twos), 1)
125+
}
126+
127+
// Shift in bits from high into low.
128+
low |= high * twos;
129+
130+
// Invert denominator mod 2²⁵⁶. Now that denominator is an odd number, it has an inverse modulo 2²⁵⁶ such
131+
// that denominator * inv ≡ 1 mod 2²⁵⁶. Compute the inverse by starting with a seed that is correct for
132+
// four bits. That is, denominator * inv ≡ 1 mod 2⁴.
133+
uint256 inverse = (3 * denominator) ^ 2;
134+
135+
// Use the Newton-Raphson iteration to improve the precision. Thanks to Hensel's lifting lemma, this also
136+
// works in modular arithmetic, doubling the correct bits in each step.
137+
inverse *= 2 - denominator * inverse; // inverse mod 2⁸
138+
inverse *= 2 - denominator * inverse; // inverse mod 2¹⁶
139+
inverse *= 2 - denominator * inverse; // inverse mod 2³²
140+
inverse *= 2 - denominator * inverse; // inverse mod 2⁶⁴
141+
inverse *= 2 - denominator * inverse; // inverse mod 2¹²⁸
142+
inverse *= 2 - denominator * inverse; // inverse mod 2²⁵⁶
143+
144+
// Because the division is now exact we can divide by multiplying with the modular inverse of denominator.
145+
// This will give us the correct result modulo 2²⁵⁶. Since the preconditions guarantee that the outcome is
146+
// less than 2²⁵⁶, this is the final result. We don't need to compute the high bits of the result and high
147+
// is no longer required.
148+
result = low * inverse;
149+
return result;
150+
}
151+
}
152+
153+
// /**
154+
// * @dev Calculates x * y / denominator with full precision, following the selected rounding direction.
155+
// */
156+
// function mulDiv(uint256 x, uint256 y, uint256 denominator, Rounding rounding) internal pure returns (uint256) {
157+
// return mulDiv(x, y, denominator) + toUint(unsignedRoundsUp(rounding) && mulmod(x, y, denominator) > 0);
158+
// }
159+
160+
}

0 commit comments

Comments
 (0)