zkFuzz Docs

🧰 Basic Usage

zkFuzz’s CLI provides numerous options to tailor your fuzzing session. Below is a summary of the available options:

ZK Circuit Fuzzer

USAGE:
    zkfuzz [FLAGS] [OPTIONS] [--] [input]

FLAGS:
        --constraint_assert_dissabled    Does not add asserts in the generated code for === constraint equalities
        --lessthan_dissabled             (zkFuzz) Does not detect overflow erros due to LessThan template
        --print_ast                      (zkFuzz) Prints AST
        --show_stats_of_ast              (zkFuzz) Prints the basic stats of AST
        --print_stats                    (zkFuzz) Prints the stats of constraints
        --print_stats_csv                (zkFuzz) Prints the stats of constraints in CSV format
        --symbolic_template_params       (zkFuzz) Treats the template parameters of the main template as symbolic values
        --save_output                    (zkFuzz) Save the output when the counterexample is found
    -h, --help                           Prints help information
    -V, --version                        Prints version information

OPTIONS:
    -l <link_libraries>                  Adds directory to library search path
    -p, --prime <prime>
            To choose the prime number to use to generate the circuit. Receives the name of the curve (bn128, bls12381,
            goldilocks, grumpkin, pallas, vesta, secq256r1) [default: bn128]
        --debug_prime <debug_prime>
            (zkFuzz) Prime number for zkFuzz [default:
            21888242871839275222246405745257275088548364400416034343698204186575808495617]
        --search_mode <search_mode>
            (zkFuzz) Search mode to find the counter example that shows the given circuit is not well-constrained [default: ga]
        --heuristics_range <heuristics_range>
            (zkFuzz) Heuristics range for zkFuzz [default: 100]
        --path_to_mutation_setting <path_to_mutation_setting>
            (zkFuzz) Path to the setting file for Mutation Testing [default: none]
        --path_to_whitelist <path_to_whitelist>                  
            (zkFuzz) Path to the white-lists file [default: none]

ARGS:
    <input>    Path to a circuit with a main component [default: ./circuit.circom]

Example Command

Run zkFuzz using your circuit file written in Circom:

zkfuzz target.circom

Example Output

zkFuzz CLI Result
Example of zkFuzz execution output

🔬 Fuzzing with Program Mutation

Fuzzing with program mutation mode (ga mode) supports a detailed configuration through the path_to_mutation_setting option. The configuration is specified as a JSON file.

Schema Overview

Here is an example of the JSON configuration schema:

{
    "seed": 0,
    "program_population_size": 30,
    "input_population_size": 30,
    "max_generations": 300,
    "input_initialization_method": "random",
    "trace_mutation_method": "constant",
    "fitness_function": "error",
    "mutation_rate": 0.3,
    "crossover_rate": 0.5,
    "operator_mutation_rate": 0.2,
    "num_eliminated_individuals": 5,
    "max_num_mutation_points": 10,
    "input_update_interval": 1,
    "input_generation_max_iteration": 30,
    "input_generation_crossover_rate": 0.66,
    "input_generation_mutation_rate": 0.5,
    "input_generation_singlepoint_mutation_rate": 0.5,
    "random_value_ranges": [
        [   "-10", 
            "10"
        ],
        [
            "21888242871839275222246405745257275088548364400416034343698204186575808495517", 
            "21888242871839275222246405745257275088548364400416034343698204186575808495617"
        ]
    ],
    "random_value_probs": [
        0.5,
        0.5
    ],
    "save_fitness_scores": false
}

If the configuration JSON file omits some keys, the default values are used for those omitted keys.

Click to view all configuration options
- seed (u64)
  - Purpose: Seed for random number generation to ensure reproducibility. If set to 0, a new seed is internally generated using the thread-local random number generator.
  - Default: 0

- program_population_size (usize)
  - Purpose: Size of the program population in the genetic algorithm.
  - Default: 30

- input_population_size (usize)
  - Purpose: Size of the input population in the genetic algorithm.
  - Default: 30

- max_generations (usize)
  - Purpose: Maximum number of generations for the evolutionary process.
  - Default: 500

- input_initialization_method (String)
  - Purpose: Method used to initialize inputs ("random", "fitness", "coverage").
  - Default: "random"

- trace_mutation_method (String)
  - Purpose: Method used for trace mutation ("naive", "constant", "constant_operator", "constant_operator_add", "constant_operator_delete").
  - Default: "constant_operator"

- fitness_function (String)
  - Purpose: Function used to evaluate fitness of solutions ("error", "const").
  - Default: "error"

- mutation_rate (f64)
  - Purpose: Rate at which mutations occur in the genetic algorithm.
  - Default: 0.3

- crossover_rate (f64)
  - Purpose: Rate at which crossover occurs in the genetic algorithm.
  - Default: 0.5

