Skip to content

Conversation

@kayagokalp
Copy link
Member

@kayagokalp kayagokalp commented Oct 6, 2025

Add Random Number Generation and Fuzzing Support to forc-test

Summary

This PR introduces deterministic and non-deterministic random number generation capabilities to the forc-test VM through new syscalls, and provides a comprehensive Sway fuzzing library that enables property-based testing for any Sway type without requiring trait implementations.

Changes

1. New VM Syscalls

Added two new environment call (ecal) syscalls to the forc-test VM:

  • Syscall 1002 (random): Non-deterministic random byte generation
  • Syscall 1003 (random_seeded): Deterministic seeded random byte generation

These syscalls are implemented in forc-test/src/ecal.rs and write random bytes directly to VM memory.

2. Sway Fuzzing Library

Created a new library at forc-test/sway-test with three modules:

random module

Low-level functions for random number generation:

use sway_test::random::*;

// Generate random primitives
let random_num: u64 = random_u64();
let random_byte: u8 = random_u8();

// Deterministic generation with seeds
let value1: u32 = random_u32_seeded(42);
let value2: u32 = random_u32_seeded(42);
assert(value1 == value2); // Same seed produces same value

fuzz module

High-level fuzzing framework using memory-level fuzzing to support any Sway type without trait implementations:

use sway_test::fuzz::*;

// Fuzz any primitive type
let value: u64 = fuzz_any(42);

// Fuzz any struct automatically
struct MyStruct { a: u64, b: u32, c: bool }
let s: MyStruct = fuzz_any(100);

// Fuzz enums
enum MyEnum { A: u64, B: bool }
let e: MyEnum = fuzz_any(200);

// Use the Fuzzer for property-based testing
let mut fuzzer = Fuzzer::<MyStruct>::new(100);
while fuzzer.has_next() {
    let value = fuzzer.next();
    // Test properties with random values
    assert(value.a >= 0); // Properties hold for all generated values
}

Deterministic Fuzzing

// Configure deterministic fuzzing with custom seed
let config = FuzzConfig::new(50).with_seed(12345);
let mut fuzzer = Fuzzer::<ComplexType>::with_config(config);

// Run the same tests with identical results every time
while fuzzer.has_next() {
    test_property(fuzzer.next());
}

Key Features

  • Universal Type Support: Works with any Sway type (primitives, structs, enums) without trait implementations
  • Memory-Level Fuzzing: Uses __size_of and __addr_of intrinsics to fill type memory with random bytes
  • Deterministic Testing: Seeded RNG ensures reproducible test runs

Implementation Details

The fuzzing works by:

  1. Determining the memory size of type T using __size_of::<T>()
  2. Getting the memory address using __addr_of(value)
  3. Calling the VM syscall to fill that memory with random bytes based on a seed
  4. Returning the value with its memory now randomized

This approach requires no trait implementations and works uniformly across all types.

Testing

Added 11 comprehensive tests covering:

  • Primitive type fuzzing (u64, u32, bool)
  • Struct field independence and range validation
  • Enum fuzzing (simple, primitive variants, complex nested variants)
  • Deterministic behavior verification
  • Statistical distribution checks

Example

#[test]
fn test_addition_commutative_property() {
    let mut fuzzer = Fuzzer::<(u64, u64)>::new(100);
    let mut i = 0;

    while i < 100 {
        let (a, b) = fuzzer.next();
        assert(a + b == b + a); // Test holds for all random inputs
        i += 1;
    }
}

@kayagokalp kayagokalp changed the title [WIP] feat: library based fuzzing feat: library based fuzzing Oct 7, 2025
@kayagokalp kayagokalp self-assigned this Oct 7, 2025
@xunilrj
Copy link
Contributor

xunilrj commented Oct 8, 2025

How to deal with types that do not accept any value like: bool, enum tags, u16, u32 etc... Their domain is much smaller than their runtime representation allows.

And how to deal with pointers? Randomizing a Vec, will always create invalid Vec.

I can see the value of fuzzing with truly random data, but I also have the impression that sway test may be more interested in PBT.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants