Skip to content

Effectiveness Evaluation Framework for Different Mutator Configurations #115

Description

@Chand-ra

Use this statistical framework to rigorously compare two IR‑mutator configurations (e.g., “full stack” vs. “full stack + new operator”) across Lightning implementations. The primary metric is edge coverage growth over 24‑hour campaigns.

The framework is largely inspired by Evaluating Fuzz Testing (Klees et al., 2018).

1. What You Compare

Both configurations run the IR fuzzing scenario against the same Lightning targets, starting from the same snapshot. The only difference is the set of mutators.

Configuration A Configuration B
Mutators e.g., current Full Stack e.g., Full Stack + your new operator
Scenario IR scenario (IrScenario) Same
Snapshot PostInitSetup (or advanced, but identical for both) Same
Generators Existing suite Same
Seeds Empty corpus, or a small set of simple programs (see Section 2) Same
Engine AFL++ (latest stable) + Nyx, fast schedule Same

Why everything except the mutators is identical?

We want to isolate the effect of the mutator changes. If we also changed the scenario, snapshot, or seeds, any observed difference in coverage growth could be caused by those factors rather than the mutators themselves. Keeping all other variables constant lets us attribute differences directly to the mutation strategy.

2. Seed Corpus

The IR fuzzer includes generators that produce valid programs at runtime, an empty initial corpus is acceptable and often simplest. The generators will populate the queue with structurally sound seeds.

Alternatively, you may start with a small set of simple IR programs (e.g., ping/pong, a minimal open_channel). These give a slight head start but are not strictly necessary.

Important: If the IR format changes (e.g., a new instruction set or a new postcard schema), all seeds must be regenerated from the new IR. Never mix seeds produced by different IR versions in the same comparison: that would introduce a confounding variable.

  • Same seeds for all trials: Use the identical seed set for every trial (empty or not) and every configuration to ensure fairness.

3. Trial Structure

  • Number of trials: 30 independent trials per configuration, per target. This number is recommended by Klees et al. (2018) to achieve reasonable statistical power for detecting meaningful differences.
  • Duration: Each trial runs for 24 hours (wall‑clock). This is long enough to observe substantial coverage growth and plateaus.
  • Parallelism:
    • Each trial is a single AFL++ process, so it uses exactly one CPU core.
    • You do not need to give each trial a dedicated machine: multiple trials can share a multi‑core machine by running in parallel, each pinned to a physical core to avoid cache contention.
    • For example, on a 30‑core server you can run all 30 trials in parallel, each pinned to a physical core. The entire campaign for one configuration per target finishes in slightly over 24 hours.

4. Data to Collect

For each trial, collect from AFL++’s output directory:

  • plot_data – time series of edges_found. We extract two metrics:

    • Final coverage (the number of edges found at the 24‑hour mark). This is the primary metric.
    • AUC (Area Under the edge‑Coverage Curve) as a secondary metric that summarises early exploration speed.

    Why AUC? It summarises the entire coverage growth trajectory: a higher AUC means the fuzzer discovered more edges, sooner.

  • fuzzer_stats – we only care about execs_per_sec (to check if one configuration trades coverage quality for raw speed). We ignore other stats (e.g., pending_favs, cycles_done, stability) because they are either redundant with coverage data or not directly relevant to our comparison of coverage growth.

  • fuzz_bitmap – Used to calculate union coverage (see section 5.8).

5. Analysis (per target)