- operator_mutation_rate (f64)
  - Purpose: Rate of mutation for operators in the genetic algorithm.
  - Default: 0.1

- runtime_mutation_rate (f64)
  - Purpose: Specifies the mutation rate applied during runtime mutation processes.
  - Default: 0.3

- num_eliminated_individuals (usize)
  - Purpose: The number of individuals with poor fitness eliminated in each generation.
  - Default: 5

- max_num_mutation_points (usize)
  - Purpose: The maximum number of mutation points allowed in the symbolic trace.
  - Default: 10

- input_update_interval (usize)
  - Purpose: Interval at which inputs are updated.
  - Default: 1

- input_generation_max_iteration (usize)
  - Purpose: Maximum number of iterations for input generation.
  - Default: 30

- input_generation_crossover_rate (f64)
  - Purpose: Crossover rate for input generation.
  - Default: 0.66

- input_generation_mutation_rate (f64)
  - Purpose: Mutation rate for input generation.
  - Default: 0.5

- input_generation_singlepoint_mutation_rate (f64)
  - Purpose: Single-point mutation rate for input generation.
  - Default: 0.5

- random_value_ranges (Array of Arrays)
  - Purpose: Specifies ranges for random value generation. Each range is defined as a pair of big integers (provided as strings) representing the lower and upper bounds.
  - Default: [["0", "2"], ["2", "11"], ["11", "21888242871839275222246405745257275088548364400416034343698204186575808495517"], ["21888242871839275222246405745257275088548364400416034343698204186575808495517", "21888242871839275222246405745257275088548364400416034343698204186575808495617"]]

- random_value_probs (Array of f64)
  - Purpose: Probabilities associated with each range in `random_value_ranges`.
  - Default: [0.15, 0.34, 0.01, 0.5]

- binary_mode_prob (f64)
  - Purpose: Probability of restricting random input to only 0 or 1.
  - Default: 0.0

- binary_mode_search_level (usize)
  - Purpose: Search depth for the binary pattern (x * (1 - x) === 0) check.
  - Default: 1

- binary_mode_warmup_round (f64)
  - Purpose: Ratio of warmup rounds where binary_mode_prob is temporarily set to 1 upon detecting the binary pattern.
  - Default: 0.0

- zero_div_attempt_prob (f64)
  - Purpose: Probability of invoking the quadratic equation solver to analytically determine solutions for zero-division patterns.
  - Default: 0.2

- statement_deletion_prob (f64)
  - Purpose: Probability of deleting a statement during mutation.
  - Default: 0.2

- add_random_const_prob (f64)
  - Purpose: Probability of adding a random constant during mutation.
  - Default: 0.2

- dissable_runtime_mutation_for_hash_check (bool)
  - Purpose: When enabled, disables runtime mutation for hash checks.
  - Default: false

- dissable_heuristic_for_invalid_array_subscript (bool)
  - Purpose: When enabled, disables heuristics that handle invalid array subscripts.
  - Default: false

- save_fitness_scores (bool)
  - Purpose: Flag indicating whether fitness scores should be saved.
  - Default: false

💡 Tips & Advanced Features

💾 Saving Output

When the --save_output option is enabled, the counterexample is saved to the directory when found.

Example Command:

zkfuzz ./tests/sample/test_vuln_iszero.circom --search_mode="ga" --save_output

The output filename will follow the pattern <TARGET_FILE_NAME>_<RANDOM_SUFFIX>_counterexample.json.

🧪 Verbose Logging

zkFuzz offers multiple verbosity levels via the RUST_LOG environment variable:

  • warn: Warnings and errors only.
  • info: Adds basic statistics about the trace and constraints.
  • debug: Adds the trace of the final state.
  • trace: Outputs all intermediate trace states.

Example Command:

RUST_LOG=trace zkfuzz target.circom --print_ast --print_stats

Example Output JSON

{
  "0_target_path": "./tests/sample/test_vuln_iszero.circom",
  "1_main_template": "VulnerableIsZero",
  "2_search_mode": "ga",
  "3_execution_time": "36.3001ms",
  "4_git_hash_of_zkfuzz": "106b20ddad6431d0eee3cd73f9aac0153af4bbd9",
  "5_flag": {
    "1_type": "UnderConstrained-NonDeterministic",
    "2_expected_output": {
      "name": "main.out",
      "value": "0"
    }
  },
  "6_target_output": "main.out",
  "7_assignment": {
    "main.in": "21888242871839275222246405745257275088548364400416034343698204186575808495524",
    "main.inv": "0",
    "main.out": "1"
  },
  "8_auxiliary_result": {
    "mutation_test_config": {
      "fitness_function": "error",
      "max_generations": 300,
      "mutation_rate": 0.3,
      "...": "..."
    },
    "mutation_test_log": {
      "fitness_score_log": [],
      "generation": 7,
      "random_seed": 13057132941229430025
    }
  }
}