Summary
The standard deviation calculation in the Statistics library causes an underflow for normal input values, causing validation to revert and breaking core protocol functionality.
Vulnerability Details
function finalizeValidation(uint256 taskId) private {
TaskRequest storage task = requests[taskId];
for (uint256 g_i = 0; g_i < task.parameters.numGenerations; g_i++) {
uint256[] memory scores = new uint256[]();
for (uint256 v_i = 0; v_i < task.parameters.numValidations; v_i++) {
scores[v_i] = validations[taskId][v_i].scores[g_i];
}
>> (uint256 _stddev, uint256 _mean) = Statistics.stddev(scores);
...
}
The finalizeValidation function calculates the standard deviation of validation scores.
function avg(uint256[] memory data) internal pure returns (uint256 ans) {
uint256 sum = 0;
for (uint256 i = 0; i < data.length; i++) {
sum += data[i];
}
ans = sum / data.length;
}
function variance(uint256[] memory data) internal pure returns (uint256 ans, uint256 mean) {
mean = avg(data);
uint256 sum = 0;
for (uint256 i = 0; i < data.length; i++) {
>> uint256 diff = data[i] - mean;
sum += diff * diff;
}
ans = sum / data.length;
}
function stddev(uint256[] memory data) internal pure returns (uint256 ans, uint256 mean) {
>> (uint256 _variance, uint256 _mean) = variance(data);
mean = _mean;
ans = sqrt(_variance);
}
When calculating variance, the function subtracts the mean from each data. An underflow occurs when data[i] is less than the mean.
Impact
Validation will always revert unless all scores are identical so LLMOracleCoordinator and BuyerAgent cannot function properly.
And users pay fees for requests but never receive results due to validation failures because request function is working.
Tools Used
None
Recommendations
Modify the difference calculation logic in the variance function to handle values below mean:
function variance(uint256[] memory data) internal pure returns (uint256 ans, uint256 mean) {
mean = avg(data);
uint256 sum = 0;
for (uint256 i = 0; i < data.length; i++) {
>> uint256 diff = data[i] > mean ? data[i] - mean : mean - data[i];
sum += diff * diff;
}
ans = sum / data.length;
}