Entropy.java
package org.egothor.methodatlas.detect.secrets.internal;
import java.util.Arrays;
/**
* Shannon-entropy helper for the unanchored high-entropy detection pass.
*
* @since 4.1.0
*/
public final class Entropy {
/** Natural log of 2, used to convert {@link Math#log(double)} to base-2. */
private static final double LOG2 = Math.log(2);
private Entropy() {
// utility class
}
/**
* Computes the Shannon entropy of {@code s} in bits per character.
*
* <p>
* Character frequencies are computed by sorting a {@code char[]} copy and
* counting runs of equal characters, which is allocation-light (one small
* array, no autoboxing) and correct for the full char range.
* </p>
*
* @param s input string; never {@code null}
* @return entropy in bits per character; {@code 0.0} for an empty string
*/
public static double shannonBitsPerChar(String s) {
if (s.isEmpty()) {
return 0.0;
}
char[] chars = s.toCharArray();
Arrays.sort(chars);
double entropy = 0.0;
double len = chars.length;
int runStart = 0;
for (int i = 1; i <= chars.length; i++) {
if (i == chars.length || chars[i] != chars[runStart]) {
double p = (i - runStart) / len;
entropy -= p * (Math.log(p) / LOG2);
runStart = i;
}
}
return entropy;
}
}