- __:fontawesome-solid-arrow-right: Get Started__
---
Welcome to the Revizor documentation! Whether you're a new user looking to get started or a developer interested in contributing, you'll find all the information you need here.
[Start Here](intro/start-here.md){ .md-button .md-button--primary }
[Learn Revizor](intro/01-overview.md){ .md-button }
[Ask a Question](howto/ask-a-question.md){ .md-button }
[Cite Revizor](ref/papers.md){ .md-button }
- __:fontawesome-solid-code: Source Code__
---
The Revizor project lives on GitHub. Explore the source code, report issues, and contribute to the project.
[GitHub](https://github.com/microsoft/side-channel-fuzzer){ .md-button }
[Contributing](internals/contributing/overview.md){ .md-button }
[Bug Reports](https://github.com/microsoft/side-channel-fuzzer/issues){ .md-button }
[Explore Docs](structure.md){ .md-button }
- __:fontawesome-solid-comments: Join the Community__
---
Join the Revizor community to get help, discuss ideas, suggest features, and share your experiences.
[Zulip Community](https://rvzr.zulipchat.com/){ .md-button }
[GitHub Discussions](https://github.com/microsoft/side-channel-fuzzer/discussions){ .md-button }
---
## __:fontawesome-solid-bug: Trophies__{ .trophies-header }
#### Transient Scheduler Attack - L1 Cache (TSA-L1)
=== "Description"
A speculative leak affecting AMD Family 19h processors where false completions in load instructions can leak data from the L1 data cache across security boundaries. The attack exploits the linear address-based microtag system used for L1 cache lookups - when a load finds a matching microtag entry but the L1 doesn't contain valid data, invalid data from the matching microtag entry is used in a false completion. This leak enables information disclosure between kernel/userspace, hypervisor/guest, across different applications or VMs, and from SEV-SNP VMs to the host.
=== "CVE"
[CVE-2024-36357](https://nvd.nist.gov/vuln/detail/CVE-2024-36357)
=== "Links"
* More details in: [Enter, Exit, Page Fault, Leak: Testing Isolation Boundaries for Microarchitectural Leaks](https://aka.ms/enter-exit-leak)
* AMD Security Advisory: [Advisory](https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7029.html)
#### Transient Scheduler Attack - Store Queue (TSA-SQ)
=== "Description"
A speculative leak affecting AMD Family 19h processors where false completions in Store-To-Load Forwarding operations can leak data from previous store instructions. When a load matches an older store's address but the store data isn't yet available, a false completion occurs using invalid data from a previously executed store that occupied the same store queue entry. This effect enables information leakage from the OS kernel to user applications, hypervisor to guest, and to a lesser extent, between application.
=== "CVE"
[CVE-2024-36350](https://cve.mitre.org/cgi-bin/cvename.cgi?name=2024-36350)
=== "Links"
* More details in: [Enter, Exit, Page Fault, Leak: Testing Isolation Boundaries for Microarchitectural Leaks](https://aka.ms/enter-exit-leak)
* AMD Security Advisory: [Advisory](https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7029.html)
#### Control Register Speculation
=== "Description"
A speculative leak affecting AMD processors where user processes can speculatively infer control register values even when User Mode Instruction Prevention (UMIP) is enabled. This bypasses intended security boundaries by allowing unprivileged code to access system-level configuration information through speculative channels.
=== "CVE"
[CVE-2024-36348](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2024-36348)
=== "Links"
* More details in: [Enter, Exit, Page Fault, Leak: Testing Isolation Boundaries for Microarchitectural Leaks](https://aka.ms/enter-exit-leak)
* AMD Security Advisory: [Advisory](https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7029.html)
#### TSC_AUX Speculation
=== "Description"
A speculative leak affecting AMD processors affecting AMD processors that permits user processes to infer the Time Stamp Counter Auxiliary (TSC_AUX) register value even when direct reads are disabled.
=== "CVE"
[CVE-2024-36349](https://nvd.nist.gov/vuln/detail/CVE-2024-36349)
=== "Links"
* More details in: [Enter, Exit, Page Fault, Leak: Testing Isolation Boundaries for Microarchitectural Leaks](https://aka.ms/enter-exit-leak)
* AMD Security Advisory: [Advisory](https://www.amd.com/en/resources/product-security/bulletin/amd-sb-7029.html)
#### Divider State Sampling (DSS)
=== "Description"
A speculative leak where division-by-zero operations can transiently return values that depend on previous division operations. The leaked state persists across privilege boundaries. The discovery of the leak triggered a patch to the Linux kernel as well as other operating systems.
=== "CVE"
[CVE-2023-20588](https://nvd.nist.gov/vuln/detail/CVE-2023-20588)
=== "Links"
More details in: [Speculation at Fault](https://www.usenix.org/system/files/usenixsecurity23-hofmann.pdf)
#### String Comparison Overrun (SCO)
=== "Description"
Revizor discovered that string operations on Intel and AMD CPUs (in particular, string comparison and string scan) can speculatively bypass the bounds of their target strings, which permits the attacker to leak data from out-of-bounds memory locations.
=== "Links"
More details in: [Hide & Seek with Spectres](https://www.microsoft.com/en-us/research/publication/hide-and-seek-with-spectres-efficient-discovery-of-speculative-information-leaks-with-random-testing/)
#### Zero Dividend Injection (ZDI)
=== "Description"
64-bit division operations on Intel CPUs can speculative ignore the upper bits of the divisor, thus producing an incorrect computational result. This speculation can potentially impact the security of cryptographic algorithms that use division to implement modulo operations.
=== "Links"
More details in: [Hide & Seek with Spectres](https://www.microsoft.com/en-us/research/publication/hide-and-seek-with-spectres-efficient-discovery-of-speculative-information-leaks-with-random-testing/)
#### Read-Modify-Write Speculation
=== "Description"
A new variant of Microarchitectural Data Sampling (MDS) where a store operation to read-only memory triggers speculative behavior. When a read-modify-write instruction (like XADD) attempts to access read-only memory, it speculatively returns stale data from internal CPU buffers, even though the read itself would be permitted.
=== "Links"
More details in: [Speculation at Fault](https://www.usenix.org/system/files/usenixsecurity23-hofmann.pdf)
#### Non-canonical Store Forwarding
=== "Description"
A speculative leak where stores to non-canonical addresses can be forwarded to subsequent loads from the canonical versions of those addresses. This means that even though a store operation fails due to an invalid address format, its data can still be transiently accessed by later instructions using a related valid address.
=== "Links"
More details in: [Speculation at Fault](https://www.usenix.org/system/files/usenixsecurity23-hofmann.pdf)
#### Variable-latency Spectre
=== "Description"
A variant of Spectre vulnerability where the leakage is caused by the race condition that appears when a speculative memory access is data-dependent on a variable-latency instruction. This race condition can expose the operands of the variable-latency instruction.
=== "Links"
More details in [the Revizor paper](https://www.microsoft.com/en-us/research/publication/revizor-testing-black-box-cpus-against-speculation-contracts/)
#### Store-based Spectre V1
=== "Description"
Several defense proposals (e.g., STT, KLEESpectre) assumed that stores do not modify the cache state until they retire. We used Revizor to validate this assumption, and discovered that is not true on recent Intel CPUs (e.g., CoffeeLake).
=== "Links"
More details in [the Revizor paper](https://www.microsoft.com/en-us/research/publication/revizor-testing-black-box-cpus-against-speculation-contracts/)
#### Speculative Store with Forwarding
=== "Description"
Revizor discovered that two consecutive loads from the same address can speculatively return two different values if one of them receives a forwarded value from a store while the other load experiences a speculative store bypass. This combination exposes more information to the attacker compared to the original store bypass.
=== "Links"
More details in [the appendix to the Revizor paper](https://www.microsoft.com/en-us/research/publication/revizor-testing-black-box-cpus-against-speculation-contracts/)
================================================
FILE: docs/internals/architecture/analysis.md
================================================
| | |
| ---------------- | ------------------ |
| Module | `rvzr/analyser.py` |
| Public interface | `Analyser` |
| Inputs | `CTrace`, `HTrace` |
| Outputs | `Violation` |
The Analyser compares contract traces with hardware traces to detect violations. The core principle: inputs with identical CTraces should produce equivalent HTraces. When they don't, a contract violation has occurred.
```python
For all inputs i, j:
if CTrace(i) == CTrace(j) and HTrace(i) != HTrace(j):
→ Violation detected
```
Analyser implementations:
Different analysers define "equivalent HTrace" differently:
- `MergedBitmapAnalyser` (default) — Merges samples using bitwise OR, compares bitmaps. For cache-based channels.
- `SetAnalyser` — Compares sets of unique samples.
- `MWUAnalyser` — Uses Mann-Whitney U statistical test. For timing-based channels.
- `ChiSquaredAnalyser` — Uses chi-squared test for distribution differences.
================================================
FILE: docs/internals/architecture/code.md
================================================
# Test Case Code Generation
| | |
| ---------------- | ------------------------ |
| Module | `rvzr/code_generator.py` |
| Public interface | `CodeGenerator` |
| Inputs | `InstructionSet` |
| Outputs | `TestCaseProgram` |
This module generates random assembly programs for testing. The generator creates programs designed to trigger speculative execution and expose microarchitectural leaks.
### Generation process
1. Create control flow graph — Generate a random Directed Acyclic Graph (DAG) of basic blocks. The DAG structure prevents infinite loops while allowing branches and mispredictions.
2. Add jump instructions — Insert conditional and unconditional jumps at block boundaries to connect the blocks according to the DAG.
3. Fill basic blocks — Populate blocks with random instructions from the tested instruction pool, respecting instruction frequencies and operand constraints.
4. Instrument — (Optionally) Prevent faults by masking memory addresses, avoiding division by zero, and ensuring all accesses stay within the sandbox.
5. Assemble — Convert to binary and extract metadata.
6. Transform into RCBF — Serialize the test case into Revizor's custom binary format ([RCBF](../../ref/binary-formats.md)) for execution.
### Test case representation
```text
TestCaseProgram
├─ CodeSection (one per actor)
│ └─ Function
│ └─ BasicBlock
│ └─ InstructionNode
│ └─ Instruction
│ └─ Operand
└─ TestCaseBinary
└─ SymbolTable
```
### Variants
Architecture-specific implementations of the code generator exist for x86 and ARM64, named `X86Generator` and `ARM64Generator` in `rvzr/arch/*/code_generator.py`
================================================
FILE: docs/internals/architecture/data.md
================================================
# Test Case Data Generation
| | |
| ---------------- | ------------------------ |
| Module | `rvzr/data_generator.py` |
| Public interface | `DataGenerator` |
| Inputs | `Config` |
| Outputs | `InputData` |
`DataGenerator` generates input data that is used to initialize registers and memory before executing a test case, on both the model and the target hardware.
## Generation modes
Two input generation modes are supported:
### Standard generation
Interface: `DataGenerator.generate(...)`
This method creates fully random inputs using a PRNG. Can optionally reduce entropy (to increase trace collisions) or inject special values (zeros, boundary values) to trigger edge cases.
### Boosted generation
Interface: `DataGenerator.generate_boosted(...)`
Boosted generation solves the following challenge:
Two detect a violation via relational non-interference testing, we always need at least two inputs that produce identical contract traces (see [Trace Analysis](overview.md#6-trace-analysis)). Generating such contract-equivalent inputs through pure randomness is extremely inefficient because the entropy of contract traces is usually very high, and thus most random inputs produce unique traces.
Boosted generation addresses this by leveraging dynamic taint analysis on the model side. It works as follows: Start by producing a set of random inputs using standard generation. Then, we execute the test case with each input in the model and perform backwards taint analysis to identify which input bytes affect the contract trace (tainted) and which don't (untainted). This produces a set of `InputTaint` objects that map input bytes to their taint status. These taint maps a fed back into the `generate_boosted()` method, which creates new inputs such that the tainted bytes remain fixed while the untainted bytes are randomized.
```text
Original InputData → Model → InputTaint → N contract-equivalent inputs
```
Such "boosted" inputs are guaranteed to produce the same contract trace as the original input while still being mostly random.
## Data Representation
Each input is represented as an `InputData` object, which is a numpy structured array containing
- Memory contents
- General-purpose registers
- SIMD registers
- Flags and special registers
for each actor in the test case. This object can be serialized into Revizor's custom binary format ([RDBF](../../ref/binary-formats.md)) for consumption by the model and executor.
================================================
FILE: docs/internals/architecture/exec.md
================================================
# Hardware Tracing
| | |
| ---------------- | --------------------------------------- |
| Module | `rvzr/executor.py`, `rvzr/executor_km/` |
| Public interface | `Executor` |
| Inputs | `TestCaseProgram`, `InputData` |
| Outputs | `HTrace` |
## Executor
The Executor runs test cases on real hardware and collects hardware traces (HTraces) using side-channel measurements. It uses a two-layer architecture: Python code communicates with a kernel module that performs measurements in kernel space.
```text
Python (executor.py)
├─ X86IntelExecutor
├─ X86AMDExecutor
└─ ARM64Executor
│
│ /sys/rvzr_executor/ interface
▼
Kernel Module (executor_km/)
```
## HTrace representation
The `HTrace` class (`rvzr/traces.py`) represents hardware traces collected during execution. The executor produces one `HTrace` object per program-input pair, meaning that for each `TestCaseProgram` execution with each `InputData` input, one `HTrace` is generated.
Each `HTrace` encapsulates multiple measurements results (samples): This is because the executor typically repeats the execution several times and each execution produces one measurement sample. Such repeated measurements allow us to apply statistical methods when comparing noisy hardware traces (see [Trace Analysis](analysis.md) below).
The structure of an `HTrace` is as follows:
```text
HTrace
└─ Array[RawHTraceSample]
├─ trace Main measurement (cache bitmap, timestamp, or registers)
└─ pfc0-pfc4 Performance counter values
```
================================================
FILE: docs/internals/architecture/fuzz.md
================================================
# Orchestration Module
| | |
| ---------------- | ---------------------------------------- |
| Module | `rvzr/fuzzer.py` |
| Public interface | `Fuzzer` |
| Inputs | `Config`, `InstructionSet`, ASM Template |
| Outputs | Violation artifact, logs |
The `Fuzzer` class is the main coordinator. It manages the core components (`CodeGenerator`, `DataGenerator`, `Model`, `Executor`, and `Analyser`) and orchestrates the fuzzing loop.
## Main workflow
```text
Fuzzer.start()
└─> for each test case:
├─> CodeGenerator.create_test_case() → TestCaseProgram
├─> DataGenerator.generate() → List[InputData]
└─> Fuzzer.fuzzing_round(program, inputs)
├─> Model.trace_test_case() → List[CTrace]
├─> Executor.trace_test_case() → List[HTrace]
├─> Analyser.filter_violations() → List[Violation]
└─> if violation: multi-stage filtering pipeline
```
## Multi-stage filtering
When a potential violation is found, the Fuzzer runs it through several validation stages. Each stage modifies parameters and re-checks the violation to rule out false positives:
1. `fast` — Initial fast detection using minimal speculative nesting on the model side and small sample size on the executor side
2. `nesting` — Re-collect ctraces with the model using full speculative nesting. This rules out false positives caused by incomplete speculation modeling
3. `taint_mistake` — Re-collect ctraces for the boosted inputs to rule out boosting-based generation mistakes
4. `priming` — Perform a so-called "priming test" (swap the order of violating inputs) to rule out false positives caused by inconsistent microarchitectural state across executions
5. `noise` — Increase sample size on the executor side to increase statistical confidence and rule out noise-induced violations
6. `arch_mismatch` — Compare the architectural output (i.e., register/memory states) of the model and executor to rule out violations caused by functional mismatches (i.e., by bugs in the model or executor)
If a violation survives all stages, Revizor saves a reproduction package (called "violation artifact") containing the test case, inputs, configuration, and detailed report.
## Fuzzer variants
The `Fuzzer` class is abstract. There are several variants modifying the baseline logic:
- `X86Fuzzer` / `ARM64Fuzzer` — Architecture-specific implementations
- `ArchitecturalFuzzer` — Validates model correctness (i.e., performs stage 6 `arch_mismatch` for all test cases, even non-violating ones)
- `ArchDiffFuzzer` — Completely discards the model, and instead compares two hardware executions, one with a normal test case and one with a speculation fence added after every instruction. This variant is used to detect speculation-induced architectural bugs, like zenbleed.
================================================
FILE: docs/internals/architecture/isa.md
================================================
# Instruction Set Specification
| | |
| ---------------- | ------------------ |
| Module | `rvzr/isa_spec.py` |
| Public interface | `InstructionSet` |
| Inputs | `base.json` |
| Outputs | `InstructionSet` |
This module manages the instruction set available for fuzzing. It loads ISA definitions from a JSON file (`base.json`) and applies user-configured filters to create a pool of allowed instructions.
Each instruction is represented by an `InstructionSpec` containing instruction name and category, operand specifications, and instruction properties.
Processing pipeline:
1. Load ISA specification from JSON
2. Apply filters (allowlist, blocklist, categories, register restrictions)
3. Remove duplicates
4. Categorize instructions by type (control flow, memory access, etc.)
================================================
FILE: docs/internals/architecture/logging.md
================================================
# Logging
| | |
| ---------------- | ----------------------------- |
| Module | `rvzr/logs.py` |
| Public interface | `FuzzLogger`, etc. |
| Inputs | N/A |
| Outputs | Log messages (stdout, stderr) |
Revizor uses a centralized logging system with configurable verbosity. The system uses the Borg pattern to share state across modules.
Available logging modes:
- info — General messages and progress
- stat — Statistics
- dbg_* — Debug modes for specific components
Logging components:
- Basic functions: `error()`, `warning()`, `inform()`, `dbg()`
- Module-specific loggers: `FuzzLogger`, `GeneratorLogger`, `ISALogger`, `ExecutorLogger`, `AnalyserLogger`
================================================
FILE: docs/internals/architecture/mini.md
================================================
# Post-violation Analysis
| | |
| ---------------- | ------------------------------- |
| Module | `rvzr/postprocessing/` |
| Public interface | `Minimizer` |
| Inputs | Violation artifact (.asm, .bin) |
| Outputs | Minimized test case and inputs |
After confirming a violation, users can run post-processing to simplify the test case and identify the root cause. The postprocessing module applies minimization passes that reduce complexity while preserving the violation.
Class hierarchy:
```text
Minimizer
└─ Orchestrates passes, manages files
BaseMinimizationPass
├─ Instruction passes (modify code)
├─ Data passes (modify inputs)
└─ Analysis passes (add annotations)
```
Instruction passes (operate on test case code):
- `InstructionRemovalPass` — Remove instructions one at a time to find essential ones
- `NopReplacementPass` — Replace with NOPs (preserves alignment)
- `InstructionSimplificationPass` — Replace complex instructions with simpler ones
- `ConstantSimplificationPass` — Simplify immediate values
- `MaskSimplificationPass` — Simplify bitmasks
- `LabelRemovalPass` — Remove unused labels
- `FenceInsertionPass` — Insert fences to identify speculation boundaries
Data passes (operate on inputs):
- `DifferentialInputMinimizerPass` — Use delta debugging to find minimal byte differences
- `InputSequenceMinimizationPass` — Reduce number of inputs
Analysis passes (add annotations):
- `AddViolationCommentsPass` — Annotate assembly with memory addresses from execution
================================================
FILE: docs/internals/architecture/model.md
================================================
# Contract Tracing
| | |
| ---------------- | ------------------------------ |
| Module | `rvzr/model.py` |
| Public interface | `Model` |
| Inputs | `TestCaseProgram`, `InputData` |
| Outputs | `CTrace` |
## Model
The Model executes test cases according to a leakage contract and produces contract traces (CTraces). These represent the information expected to leak during execution, including speculative execution.
Revizor supports two model backends:
- **Unicorn**: This backend is based on the [Unicorn CPU emulator](https://www.unicorn-engine.org/). It implements the contract by hooking into instruction execution and memory access events. Documentation is provided in [Unicorn Backend](../model-backends/model-unicorn.md).
- **DynamoRIO**: This backend uses [DynamoRIO](https://dynamorio.org/) for dynamic binary instrumentation. It instruments the test case to insert hooks for tracing and speculation simulation. Documentation is provided in [DynamoRIO Backend](../model-backends/model-dr.md).
Both implement the same interface defined by the abstract `Model` class.
## Contract Trace Representation
A `CTrace` is a sequence of typed observations representing leaked information:
```text
CTrace
└─ List[CTraceEntry]
├─ mem Memory address
├─ pc Program counter
├─ val Data value
├─ reg Register value
└─ ind Indirect branch target
```
CTraces use `xxhash` for fast equality checking, enabling efficient grouping into equivalence classes.
================================================
FILE: docs/internals/architecture/overview.md
================================================
# Architecture Overview & Code Structure
This document introduces Revizor's architecture and key components. It is designed to provide an overview of how the codebase is organized and how the main pieces work together.
!!! info "Prerequisites"
This document assumes familiarity with the concepts of side-channel attacks, speculative execution, and [Speculation Contracts and Model-based Relational Testing (MRT)](../../topics/contracts.md).
## How Revizor Works
Revizor detects CPU security vulnerabilities using Model-based Relational Testing (MRT). The core idea is to compare what a CPU should leak (according to a leakage model) with what it actually leaks during execution.
Basic process:
1. Generate random assembly programs
2. Execute them on both a leakage model and real hardware
3. Compare the observed hardware behavior with the model's predictions
4. If they match, the CPU behaves as expected (discard the test)
5. If they differ, a potential vulnerability has been found
The leakage model acts as a reference model of the expected CPU behavior. If the real CPU leaks more information than the model predicts (i.e., if it diverges from the reference), this indicates a potential security vulnerability. For details on how leakage models work, see [Speculation Contracts](../../topics/contracts.md).
Revizor runs the following loop until it finds a violation or completes the configured number of test cases:

## 1. Initialization
This step runs once at startup. Revizor reads the fuzzing configuration, which specifies:
- Target CPU architecture
- ISA (instruction set) specification
- Which instructions to test
- Which side channels to monitor
- Other fuzzing parameters
The `cli.py` module handles command-line arguments and creates the main objects: `InstructionSet` (from `isa_spec.py`), `Config` (from `config.py`), and `Fuzzer` (from `fuzzer.py`).
## 2. Code Generation
Each fuzzing round starts by generating a random test program. This is an assembly program with semi-random control flow, built from a pool of allowed instructions.
The code generator can be configured to control the shape of the control flow graph, which instructions to include, and how often each instruction appears. It also (optionally) instruments the program to prevent faults like division by zero.
The `Fuzzer` calls `CodeGenerator.create_test_case()` (in `code_generator.py`), which returns a `TestCaseProgram` object representing the generated assembly program.
## 3. Data Generation
Next, Revizor generates random inputs for the test program. Each input contains initial values for registers and memory. These values are pseudo-random but use fixed seeds for reproducibility.
The `DataGenerator` class (in `data_generator.py`) creates these inputs and returns them as `InputData` objects. See [binary formats](../../ref/binary-formats.md#revizor-data-binary-format-rdbf) for the structure of input data.
## 3.5 Test Case Filtering (Optional)
Some test cases are unlikely to reveal vulnerabilities, so Revizor can filter them out early to save time. This is optional and disabled by default.
Two filters are available:
- Speculation filter: Uses performance counters to check if the test case triggers branch mispredictions. Without mispredictions, the test cannot expose speculative leaks.
- Observation filter: Compares the original test case with a "fenced" version (with serialization instructions added). If both produce identical traces, speculation left no observable effects.
These filters are implemented in architecture-specific fuzzer classes (like `X86Fuzzer` in `rvzr/arch/x86/fuzzer.py`).
## 4. Model Execution
The model executes the test program with each generated input and produces contract traces (CTraces). These traces represent what the model predicts should leak during execution.
The `Model` class (in `model.py`) provides two key methods:
- `load_test_case()`: Loads the program into the model
- `trace_test_case()`: Executes the program with each input and returns CTraces
Revizor supports multiple model backends: [Unicorn](../model-backends/model-unicorn.md) (CPU emulator) and [DynamoRIO](../model-backends/model-dr.md) (dynamic instrumentation). Both implement the same interface.
## 5. Hardware Execution
The executor runs the test program on the target hardware with each input and collects hardware traces (HTraces). A hardware trace is a set of observable microarchitectural effects (like cache state or timing) caused by the test case execution. Traces are typically collected using side-channel techniques (e.g., Prime+Probe, Flush+Reload) or by reading performance counters.
To ensure that the measurements reflect the test case execution (rather than noise), the executor creates a controlled measurement environment by disabling interrupts, flushing caches, and repeating executions multiple times.
The `Executor` class (in `executor.py`) works through a kernel module (`executor_km/`) that performs measurements in kernel space. It provides the same interface as the model: `load_test_case()` and `trace_test_case()`.
## 6. Trace Analysis
The analyzer compares contract traces (what should leak) with hardware traces (what actually leaked) to detect violations. Instead of directly comparing traces, it uses an equivalence class approach.
How it works:
1. Group by contract: Inputs with identical CTraces form a ContractEqClass. According to the model, these inputs should be indistinguishable.
2. Group by hardware: Within each ContractEqClass, inputs with similar HTraces form HardwareEqClasses. These inputs are actually indistinguishable on real hardware.
3. Detect violations: If a ContractEqClass splits into multiple HardwareEqClasses, a violation has occurred. The model says the inputs should look the same, but hardware reveals differences between them.
This approach focuses on information leakage rather than exact trace values, and it essentially implements a non-interference check (see [Theoretical Foundations](../../topics/contracts.md)).
The `Analyser` class (in `analyser.py`) implements this logic in its `filter_violations()` method.
## 7. Post-violation Analysis
When Revizor detects a potential violation, it runs additional tests to filter out false positives. These tests modify execution parameters and verify the violation still occurs. See [post-violation tests](mini.md) for details.
If the violation survives all filters, Revizor reports it to the user and saves reproduction artifacts. The user can then use [minimization tools](../../howto/minimize.md) to simplify the test case and identify the root cause.
The post-violation logic is implemented in `Fuzzer.fuzzing_round()`, and the `FuzzLogger` class handles reporting.
================================================
FILE: docs/internals/code-structure.md
================================================
# Code Structure
The Revizor codebase is organized into the following main directories:
```text
rvzr/ Main source code directory containing core fuzzing logic
├── *.py Core modules that implement main fuzzing components
├── tc_components/ Test case representation objects (code and data)
├── model_unicorn/ Unicorn-based leakage model
├── model_dynamorio/ DynamoRIO-based leakage model
├── executor_km/ Kernel module that implements the hardware executor
├── postprocessing/ Minimization utilities for contract counterexamples
└── arch/ Architecture-specific implementations (x86/ and arm64/)
tests/ Unit and integration tests
docs/ Documentation files
```
The main entry point is `rvzr/cli.py`, which parses command-line arguments and initializes the `Fuzzer` object.
================================================
FILE: docs/internals/contributing/code-style.md
================================================
# Code Style
Please follow these coding standards when writing code for inclusion in Revizor.
## Python
* Unless otherwise specified, follow PEP 8. But remember that PEP 8 is only a guide, so respect the style of the surrounding code as a primary goal.
* An exception to PEP 8 is our rules on line lengths. Don’t limit lines of code to 79 characters if it means the code looks significantly uglier or is harder to read. We allow up to 100 characters.
* All files should be formatted using the `flake8` auto-formatter. Use all default settings except for the line width (`--max-line-length 100`)
* The Python and C files use 4 spaces for indentation, and YAML uses 2 spaces.
* The project repository includes an .editorconfig file. We recommend using a text editor with EditorConfig support to avoid indentation and whitespace issues.
* Use underscores, not camelCase, for variable, function and method names (i.e. poll.get_unique_voters(), not poll.getUniqueVoters()).
* Use InitialCaps for class names (or for factory functions that return classes).
* In docstrings, follow PEP 257.
## C
* All files should be formatted using the `clang-format`. The settings are included into the `.clang-format` files in the directories with C files. Just run the formatter with: `clang-format -i *.c`
## Misc
* Remove import statements that are no longer used when you change code. flake8 will identify these imports for you. If an unused import needs to remain for backwards-compatibility, mark the end of with `# NOQA` to silence the flake8 warning.
* Systematically remove all trailing whitespaces from your code as those add unnecessary bytes, add visual clutter to the patches and can also occasionally cause unnecessary merge conflicts. Some IDE’s can be configured to automatically remove them and most VCS tools can be set to highlight them in diff outputs.
================================================
FILE: docs/internals/contributing/general.md
================================================
# General Development Guidelines
## Testing
To run automated tests you will need to install a few more dependencies:
* [Bash Automated Testing System](https://bats-core.readthedocs.io/en/latest/index.html)
* [mypy](https://mypy.readthedocs.io/en/latest/getting_started.html#installing-and-running-mypy)
* [flake8](https://flake8.pycqa.org/en/latest/index.html)
With the dependencies installed, you can run the tests with:
```bash
./tests/runtests.sh
```
Note that some of the acceptance tests are microarchitecture-dependent.
These tests are labeled "Detection" (e.g., `"Detection [spectre-type] Spectre V1; load variant"`), and they may fail if the CPU under test does not have a given vulnerability.
Generally, if a few of these tests fail, it is not a problem, but if all of them (or a significant portion) fail, it indicates an issue with the fuzzer.
## Submitting Patches
To submit a patch, use the following procedure:
* Fork Revizor on github:
[https://docs.github.com/en/github/getting-started-with-github/fork-a-repo](https://docs.github.com/en/github/getting-started-with-github/fork-a-repo)
* Create a topic branch:
```bash
git checkout -b my_branch
```
* Make sure all tests pass (see [Testing](#testing))
* Make sure your code follows the guidelines in [Code Style](code-style.md)
* Push to your branch
```bash
git push origin my_branch
```
* Initiate a pull request on github:
[https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request](https://docs.github.com/en/github/collaborating-with-issues-and-pull-requests/creating-a-pull-request)
* Wait for the PR to get reviewed and merged
================================================
FILE: docs/internals/contributing/git.md
================================================
# Git Workflow Guidelines
## Git Messages
We practice the following conventions for commit messages:
```