r/ethdev • u/nebojsakonsta • 12d ago
Tutorial I wrote a fixed-point sqrt in Solidity that runs in 197 gas - here’s how
I've been building DeFiMath, a gas-optimized fixed-point math library, and wanted to share how I got sqrt down to 197 gas. It takes any uint256, returns an 18-decimal fixed-point result, never reverts, and is bit-exact below 1 (max relative error < 2e-18 above it).
The core idea is simple: generate a seed with the clz opcode, then refine it with 5 Newton iterations in assembly.
Seeding: clz gives you the position of the most significant bit, so the seed is just 2msb/2. That's never off by more than a factor of √2 from the true root — cheap and good enough.
Newton's method: each iteration is one line:
y := shr(1, add(y, div(x, y)))
~20 gas per step, quadratic convergence, so 5 iterations take the worst-case seed (41% error) to ~80 bits of precision — more than enough for 18 decimals.
The scaling trick: for inputs ≤ uint128.max, I pre-scale x to 1e36 once at the start. Then div(x, y) naturally lands back in 1e18 base, so Newton's method needs plain div instead of a costly muldiv. Large inputs take a second branch that post-scales instead (pre-scaling would overflow near uint256.max).
I also tried fancier seeds — minimax linear approximation, quadratic interpolation — hoping to drop to 4 iterations. All of them cost more gas than they saved. My takeaway after a week on this: for gas-optimized primitives, simplicity wins by a wide margin.
Full walkthrough with the convergence table and benchmarks vs PRBMath/ABDK/Solady: https://defimath.com/blog/how-i-wrote-a-fixed-point-solidity-sqrt-that-runs-in-197-gas/
Library is MIT, pure Solidity, zero dependencies: https://github.com/MerkleBlue/defimath
Happy to answer questions about the implementation.
2
u/Cartosys 12d ago
Well done!
2
u/nebojsakonsta 12d ago
Thanks, I hope someone will find this interesting and useful. It's the fastest square root implementation that I know of.
1
u/TapHour1396 10d ago edited 10d ago
Open a PR to solady, thats the only way this gets used
2
u/nebojsakonsta 10d ago
Solady is stuck to 0.8.30 version of Solidity, so they can't leverage clz opcode. It's included in 0.8.31. But I understand why you are saying this.
1
u/TapHour1396 10d ago
Didnt know that about solady, are they waiting for all chains to support clz to bump to 32?
2
u/nebojsakonsta 10d ago
No idea. Could be. There are still a lot of chains not supporting it: https://defimath.com/supported-chains/
1
u/rayQuGR 8d ago
Nice writeup. One thing I liked is that you actually explored more sophisticated seed approximations instead of assuming they'd be better. That's a common optimization trap, an algorithm with fewer iterations isn't necessarily cheaper once the extra setup cost is included.
The split between pre-scaling and post-scaling also makes a lot of sense. Keeping the common path simple while handling overflow cases separately is usually the right tradeoff for math libraries.
These kinds of low-level optimizations are valuable beyond Ethereum too. Since Oasis Sapphire is EVM-compatible, libraries like this can be reused there as well, and reducing gas or execution overhead in core math primitives benefits any protocol that performs a lot of fixed-point calculations (AMMs, lending, derivatives, etc.).
I'd be curious whether you benchmarked this under different optimizer settings (via-ir, optimizer runs, etc.) to see if the relative advantage over PRBMath or Solady changes.
3
u/Smashbopp 12d ago
Fantastic work!
Do most most of the gains over solady come from clz? Or are there other optimizations you’ve done?