Summary
The Math.sol violates the fundamental properties of division namely
-
X divided by 1
-
X divided by itself
-
Division must be the inverse of multiplication
Vulnerability Details
The issues described are tested by Foundry and their respective responses by running the tests are attached
X divided by 1 , division result should be X , but the library's output is different
emit val_with_caption(title=«expected », value=1)
emit val_with_caption(title=«actual », value=-1000000000000000000)
X divided by itself , result should be 1
[FAIL. Reason: panic: assertion failed (0x01); counterexample: calldata=0x04a3de55fffffffffffffffffffffffffffffffffc071f3f639b4c849ff50fe923868d8c args=[-5279932128231207277076622544905794164 [-5.279e36]]] test_division_by_itself(int256) (runs: 0, μ: 0, ~: 0)
Traces:
[4720] TestMath::test_division_by_itself(-5279932128231207277076622544905794164 [-5.279e36])
├─ emit val_with_caption(title: "expected ", value: 1)
├─ emit val_with_caption(title: "actual ", value: 1000000000000000000 [1e18])
└─ ← [Revert] panic: assertion failed (0x01)
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 29.70ms (15.36ms CPU time)
Division and Multiplication must be inverses of each other i.e a/b = a*1/b
[FAIL. Reason: panic: assertion failed (0x01); counterexample: calldata=0x3059d84b0000000000000000000902b5efdb52f4d43faa240c42621aec5994db88b478a00000000007d981425ffc8b45e777767b3c99980c487f3cac139630f22a88b474 args=[863042931711616742395571839419341622713847975807056032 [8.63e53], 826662375564581815062914149040971734032835598727036180843706496116 [8.266e65]]] testFuzz_divide_mul_inv(int256,int256) (runs: 0, μ: 0, ~: 0)
Traces:
[9678] TestMath::testFuzz_divide_mul_inv(863042931711616742395571839419341622713847975807056032 [8.63e53], 826662375564581815062914149040971734032835598727036180843706496116 [8.266e65])
├─ [0] VM::assume(true) [staticcall]
│ └─ ← [Return]
├─ emit val_with_caption(title: "a/b ", value: 1044009 [1.044e6])
├─ emit val_with_caption(title: "a*1/b", value: 863042931711616742395571839419341622 [8.63e35])
└─ ← [Revert] panic: assertion failed (0x01)
Suite result: FAILED. 0 passed; 1 failed; 0 skipped; finished in 35.42ms (18.69ms CPU time)
But as we see , the attached bash responses , all the tests fail.
Here is the exact test file i've used
pragma solidity 0.8.25;
import { UD60x18, ud60x18 } from "@prb-math/UD60x18.sol";
import { SD59x18, sd59x18 } from "@prb-math/SD59x18.sol";
import{Vm} from "forge-std/Vm.sol";
library Math {
function divUp(SD59x18 a, SD59x18 b) internal pure returns (SD59x18) {
return a.mod(b).isZero() ? a.div(b) : a.div(b).add(sd59x18(1));
}
function divUp(UD60x18 a, UD60x18 b) internal pure returns (UD60x18) {
return a.mod(b).isZero() ? a.div(b) : a.div(b).add(ud60x18(1));
}
function max(SD59x18 a, SD59x18 b) internal pure returns (SD59x18) {
return a.gt(b) ? a : b;
}
function max(UD60x18 a, UD60x18 b) internal pure returns (UD60x18) {
return a.gt(b) ? a : b;
}
function min(SD59x18 a, SD59x18 b) internal pure returns (SD59x18) {
return a.lt(b) ? a : b;
}
function min(UD60x18 a, UD60x18 b) internal pure returns (UD60x18) {
return a.lt(b) ? a : b;
}
}
contract TestMath {
using Math for SD59x18;
Vm private constant vm = Vm(address(uint160(uint256(keccak256("hevm cheat code")))));
constructor() {}
event val_with_caption(string title, SD59x18 value);
function test_division_by_1(SD59x18 a) external {
SD59x18 one=(sd59x18(1));
SD59x18 res = a.divUp(one);
emit val_with_caption('expected ',a);
emit val_with_caption('actual ',res);
assert(res==a);
}
function test_division_by_itself(SD59x18 a) external {
SD59x18 res = a.divUp(a);
emit val_with_caption('expected ',sd59x18(1));
emit val_with_caption('actual ',res);
assert(res==sd59x18(1));
}
function testFuzz_divide_mul_inv(SD59x18 a,SD59x18 b) external {
*
* a/b = a*1/b
*/
vm.assume(b>sd59x18(0));
SD59x18 a_by_b = a.divUp(b);
SD59x18 one=sd59x18(1);
SD59x18 one_by_b = one.divUp(b);
emit val_with_caption('a/b ',a_by_b);
emit val_with_caption('a*1/b',a*one_by_b);
assert(a_by_b==a*one_by_b);
}
}
Impact
Incorrect calculation lead to jeopardizing the system as a whole
Tools Used
Foundry
Recommendations
Carefully examine these properties and make sure all of them hold