# Early 72-digit adjustment in sqrt will lead to incorrect result exponent calculation

Float128.sqrt halves the exponent after trimming a 73-digit mantissa, producing an off-by-one exponent and grossly wrong square roots for large floats.

- Payout: Contest reward
- Severity: high
- Program: Forte
- Credited: montecristo
- Disclosed: 2025-04-29
- Write-up quality: 7/10
- Original: https://code4rena.com/reports/2025-04-forte-float128-solidity-library#h-01
- Library page: https://bugbountylibrary.com/r/c4%3A2025-04-forte-float128-solidity-library%3AH-01
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error vuln:precision-loss

**Target:** Float128 fixed-point math library (sqrt function)
**Root cause:** In the Uint512 sqrt path, the mantissa digit-trim adjustment (rMan/=BASE; ++rExp) is applied before rExp is halved, so the +1 increment is not halved, yielding an off-by-one exponent.
**Steps:**
1. Call Float128.sqrt on a packedFloat with 72-digit mantissa, e.g. mantissa=382e69, exponent=2267 (3.82e2338).
2. Observe Uint512.sqrt512 returns a 73-digit rMan; code trims it and increments rExp before halving.
3. Result exponent is 1168 instead of 1169.
4. Verify: float.div(result.mul(result)) returns >99 instead of ~1.
**How found:** Code review of sqrt's exponent bookkeeping; noticed the digit-trim increment happens before the /2 halving, unlike the non-Uint512 branch which halves first.
**Insight:** When auditing fixed-point math, compare parallel code paths (library vs fallback) for ordering differences; any pre-halving adjustment in a sqrt-like op is suspect because increments must be halved too.
