Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 17 additions & 0 deletions audit/mutation-test-scans.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
[
{
"timestamp": "2026-07-18T01:50:46Z",
"commit": "208336a29fc53b74226e385594f02703336974d5",
"publishedTag": "0.1.3",
"commitsAheadOfTag": 0,
"scope": "change-only: LibCtPop test hardening (mask-constant pins, lone-high-bit) + NatSpec/README docs",
"tool": "adversarial-mutation-test",
"skillVersion": "0.27.0",
"summary": {
"behaviours": 11,
"candidates": 0,
"confirmed": 0,
"filed": []
}
}
]
51 changes: 50 additions & 1 deletion test/src/lib/LibCtPop.ctpop.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,18 @@
pragma solidity =0.8.25;

import {Test} from "forge-std-1.16.1/src/Test.sol";
import {LibCtPop} from "src/lib/LibCtPop.sol";
import {
LibCtPop,
CTPOP_M1,
CTPOP_M2,
CTPOP_M4,
CTPOP_M8,
CTPOP_M16,
CTPOP_M32,
CTPOP_M64,
CTPOP_M128,
CTPOP_H01
} from "../../../src/lib/LibCtPop.sol";

/// @title LibCtPopTest
/// CTPOP (count population) is a function that counts the number of bits set in
Expand Down Expand Up @@ -72,4 +83,42 @@ contract LibCtPopTest is Test {
uint256 ctSlow = LibCtPop.ctpopSlow(x);
assertEq(ct, ctSlow);
}

/// A lone bit in the highest position is counted, deterministically
/// pinning the top of the range rather than relying on fuzz coverage.
function testCtPopLoneHighBit() external pure {
uint256 x = 1 << 255;
assertEq(1, LibCtPop.ctpop(x));
assertEq(1, LibCtPop.ctpopSlow(x));
}

/// Build the alternating mask with `width` bits set then `width` bits
/// clear, starting from the low bit, across the whole word.
function altMask(uint256 width) internal pure returns (uint256 mask) {
unchecked {
uint256 chunk = (1 << width) - 1;
for (uint256 i = 0; i < 256; i += 2 * width) {
mask |= chunk << i;
}
}
}

/// Every mask constant is pinned against an independent re-derivation so
/// a corrupted constant cannot hide behind ctpop and ctpopSlow sharing it.
function testMaskConstantsRederived() external pure {
assertEq(altMask(1), CTPOP_M1);
assertEq(altMask(2), CTPOP_M2);
assertEq(altMask(4), CTPOP_M4);
assertEq(altMask(8), CTPOP_M8);
assertEq(altMask(16), CTPOP_M16);
assertEq(altMask(32), CTPOP_M32);
assertEq(altMask(64), CTPOP_M64);
assertEq(altMask(128), CTPOP_M128);

uint256 h01 = 0;
for (uint256 i = 0; i < 256; i += 8) {
h01 |= uint256(1) << i;
}
assertEq(h01, CTPOP_H01);
}
}
Loading