# Erroneous probability calculation in physical attributes can lead to significant issues

Off-by-one in AiArenaHelper.dnaToIndex uses >= instead of >, skewing attribute probabilities by 1% and making rare traits up to twice as common or impossible.

- Payout: Contest reward
- Severity: medium
- Program: AI Arena
- Credited: haxatron
- Disclosed: 2024-05-14
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2024-02-ai-arena-findings/issues/112
- Library page: https://bugbountylibrary.com/r/c4%3A2024-02-ai-arena%3AM-07
- Tags: domain:web3 impact:integrity kind:contest platform:code4rena sev:medium tech:solidity technique:source-review vuln:business-logic

**Target:** AiArenaHelper.sol attribute generation (dnaToIndex)
**Root cause:** Cumulative probability comparison uses `cumProb >= rarityRank` while rarityRank ranges [0,99], so the boundary value is counted in the earlier bucket, shifting 1% probability mass toward earlier indices.
**Steps:**
1. Compute rarityRank = (dna / attributeToDnaDivisor[attr]) % 100, giving [0,99].
2. In dnaToIndex, loop accumulating cumProb and select index when `cumProb >= rarityRank`.
3. With attrProbabilities [50,50], index 0 matches rarityRank [0,50] (51%) instead of [0,49] (50%).
4. With [1,99], first trait gets 2% instead of 1%; with [99,1], last trait gets 0% instead of 1%.
5. Fix: change comparison to `cumProb > rarityRank`.
**How found:** Code reading of the modulo range [0,99] versus the inclusive `>=` boundary in the cumulative probability loop; verified by hand-computing small probability arrays.
**Insight:** When a random value is taken modulo N (range 0..N-1) and compared against cumulative sums, the boundary comparison must be strict `>`; test with a probability array whose first or last element is 1 to expose the skew.
