Skip to content

Commit d17ae0b

Browse files
authored
Signed SafeMath (#1559)
* signed safe math * fix lint errors * refactor overflow checks and add descriptions * remove incorrect description * add test for reversed arguments in multiplication test * fix power operator * improve multiplication test descriptions * Update SafeMath.test.js * add feature to changelog
1 parent fad30c3 commit d17ae0b

File tree

5 files changed

+295
-91
lines changed

5 files changed

+295
-91
lines changed

CHANGELOG.md

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
* `ERC20`: `transferFrom` and `_burnFrom ` now emit `Approval` events, to represent the token's state comprehensively through events. ([#1524](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1524))
1010
* `ERC721`: added `_burn(uint256 tokenId)`, replacing the similar deprecated function (see below). ([#1550](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1550))
1111
* `ERC721`: added `_tokensOfOwner(address owner)`, allowing to internally retrieve the array of an account's owned tokens. ([#1522](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1522))
12+
* `SafeMath`: added overflow-safe operations for signed integers (`int256`). ([#1559](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1559))
1213

1314
### Improvements:
1415
* The compiler version required by `Array` was behind the rest of the libray so it was updated to `v0.4.24`. ([#1553](https://github.com/OpenZeppelin/openzeppelin-solidity/pull/1553))

contracts/math/SafeMath.sol

+58-5
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,10 @@ pragma solidity ^0.4.24;
55
* @dev Math operations with safety checks that revert on error
66
*/
77
library SafeMath {
8+
int256 constant private INT256_MIN = -2**255;
9+
810
/**
9-
* @dev Multiplies two numbers, reverts on overflow.
11+
* @dev Multiplies two unsigned integers, reverts on overflow.
1012
*/
1113
function mul(uint256 a, uint256 b) internal pure returns (uint256) {
1214
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
@@ -23,7 +25,26 @@ library SafeMath {
2325
}
2426

2527
/**
26-
* @dev Integer division of two numbers truncating the quotient, reverts on division by zero.
28+
* @dev Multiplies two signed integers, reverts on overflow.
29+
*/
30+
function mul(int256 a, int256 b) internal pure returns (int256) {
31+
// Gas optimization: this is cheaper than requiring 'a' not being zero, but the
32+
// benefit is lost if 'b' is also tested.
33+
// See: https://github.com/OpenZeppelin/openzeppelin-solidity/pull/522
34+
if (a == 0) {
35+
return 0;
36+
}
37+
38+
require(!(a == -1 && b == INT256_MIN)); // This is the only case of overflow not detected by the check below
39+
40+
int256 c = a * b;
41+
require(c / a == b);
42+
43+
return c;
44+
}
45+
46+
/**
47+
* @dev Integer division of two unsigned integers truncating the quotient, reverts on division by zero.
2748
*/
2849
function div(uint256 a, uint256 b) internal pure returns (uint256) {
2950
// Solidity only automatically asserts when dividing by 0
@@ -35,7 +56,19 @@ library SafeMath {
3556
}
3657

3758
/**
38-
* @dev Subtracts two numbers, reverts on overflow (i.e. if subtrahend is greater than minuend).
59+
* @dev Integer division of two signed integers truncating the quotient, reverts on division by zero.
60+
*/
61+
function div(int256 a, int256 b) internal pure returns (int256) {
62+
require(b != 0); // Solidity only automatically asserts when dividing by 0
63+
require(!(b == -1 && a == INT256_MIN)); // This is the only case of overflow
64+
65+
int256 c = a / b;
66+
67+
return c;
68+
}
69+
70+
/**
71+
* @dev Subtracts two unsigned integers, reverts on overflow (i.e. if subtrahend is greater than minuend).
3972
*/
4073
function sub(uint256 a, uint256 b) internal pure returns (uint256) {
4174
require(b <= a);
@@ -45,7 +78,17 @@ library SafeMath {
4578
}
4679

4780
/**
48-
* @dev Adds two numbers, reverts on overflow.
81+
* @dev Subtracts two signed integers, reverts on overflow.
82+
*/
83+
function sub(int256 a, int256 b) internal pure returns (int256) {
84+
int256 c = a - b;
85+
require((b >= 0 && c <= a) || (b < 0 && c > a));
86+
87+
return c;
88+
}
89+
90+
/**
91+
* @dev Adds two unsigned integers, reverts on overflow.
4992
*/
5093
function add(uint256 a, uint256 b) internal pure returns (uint256) {
5194
uint256 c = a + b;
@@ -55,7 +98,17 @@ library SafeMath {
5598
}
5699

57100
/**
58-
* @dev Divides two numbers and returns the remainder (unsigned integer modulo),
101+
* @dev Adds two signed integers, reverts on overflow.
102+
*/
103+
function add(int256 a, int256 b) internal pure returns (int256) {
104+
int256 c = a + b;
105+
require((b >= 0 && c >= a) || (b < 0 && c < a));
106+
107+
return c;
108+
}
109+
110+
/**
111+
* @dev Divides two unsigned integers and returns the remainder (unsigned integer modulo),
59112
* reverts when dividing by zero.
60113
*/
61114
function mod(uint256 a, uint256 b) internal pure returns (uint256) {

contracts/mocks/SafeMathMock.sol

+23-5
Original file line numberDiff line numberDiff line change
@@ -1,25 +1,43 @@
11
pragma solidity ^0.4.24;
22

3+
34
import "../math/SafeMath.sol";
45

6+
57
contract SafeMathMock {
6-
function mul(uint256 a, uint256 b) public pure returns (uint256) {
8+
function mulUints(uint256 a, uint256 b) public pure returns (uint256) {
79
return SafeMath.mul(a, b);
810
}
911

10-
function div(uint256 a, uint256 b) public pure returns (uint256) {
12+
function mulInts(int256 a, int256 b) public pure returns (int256) {
13+
return SafeMath.mul(a, b);
14+
}
15+
16+
function divUints(uint256 a, uint256 b) public pure returns (uint256) {
17+
return SafeMath.div(a, b);
18+
}
19+
20+
function divInts(int256 a, int256 b) public pure returns (int256) {
1121
return SafeMath.div(a, b);
1222
}
1323

14-
function sub(uint256 a, uint256 b) public pure returns (uint256) {
24+
function subUints(uint256 a, uint256 b) public pure returns (uint256) {
25+
return SafeMath.sub(a, b);
26+
}
27+
28+
function subInts(int256 a, int256 b) public pure returns (int256) {
1529
return SafeMath.sub(a, b);
1630
}
1731

18-
function add(uint256 a, uint256 b) public pure returns (uint256) {
32+
function addUints(uint256 a, uint256 b) public pure returns (uint256) {
33+
return SafeMath.add(a, b);
34+
}
35+
36+
function addInts(int256 a, int256 b) public pure returns (int256) {
1937
return SafeMath.add(a, b);
2038
}
2139

22-
function mod(uint256 a, uint256 b) public pure returns (uint256) {
40+
function modUints(uint256 a, uint256 b) public pure returns (uint256) {
2341
return SafeMath.mod(a, b);
2442
}
2543
}

test/helpers/constants.js

+2
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,6 @@ const BigNumber = web3.BigNumber;
33
module.exports = {
44
ZERO_ADDRESS: '0x0000000000000000000000000000000000000000',
55
MAX_UINT256: new BigNumber(2).pow(256).minus(1),
6+
MAX_INT256: new BigNumber(2).pow(255).minus(1),
7+
MIN_INT256: new BigNumber(2).pow(255).times(-1),
68
};

0 commit comments

Comments
 (0)