3 Commits
Author SHA1 Message Date
zeekay 5ec478c3ed stableswap, math: two halts from calldata, and a pool that leaked a wei per swap
A precompile panic aborts the block rather than the call, so both of these
stopped every validator on any chain with stableswap enabled.

An amplification coefficient of zero divides by zero in all three Newton ops --
computeY's c/(A*n*n) and D/(A*n), and computeD's denominator (A*n-1)*D +
(n+1)*dP, which crosses exactly zero. A 40,000-input sweep hit it 665 times. A
is now read and refused at the boundary, which is also the honest answer: the
invariant is undefined at A=0.

addLiquidity divides by D0, and computeD returns zero for an empty pool.
Balances and totalSupply arrive as independent calldata, so "no assets, LP
tokens outstanding" is reachable. Post-fix sweep: zero panics in 40,000 inputs.

computeY used floor division, so its iterates drifted BELOW the true root in
55% of solves, by up to 2 wei, which getDy's single -1 margin did not cover.
The invariant therefore DECREASED across a swap -- 27 losses in 19,996 random
swaps, a wei at a time out of the pool. Newton converges from above on this
convex function, so ceiling division restores the one-sidedness the proof
depends on. After: zero losses, 19,847 gains.

math returned every result through padTo32, which keeps only the low 32 bytes.
MulDiv(2^255, 4, 1) returned 0. MulDiv(max, max, 1) returned 1. And dex.MulDiv
PANICS on the same input -- two behaviours for one operation, one of them a
plausible-looking wrong number in the primitive that computes fees and share
ratios. Now refuses with ErrOverflow, matching FullMath.sol. Consensus-visible;
it needs a coordinated upgrade.

Coverage: dex 57.1 -> 99.1, stableswap 80.6 -> 98.6, swap 87.6 -> 99.6,
v3 78.1 -> 98.7, math 78.5 -> 97.6. 50 of 52 mutations caught, both survivors
proven unreachable rather than assumed. dex is now order-independent: -count=2
and -shuffle=on both pass, 843 tests run individually and 260 shuffle seeds
clean. The leak was a package-level resolver latch that installed on top of
whatever was live; t.Cleanup had fixed the exit and not the entry.

Also corrected five comments describing the CLOB price limit as IEEE-754
float64 bits. It is exact big.Int on an integer grid, and a reviewer would have
believed consensus compared float bit patterns.
2026-08-28 13:46:40 -07:00
zeekay e79a887d0e fix: P0-P2 hardening — consensus safety, OOM prevention, error unification
P0 consensus-critical:
- FHE: deterministic keygen from SHA-256("LUX_FHE_KEYGEN_v1"), StateDB
  ciphertext storage (replaces ephemeral in-memory ctStore), remove
  crypto/rand fallback
- time.Now() eliminated from 20 state-modifying paths across bridge (12),
  dex (7), attestation (5) — all now use blockTimestamp parameter
- WebSocket: 1024-client semaphore, 64KB read limit, 60s deadline, pong
  handler, origin check on chain/dag/evm indexer subscribers

P1 correctness:
- I-Chain indexer: identity.Health → identity.getLatestBlock
- Graph pagination: min(limit, 1000) cap across 25 resolver files
- Error sentinels: 31 packages unified to contract.ErrInvalidInput

P2 standardization:
- 14 packages migrated from manual gas checks to contract.DeductGas()
- Gas naming: {Name}Gas → Gas{Name} in secp256r1, ed25519, math, quasar
- Registry address format comment clarified (PCII vs legacy ranges)

37/37 precompile tests pass.
2026-03-02 10:11:20 +00:00
zeekay 3d48a72d2e feat: precompiles — anchor, babyjubjub EIP-2494, coverage, slug validation 2026-03-02 02:00:00 +00:00