Skip to content

Determinism & seeds

Obfuscation is randomised, but not unpredictable. Given the same input and the same seed, xollvm produces byte-identical output — essential for reproducible builds, debugging, and auditing what shipped.

The seed cascade

Seeds derive top-down, so every pass on every function gets its own stable stream without any two passes sharing state:

flowchart TD
    B["base seed<br/>-obf-seed=N"] --> M["module seed<br/>hash(base, module id)"]
    M --> F1["function seed<br/>hash(module, fn name)"]
    M --> F2["function seed<br/>..."]
    F1 --> P1["pass seed<br/>hash(function, pass id)"]
    F1 --> P2["pass seed<br/>..."]

Each level is a stable hash of the level above plus a stable key (module identifier, function name, canonical pass id). Nothing depends on hash-map iteration order or wall-clock time.

Controlling the base seed

Flag Effect
-obf-seed=<N> Pins the base seed. Any non-zero value makes every run reproducible.
-obf-deterministic When the seed is 0, derive the module seed from a hash of the module identifier instead of random_device.

Recommended during development and for release builds alike:

opt -passes=obfuscation app.ll -S -o app.obf.ll -obf-seed=1 -obf-deterministic

Seed 0 without -obf-deterministic is non-reproducible

With seed 0 and no -obf-deterministic, the module seed comes from random_device — output changes every run. Fine for shipping diversity; bad for debugging. Pin a seed while developing.

The seed manifest

For auditable builds, dump the full derived-seed tree:

Flag Effect
-obf-seed-manifest=<path> Write a JSON manifest (base / module / function / pass seeds). - writes to stderr.
-obf-seed-manifest-md Also embed per-pass seeds into IR metadata (obf.seed.manifest.<passId>).
opt -passes=obfuscation app.ll -S -o app.obf.ll \
    -obf-seed=1 -obf-deterministic -obf-seed-manifest=seeds.json

The manifest lets you reproduce a specific historical build exactly, or diff two builds to confirm only the intended functions changed.

Build diversity vs reproducibility

The two goals are a single knob:

  • Reproducible (CI, debugging, signed releases): fix -obf-seed=<N>.
  • Per-build diversity (ship a different binary each release to defeat signature matching): vary the seed per build — e.g. derive it from the version or a build counter — and archive the manifest so you can still reproduce any given build later.

See Reproducible builds for a full workflow.