For each target separately:

  1. Extract metrics from each trial:

    • Primary metric: The final coverage value (the edges_found at the 24‑hour mark).
    • Secondary metric (AUC): Compute the Area Under the edge‑Coverage Curve from plot_data using trapezoidal integration. AUC summarises early exploration speed and is reported alongside final coverage for additional context.
  2. Sanity‑check visualisation (coverage‑over‑time):

    For each configuration, plot the median edges_found over time with IQR bands. If the two configurations' bands overlap for most of the campaign and only diverge near hour 24, the final‑coverage result should be interpreted cautiously: the advantage may be driven by late, noisy differences rather than sustained improvement.

  3. Visualise: Box‑plots of final-coverage values for Configuration A and B.

  4. Statistical test: Use the Mann‑Whitney U test (also called Wilcoxon rank‑sum).

    • Why not a t‑test or just compare means? Fuzzing metrics like final-coverage are almost never normally distributed. The Mann‑Whitney U test is non‑parametric: it doesn’t assume normality, and instead tests whether one configuration tends to produce higher final-coverage values more often than the other.
    • Why not simply compare medians? Medians alone don’t tell you if the difference is statistically reliable. The Mann‑Whitney test assesses whether the observed difference could be due to random chance, and it works on the full distributions, not just a central value.
    • The test gives a p‑value: the probability of seeing a difference at least as extreme as observed, assuming the two configurations are equally effective.
  5. Measure the magnitude of difference: We use the Vargha‑Delaney $\hat{A}_{12}$ statistic.

    It measures the probability that a randomly chosen trial from Configuration B will have a higher final-coverage than a randomly chosen trial from Configuration A.

    • $\hat{A}_{12} = 0.5$ → no difference (both equally likely to win).
    • $\hat{A}_{12} > 0.5$ → B tends to outperform A.
    • For example, $\hat{A}_{12} = 0.68$ means that in about 68% of random pairings, B’s final-coverage is larger than A’s.

    This is straightforward to compute: it’s the Mann‑Whitney U statistic divided by the product of the two sample sizes ($n_A \times n_B$).

  6. Report:

    • Median final-coverage and AUC for each configuration.
    • Inter‑quartile range (IQR) = difference between the 75th and 25th percentiles.
      • Why IQR? The IQR captures the spread of the middle 50% of the data. A small IQR means the fuzzer’s performance is consistent across trials; a large IQR indicates high variability. If Configuration B has a higher median but also a much wider IQR, the improvement might be less reliable: some runs may perform exceptionally well while others lag. Reporting both median and IQR gives a fuller picture than a single number.
    • Raw p‑value from the Mann‑Whitney test.
    • Effect size $\hat{A}_{12}$.
  7. Adjusting for multiple comparisons:

    When you test multiple targets (up to 4), the chance of getting at least one false‑positive (p < 0.05) simply by luck increases. This is easiest to see with a short calculation.

    If you run an independent test on each of $m$ targets and use the standard $\alpha = 0.05$ threshold, the probability that all tests correctly fail to reject the null hypothesis (no false positives) is $(1 - 0.05)^m = 0.95^m$.

    For $m = 4$, that is $0.95^4 \approx 0.8145$.

    Thus, the probability of at least one false positive is $1 - 0.8145 = 0.1855$, or about 18.6%. That is, you have a nearly one‑in‑five chance of concluding a difference exists when in fact none does. That’s too high for a rigorous evaluation.

    The Holm‑Bonferroni correction controls this family‑wise error rate so that the overall probability of any false positive remains ≤ 0.05, regardless of how many targets you test. It works by adjusting each raw p‑value according to its rank, making it harder to reach significance when many tests are performed.

    The procedure:

    • Sort the p‑values from smallest to largest: $p_1 \le p_2 \le p_3 \le p_4$.
    • Compute adjusted values:
      $$p_{\text{adj},i} = \min(1, ; p_i \times (m - i + 1))$$, where $m$ is the number of targets (e.g., 4).
    • Compare each $p_{\text{adj},i}$ to 0.05. If the smallest adjusted p‑value is < 0.05, that target’s difference is significant; then proceed to the next, and so on. Stop at the first non‑significant one.
  8. Union coverage (descriptive only):

    For each configuration, perform a byte‑wise maximum (logical OR) across all 30 bitmaps, then count the number of non‑zero bytes. This gives the union of edges covered by any trial, representing the coverage ceiling for a multi‑core deployment. This is a single scalar per configuration, so it cannot be statistically tested. Report it purely as a practical upper‑bound estimate.

