Dria

Swan
NFTHardhat
21,000 USDC
View results
Submission Details
Severity: medium
Invalid

`Statistics::sqrt` function overflows

Summary

Statistics::sqrt function reverts when the input is type(uint256).max due to an integer overflow.

Vulnerability Details

When the input to the Statistics::sqrt function is type(uint256).max, the following line in the function causes an integer overflow:

https://github.com/Cyfrin/2024-10-swan-dria/blob/main/contracts/libraries/Statistics.sol#L40-L47

function sqrt(uint256 x) internal pure returns (uint256 y) {
@> uint256 z = (x + 1) / 2;
y = x;
while (z < y) {
y = z;
z = (x / z + z) / 2;
}
}

x + 1 overflows when x is the maximum uint256 value.

Poc

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test, console} from "../lib/forge-std/src/Test.sol";
import {Statistics} from "../contracts/libraries/Statistics.sol";
contract StatisticsTest is Test {
// 1. Fuzz test for the Statistics library's sqrt function, comparing it to UniSwap's sqrt function.
function testFuzzUniSqrt(uint256 x) public pure{
assertEq(Statistics.sqrt(x), uniSqrt(x));
}
// 2. After executing the `testFuzzUniSqrt` test, we get a revert error with the argument
// `type(uint256).max` (115792089237316195423570985008687907853269984665640564039457584007913129639935)
function testStatisticsSqrt() public {
vm.expectRevert();
Statistics.sqrt(type(uint256).max);
}
function testUniSqrt() public pure{
uint256 sqrt = uniSqrt(type(uint256).max);
console.log("uniSqrt(type(uint256).max): ", sqrt); // UniSwap's sqrt function does not revert when called with the argument `type(uint256).max`
}
// UniSwap's sqrt function is used to compare the results of the Statistics library's sqrt function.
function uniSqrt(uint256 y) internal pure returns (uint256 z) {
if (y > 3) {
z = y;
uint256 x = y / 2 + 1;
while (x < z) {
z = x;
x = (y / x + x) / 2;
}
} else if (y != 0) {
z = 1;
}
}
}

Steps to reproduce:

Inside the 2024-10-swan-dria directory:

  1. Run npm i --save-dev @nomicfoundation/hardhat-foundry to install the hardhat-foundry plugin.

  2. Add require("@nomicfoundation/hardhat-foundry"); to the top of the hardhat.config.js file.

  3. Run npx hardhat init-foundry in the terminal. This will generate a foundry.toml file based on the Hardhat project’s existing configuration, and will install the forge-std library.

  4. Create a file ("StatisticsTest.t.sol") in the ./test/ directory.

  5. Copy the provided test case into the file.

  6. Run forge test --mt testFuzzUniSqrt in the terminal

Test logs:

[FAIL: panic: arithmetic underflow or overflow (0x11); counterexample: calldata=0x4ecaaec0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff args=[115792089237316195423570985008687907853269984665640564039457584007913129639935 [1.157e77]]] testFuzzUniSqrt(uint256) (runs: 154, μ: 23902, ~: 12665)

Impact

The Statistics::sqrt function reverts when the input is type(uint256).max.

Statistics::stddev function calls the sqrt function. If the sqrt function overflows, stddev will revert.

Tools Used

Foundry Fuzz Test

Recommendations

Consider using the UniSwap's sqrt function as a reference to update the Statistics::sqrt function to handle the edge case when the input is type(uint256).max, or using Solmate FixedPointMathLib::sqrt implementation.

https://github.com/transmissions11/solmate/blob/main/src/utils/FixedPointMathLib.sol#L164

Updates

Lead Judging Commences

inallhonesty Lead Judge 12 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.