🧰 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
🔬 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
}
}
}