6. Interpretation

  • Why 0.05? It’s the conventional significance level in empirical sciences, meaning there’s only a 5% risk of concluding a difference exists when in fact it doesn’t. It’s not a magic number, but a widely accepted trade‑off between sensitivity and false positives.

  • If Configuration B gives a higher median final-coverage, an adjusted p‑value < 0.05, and $\hat{A}_{12} &gt; 0.5$ (say > 0.56):

    The new mutator likely improves coverage growth. The effect is statistically significant, and the effect size indicates a meaningful (not just trivial) advantage. Check the IQR: a smaller or comparable IQR relative to A suggests the improvement is consistent.

  • If adjusted p‑value < 0.05 but $\hat{A}_{12}$ is very close to 0.5 (e.g., 0.51):

    The difference is statistically significant but practically tiny. The new mutator provides a marginal, possibly negligible, improvement. Consider whether the extra code complexity is worth it.

  • If adjusted p‑value > 0.05 but $\hat{A}_{12}$ is large (e.g., > 0.6):

    The effect is substantial, but your trial count might be too low to reach significance. Consider increasing the number of trials (e.g., to 50) before drawing firm conclusions. Always look at the effect size alongside the p‑value.

  • If adjusted p‑value > 0.05 and $\hat{A}_{12}$ is very close to 0.5:

    There is no evidence that the new mutator changes coverage. The observed difference is well within the range of random noise. The mutator likely has no practical impact; consider whether it might still be useful in niche protocol states not captured by the default snapshot, or whether a larger experiment (more trials) could reveal a subtle effect.

  • If $\hat{A}_{12}$ < 0.5 (Configuration B tends to produce lower final-coverage than A):

    The new mutator might degrade coverage. If this trend is statistically significant (adjusted p < 0.05), the mutator is harmful and should be rejected or redesigned. If not significant, the negative trend is weak and could be due to chance; more trials can clarify.

  • IQR interpretation:

    • A configuration with higher median and smaller IQR is clearly superior: it consistently achieves better coverage.
    • A configuration with higher median but larger IQR may have a few excellent runs masking many mediocre ones; the advantage is less reliable.
    • If the IQRs overlap substantially, the difference in medians may not be meaningful.
  • Check execution speed: Report median execs_per_sec. If Configuration B achieves equal or better coverage at a lower execution speed, the mutations are more efficient. If speed is much lower without coverage gain, the mutator may be too expensive.

7. Quick Sanity Checks

  • Throughput (execs_per_sec): compare medians; large discrepancies should be discussed.
  • Hardware noise: If you run many parallel trials, monitor whether execution speed varies across cores. You can group trials by throughput and re‑run the analysis on each group to check if results hold.

8. What to Do with the Results

  • Coverage improves significantly → consider merging the new mutator into the default set.
  • No significant difference → the mutator might still be useful for specific protocol corners; test on advanced snapshots (e.g., PostChannelOpenSetup) or run the full ground‑truth evaluation to see if it helps find real bugs.
  • Coverage degrades → examine whether the mutations are too destructive, too slow, or interfere with other operators.

9. Walkthrough Examples

Single Target Example

9.1 Single Target (CLN)

Configurations:

  • A (Baseline): Current full mutator stack (InstructionReorder, InputSwap, OperationParam, Splice, GeneratorInsertion).
  • B (Experimental): Baseline + a new InstructionDelete mutator.

We run 30 trials of each configuration on the same machine (30 cores, each trial pinned to a physical core), all starting from the same 5 IR program seeds and the PostInitSetup snapshot.

9.1.1 Final-coverage from plot_data

For each trial, AFL++ writes plot_data as a table of timestamps (Unix seconds) and cumulative edge counts. Consider one trial from Configuration A, whose plot_data (abbreviated) looks like:

Time (hours) edges_found
0 0
1 100
2 150
4 170
8 175
24 180

Thus, this trial’s final-coverage = 180.

For Configuration A, suppose the 30 resulting final-coverage values (after rounding) are:

152, 148, 155, 147, 150, 153, 149, 151, 148, 154, 150, 149, 152, 147, 153, 148, 151, 150, 149, 152, 154, 148, 150, 151, 149, 153, 150, 148, 152, 151

For Configuration B:

160, 162, 158, 163, 159, 161, 164, 160, 162, 161, 159, 163, 160, 162, 164, 161, 163, 160, 162, 164, 161, 159, 163, 160, 162, 164, 161, 163, 160, 162

9.1.2 Medians and IQRs

  • A: Median (15th/16th average of sorted values) = 150.5; Q1 (25th percentile) = 149, Q3 (75th percentile) = 152 → IQR = 152 - 149 = 3.
  • B: Median = 162. Q1 = 160, Q3 = 163 → IQR = 3.

Both IQRs are small and equal, indicating consistent performance in each configuration.

9.1.3 Mann‑Whitney U test

