Skip to content

Commit c259228

Browse files
maciejka0xLucqs
andauthored
Feat: First round of fuzzing tests (#63)
Co-authored-by: LucasLvy <[email protected]>
1 parent f2edcc8 commit c259228

11 files changed

+318
-1
lines changed

.gitignore

+5
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,10 @@ Cargo.lock
1818
# Added by cargo
1919

2020
/target
21+
.DS_Store
2122

23+
corpus/
24+
artifacts/
25+
26+
.idea
2227
*.DS_Store

Cargo.toml

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ members = [
44
"crates/starknet-types-rpc",
55
]
66

7-
exclude = ["ensure_no_std"]
7+
exclude = ["ensure_no_std", "fuzz"]
88
resolver = "2"
99

1010
[workspace.package]

fuzz/Cargo.toml

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
[workspace]
2+
members = ["felt"]
3+
4+
resolver = "2"
5+
6+
[workspace.package]
7+
authors = [
8+
"Lucas Levy <@LucasLvy>",
9+
]
10+
edition = "2021"
11+
repository = "https://github.com/starknet-io/types-rs"
12+
13+
[workspace.dependencies]
14+
starknet-types-core = { path = "../crates/starknet-types-core", default-features = false, features = ["arbitrary"] }
15+
libfuzzer-sys = "0.4"

fuzz/Makefile

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
.PHONY: fuzz-add fuzz-div fuzz-mul fuzz-conversions
2+
3+
fuzz-add_sub:
4+
cargo +nightly fuzz run add_sub_fuzzer --fuzz-dir=./felt
5+
6+
fuzz-div:
7+
cargo +nightly fuzz run div_fuzzer --fuzz-dir=./felt
8+
9+
fuzz-mul:
10+
cargo +nightly fuzz run mul_fuzzer --fuzz-dir=./felt
11+
12+
fuzz-conversions:
13+
cargo +nightly fuzz run conversions_fuzzer --fuzz-dir=./felt

fuzz/README.md

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
# Fuzzing
2+
3+
This directory contains the fuzzing infrastructure for the `types-rs` project.
4+
5+
## Setup
6+
```
7+
cargo install cargo-fuzz
8+
```
9+
10+
## Running the fuzzers
11+
* cd into one of the directories, e.g., `cd felt`
12+
* list the available fuzz targets, e.g., `cargo fuzz list --fuzz-dir=.`
13+
* run the fuzzer, e.g., `cargo +nightly fuzz run add_fuzzer --fuzz-dir=.`

fuzz/felt/Cargo.toml

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
[package]
2+
name = "fuzzing_felt"
3+
version = "0.0.1"
4+
edition = "2021"
5+
license = "MIT"
6+
homepage = "https://github.com/starknet-io/types-rs"
7+
repository = "https://github.com/starknet-io/types-rs"
8+
categories = ["types", "math", "crypto", "fuzzing"]
9+
keywords = ["stark", "zkp", "cairo", "fuzzing"]
10+
description = "Fuzzing crate for the starknet common felt type"
11+
readme = "README.md"
12+
13+
[package.metadata]
14+
cargo-fuzz = true
15+
16+
[dependencies]
17+
starknet-types-core = { path = "../../crates/starknet-types-core", default-features = false, features = ["arbitrary", "alloc"] }
18+
libfuzzer-sys.workspace = true
19+
num-bigint = "0.4.4"
20+
num-traits = "0.2.18"
21+
lambdaworks-math = { version = "0.7.0", default-features = false }
22+
23+
[[bin]]
24+
name = "add_sub_fuzzer"
25+
path = "fuzz_targets/add_sub.rs"
26+
test = false
27+
doc = false
28+
29+
[[bin]]
30+
name = "mul_fuzzer"
31+
path = "fuzz_targets/mul.rs"
32+
test = false
33+
doc = false
34+
[[bin]]
35+
name = "conversions_fuzzer"
36+
path = "fuzz_targets/conversions.rs"
37+
test = false
38+
doc = false
39+
bench = false
40+
41+
[[bin]]
42+
name = "div_fuzzer"
43+
path = "fuzz_targets/div.rs"
44+
test = false
45+
doc = false
46+
bench = false

fuzz/felt/README.md

Whitespace-only changes.

fuzz/felt/fuzz_targets/add_sub.rs

+58
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
#![no_main]
2+
use libfuzzer_sys::fuzz_target;
3+
use starknet_types_core::felt::Felt;
4+
5+
fuzz_target!(|data: (Felt, Felt)| {
6+
let zero = Felt::ZERO;
7+
let one = Felt::ONE;
8+
let max = Felt::MAX;
9+
let (a, b) = data;
10+
11+
// Check a + 0 = a
12+
assert_eq!(a + zero, a);
13+
assert_eq!(b + zero, b);
14+
15+
// Check a - 0 = a
16+
assert_eq!(a - zero, a);
17+
assert_eq!(b - zero, b);
18+
19+
// Check a - a = 0
20+
assert_eq!(a - a, zero);
21+
assert_eq!(b - b, zero);
22+
23+
// Check a + (-a) = 0
24+
assert_eq!(a + (-a), zero);
25+
assert_eq!(b + (-b), zero);
26+
27+
// Check a + b = a - (-b)
28+
assert_eq!(a + b, a - (-b));
29+
30+
// Check a + a = a - (-a)
31+
assert_eq!(a + a, a - (-a));
32+
assert_eq!(b + b, b - (-b));
33+
34+
// Check a + a = 2 * a
35+
assert_eq!(a + a, Felt::TWO * a);
36+
assert_eq!(b + b, Felt::TWO * b);
37+
38+
// Check a + b = b + a
39+
assert_eq!(a + b, b + a);
40+
41+
// Check (a + b) + b = a + (b + b)
42+
assert_eq!((a + b) + b, a + (b + b));
43+
44+
// Check a + max = a - 1
45+
assert_eq!(a + max, a - one);
46+
assert_eq!(b + max, b - one);
47+
48+
// Check 0 - a = max - a + 1
49+
assert_eq!(zero - a, max - a + one);
50+
assert_eq!(zero - b, max - b + one);
51+
52+
// Check a + b = (a.to_biguint() + b.to_biguint()) % PRIME
53+
assert_eq!(a + b, Felt::from(a.to_biguint() + b.to_biguint()));
54+
55+
// a.double = a + a
56+
assert_eq!(a.double(), a + a);
57+
assert_eq!(b.double(), b + b);
58+
});

fuzz/felt/fuzz_targets/conversions.rs

+78
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
#![no_main]
2+
use libfuzzer_sys::fuzz_target;
3+
use starknet_types_core::felt::Felt;
4+
5+
use num_bigint::BigUint;
6+
use num_traits::{One, Zero};
7+
8+
use lambdaworks_math::unsigned_integer::element::UnsignedInteger;
9+
10+
fn pad_left_with_0(v: Vec<u8>) -> Vec<u8> {
11+
let mut padded = vec![0; 32_usize.saturating_sub(v.len())];
12+
padded.extend(v);
13+
padded
14+
}
15+
16+
fn pad_right_with_0(v: Vec<u8>) -> Vec<u8> {
17+
let padded = vec![0; 32_usize.saturating_sub(v.len())];
18+
[v, padded].concat()
19+
}
20+
21+
fuzz_target!(|felt: Felt| {
22+
// to_bytes_be, to_bytes_le
23+
assert_eq!(felt, Felt::from_bytes_be(&felt.to_bytes_be()));
24+
assert_eq!(felt, Felt::from_bytes_le(&felt.to_bytes_le()));
25+
assert_eq!(felt, Felt::from_bytes_be_slice(&felt.to_bytes_be()));
26+
assert_eq!(felt, Felt::from_bytes_le_slice(&felt.to_bytes_le()));
27+
28+
// to_bits_be
29+
let felt_as_bits = &felt.to_bits_be();
30+
let felt_as_buint = felt.to_biguint();
31+
for i in 0..256 {
32+
let bit = (&felt_as_buint & (BigUint::one() << i)) != BigUint::zero();
33+
assert_eq!(felt_as_bits[255 - i], bit);
34+
}
35+
36+
// to_bits_le
37+
let felt_as_bits = &felt.to_bits_le();
38+
for i in 0..256 {
39+
let bit = (&felt_as_buint & (BigUint::one() << i)) != BigUint::zero();
40+
assert_eq!(felt_as_bits[i], bit);
41+
}
42+
43+
// to_hex_string, to_fixed_hex_string, from_hex_unchecked
44+
assert_eq!(felt, Felt::from_hex_unchecked(&felt.to_hex_string()));
45+
assert_eq!(felt, Felt::from_hex_unchecked(&felt.to_fixed_hex_string()));
46+
assert_eq!(66, felt.to_fixed_hex_string().len());
47+
48+
// from_dec_str
49+
assert_eq!(
50+
felt,
51+
Felt::from_dec_str(&felt_as_buint.to_string()).unwrap()
52+
);
53+
54+
// to_bytes_be, to_bytes_le, to_big_uint
55+
assert_eq!(
56+
felt.to_bytes_be().to_vec(),
57+
pad_left_with_0(felt_as_buint.to_bytes_be())
58+
);
59+
assert_eq!(
60+
felt.to_bytes_le().to_vec(),
61+
pad_right_with_0(felt_as_buint.to_bytes_le())
62+
);
63+
64+
// to_raw, from_raw
65+
assert_eq!(felt, Felt::from_raw(felt.to_raw()));
66+
67+
// to_be_digits, to_le_digits
68+
assert_eq!(
69+
UnsignedInteger::<4>::from_hex(&felt.to_hex_string()).unwrap(),
70+
UnsignedInteger::<4>::from_limbs(felt.to_be_digits())
71+
);
72+
let mut le_digits_reversed = felt.to_le_digits();
73+
le_digits_reversed.reverse();
74+
assert_eq!(
75+
UnsignedInteger::<4>::from_hex(&felt.to_hex_string()).unwrap(),
76+
UnsignedInteger::<4>::from_limbs(le_digits_reversed)
77+
);
78+
});

fuzz/felt/fuzz_targets/div.rs

+52
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
#![no_main]
2+
3+
use libfuzzer_sys::fuzz_target;
4+
use starknet_types_core::felt::{Felt, NonZeroFelt};
5+
6+
fuzz_target!(|data: (Felt, Felt)| {
7+
let zero = Felt::ZERO;
8+
let one = Felt::ONE;
9+
10+
let (a, b) = data;
11+
12+
// Check a/a = 1
13+
if a != zero {
14+
let a_non_zero = NonZeroFelt::try_from(a).unwrap();
15+
assert_eq!(a.field_div(&a_non_zero), one);
16+
}
17+
18+
// Check a / 1 = a
19+
assert_eq!(a.field_div(&NonZeroFelt::try_from(one).unwrap()), a);
20+
21+
// Check a * a^-1 = 1
22+
if a != zero {
23+
assert_eq!(one, a * a.inverse().unwrap(),);
24+
}
25+
26+
// Check a / b = a * b^-1
27+
if b != zero {
28+
let b_non_zero = NonZeroFelt::try_from(b).unwrap();
29+
let b_inverse = b.inverse().unwrap();
30+
assert_eq!(a.field_div(&b_non_zero), a * b_inverse);
31+
}
32+
33+
// Check (a / b) / b = a / (b * b)
34+
if b != zero {
35+
let b_non_zero = NonZeroFelt::try_from(b).unwrap();
36+
let b_times_b_non_zero = NonZeroFelt::try_from(b * b).unwrap();
37+
assert_eq!(
38+
a.field_div(&b_non_zero).field_div(&b_non_zero),
39+
a.field_div(&b_times_b_non_zero),
40+
);
41+
}
42+
43+
// Check a / b = (a.to_biguint() * b^-1.to_biguint()) % PRIME
44+
if b != zero {
45+
let b_non_zero = NonZeroFelt::try_from(b).unwrap();
46+
let b_inverse = b.inverse().unwrap();
47+
assert_eq!(
48+
a.field_div(&b_non_zero),
49+
Felt::from(a.to_biguint() * b_inverse.to_biguint()),
50+
);
51+
}
52+
});

fuzz/felt/fuzz_targets/mul.rs

+37
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
#![no_main]
2+
use libfuzzer_sys::fuzz_target;
3+
use starknet_types_core::felt::Felt;
4+
5+
fuzz_target!(|data: (Felt, Felt)| {
6+
let zero = Felt::ZERO;
7+
let one = Felt::ONE;
8+
let (a, b) = data;
9+
10+
// Check a * 1 = a
11+
assert_eq!(a * one, a);
12+
assert_eq!(b * one, b);
13+
14+
// Check 1 * a = a
15+
assert_eq!(one * a, a);
16+
assert_eq!(one * b, b);
17+
18+
// Check a * 0 = 0
19+
assert_eq!(a * zero, zero);
20+
assert_eq!(b * zero, zero);
21+
22+
// Check 0 * a = a
23+
assert_eq!(zero * a, zero);
24+
assert_eq!(zero * b, zero);
25+
26+
// Check a * max = max - a + 1
27+
assert_eq!(a * Felt::MAX, Felt::MAX - a + 1);
28+
29+
// Check a * b = b * a
30+
assert_eq!(a * b, b * a);
31+
32+
// Check a * b = (a.to_biguint() * b.to_biguint()) % PRIME
33+
assert_eq!(a * b, Felt::from(a.to_biguint() * b.to_biguint()));
34+
35+
assert_eq!(a.square(), a * a);
36+
assert_eq!(b.square(), b * b);
37+
});

0 commit comments

Comments
 (0)