# The 512-bit multiply: why every BlazePhoenix number is exact to the last wei

> Canonical: https://blazephoenix.xyz/learn/the-512-bit-multiply
> License: CC BY 4.0 (attribution + link) · © 2026 BlazePhoenix
> Updated: 2026-07-21

Every proportion in BlazePhoenix — reward shares, collateral ratios, interest slices — runs through one full 512-bit multiply-then-divide (mulDiv), so the intermediate a·b product never overflows and no figure drifts by a single wei; dividing by an odd number uses a Newton-Raphson modular inverse that doubles its correct bits each step, 4 → 256.

A reward share, a collateral ratio, an interest slice — every one is a multiplication followed by a division: a·b/d. The trap is the middle. On the EVM a and b are each up to 256 bits, so their product a·b can be up to 512 bits — and a naive `a * b / d` silently discards everything above bit 256. The number you get back is not rounded; it is corrupt. Most contracts dodge this by keeping values small and hoping. BlazePhoenix does not hope: every proportion in both engines flows through one function, BlazePhoenixMathLib.mulDiv, which keeps the full 512-bit product and returns the exact floor of a·b/d.

This is the same full-precision multiply popularised by Remco Bloemen and Solady, reproduced here as the arithmetic floor the whole protocol stands on. The Master Conservation Identity, the boost weights, the dual accumulators, the liquidation math — none of them can drift by a single wei from a silent overflow, because the multiply underneath them cannot overflow.

## Splitting the product into 512 bits

The routine first computes the product as a 512-bit number held in two words, hi:lo, using the classic mulmod identity — the full product modulo 2^256 minus the low word, borrow-corrected:

```
let mm := mulmod(a, b, not(0))   // a·b mod (2^256 − 1)
let lo := mul(a, b)              // low 256 bits
let hi := sub(sub(mm, lo), lt(mm, lo))  // high 256 bits, borrow-corrected
```

## The Newton-Raphson modular inverse

When the high word is zero the product fits in 256 bits and a plain division is exact. Otherwise the routine does a true 512-by-256 division: it removes the remainder, factors out the powers of two, then needs to divide by an odd number d — which on a two’s-complement machine means multiplying by the modular inverse of d mod 2^256. That inverse is found by Newton-Raphson. A seed correct to 4 bits, then each step DOUBLES the number of correct bits:

> equation: invk+1=invk·(2−d·invk)4→8→16→32→64→128→256 — Quadratic convergence: the same doubling of correct digits as real-number Newton’s method. Six iterations from a 4-bit seed reach a full 256-bit inverse — exactly the six `inv := mul(inv, sub(2, mul(d, inv)))` lines in the source.

## The safe sibling, and why it exists

Alongside mulDiv sits mulDivSafe, which returns 0 rather than reverting when an input is zero or the result would overflow. The two are not interchangeable: mulDiv guards places where a wrong number must halt the transaction (a share that cannot be represented is a bug); mulDivSafe guards places where zero is the correct, safe answer (no stake, no interest). Choosing the right one at each call site is itself part of the safety argument.

And one detail that ties the multiply to solvency: rawBalanceOf, in the same library, reads the contract’s own BZPX balance by staticcall and returns 0 on any malformed response — which the conservation guard treats as a (safe-fail) breach. The contract measures its own backing with the same rigor it multiplies with.

**Verify it yourself:** read the exactness yourself: cast call 0x3f60C7aa0c36a78D200405feBE143d2Cf3fA0c77 "collateralRatio()(uint256)" --rpc-url https://mainnet.base.org, then call backing() and owed() and check backing·1e18/owed equals it to the wei — that ratio is a mulDiv

Related: https://blazephoenix.xyz/learn/master-conservation-identity · https://blazephoenix.xyz/learn/proof-of-solvency · https://blazephoenix.xyz/learn/transient-storage · https://blazephoenix.xyz/learn/the-monoslot
