Dandy Mahogany Buffalo
Medium
The _rpow
function, used to compute exponentiation with rounding in assembly, is prone to precision loss and undefined behavior. The function performs repeated multiplications and divisions, which are susceptible to edge cases such as zero input values (x = 0
) or excessively large exponents (n
). Despite implementing checks to prevent overflow, these checks do not fully guard against all edge cases, resulting in incorrect results or reverts in unexpected scenarios.
The _rpow
function is implemented as follows:
https://github.com/sherlock-audit/2024-11-autonomint/blob/main/Blockchain/Blockchian/contracts/lib/BorrowLib.sol#L1038-L1060
function _rpow(uint x, uint n, uint b) public pure returns (uint z) {
assembly {
switch x case 0 {switch n case 0 {z := b} default {z := 0}}
default {
switch mod(n, 2) case 0 { z := b } default { z := x }
let half := div(b, 2) // for rounding.
for { n := div(n, 2) } n { n := div(n,2) } {
let xx := mul(x, x)
if iszero(eq(div(xx, x), x)) { revert(0,0) }
let xxRound := add(xx, half)
if lt(xxRound, xx) { revert(0,0) }
x := div(xxRound, b)
if mod(n,2) {
let zx := mul(z, x)
if and(iszero(iszero(x)), iszero(eq(div(zx, x), z))) { revert(0,0) }
let zxRound := add(zx, half)
if lt(zxRound, zx) { revert(0,0) }
z := div(zxRound, b)
}
}
}
}
}
-
Edge case for
x = 0
: Whenx = 0
, computations such aslet xx := mul(x, x)
result inxx = 0
. While some cases are covered by theswitch x
logic, the subsequent arithmetic operations may still lead to undefined behavior. -
Exponentiation with large
n
: Iterative squaring (x := mul(x, x)
) and dividing operations can lead to precision loss or undefined values due to the finite size ofuint
.
For example:
Input: _rpow(0, 3, 10)
Expected Behavior: 0
Actual Behavior: Potential revert or incorrect result.
No response
No response
No response
- Results in invalid calculations for contracts that rely on precise exponentiation, potentially causing financial loss or unintended behavior.
- A contract invoking
_rpow
with edge-case inputs may revert, leading to DoS for critical operations. - Improper rounding or incorrect values may lead to mismanagement of funds in financial applications, affecting protocol integrity.
const { ethers } = require("hardhat");
const { expect } = require("chai");
describe("Testing rpow function", function () {
let contract;
before(async () => {
const Rpow = await ethers.getContractFactory("RpowContract"); // Replace with actual contract name
contract = await Rpow.deploy();
await contract.deployed();
});
it("should handle x=0 and n > 0", async () => {
const result = await contract._rpow(0, 3, 10);
console.log("Result:", result.toString());
expect(result).to.equal(0); // Expected behavior
});
it("should handle large n", async () => {
const result = await contract._rpow(2, 1e6, 1e18);
console.log("Result for large n:", result.toString());
});
});
Output:
For _rpow(0, 3, 10)
: Reverts or returns incorrect value.
For _rpow(2, 1e6, 1e18)
: Causes unexpected behavior, such as incorrect results due to precision loss.
- Explicitly handle
x = 0
andn = 0
at the beginning of the function. Reject excessively large values ofn
to prevent precision loss. - Use safe math libraries for all arithmetic operations, even in assembly.