Skip to content

Commit

Permalink
Add abitrary fuzzing (#1306)
Browse files Browse the repository at this point in the history
* Create fuzzer

* Remove cli

* Update fuzzer

* Change fuzzer name

* Add arbitrary

* Add fuzzer using arbitrary

* Add fuzzer

* Use run until steps

* Remove end

* Update changelog

* Update CHANGELOG.md

* Update CHANGELOG.md

* Change macro cfg

* Update bincode

* Update Arbitrary deps

* Check for std with arbitrary

* Update Cargo.toml

* Revert "Update bincode"

This reverts commit 6b5a95a.

* Revert to update bincode

* Fix arbitrary imports

* Run linter

* Run linter

---------

Co-authored-by: Juanma <juanma@Juanmas-MacBook-Air.local>
Co-authored-by: Pedro Fontana <fontana.pedro93@gmail.com>
  • Loading branch information
3 people committed Jul 11, 2023
1 parent b7ac1e8 commit 2d5b2cc
Show file tree
Hide file tree
Showing 16 changed files with 163 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,11 @@

#### Upcoming Changes

* feat: add `arbitrary` feature to enable arbitrary derive in `Program` and `CairoRunConfig`

* perf: remove pointless iterator from rc limits tracking [#1316](https://github.com/lambdaclass/cairo-vm/pull/1316)


#### [0.8.2] - 2023-7-10

* chore: update dependencies, particularly lamdaworks 0.1.2 -> 0.1.3 [#1323](https://github.com/lambdaclass/cairo-vm/pull/1323)
Expand Down
23 changes: 23 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

3 changes: 3 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -61,5 +61,8 @@ cairo-lang-casm = { version = "2.0.0", default-features = false }
ark-ff = { version = "0.4.2", default-features = false }
ark-std = { version = "0.4.0", default-features = false }

# For fuzzing
arbitrary = { version = "1.3.0", features = ["derive"] }

[profile.release]
lto = "fat"
2 changes: 2 additions & 0 deletions felt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ default = ["std"]
std = []
alloc = []
lambdaworks-felt = ["dep:lambdaworks-math"]
arbitrary = ["dep:arbitrary", "num-bigint/arbitrary"]

[dependencies]
num-integer = { version = "0.1.45", default-features = false }
Expand All @@ -22,6 +23,7 @@ lazy_static = { version = "1.4.0", default-features = false, features = [
] }
serde = { version = "1.0", features = ["derive"], default-features = false }
lambdaworks-math = { version = "0.1.2", default-features = false, optional = true }
arbitrary = { version = "1.3.0", features = ["derive"], optional = true }

[dev-dependencies]
proptest = "1.2.0"
Expand Down
4 changes: 4 additions & 0 deletions felt/src/bigint_felt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ use core::{

use crate::{lib_bigint_felt::FeltOps, ParseFeltError};

#[cfg(all(feature = "std", feature = "arbitrary"))]
use arbitrary::Arbitrary;

pub const FIELD_HIGH: u128 = (1 << 123) + (17 << 64); // this is equal to 10633823966279327296825105735305134080
pub const FIELD_LOW: u128 = 1;
use lazy_static::lazy_static;
Expand All @@ -31,6 +34,7 @@ lazy_static! {
.expect("Conversion BigUint -> BigInt can't fail");
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Eq, Hash, PartialEq, PartialOrd, Ord, Clone, Deserialize, Default, Serialize)]
pub(crate) struct FeltBigInt<const PH: u128, const PL: u128> {
val: BigUint,
Expand Down
4 changes: 4 additions & 0 deletions felt/src/lib_bigint_felt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@ use core::{
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::{string::String, vec::Vec};

#[cfg(all(feature = "arbitrary", feature = "std"))]
use arbitrary::Arbitrary;

pub(crate) trait FeltOps {
fn new<T: Into<FeltBigInt<FIELD_HIGH, FIELD_LOW>>>(value: T) -> Self;

Expand Down Expand Up @@ -64,6 +67,7 @@ macro_rules! felt_str {
};
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Eq, Hash, PartialEq, PartialOrd, Ord, Clone, Deserialize, Default, Serialize)]
pub struct Felt252 {
pub(crate) value: FeltBigInt<FIELD_HIGH, FIELD_LOW>,
Expand Down
11 changes: 11 additions & 0 deletions felt/src/lib_lambdaworks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,19 @@ use serde::{Deserialize, Serialize};
#[cfg(all(not(feature = "std"), feature = "alloc"))]
use alloc::{string::String, vec::Vec};

#[cfg(feature = "arbitrary")]
use arbitrary::{Arbitrary, Unstructured};

use crate::{ParseFeltError, FIELD_HIGH, FIELD_LOW};

#[cfg(feature = "arbitrary")]
impl<'a> Arbitrary<'a> for Felt252 {
fn arbitrary(u: &mut Unstructured<'a>) -> arbitrary::Result<Self> {
let num: BigUint = BigUint::arbitrary(u)?;
Ok(Felt252::from(num))
}
}

lazy_static! {
pub static ref CAIRO_PRIME_BIGUINT: BigUint =
(Into::<BigUint>::into(FIELD_HIGH) << 128) + Into::<BigUint>::into(FIELD_LOW);
Expand Down
12 changes: 8 additions & 4 deletions fuzzer/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,14 @@ edition = "2021"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[workspace]
members = ["."]

[dependencies]
arbitrary = { version = "1.3.0", features = ["derive"] }
honggfuzz = "0.5.55"
bincode = { version = "2.0.0-rc.3", tag = "v2.0.0-rc.3", git = "https://github.com/bincode-org/bincode.git" }
cairo-vm = { path = "../vm" }
cairo-vm = { path = "../vm", features = ["arbitrary"] }
mimalloc = { version = "0.1.29", default-features = false, optional = true }
nom = "7"
thiserror = { version = "1.0.32" }
Expand All @@ -18,13 +21,14 @@ thiserror = { version = "1.0.32" }
assert_matches = "1.5.0"
rstest = "0.17.0"

[workspace]
members = ["."]

[features]
default = ["with_mimalloc"]
with_mimalloc = ["cairo-vm/with_mimalloc", "mimalloc"]

[[bin]]
name = "fuzz_json"
path = "src/fuzz_json.rs"

[[bin]]
name = "fuzz_program"
path = "src/fuzz_program.rs"
27 changes: 27 additions & 0 deletions fuzzer/src/fuzz_program.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
use cairo_vm::{
cairo_run::{cairo_run_parsed_program, CairoRunConfig},
hint_processor::builtin_hint_processor::builtin_hint_processor_definition::BuiltinHintProcessor,
types::program::Program,
};
use honggfuzz::fuzz;

const STEPS_LIMIT: usize = 1000000;
fn main() {
loop {
fuzz!(|data: (CairoRunConfig, Program)| {
let (cairo_config, program) = data;
let _ = cairo_run_parsed_program(
program.clone(),
&CairoRunConfig::default(),
&mut BuiltinHintProcessor::new_empty(),
STEPS_LIMIT,
);
let _ = cairo_run_parsed_program(
program,
&cairo_config,
&mut BuiltinHintProcessor::new_empty(),
STEPS_LIMIT,
);
});
}
}
4 changes: 4 additions & 0 deletions vm/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ cairo-1-hints = [
"dep:ark-ff",
"dep:ark-std",
]
arbitrary = ["dep:arbitrary", "felt/arbitrary", "felt/std", "std"]
lambdaworks-felt = ["felt/lambdaworks-felt"]

# Note that these features are not retro-compatible with the cairo Python VM.
Expand Down Expand Up @@ -69,6 +70,9 @@ cairo-lang-casm = { workspace = true, optional = true }
ark-ff = { workspace = true, optional = true }
ark-std = { workspace = true, optional = true }

# Enable arbitrary when fuzzing
arbitrary = { workspace = true, features = ["derive"], optional = true }

[dev-dependencies]
assert_matches = "1.5.0"
rstest = { version = "0.17.0", default-features = false }
Expand Down
41 changes: 41 additions & 0 deletions vm/src/cairo_run.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ use felt::Felt252;

use thiserror_no_std::Error;

#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;

#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
pub struct CairoRunConfig<'a> {
pub entrypoint: &'a str,
pub trace_enabled: bool,
Expand Down Expand Up @@ -75,6 +79,43 @@ pub fn cairo_run(
Ok((cairo_runner, vm))
}

#[cfg(feature = "arbitrary")]
pub fn cairo_run_parsed_program(
program: Program,
cairo_run_config: &CairoRunConfig,
hint_executor: &mut dyn HintProcessor,
steps_limit: usize,
) -> Result<(CairoRunner, VirtualMachine), CairoRunError> {
let secure_run = cairo_run_config
.secure_run
.unwrap_or(!cairo_run_config.proof_mode);

let mut cairo_runner = CairoRunner::new(
&program,
cairo_run_config.layout,
cairo_run_config.proof_mode,
)?;

let mut vm = VirtualMachine::new(cairo_run_config.trace_enabled);

cairo_runner
.run_until_steps(steps_limit, &mut vm, hint_executor)
.map_err(|err| VmException::from_vm_error(&cairo_runner, &vm, err))?;
cairo_runner.end_run(false, false, &mut vm, hint_executor)?;

vm.verify_auto_deductions()?;
cairo_runner.read_return_values(&mut vm)?;
if cairo_run_config.proof_mode {
cairo_runner.finalize_segments(&mut vm)?;
}
if secure_run {
verify_secure_runner(&cairo_runner, true, None, &mut vm)?;
}
cairo_runner.relocate(&mut vm, cairo_run_config.relocate_mem)?;

Ok((cairo_runner, vm))
}

#[derive(Debug, Error)]
#[error("Failed to encode trace at position {0}, serialize error: {1}")]
pub struct EncodeTraceError(usize, bincode::error::EncodeError);
Expand Down
4 changes: 4 additions & 0 deletions vm/src/hint_processor/hint_processor_definition.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,9 @@ use crate::vm::vm_core::VirtualMachine;
use super::builtin_hint_processor::builtin_hint_processor_definition::HintProcessorData;
use felt::Felt252;

#[cfg(feature = "arbitrary")]
use arbitrary::Arbitrary;

pub trait HintProcessorLogic {
//Executes the hint which's data is provided by a dynamic structure previously created by compile_hint
fn execute_hint(
Expand Down Expand Up @@ -75,6 +78,7 @@ fn get_ids_data(
Ok(ids_data)
}

#[cfg_attr(feature = "arbitrary", derive(Arbitrary))]
#[derive(Debug, PartialEq, Eq, Clone)]
pub struct HintReference {
pub offset1: OffsetValue,
Expand Down
15 changes: 15 additions & 0 deletions vm/src/serde/deserialize_program.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,11 @@ use num_traits::{Num, Pow};
use serde::{de, de::MapAccess, de::SeqAccess, Deserialize, Deserializer, Serialize};
use serde_json::Number;

#[cfg(all(feature = "arbitrary", feature = "std"))]
use arbitrary::Arbitrary;

// This enum is used to deserialize program builtins into &str and catch non-valid names
#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Serialize, Deserialize, Debug, PartialEq, Copy, Clone, Eq, Hash)]
#[allow(non_camel_case_types)]
pub enum BuiltinName {
Expand Down Expand Up @@ -65,20 +69,23 @@ pub struct ProgramJson {
pub debug_info: Option<DebugInfo>,
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct HintParams {
pub code: String,
pub accessible_scopes: Vec<String>,
pub flow_tracking_data: FlowTrackingData,
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct FlowTrackingData {
pub ap_tracking: ApTracking,
#[serde(deserialize_with = "deserialize_map_to_string_and_usize_hashmap")]
pub reference_ids: HashMap<String, usize>,
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq)]
pub struct ApTracking {
pub group: usize,
Expand All @@ -100,6 +107,7 @@ impl Default for ApTracking {
}
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct Identifier {
pub pc: Option<usize>,
Expand All @@ -114,12 +122,14 @@ pub struct Identifier {
pub cairo_type: Option<String>,
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct Member {
pub cairo_type: String,
pub offset: usize,
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Clone, Debug, Serialize, Deserialize, PartialEq, Eq)]
pub struct Attribute {
pub name: String,
Expand All @@ -129,6 +139,7 @@ pub struct Attribute {
pub flow_tracking_data: Option<FlowTrackingData>,
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct Location {
pub end_line: u32,
Expand All @@ -144,17 +155,20 @@ pub struct DebugInfo {
instruction_locations: HashMap<usize, InstructionLocation>,
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct InstructionLocation {
pub inst: Location,
pub hints: Vec<HintLocation>,
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Serialize, Deserialize, Clone, Debug, PartialEq, Eq)]
pub struct InputFile {
pub filename: String,
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub struct HintLocation {
pub location: Location,
Expand Down Expand Up @@ -211,6 +225,7 @@ pub struct Reference {
pub value_address: ValueAddress,
}

#[cfg_attr(all(feature = "arbitrary", feature = "std"), derive(Arbitrary))]
#[derive(Serialize, Deserialize, Debug, PartialEq, Eq, Clone)]
pub enum OffsetValue {
Immediate(Felt252),
Expand Down

0 comments on commit 2d5b2cc

Please sign in to comment.