Skip to main content
Sigvex

Divide Before Multiply

Detects arithmetic expressions where division precedes multiplication, causing precision loss from integer truncation.

Divide Before Multiply

Overview

The divide-before-multiply detector identifies arithmetic expressions where a division operation is performed before a multiplication, causing unnecessary precision loss. In Solidity’s integer arithmetic, division truncates toward zero. When the truncated result is subsequently multiplied, the rounding error is amplified. Reordering the operations to multiply first preserves precision.

Why This Is an Issue

Consider (a / b) * c versus (a * c) / b. If a = 7, b = 3, c = 2: the first evaluates to (2) * 2 = 4, while the second evaluates to 14 / 3 = 4. But with a = 5, b = 3, c = 2: the first gives (1) * 2 = 2, while the second gives 10 / 3 = 3. The error compounds in DeFi protocols processing large numbers of transactions, leading to systematic value extraction or accumulated losses.

How to Resolve

// Before: Vulnerable — division before multiplication
uint256 reward = (totalReward / totalStaked) * userStake;
// Loses precision: if totalReward = 999, totalStaked = 1000, result = 0

// After: Fixed — multiply first
uint256 reward = (totalReward * userStake) / totalStaked;
// Preserves precision: result = 999 * userStake / 1000

When multiplication-first risks overflow, use a mulDiv function:

uint256 reward = Math.mulDiv(totalReward, userStake, totalStaked);

Detection Methodology

  1. Division instruction identification: Locates DIV and SDIV opcodes in the bytecode.
  2. Result tracking: Traces the division result forward to check if it feeds into a subsequent MUL.
  3. Reordering safety check: Verifies whether reordering to multiply-first would risk overflow (in which case a mulDiv helper is recommended instead).
  4. Constant analysis: Filters out divisions by powers of 2 (which are bit shifts) and trivial cases.

Limitations

False positives: Intentional rounding-down-then-multiply patterns (e.g., computing per-share values that should be truncated) may be flagged. False negatives: Divide-before-multiply patterns split across multiple functions or temporaries may not be detected.

References