We rank all 60 final-coverage values together. Every value from B (min 158) is larger than every value from A (max 155). Therefore, the Mann‑Whitney U statistic for B vs. A is $30 \times 30 = 900$, the maximum possible.

The exact p‑value can be calculated using an online calculator, and is < 0.0001. This means the probability of such an extreme separation happening by chance is essentially zero.

9.1.4 Effect size

$\hat{A}_{12} = U / (n_A \times n_B) = 900 / 900 = 1.0$.

A randomly chosen trial from Configuration B always has a higher final-coverage than a randomly chosen trial from A. A massive effect.

9.1.5 Execution speed

From fuzzer_stats:

  • Median execs_per_sec: A = 125, B = 122 (slight drop).

9.1.6 Interpretation

  • Statistically significant: p < 0.05 (no correction needed for a single target).
  • Effect size $\hat{A}_{12} = 1.0$ – overwhelming.
  • Performance is consistent (identical IQRs).
  • The negligible speed loss (125 → 122 execs/sec) is far outweighed by the coverage gain.

Conclusion: The InstructionDeleteMutator substantially improves coverage on CLN. Merge it into the default mutator set.

Note: The separation in this example is artificially clean for illustration. Real‑world coverage distributions typically show overlap and noise, as seen in the multi‑target example below.

The same procedure applies when using AUC as the metric: we’d compute medians, IQRs, and p‑values.

Multiple Targets Example

9.2 Multiple Targets (All Four Implementations)

Now suppose we repeat the same experiment on LND, LDK, and Eclair in addition to CLN. All other parameters (30 trials, 24 hours, identical seeds and snapshot) remain the same. We obtain:

Target Median A Median B IQR A IQR B raw p‑value $\hat{A}_{12}$
CLN 150.5 162 3 3 < 0.0001 1.00
LND 210 215 12 14 0.032 0.61
LDK 180 182 5 6 0.410 0.53
Eclair 90 105 8 9 0.007 0.66

9.2.1 Holm‑Bonferroni correction

We have $m = 4$ tests. Sort the raw p‑values from smallest to largest:

  1. CLN: < 0.0001
  2. Eclair: 0.007
  3. LND: 0.032
  4. LDK: 0.410

Apply the formula $p_{\text{adj},i} = \min(1, ; p_i \times (m - i + 1))$:

  • CLN: $p_{\text{adj}} = 0.0001 \times 4 \approx 0.0004$
  • Eclair: $p_{\text{adj}} = 0.007 \times 3 = 0.021$
  • LND: $p_{\text{adj}} = 0.032 \times 2 = 0.064$
  • LDK: $p_{\text{adj}} = 0.410 \times 1 = 0.410$

Compare each to 0.05:

  • CLN: significant (0.0004 < 0.05)
  • Eclair: significant (0.021 < 0.05)
  • LND: not significant (0.064 > 0.05) – stop here; LDK is automatically not significant.

9.2.2 Interpretation per target

  • CLN: Huge, significant effect ($\hat{A}_{12}=1.0$). Clear win for B.
  • Eclair: Significant with a medium‑large effect ($\hat{A}_{12}=0.66$). IQRs comparable → consistent improvement.
  • LND: Raw p = 0.032 looked promising, but after correction it is 0.064 (not significant). The effect size (0.61) suggests a moderate advantage; with more trials (e.g., 50) it might become significant.
  • LDK: No significant difference ($\hat{A}_{12}=0.53$ nearly 0.5). The mutator has essentially no effect here.

9.2.3 Overall conclusion

The new InstructionDeleteMutator clearly and significantly improves coverage on CLN and Eclair, shows a promising but unconfirmed trend on LND, and has no impact on LDK. The variability suggests the mutator’s benefit may depend on implementation‑specific code patterns. We recommend merging it, while considering a follow‑up experiment with more trials on LND. The same evaluation pipeline can be re‑run if the mutator is later refined.

10. Future Work

  • Automated evaluation script: A single script that runs the full per‑target analysis pipeline from a directory of plot_data and fuzzer_stats files and outputs a summary table like the one in Section 9.2, alongside box-plots for visualization.

For the formal evaluation that performs ground truth evaluation with real historical vulnerabilities using survival analysis, see the artifact at [WIP].

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions