Skip to content

audit/H03: packLossy lossless flag discarded by every caller in LibDecimalFloat #191

@thedavidmeister

Description

@thedavidmeister

Audit reference

Protofire, March 2026, finding H03 — Silent Precision Loss in Packed Arithmetic Operations. Severity: High. Status at audit (19a65ffa): New.

What

Every public arithmetic function in LibDecimalFloat finalizes with (Float c,) = packLossy(...), discarding the bool lossless flag. On extreme exponent underflow (e.g. mul where expA + expB < int32.min), packLossy returns (FLOAT_ZERO, false) to indicate the value rounded to zero. The discarded flag means the library silently propagates zero in place of the true (tiny but non-zero) result.

Affected callers (every packLossy use site in LibDecimalFloat.sol):

  • add (line 397), sub (line 415), minus (line 430), negate path (line 454)
  • mul (line 486), div (line 505), inv (line 518)
  • intFrac calls (lines 602, 613)
  • floor (line 632), ceil (line 659)
  • pow10 (line 677), log10 (line 693), pow (line 772)
  • fromFixedDecimalLossyPacked (line 134) — only legitimate lossy: true propagation in the public surface

Impact

Math library composition breaks: f(x) * 0 shapes appear from values that should be small but non-zero. Triggers downstream "x must be non-zero" reverts in caller protocols, or worse, silent acceptance of zero where a small non-zero was expected. Reaching exponent ≈ int32.min requires adversarial input construction; not reachable from typical arithmetic on parsed values.

Recommendation

Two options, not mutually exclusive:

  1. Revert at every caller when lossless = false for the underflow case (returns FLOAT_ZERO). Distinguishes the coefficient too big for int224 form of lossless = false from the exponent underflow → zero form so the latter reverts.
  2. Expose lossy variants of each op that surface the flag to the caller.

Verification

Per-op tests that hand-construct exponent inputs near int32.min and assert either revert (option 1) or lossless = false propagation (option 2).

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions