From 4cbb4d80964e1fb7f05d781db9764a7dc0c024cc Mon Sep 17 00:00:00 2001 From: integritychain Date: Tue, 14 Jan 2025 15:32:20 -0600 Subject: [PATCH 1/3] init fuzz scalars --- Cargo.toml | 1 + fuzz/Cargo.toml | 35 ++++ fuzz/fuzz_targets/scalars.rs | 379 +++++++++++++++++++++++++++++++++++ 3 files changed, 415 insertions(+) create mode 100755 fuzz/Cargo.toml create mode 100755 fuzz/fuzz_targets/scalars.rs diff --git a/Cargo.toml b/Cargo.toml index 126bda128..45338d042 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -4,6 +4,7 @@ members = [ "bign256", "bp256", "bp384", + "fuzz", "k256", "p192", "p224", diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml new file mode 100755 index 000000000..bd2ffe5e2 --- /dev/null +++ b/fuzz/Cargo.toml @@ -0,0 +1,35 @@ +[package] +name = "fuzz-elliptic-curves" +version = "0.0.0" +authors = ["eschorn@integritychain.com"] +publish = false +edition = "2021" + +[package.metadata] +cargo-fuzz = true + +[dependencies] +libfuzzer-sys = "0.4" +ciborium = "0.2.2" +rand_chacha = "0.3" +elliptic-curve = "0.13.0" +bign256 = { path = "../bign256", features = ["arithmetic", "serde"] } +k256 = { path = "../k256", features = ["arithmetic", "serde"] } +p192 = { path = "../p192", features = ["arithmetic", "serde"] } +p224 = { path = "../p224", features = ["arithmetic", "serde"] } +p256 = { path = "../p256", features = ["arithmetic", "serde"] } +p384 = { path = "../p384", features = ["arithmetic", "serde"] } +p521 = { path = "../p521", features = ["arithmetic", "serde"] } +sm2 = { path = "../sm2", features = ["arithmetic", "serde"] } + +[[bin]] +name = "scalars" +path = "fuzz_targets/scalars.rs" +test = false +doc = false + +[[bin]] +name = "points" +path = "fuzz_targets/points.rs" +test = false +doc = false diff --git a/fuzz/fuzz_targets/scalars.rs b/fuzz/fuzz_targets/scalars.rs new file mode 100755 index 000000000..451ed90c0 --- /dev/null +++ b/fuzz/fuzz_targets/scalars.rs @@ -0,0 +1,379 @@ +#![no_main] +use bign256; +use std::any::{Any, TypeId}; +// bp256 and bp384 are under construction +use ciborium::de; +use elliptic_curve::{Field, PrimeField}; +use k256; +use libfuzzer_sys::fuzz_target; +use p192; +use p224; +use p256; +use p384; +use p521; +use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; +use sm2; + +fn test_field(fe1: F, fe2: F, fe3: F) { + // Associativity + assert_eq!(fe1 + (fe2 + fe3), (fe1 + fe2) + fe3); + assert_eq!(fe1 * (fe2 * fe3), (fe1 * fe2) * fe3); + + // Commutativity + assert_eq!(fe1 + fe2, fe2 + fe1); + assert_eq!(fe1 * fe2, fe2 * fe1); + + // Identity + assert_eq!(fe1 + F::ZERO, fe1); + assert_eq!(fe1 * F::ONE, fe1); + assert_eq!(fe1 - fe1, F::ZERO); + + // Distributivity + assert_eq!(fe1 * (fe2 + fe3), fe1 * fe2 + fe1 * fe3); + assert_eq!((fe1 + fe2) * fe3, fe1 * fe3 + fe2 * fe3); + + // Inverse, square, cube, sqrt_ratio + assert_eq!(fe1 + (-fe1), F::ZERO); + let fe1_sq = fe1.square(); + let fe1_cube = fe1.cube(); + if !bool::from(fe1.is_zero()) { + assert_eq!(fe1_cube * fe1_sq.invert().unwrap(), fe1); + if TypeId::of::() != fe1.type_id() { + assert_eq!(fe1_sq.sqrt().unwrap().square(), fe1_sq); + assert!(bool::from(fe1_sq.sqrt_alt().0)); + assert!(bool::from(F::sqrt_ratio(&fe1_cube, &fe1).0)); + } + } + assert_eq!( + bool::from(fe1_sq.is_zero()), + bool::from(fe1_sq.is_zero_vartime()) + ); + + // Double, even, odd + let fe1_double: F = fe1.double(); + assert_eq!(fe1_double, fe1 + fe1); + assert_ne!( + bool::from(fe1_double.is_odd()), + bool::from(fe1_double.is_even()) + ); + + let limb0 = u64::from_le_bytes(fe3.to_repr().as_ref()[0..8].try_into().unwrap()); + let limb1 = u64::from_le_bytes(fe3.to_repr().as_ref()[8..16].try_into().unwrap()); + let limb2 = u64::from_le_bytes(fe3.to_repr().as_ref()[16..24].try_into().unwrap()); + let xx = fe1.pow(&[limb0, limb1, limb2, limb1.wrapping_add(limb2)]); + let yy = fe1.pow_vartime(&[limb0, limb1, limb2, limb1.wrapping_add(limb2)]); + assert_eq!(xx, yy); +} + +fuzz_target!(|data: &[u8]| { + if data.len() < 256 { + return; + } + + // Backup plan for `from` failures + let mut rng = ChaChaRng::from_seed(data[0..32].try_into().unwrap()); + + // + // + /////////////////////////////////////////////////////////////////////////// + // Test bign256 (does not support serde) + let repr1 = &data[16..(16 + (bign256::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe1 = bign256::Scalar::from_bytes(repr1.try_into().unwrap()); + let fe1 = opt_fe1.unwrap_or(bign256::Scalar::random(&mut rng)); + + // bign256 de::from_reader() not supported/implemented + + let repr2 = &data[32..(32 + (bign256::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe2 = bign256::Scalar::from_repr(repr2.try_into().unwrap()); + let fe2 = opt_fe2.unwrap_or(bign256::Scalar::random(&mut rng)); + + let repr3 = &data[48..(48 + (bign256::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe3 = bign256::Scalar::from_repr_vartime(repr3.try_into().unwrap()); + let fe3 = opt_fe3.unwrap_or(bign256::Scalar::random(&mut rng)); + + let repr4 = &data[64..64 + usize::from(data[1] & 0x7f)]; + let opt_fe4 = bign256::Scalar::from_slice(repr4); + let fe4 = opt_fe4.unwrap_or(bign256::Scalar::random(&mut rng)); + + let repr5 = &data[96..(96 + usize::from(data[2] & 0x7f))]; + let str5 = std::str::from_utf8(&repr5).unwrap_or("123"); + let fe5 = bign256::Scalar::from_str_vartime(str5).unwrap_or(bign256::Scalar::random(&mut rng)); + + let uint6 = bign256::elliptic_curve::bigint::U256::from_le_slice(&data[128..160]); + let fe6 = bign256::Scalar::from_uint(uint6).unwrap_or(bign256::Scalar::random(&mut rng)); + + let fe7 = bign256::Scalar::from_u64(u64::from_le_bytes(data[160..168].try_into().unwrap())); + + let fe8 = bign256::Scalar::from_u128(u128::from_le_bytes(data[168..184].try_into().unwrap())); + + // bign256::Scalar::generate_biased() not supported/implemented + + // bign256::Scalar::generate_vartime() not supported/implemented + + test_field(fe1 + fe2 + fe3, fe4 + fe5 + fe6, fe7 + fe8); + + // + // + /////////////////////////////////////////////////////////////////////////// + // Test k256 (secp256k1) + + // k256::Scalar::from_bytes() not supported/implemented + + let fe1 = de::from_reader(&data[32..]).unwrap_or(k256::Scalar::random(&mut rng)); + + let repr2 = &data[32..(32 + (k256::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe2 = k256::Scalar::from_repr(repr2.try_into().unwrap()); + let fe2 = opt_fe2.unwrap_or(k256::Scalar::random(&mut rng)); + + let repr3 = &data[48..(48 + (k256::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe3 = k256::Scalar::from_repr_vartime(repr3.try_into().unwrap()); + let fe3 = opt_fe3.unwrap_or(k256::Scalar::random(&mut rng)); + + // k256::Scalar::from_slice() not supported/implemented + + let repr4 = &data[96..(96 + usize::from(data[1] & 0x7f))]; + let str4 = std::str::from_utf8(&repr4).unwrap_or("123"); + let fe4 = k256::Scalar::from_str_vartime(str4).unwrap_or(k256::Scalar::random(&mut rng)); + + // k256::Scalar::from_uint() not supported/implemented + + // k256::Scalar::from_u64() not supported/implemented + + let fe5 = k256::Scalar::from_u128(u128::from_le_bytes(data[168..184].try_into().unwrap())); + + let fe6 = k256::Scalar::generate_biased(&mut rng); + + let fe7 = k256::Scalar::generate_vartime(&mut rng); + + test_field(fe1 + fe2 + fe3, fe4 + fe5 + fe6, fe7); + + // + // + /////////////////////////////////////////////////////////////////////////// + // Test p192 + let repr1 = &data[16..(16 + (p192::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe1 = p192::Scalar::from_bytes(repr1.try_into().unwrap()); + let fe1 = opt_fe1.unwrap_or(p192::Scalar::random(&mut rng)); + + let fe2 = de::from_reader(&data[32..]).unwrap_or(p192::Scalar::random(&mut rng)); + + let repr3 = &data[32..(32 + (p192::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe3 = p192::Scalar::from_repr(repr3.try_into().unwrap()); + let fe3 = opt_fe3.unwrap_or(p192::Scalar::random(&mut rng)); + + let repr4 = &data[48..(48 + (p192::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe4 = p192::Scalar::from_repr_vartime(repr4.try_into().unwrap()); + let fe4 = opt_fe4.unwrap_or(p192::Scalar::random(&mut rng)); + + let repr5 = &data[64..64 + usize::from(data[1] & 0x7f)]; + let opt_fe5 = p192::Scalar::from_slice(repr5); + let fe5 = opt_fe5.unwrap_or(p192::Scalar::random(&mut rng)); + + let repr6 = &data[96..(96 + usize::from(data[2] & 0x7f))]; + let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let fe6 = p192::Scalar::from_str_vartime(str6).unwrap_or(p192::Scalar::random(&mut rng)); + + let uint7 = p192::elliptic_curve::bigint::U192::from_le_slice(&data[128..152]); + let fe7 = p192::Scalar::from_uint(uint7).unwrap_or(p192::Scalar::random(&mut rng)); + + let fe8 = p192::Scalar::from_u64(u64::from_le_bytes(data[160..168].try_into().unwrap())); + + let fe9 = p192::Scalar::from_u128(u128::from_le_bytes(data[168..184].try_into().unwrap())); + + // p192::Scalar::generate_biased() not supported/implemented + + // p192::Scalar::generate_vartime() not supported/implemented + + test_field(fe1 + fe2 + fe3, fe4 + fe5 + fe6, fe7 + fe8 + fe9); + + // + // + /////////////////////////////////////////////////////////////////////////// + // Test p224 + let repr1 = &data[16..(16 + (p224::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe1 = p224::Scalar::from_bytes(repr1.try_into().unwrap()); + let fe1 = opt_fe1.unwrap_or(p224::Scalar::random(&mut rng)); + + let fe2 = de::from_reader(&data[32..]).unwrap_or(p224::Scalar::random(&mut rng)); + + let repr3 = &data[32..(32 + (p224::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe3 = p224::Scalar::from_repr(repr3.try_into().unwrap()); + let fe3 = opt_fe3.unwrap_or(p224::Scalar::random(&mut rng)); + + let repr4 = &data[48..(48 + (p224::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe4 = p224::Scalar::from_repr_vartime(repr4.try_into().unwrap()); + let fe4 = opt_fe4.unwrap_or(p224::Scalar::random(&mut rng)); + + let repr5 = &data[64..64 + usize::from(data[1] & 0x7f)]; + let opt_fe5 = p224::Scalar::from_slice(repr5); + let fe5 = opt_fe5.unwrap_or(p224::Scalar::random(&mut rng)); + + let repr6 = &data[96..(96 + usize::from(data[2] & 0x7f))]; + let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let fe6 = p224::Scalar::from_str_vartime(str6).unwrap_or(p224::Scalar::random(&mut rng)); + + let uint7 = p224::elliptic_curve::bigint::U256::from_le_slice(&data[128..160]); // note U256 vs U224 + let fe7 = p224::Scalar::from_uint(uint7).unwrap_or(p224::Scalar::random(&mut rng)); + + let fe8 = p224::Scalar::from_u64(u64::from_le_bytes(data[160..168].try_into().unwrap())); + + let fe9 = p224::Scalar::from_u128(u128::from_le_bytes(data[168..184].try_into().unwrap())); + + // p224::Scalar::generate_biased() not supported/implemented + + // p224::Scalar::generate_vartime() not supported/implemented + + test_field(fe1 + fe2 + fe3, fe4 + fe5 + fe6, fe7 + fe8 + fe9); + + // + // + /////////////////////////////////////////////////////////////////////////// + // Test p256 + + // p256::Scalar::from_bytes() not supported/implemented + + let fe2 = de::from_reader(&data[32..]).unwrap_or(p256::Scalar::random(&mut rng)); + + let repr3 = &data[32..(32 + (p256::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe3 = p256::Scalar::from_repr(repr3.try_into().unwrap()); + let fe3 = opt_fe3.unwrap_or(p256::Scalar::random(&mut rng)); + + let repr4 = &data[48..(48 + (p256::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe4 = p256::Scalar::from_repr_vartime(repr4.try_into().unwrap()); + let fe4 = opt_fe4.unwrap_or(p256::Scalar::random(&mut rng)); + + // p256::Scalar::from_slice() not supported/implemented + + let repr6 = &data[96..(96 + usize::from(data[1] & 0x7f))]; + let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let fe6 = p256::Scalar::from_str_vartime(str6).unwrap_or(p256::Scalar::random(&mut rng)); + + // p256::Scalar::from_uint() not supported/implemented + + // p256::Scalar::from_u64() not supported/implemented + + let fe9 = p256::Scalar::from_u128(u128::from_le_bytes(data[168..184].try_into().unwrap())); + + // p256::Scalar::generate_biased() not supported/implemented + + // p256::Scalar::generate_vartime() not supported/implemented + + test_field(fe2 + fe3, fe4 + fe6, fe9); + + // + // + /////////////////////////////////////////////////////////////////////////// + // Test p384 + let repr1 = &data[16..(16 + (p384::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe1 = p384::Scalar::from_bytes(repr1.try_into().unwrap()); + let fe1 = opt_fe1.unwrap_or(p384::Scalar::random(&mut rng)); + + let fe2 = de::from_reader(&data[32..]).unwrap_or(p384::Scalar::random(&mut rng)); + + let repr3 = &data[32..(32 + (p384::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe3 = p384::Scalar::from_repr(repr3.try_into().unwrap()); + let fe3 = opt_fe3.unwrap_or(p384::Scalar::random(&mut rng)); + + let repr4 = &data[48..(48 + (p384::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe4 = p384::Scalar::from_repr_vartime(repr4.try_into().unwrap()); + let fe4 = opt_fe4.unwrap_or(p384::Scalar::random(&mut rng)); + + let repr5 = &data[64..64 + usize::from(data[1] & 0x7f)]; + let opt_fe5 = p384::Scalar::from_slice(repr5); + let fe5 = opt_fe5.unwrap_or(p384::Scalar::random(&mut rng)); + + let repr6 = &data[96..(96 + usize::from(data[2] & 0x7f))]; + let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let fe6 = p384::Scalar::from_str_vartime(str6).unwrap_or(p384::Scalar::random(&mut rng)); + + let uint7 = p384::elliptic_curve::bigint::U384::from_le_slice(&data[128..176]); + let fe7 = p384::Scalar::from_uint(uint7).unwrap_or(p384::Scalar::random(&mut rng)); + + let fe8 = p384::Scalar::from_u64(u64::from_le_bytes(data[160..168].try_into().unwrap())); + + let fe9 = p384::Scalar::from_u128(u128::from_le_bytes(data[168..184].try_into().unwrap())); + + // p384::Scalar::generate_biased() not supported/implemented + + // p384::Scalar::generate_vartime() not supported/implemented + + test_field(fe1 + fe2 + fe3, fe4 + fe5 + fe6, fe7 + fe8 + fe9); + + // + // + /////////////////////////////////////////////////////////////////////////// + // Test p521 + let repr1 = &data[16..(16 + (p521::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe1 = p521::Scalar::from_bytes(repr1.try_into().unwrap()); + let fe1 = opt_fe1.unwrap_or(p521::Scalar::random(&mut rng)); + + let fe2 = de::from_reader(&data[32..]).unwrap_or(p521::Scalar::random(&mut rng)); + + let repr3 = &data[32..(32 + (p521::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe3 = p521::Scalar::from_repr(repr3.try_into().unwrap()); + let fe3 = opt_fe3.unwrap_or(p521::Scalar::random(&mut rng)); + + let repr4 = &data[48..(48 + (p521::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe4 = p521::Scalar::from_repr_vartime(repr4.try_into().unwrap()); + let fe4 = opt_fe4.unwrap_or(p521::Scalar::random(&mut rng)); + + let repr5 = &data[64..64 + usize::from(data[1] & 0x7f)]; + let opt_fe5 = p521::Scalar::from_slice(repr5); + let fe5 = opt_fe5.unwrap_or(p521::Scalar::random(&mut rng)); + + let repr6 = &data[96..(96 + usize::from(data[2] & 0x7f))]; + let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let fe6 = p521::Scalar::from_str_vartime(str6).unwrap_or(p521::Scalar::random(&mut rng)); + + let uint7 = p521::elliptic_curve::bigint::U576::from_le_slice(&data[128..200]); + let fe7 = p521::Scalar::from_uint(uint7).unwrap_or(p521::Scalar::random(&mut rng)); + + let fe8 = p521::Scalar::from_u64(u64::from_le_bytes(data[160..168].try_into().unwrap())); + + let fe9 = p521::Scalar::from_u128(u128::from_le_bytes(data[168..184].try_into().unwrap())); + + // p521::Scalar::generate_biased() not supported/implemented + + // p521::Scalar::generate_vartime() not supported/implemented + + test_field(fe1 + fe2 + fe3, fe4 + fe5 + fe6, fe7 + fe8 + fe9); + + // + // + /////////////////////////////////////////////////////////////////////////// + // Test sm2 + let repr1 = &data[16..(16 + (sm2::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe1 = sm2::Scalar::from_bytes(repr1.try_into().unwrap()); + let fe1 = opt_fe1.unwrap_or(sm2::Scalar::random(&mut rng)); + + let fe2 = de::from_reader(&data[32..]).unwrap_or(sm2::Scalar::random(&mut rng)); + + let repr3 = &data[32..(32 + (sm2::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe3 = sm2::Scalar::from_repr(repr3.try_into().unwrap()); + let fe3 = opt_fe3.unwrap_or(sm2::Scalar::random(&mut rng)); + + let repr4 = &data[48..(48 + (sm2::Scalar::NUM_BITS + 7) / 8) as usize]; + let opt_fe4 = sm2::Scalar::from_repr_vartime(repr4.try_into().unwrap()); + let fe4 = opt_fe4.unwrap_or(sm2::Scalar::random(&mut rng)); + + let repr5 = &data[64..64 + usize::from(data[1] & 0x7f)]; + let opt_fe5 = sm2::Scalar::from_slice(repr5); + let fe5 = opt_fe5.unwrap_or(sm2::Scalar::random(&mut rng)); + + let repr6 = &data[96..(96 + usize::from(data[1] & 0x7f))]; + let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let fe6 = sm2::Scalar::from_str_vartime(str6).unwrap_or(sm2::Scalar::random(&mut rng)); + + let uint7 = sm2::elliptic_curve::bigint::U256::from_le_slice(&data[128..160]); + let fe7 = sm2::Scalar::from_uint(uint7).unwrap_or(sm2::Scalar::random(&mut rng)); + + let fe8 = sm2::Scalar::from_u64(u64::from_le_bytes(data[160..168].try_into().unwrap())); + + let fe9 = sm2::Scalar::from_u128(u128::from_le_bytes(data[168..184].try_into().unwrap())); + + // sm2::Scalar::generate_biased() not supported/implemented + + // sm2::Scalar::generate_vartime() not supported/implemented + + test_field(fe1 + fe2 + fe3, fe4 + fe5 + fe6, fe7 + fe8 + fe9); +}); From dd8472e4b7b663a2434a3e010880700418f70d19 Mon Sep 17 00:00:00 2001 From: integritychain Date: Wed, 15 Jan 2025 17:39:34 -0600 Subject: [PATCH 2/3] init points --- fuzz/Cargo.toml | 2 +- fuzz/README.md | 31 ++++ fuzz/fuzz_targets/points.rs | 296 +++++++++++++++++++++++++++++++++++ fuzz/fuzz_targets/scalars.rs | 62 ++++++-- 4 files changed, 374 insertions(+), 17 deletions(-) create mode 100644 fuzz/README.md create mode 100755 fuzz/fuzz_targets/points.rs diff --git a/fuzz/Cargo.toml b/fuzz/Cargo.toml index bd2ffe5e2..3c89704c4 100755 --- a/fuzz/Cargo.toml +++ b/fuzz/Cargo.toml @@ -12,7 +12,7 @@ cargo-fuzz = true libfuzzer-sys = "0.4" ciborium = "0.2.2" rand_chacha = "0.3" -elliptic-curve = "0.13.0" +elliptic-curve = { version = "0.13.0", features = ["sec1"] } bign256 = { path = "../bign256", features = ["arithmetic", "serde"] } k256 = { path = "../k256", features = ["arithmetic", "serde"] } p192 = { path = "../p192", features = ["arithmetic", "serde"] } diff --git a/fuzz/README.md b/fuzz/README.md new file mode 100644 index 000000000..fd76598f5 --- /dev/null +++ b/fuzz/README.md @@ -0,0 +1,31 @@ +# Fuzzing harnesses for the `elliptic-curve` crate + +This directory is under development; the coverage stats are from relatively brief runs. +Ultimately, the goal is to join Google's OSS-Fuzz: Continuous Fuzzing for Open Source Software, see https://google.github.io/oss-fuzz/ + + +## Scalars + +The `scalars.rs` harness has fairly complete coverage of deserializors and arithmetic operations. + +~~~ +$ cargo +nightly fuzz run scalars -j 4 + + +#722833: cov: 2025 ft: 3282 corp: 309 exec/s: 1941 oom/timeout/crash: 0/0/0 time: 106s job: 26 dft_time: 0 +#775578: cov: 2025 ft: 3282 corp: 309 exec/s: 1883 oom/timeout/crash: 0/0/0 time: 113s job: 27 dft_time: 0 +~~~ + + +## Points + +The `points.rs` harness is currently being built. Some of the coverage is inherently duplicative of the scalars. + +~~~ +$ cargo +nightly fuzz run points -j 4 + + +#2068356: cov: 3130 ft: 6073 corp: 359 exec/s: 93 oom/timeout/crash: 0/0/0 time: 4906s job: 195 dft_time: 0 +#2086824: cov: 3130 ft: 6073 corp: 359 exec/s: 93 oom/timeout/crash: 0/0/0 time: 4955s job: 196 dft_time: 0 +~~~ + diff --git a/fuzz/fuzz_targets/points.rs b/fuzz/fuzz_targets/points.rs new file mode 100755 index 000000000..03ff98397 --- /dev/null +++ b/fuzz/fuzz_targets/points.rs @@ -0,0 +1,296 @@ +#![no_main] +use bign256; +// bp256 and bp384 are under construction +use ciborium::de; +use elliptic_curve::{group::GroupEncoding, Field, Group}; +use k256; +use libfuzzer_sys::fuzz_target; +use p192; +use p224; +use p256; +use p384; +use p521; +use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; +use sm2; + +static mut I: u64 = 0; + +fn test_group(p1: G, p2: G, s: G::Scalar) { + unsafe { + I = I.wrapping_add(1); + // Our goal is primarily to test deserialization, so we skip 6 of every 7 group tests + if I % 7 != 0 { + return; + } + } + + // Test point arithmetic + let sum = p1 + p2; + let scalar_mul = p1 * s; + + // Test that addition and doubling are consistent + assert!(p1.double() == p1 + p1 - G::identity()); + + // Test that negation works correctly + assert!(sum + (-sum) == G::identity()); + + // Test scalar multiplication distributive property + assert!(scalar_mul + scalar_mul == p1 * (s + s)); +} + +fuzz_target!(|data: &[u8]| { + if data.len() < 160 { + return; + } + + let mut rng = ChaChaRng::from_seed(data[0..32].try_into().unwrap()); + + // + // Test bign256 + + let len = bign256::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective + let pp1 = bign256::ProjectivePoint::from_bytes(&data[16..16 + len].try_into().unwrap()) + .unwrap_or_else(|| bign256::ProjectivePoint::random(&mut rng)); + let ap1 = bign256::AffinePoint::from(pp1); + let ap2 = bign256::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) + .unwrap_or_else(|| bign256::AffinePoint::GENERATOR); + let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) + .unwrap_or_else(|_| bign256::AffinePoint::GENERATOR); + let ap4 = bign256::AffinePoint::try_from(bign256::EncodedPoint::from_affine_coordinates( + &data[24..24 + len - 1].try_into().unwrap(), + &data[40..40 + len - 1].try_into().unwrap(), + true, + )) + .unwrap_or_else(|_| bign256::AffinePoint::GENERATOR); + let ap5 = bign256::AffinePoint::try_from( + bign256::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) + .unwrap_or_else(|_| bign256::EncodedPoint::identity()), + ) + .unwrap_or_else(|_| bign256::AffinePoint::GENERATOR); + let pp2 = bign256::ProjectivePoint::from(ap2); + let scalar = bign256::Scalar::from_slice(&data[96..96 + len]) + .unwrap_or_else(|_| bign256::Scalar::random(&mut rng)); + + test_group( + pp1 + pp2, + (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), + scalar, + ); + + // + // Test k256 (secp256k1) + + let len = k256::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective + let pp1 = k256::ProjectivePoint::from_bytes(&data[16..16 + len].try_into().unwrap()) + .unwrap_or_else(|| k256::ProjectivePoint::random(&mut rng)); + let ap1 = k256::AffinePoint::from(pp1); + let ap2 = k256::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) + .unwrap_or_else(|| k256::AffinePoint::GENERATOR); + let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) + .unwrap_or_else(|_| k256::AffinePoint::GENERATOR); + let ap4 = k256::AffinePoint::try_from(k256::EncodedPoint::from_affine_coordinates( + &data[24..24 + len - 1].try_into().unwrap(), + &data[40..40 + len - 1].try_into().unwrap(), + true, + )) + .unwrap_or_else(|_| k256::AffinePoint::GENERATOR); + let ap5 = k256::AffinePoint::try_from( + k256::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) + .unwrap_or_else(|_| k256::EncodedPoint::identity()), + ) + .unwrap_or_else(|_| k256::AffinePoint::GENERATOR); + let pp2 = k256::ProjectivePoint::from(ap2); + let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) + .unwrap_or(k256::Scalar::random(&mut rng)); + + test_group( + pp1 + pp2, + (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), + scalar, + ); + + // + // Test p192 + + let len = p192::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective + let pp1 = p192::ProjectivePoint::from_bytes(&data[16..16 + len].try_into().unwrap()) + .unwrap_or_else(|| p192::ProjectivePoint::random(&mut rng)); + let ap1 = p192::AffinePoint::from(pp1); + let ap2 = p192::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) + .unwrap_or_else(|| p192::AffinePoint::GENERATOR); + let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) + .unwrap_or_else(|_| p192::AffinePoint::GENERATOR); + let ap4 = p192::AffinePoint::try_from(p192::EncodedPoint::from_affine_coordinates( + &data[24..24 + len - 1].try_into().unwrap(), + &data[40..40 + len - 1].try_into().unwrap(), + true, + )) + .unwrap_or_else(|_| p192::AffinePoint::GENERATOR); + let ap5 = p192::AffinePoint::try_from( + p192::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) + .unwrap_or_else(|_| p192::EncodedPoint::identity()), + ) + .unwrap_or_else(|_| p192::AffinePoint::GENERATOR); + let pp2 = p192::ProjectivePoint::from(ap2); + let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) + .unwrap_or(p192::Scalar::random(&mut rng)); + + test_group( + pp1 + pp2, + (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), + scalar, + ); + + // + // Test p224 + + let len = p224::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective + let pp1 = p224::ProjectivePoint::from_bytes(&data[16..16 + len].try_into().unwrap()) + .unwrap_or_else(|| p224::ProjectivePoint::random(&mut rng)); + let ap1 = p224::AffinePoint::from(pp1); + let ap2 = p224::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) + .unwrap_or_else(|| p224::AffinePoint::GENERATOR); + let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) + .unwrap_or_else(|_| p224::AffinePoint::GENERATOR); + let ap4 = p224::AffinePoint::try_from(p224::EncodedPoint::from_affine_coordinates( + &data[24..24 + len - 1].try_into().unwrap(), + &data[40..40 + len - 1].try_into().unwrap(), + true, + )) + .unwrap_or_else(|_| p224::AffinePoint::GENERATOR); + let ap5 = p224::AffinePoint::try_from( + p224::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) + .unwrap_or_else(|_| p224::EncodedPoint::identity()), + ) + .unwrap_or_else(|_| p224::AffinePoint::GENERATOR); + let pp2 = p224::ProjectivePoint::from(ap2); + let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) + .unwrap_or(p224::Scalar::random(&mut rng)); + + test_group( + pp1 + pp2, + (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), + scalar, + ); + + // + // Test p256 + let len = p256::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective + let pp1 = p256::ProjectivePoint::from_bytes(&data[16..16 + len].try_into().unwrap()) + .unwrap_or_else(|| p256::ProjectivePoint::random(&mut rng)); + let ap1 = p256::AffinePoint::from(pp1); + let ap2 = p256::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) + .unwrap_or_else(|| p256::AffinePoint::GENERATOR); + let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) + .unwrap_or_else(|_| p256::AffinePoint::GENERATOR); + let ap4 = p256::AffinePoint::try_from(p256::EncodedPoint::from_affine_coordinates( + &data[24..24 + len - 1].try_into().unwrap(), + &data[40..40 + len - 1].try_into().unwrap(), + true, + )) + .unwrap_or_else(|_| p256::AffinePoint::GENERATOR); + let ap5 = p256::AffinePoint::try_from( + p256::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) + .unwrap_or_else(|_| p256::EncodedPoint::identity()), + ) + .unwrap_or_else(|_| p256::AffinePoint::GENERATOR); + let pp2 = p256::ProjectivePoint::from(ap2); + let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) + .unwrap_or(p256::Scalar::random(&mut rng)); + + test_group( + pp1 + pp2, + (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), + scalar, + ); + + // Test p384 + let len = p384::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective + let pp1 = p384::ProjectivePoint::from_bytes(&data[16..16 + len].try_into().unwrap()) + .unwrap_or_else(|| p384::ProjectivePoint::random(&mut rng)); + let ap1 = p384::AffinePoint::from(pp1); + let ap2 = p384::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) + .unwrap_or_else(|| p384::AffinePoint::GENERATOR); + let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) + .unwrap_or_else(|_| p384::AffinePoint::GENERATOR); + let ap4 = p384::AffinePoint::try_from(p384::EncodedPoint::from_affine_coordinates( + &data[24..24 + len - 1].try_into().unwrap(), + &data[40..40 + len - 1].try_into().unwrap(), + true, + )) + .unwrap_or_else(|_| p384::AffinePoint::GENERATOR); + let ap5 = p384::AffinePoint::try_from( + p384::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) + .unwrap_or_else(|_| p384::EncodedPoint::identity()), + ) + .unwrap_or_else(|_| p384::AffinePoint::GENERATOR); + let pp2 = p384::ProjectivePoint::from(ap2); + let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) + .unwrap_or(p384::Scalar::random(&mut rng)); + + test_group( + pp1 + pp2, + (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), + scalar, + ); + + // Test p521 + let len = p521::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective + let pp1 = p521::ProjectivePoint::from_bytes(&data[16..16 + len].try_into().unwrap()) + .unwrap_or_else(|| p521::ProjectivePoint::random(&mut rng)); + let ap1 = p521::AffinePoint::from(pp1); + let ap2 = p521::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) + .unwrap_or_else(|| p521::AffinePoint::GENERATOR); + let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) + .unwrap_or_else(|_| p521::AffinePoint::GENERATOR); + let ap4 = p521::AffinePoint::try_from(p521::EncodedPoint::from_affine_coordinates( + &data[24..24 + len - 1].try_into().unwrap(), + &data[40..40 + len - 1].try_into().unwrap(), + true, + )) + .unwrap_or_else(|_| p521::AffinePoint::GENERATOR); + let ap5 = p521::AffinePoint::try_from( + p521::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) + .unwrap_or_else(|_| p521::EncodedPoint::identity()), + ) + .unwrap_or_else(|_| p521::AffinePoint::GENERATOR); + let pp2 = p521::ProjectivePoint::from(ap2); + let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) + .unwrap_or(p521::Scalar::random(&mut rng)); + + test_group( + pp1 + pp2, + (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), + scalar, + ); + + // Test sm2 + let len = sm2::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective + let pp1 = sm2::ProjectivePoint::from_bytes(&data[16..16 + len].try_into().unwrap()) + .unwrap_or_else(|| sm2::ProjectivePoint::random(&mut rng)); + let ap1 = sm2::AffinePoint::from(pp1); + let ap2 = sm2::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) + .unwrap_or_else(|| sm2::AffinePoint::GENERATOR); + let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) + .unwrap_or_else(|_| sm2::AffinePoint::GENERATOR); + let ap4 = sm2::AffinePoint::try_from(sm2::EncodedPoint::from_affine_coordinates( + &data[24..24 + len - 1].try_into().unwrap(), + &data[40..40 + len - 1].try_into().unwrap(), + true, + )) + .unwrap_or_else(|_| sm2::AffinePoint::GENERATOR); + let ap5 = sm2::AffinePoint::try_from( + sm2::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) + .unwrap_or_else(|_| sm2::EncodedPoint::identity()), + ) + .unwrap_or_else(|_| sm2::AffinePoint::GENERATOR); + let pp2 = sm2::ProjectivePoint::from(ap2); + let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) + .unwrap_or(sm2::Scalar::random(&mut rng)); + + test_group( + pp1 + pp2, + (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), + scalar, + ); +}); diff --git a/fuzz/fuzz_targets/scalars.rs b/fuzz/fuzz_targets/scalars.rs index 451ed90c0..7f8babb93 100755 --- a/fuzz/fuzz_targets/scalars.rs +++ b/fuzz/fuzz_targets/scalars.rs @@ -1,6 +1,5 @@ #![no_main] use bign256; -use std::any::{Any, TypeId}; // bp256 and bp384 are under construction use ciborium::de; use elliptic_curve::{Field, PrimeField}; @@ -14,7 +13,17 @@ use p521; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; use sm2; -fn test_field(fe1: F, fe2: F, fe3: F) { +static mut I: u64 = 0; + +fn test_field(fe1: F, fe2: F, fe3: F) { + unsafe { + I = I.wrapping_add(1); + // Our goal is primarily to test deserialization, so we skip 6 of every 7 field tests + if I % 7 != 0 { + return; + } + } + // Associativity assert_eq!(fe1 + (fe2 + fe3), (fe1 + fe2) + fe3); assert_eq!(fe1 * (fe2 * fe3), (fe1 * fe2) * fe3); @@ -38,7 +47,7 @@ fn test_field(fe1: F, fe2: F, fe3: F) { let fe1_cube = fe1.cube(); if !bool::from(fe1.is_zero()) { assert_eq!(fe1_cube * fe1_sq.invert().unwrap(), fe1); - if TypeId::of::() != fe1.type_id() { + if std::any::TypeId::of::() != fe1.type_id() { assert_eq!(fe1_sq.sqrt().unwrap().square(), fe1_sq); assert!(bool::from(fe1_sq.sqrt_alt().0)); assert!(bool::from(F::sqrt_ratio(&fe1_cube, &fe1).0)); @@ -79,7 +88,9 @@ fuzz_target!(|data: &[u8]| { // Test bign256 (does not support serde) let repr1 = &data[16..(16 + (bign256::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe1 = bign256::Scalar::from_bytes(repr1.try_into().unwrap()); - let fe1 = opt_fe1.unwrap_or(bign256::Scalar::random(&mut rng)); + let fe1 = opt_fe1 + .unwrap_or(bign256::Scalar::random(&mut rng)) + .shr_vartime(99); // bign256 de::from_reader() not supported/implemented @@ -119,7 +130,9 @@ fuzz_target!(|data: &[u8]| { // k256::Scalar::from_bytes() not supported/implemented - let fe1 = de::from_reader(&data[32..]).unwrap_or(k256::Scalar::random(&mut rng)); + let fe1 = de::from_reader(&data[32..32 + usize::from(data[3] & 0x3f)]) + .unwrap_or(k256::Scalar::random(&mut rng)) + .shr_vartime(99); let repr2 = &data[32..(32 + (k256::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe2 = k256::Scalar::from_repr(repr2.try_into().unwrap()); @@ -153,9 +166,12 @@ fuzz_target!(|data: &[u8]| { // Test p192 let repr1 = &data[16..(16 + (p192::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe1 = p192::Scalar::from_bytes(repr1.try_into().unwrap()); - let fe1 = opt_fe1.unwrap_or(p192::Scalar::random(&mut rng)); + let fe1 = opt_fe1 + .unwrap_or(p192::Scalar::random(&mut rng)) + .shr_vartime(99); - let fe2 = de::from_reader(&data[32..]).unwrap_or(p192::Scalar::random(&mut rng)); + let fe2 = de::from_reader(&data[32..32 + usize::from(data[3] & 0x3f)]) + .unwrap_or(p192::Scalar::random(&mut rng)); let repr3 = &data[32..(32 + (p192::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe3 = p192::Scalar::from_repr(repr3.try_into().unwrap()); @@ -192,9 +208,12 @@ fuzz_target!(|data: &[u8]| { // Test p224 let repr1 = &data[16..(16 + (p224::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe1 = p224::Scalar::from_bytes(repr1.try_into().unwrap()); - let fe1 = opt_fe1.unwrap_or(p224::Scalar::random(&mut rng)); + let fe1 = opt_fe1 + .unwrap_or(p224::Scalar::random(&mut rng)) + .shr_vartime(99); - let fe2 = de::from_reader(&data[32..]).unwrap_or(p224::Scalar::random(&mut rng)); + let fe2 = de::from_reader(&data[32..32 + usize::from(data[3] & 0x3f)]) + .unwrap_or(p224::Scalar::random(&mut rng)); let repr3 = &data[32..(32 + (p224::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe3 = p224::Scalar::from_repr(repr3.try_into().unwrap()); @@ -232,7 +251,9 @@ fuzz_target!(|data: &[u8]| { // p256::Scalar::from_bytes() not supported/implemented - let fe2 = de::from_reader(&data[32..]).unwrap_or(p256::Scalar::random(&mut rng)); + let fe2 = de::from_reader(&data[32..32 + usize::from(data[3] & 0x3f)]) + .unwrap_or(p256::Scalar::random(&mut rng)) + .shr_vartime(99); let repr3 = &data[32..(32 + (p256::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe3 = p256::Scalar::from_repr(repr3.try_into().unwrap()); @@ -266,9 +287,12 @@ fuzz_target!(|data: &[u8]| { // Test p384 let repr1 = &data[16..(16 + (p384::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe1 = p384::Scalar::from_bytes(repr1.try_into().unwrap()); - let fe1 = opt_fe1.unwrap_or(p384::Scalar::random(&mut rng)); + let fe1 = opt_fe1 + .unwrap_or(p384::Scalar::random(&mut rng)) + .shr_vartime(99); - let fe2 = de::from_reader(&data[32..]).unwrap_or(p384::Scalar::random(&mut rng)); + let fe2 = de::from_reader(&data[32..32 + usize::from(data[3] & 0x3f)]) + .unwrap_or(p384::Scalar::random(&mut rng)); let repr3 = &data[32..(32 + (p384::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe3 = p384::Scalar::from_repr(repr3.try_into().unwrap()); @@ -305,9 +329,12 @@ fuzz_target!(|data: &[u8]| { // Test p521 let repr1 = &data[16..(16 + (p521::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe1 = p521::Scalar::from_bytes(repr1.try_into().unwrap()); - let fe1 = opt_fe1.unwrap_or(p521::Scalar::random(&mut rng)); + let fe1 = opt_fe1 + .unwrap_or(p521::Scalar::random(&mut rng)) + .shr_vartime(99); - let fe2 = de::from_reader(&data[32..]).unwrap_or(p521::Scalar::random(&mut rng)); + let fe2 = de::from_reader(&data[32..32 + usize::from(data[3] & 0x3f)]) + .unwrap_or(p521::Scalar::random(&mut rng)); let repr3 = &data[32..(32 + (p521::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe3 = p521::Scalar::from_repr(repr3.try_into().unwrap()); @@ -344,9 +371,12 @@ fuzz_target!(|data: &[u8]| { // Test sm2 let repr1 = &data[16..(16 + (sm2::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe1 = sm2::Scalar::from_bytes(repr1.try_into().unwrap()); - let fe1 = opt_fe1.unwrap_or(sm2::Scalar::random(&mut rng)); + let fe1 = opt_fe1 + .unwrap_or(sm2::Scalar::random(&mut rng)) + .shr_vartime(99); - let fe2 = de::from_reader(&data[32..]).unwrap_or(sm2::Scalar::random(&mut rng)); + let fe2 = de::from_reader(&data[32..32 + usize::from(data[3] & 0x3f)]) + .unwrap_or(sm2::Scalar::random(&mut rng)); let repr3 = &data[32..(32 + (sm2::Scalar::NUM_BITS + 7) / 8) as usize]; let opt_fe3 = sm2::Scalar::from_repr(repr3.try_into().unwrap()); From 5aab380f5b7ff272fc5a82404248027989d638d3 Mon Sep 17 00:00:00 2001 From: integritychain Date: Thu, 16 Jan 2025 12:31:07 -0600 Subject: [PATCH 3/3] clippy polish etc --- fuzz/README.md | 4 +- fuzz/fuzz_targets/points.rs | 105 +++++++++++------------------------ fuzz/fuzz_targets/scalars.rs | 35 +++++------- 3 files changed, 48 insertions(+), 96 deletions(-) diff --git a/fuzz/README.md b/fuzz/README.md index fd76598f5..82371f16d 100644 --- a/fuzz/README.md +++ b/fuzz/README.md @@ -12,8 +12,8 @@ The `scalars.rs` harness has fairly complete coverage of deserializors and arith $ cargo +nightly fuzz run scalars -j 4 -#722833: cov: 2025 ft: 3282 corp: 309 exec/s: 1941 oom/timeout/crash: 0/0/0 time: 106s job: 26 dft_time: 0 -#775578: cov: 2025 ft: 3282 corp: 309 exec/s: 1883 oom/timeout/crash: 0/0/0 time: 113s job: 27 dft_time: 0 +#16419246: cov: 2038 ft: 3305 corp: 292 exec/s: 1763 oom/timeout/crash: 0/0/0 time: 2350s job: 134 dft_time: 0 +#16650547: cov: 2038 ft: 3305 corp: 292 exec/s: 1700 oom/timeout/crash: 0/0/0 time: 2384s job: 135 dft_time: 0 ~~~ diff --git a/fuzz/fuzz_targets/points.rs b/fuzz/fuzz_targets/points.rs index 03ff98397..039ad6c0c 100755 --- a/fuzz/fuzz_targets/points.rs +++ b/fuzz/fuzz_targets/points.rs @@ -1,17 +1,10 @@ #![no_main] -use bign256; +// Targets: bign256, k256, p192, p224, p256, p384, p521, sm2 // bp256 and bp384 are under construction use ciborium::de; use elliptic_curve::{group::GroupEncoding, Field, Group}; -use k256; use libfuzzer_sys::fuzz_target; -use p192; -use p224; -use p256; -use p384; -use p521; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; -use sm2; static mut I: u64 = 0; @@ -55,27 +48,23 @@ fuzz_target!(|data: &[u8]| { let ap2 = bign256::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) .unwrap_or_else(|| bign256::AffinePoint::GENERATOR); let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) - .unwrap_or_else(|_| bign256::AffinePoint::GENERATOR); + .unwrap_or(bign256::AffinePoint::GENERATOR); let ap4 = bign256::AffinePoint::try_from(bign256::EncodedPoint::from_affine_coordinates( &data[24..24 + len - 1].try_into().unwrap(), &data[40..40 + len - 1].try_into().unwrap(), true, )) - .unwrap_or_else(|_| bign256::AffinePoint::GENERATOR); + .unwrap_or(bign256::AffinePoint::GENERATOR); let ap5 = bign256::AffinePoint::try_from( bign256::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) .unwrap_or_else(|_| bign256::EncodedPoint::identity()), ) - .unwrap_or_else(|_| bign256::AffinePoint::GENERATOR); + .unwrap_or(bign256::AffinePoint::GENERATOR); let pp2 = bign256::ProjectivePoint::from(ap2); let scalar = bign256::Scalar::from_slice(&data[96..96 + len]) .unwrap_or_else(|_| bign256::Scalar::random(&mut rng)); - test_group( - pp1 + pp2, - (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), - scalar, - ); + test_group(pp1 + pp2, pp1 + ap1 + ap2 + ap3 + ap4 + ap5, scalar); // // Test k256 (secp256k1) @@ -87,27 +76,23 @@ fuzz_target!(|data: &[u8]| { let ap2 = k256::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) .unwrap_or_else(|| k256::AffinePoint::GENERATOR); let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) - .unwrap_or_else(|_| k256::AffinePoint::GENERATOR); + .unwrap_or(k256::AffinePoint::GENERATOR); let ap4 = k256::AffinePoint::try_from(k256::EncodedPoint::from_affine_coordinates( &data[24..24 + len - 1].try_into().unwrap(), &data[40..40 + len - 1].try_into().unwrap(), true, )) - .unwrap_or_else(|_| k256::AffinePoint::GENERATOR); + .unwrap_or(k256::AffinePoint::GENERATOR); let ap5 = k256::AffinePoint::try_from( k256::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) .unwrap_or_else(|_| k256::EncodedPoint::identity()), ) - .unwrap_or_else(|_| k256::AffinePoint::GENERATOR); + .unwrap_or(k256::AffinePoint::GENERATOR); let pp2 = k256::ProjectivePoint::from(ap2); let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) .unwrap_or(k256::Scalar::random(&mut rng)); - test_group( - pp1 + pp2, - (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), - scalar, - ); + test_group(pp1 + pp2, pp1 + ap1 + ap2 + ap3 + ap4 + ap5, scalar); // // Test p192 @@ -119,27 +104,23 @@ fuzz_target!(|data: &[u8]| { let ap2 = p192::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) .unwrap_or_else(|| p192::AffinePoint::GENERATOR); let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) - .unwrap_or_else(|_| p192::AffinePoint::GENERATOR); + .unwrap_or(p192::AffinePoint::GENERATOR); let ap4 = p192::AffinePoint::try_from(p192::EncodedPoint::from_affine_coordinates( &data[24..24 + len - 1].try_into().unwrap(), &data[40..40 + len - 1].try_into().unwrap(), true, )) - .unwrap_or_else(|_| p192::AffinePoint::GENERATOR); + .unwrap_or(p192::AffinePoint::GENERATOR); let ap5 = p192::AffinePoint::try_from( p192::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) .unwrap_or_else(|_| p192::EncodedPoint::identity()), ) - .unwrap_or_else(|_| p192::AffinePoint::GENERATOR); + .unwrap_or(p192::AffinePoint::GENERATOR); let pp2 = p192::ProjectivePoint::from(ap2); let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) .unwrap_or(p192::Scalar::random(&mut rng)); - test_group( - pp1 + pp2, - (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), - scalar, - ); + test_group(pp1 + pp2, pp1 + ap1 + ap2 + ap3 + ap4 + ap5, scalar); // // Test p224 @@ -151,27 +132,23 @@ fuzz_target!(|data: &[u8]| { let ap2 = p224::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) .unwrap_or_else(|| p224::AffinePoint::GENERATOR); let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) - .unwrap_or_else(|_| p224::AffinePoint::GENERATOR); + .unwrap_or(p224::AffinePoint::GENERATOR); let ap4 = p224::AffinePoint::try_from(p224::EncodedPoint::from_affine_coordinates( &data[24..24 + len - 1].try_into().unwrap(), &data[40..40 + len - 1].try_into().unwrap(), true, )) - .unwrap_or_else(|_| p224::AffinePoint::GENERATOR); + .unwrap_or(p224::AffinePoint::GENERATOR); let ap5 = p224::AffinePoint::try_from( p224::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) .unwrap_or_else(|_| p224::EncodedPoint::identity()), ) - .unwrap_or_else(|_| p224::AffinePoint::GENERATOR); + .unwrap_or(p224::AffinePoint::GENERATOR); let pp2 = p224::ProjectivePoint::from(ap2); let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) .unwrap_or(p224::Scalar::random(&mut rng)); - test_group( - pp1 + pp2, - (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), - scalar, - ); + test_group(pp1 + pp2, pp1 + ap1 + ap2 + ap3 + ap4 + ap5, scalar); // // Test p256 @@ -182,27 +159,23 @@ fuzz_target!(|data: &[u8]| { let ap2 = p256::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) .unwrap_or_else(|| p256::AffinePoint::GENERATOR); let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) - .unwrap_or_else(|_| p256::AffinePoint::GENERATOR); + .unwrap_or(p256::AffinePoint::GENERATOR); let ap4 = p256::AffinePoint::try_from(p256::EncodedPoint::from_affine_coordinates( &data[24..24 + len - 1].try_into().unwrap(), &data[40..40 + len - 1].try_into().unwrap(), true, )) - .unwrap_or_else(|_| p256::AffinePoint::GENERATOR); + .unwrap_or(p256::AffinePoint::GENERATOR); let ap5 = p256::AffinePoint::try_from( p256::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) .unwrap_or_else(|_| p256::EncodedPoint::identity()), ) - .unwrap_or_else(|_| p256::AffinePoint::GENERATOR); + .unwrap_or(p256::AffinePoint::GENERATOR); let pp2 = p256::ProjectivePoint::from(ap2); let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) .unwrap_or(p256::Scalar::random(&mut rng)); - test_group( - pp1 + pp2, - (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), - scalar, - ); + test_group(pp1 + pp2, pp1 + ap1 + ap2 + ap3 + ap4 + ap5, scalar); // Test p384 let len = p384::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective @@ -212,27 +185,23 @@ fuzz_target!(|data: &[u8]| { let ap2 = p384::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) .unwrap_or_else(|| p384::AffinePoint::GENERATOR); let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) - .unwrap_or_else(|_| p384::AffinePoint::GENERATOR); + .unwrap_or(p384::AffinePoint::GENERATOR); let ap4 = p384::AffinePoint::try_from(p384::EncodedPoint::from_affine_coordinates( &data[24..24 + len - 1].try_into().unwrap(), &data[40..40 + len - 1].try_into().unwrap(), true, )) - .unwrap_or_else(|_| p384::AffinePoint::GENERATOR); + .unwrap_or(p384::AffinePoint::GENERATOR); let ap5 = p384::AffinePoint::try_from( p384::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) .unwrap_or_else(|_| p384::EncodedPoint::identity()), ) - .unwrap_or_else(|_| p384::AffinePoint::GENERATOR); + .unwrap_or(p384::AffinePoint::GENERATOR); let pp2 = p384::ProjectivePoint::from(ap2); let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) .unwrap_or(p384::Scalar::random(&mut rng)); - test_group( - pp1 + pp2, - (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), - scalar, - ); + test_group(pp1 + pp2, pp1 + ap1 + ap2 + ap3 + ap4 + ap5, scalar); // Test p521 let len = p521::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective @@ -242,27 +211,23 @@ fuzz_target!(|data: &[u8]| { let ap2 = p521::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) .unwrap_or_else(|| p521::AffinePoint::GENERATOR); let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) - .unwrap_or_else(|_| p521::AffinePoint::GENERATOR); + .unwrap_or(p521::AffinePoint::GENERATOR); let ap4 = p521::AffinePoint::try_from(p521::EncodedPoint::from_affine_coordinates( &data[24..24 + len - 1].try_into().unwrap(), &data[40..40 + len - 1].try_into().unwrap(), true, )) - .unwrap_or_else(|_| p521::AffinePoint::GENERATOR); + .unwrap_or(p521::AffinePoint::GENERATOR); let ap5 = p521::AffinePoint::try_from( p521::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) .unwrap_or_else(|_| p521::EncodedPoint::identity()), ) - .unwrap_or_else(|_| p521::AffinePoint::GENERATOR); + .unwrap_or(p521::AffinePoint::GENERATOR); let pp2 = p521::ProjectivePoint::from(ap2); let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) .unwrap_or(p521::Scalar::random(&mut rng)); - test_group( - pp1 + pp2, - (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), - scalar, - ); + test_group(pp1 + pp2, pp1 + ap1 + ap2 + ap3 + ap4 + ap5, scalar); // Test sm2 let len = sm2::ProjectivePoint::random(&mut rng).to_bytes().len(); //affine and projective @@ -272,25 +237,21 @@ fuzz_target!(|data: &[u8]| { let ap2 = sm2::AffinePoint::from_bytes(&data[32..32 + len].try_into().unwrap()) .unwrap_or_else(|| sm2::AffinePoint::GENERATOR); let ap3 = de::from_reader(&data[48..48 + usize::from(data[3] & 0x3f)]) - .unwrap_or_else(|_| sm2::AffinePoint::GENERATOR); + .unwrap_or(sm2::AffinePoint::GENERATOR); let ap4 = sm2::AffinePoint::try_from(sm2::EncodedPoint::from_affine_coordinates( &data[24..24 + len - 1].try_into().unwrap(), &data[40..40 + len - 1].try_into().unwrap(), true, )) - .unwrap_or_else(|_| sm2::AffinePoint::GENERATOR); + .unwrap_or(sm2::AffinePoint::GENERATOR); let ap5 = sm2::AffinePoint::try_from( sm2::EncodedPoint::from_bytes(&data[64..64 + usize::from(data[4] & 0x3f)]) .unwrap_or_else(|_| sm2::EncodedPoint::identity()), ) - .unwrap_or_else(|_| sm2::AffinePoint::GENERATOR); + .unwrap_or(sm2::AffinePoint::GENERATOR); let pp2 = sm2::ProjectivePoint::from(ap2); let scalar = de::from_reader(&data[96..96 + usize::from(data[5] & 0x3f)]) .unwrap_or(sm2::Scalar::random(&mut rng)); - test_group( - pp1 + pp2, - (pp1 + ap1 + ap2 + ap3 + ap4 + ap5).into(), - scalar, - ); + test_group(pp1 + pp2, pp1 + ap1 + ap2 + ap3 + ap4 + ap5, scalar); }); diff --git a/fuzz/fuzz_targets/scalars.rs b/fuzz/fuzz_targets/scalars.rs index 7f8babb93..7feb77703 100755 --- a/fuzz/fuzz_targets/scalars.rs +++ b/fuzz/fuzz_targets/scalars.rs @@ -1,20 +1,14 @@ #![no_main] -use bign256; +// Targets: bign256, k256, p192, p224, p256, p384, p521, sm2 // bp256 and bp384 are under construction use ciborium::de; use elliptic_curve::{Field, PrimeField}; -use k256; use libfuzzer_sys::fuzz_target; -use p192; -use p224; -use p256; -use p384; -use p521; use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; -use sm2; static mut I: u64 = 0; +#[allow(clippy::eq_op)] fn test_field(fe1: F, fe2: F, fe3: F) { unsafe { I = I.wrapping_add(1); @@ -53,10 +47,7 @@ fn test_field(fe1: F, fe2: F, fe3: F) { assert!(bool::from(F::sqrt_ratio(&fe1_cube, &fe1).0)); } } - assert_eq!( - bool::from(fe1_sq.is_zero()), - bool::from(fe1_sq.is_zero_vartime()) - ); + assert_eq!(bool::from(fe1_sq.is_zero()), fe1_sq.is_zero_vartime()); // Double, even, odd let fe1_double: F = fe1.double(); @@ -69,8 +60,8 @@ fn test_field(fe1: F, fe2: F, fe3: F) { let limb0 = u64::from_le_bytes(fe3.to_repr().as_ref()[0..8].try_into().unwrap()); let limb1 = u64::from_le_bytes(fe3.to_repr().as_ref()[8..16].try_into().unwrap()); let limb2 = u64::from_le_bytes(fe3.to_repr().as_ref()[16..24].try_into().unwrap()); - let xx = fe1.pow(&[limb0, limb1, limb2, limb1.wrapping_add(limb2)]); - let yy = fe1.pow_vartime(&[limb0, limb1, limb2, limb1.wrapping_add(limb2)]); + let xx = fe1.pow([limb0, limb1, limb2, limb1.wrapping_add(limb2)]); + let yy = fe1.pow_vartime([limb0, limb1, limb2, limb1.wrapping_add(limb2)]); assert_eq!(xx, yy); } @@ -107,7 +98,7 @@ fuzz_target!(|data: &[u8]| { let fe4 = opt_fe4.unwrap_or(bign256::Scalar::random(&mut rng)); let repr5 = &data[96..(96 + usize::from(data[2] & 0x7f))]; - let str5 = std::str::from_utf8(&repr5).unwrap_or("123"); + let str5 = std::str::from_utf8(repr5).unwrap_or("123"); let fe5 = bign256::Scalar::from_str_vartime(str5).unwrap_or(bign256::Scalar::random(&mut rng)); let uint6 = bign256::elliptic_curve::bigint::U256::from_le_slice(&data[128..160]); @@ -145,7 +136,7 @@ fuzz_target!(|data: &[u8]| { // k256::Scalar::from_slice() not supported/implemented let repr4 = &data[96..(96 + usize::from(data[1] & 0x7f))]; - let str4 = std::str::from_utf8(&repr4).unwrap_or("123"); + let str4 = std::str::from_utf8(repr4).unwrap_or("123"); let fe4 = k256::Scalar::from_str_vartime(str4).unwrap_or(k256::Scalar::random(&mut rng)); // k256::Scalar::from_uint() not supported/implemented @@ -186,7 +177,7 @@ fuzz_target!(|data: &[u8]| { let fe5 = opt_fe5.unwrap_or(p192::Scalar::random(&mut rng)); let repr6 = &data[96..(96 + usize::from(data[2] & 0x7f))]; - let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let str6 = std::str::from_utf8(repr6).unwrap_or("123"); let fe6 = p192::Scalar::from_str_vartime(str6).unwrap_or(p192::Scalar::random(&mut rng)); let uint7 = p192::elliptic_curve::bigint::U192::from_le_slice(&data[128..152]); @@ -228,7 +219,7 @@ fuzz_target!(|data: &[u8]| { let fe5 = opt_fe5.unwrap_or(p224::Scalar::random(&mut rng)); let repr6 = &data[96..(96 + usize::from(data[2] & 0x7f))]; - let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let str6 = std::str::from_utf8(repr6).unwrap_or("123"); let fe6 = p224::Scalar::from_str_vartime(str6).unwrap_or(p224::Scalar::random(&mut rng)); let uint7 = p224::elliptic_curve::bigint::U256::from_le_slice(&data[128..160]); // note U256 vs U224 @@ -266,7 +257,7 @@ fuzz_target!(|data: &[u8]| { // p256::Scalar::from_slice() not supported/implemented let repr6 = &data[96..(96 + usize::from(data[1] & 0x7f))]; - let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let str6 = std::str::from_utf8(repr6).unwrap_or("123"); let fe6 = p256::Scalar::from_str_vartime(str6).unwrap_or(p256::Scalar::random(&mut rng)); // p256::Scalar::from_uint() not supported/implemented @@ -307,7 +298,7 @@ fuzz_target!(|data: &[u8]| { let fe5 = opt_fe5.unwrap_or(p384::Scalar::random(&mut rng)); let repr6 = &data[96..(96 + usize::from(data[2] & 0x7f))]; - let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let str6 = std::str::from_utf8(repr6).unwrap_or("123"); let fe6 = p384::Scalar::from_str_vartime(str6).unwrap_or(p384::Scalar::random(&mut rng)); let uint7 = p384::elliptic_curve::bigint::U384::from_le_slice(&data[128..176]); @@ -349,7 +340,7 @@ fuzz_target!(|data: &[u8]| { let fe5 = opt_fe5.unwrap_or(p521::Scalar::random(&mut rng)); let repr6 = &data[96..(96 + usize::from(data[2] & 0x7f))]; - let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let str6 = std::str::from_utf8(repr6).unwrap_or("123"); let fe6 = p521::Scalar::from_str_vartime(str6).unwrap_or(p521::Scalar::random(&mut rng)); let uint7 = p521::elliptic_curve::bigint::U576::from_le_slice(&data[128..200]); @@ -391,7 +382,7 @@ fuzz_target!(|data: &[u8]| { let fe5 = opt_fe5.unwrap_or(sm2::Scalar::random(&mut rng)); let repr6 = &data[96..(96 + usize::from(data[1] & 0x7f))]; - let str6 = std::str::from_utf8(&repr6).unwrap_or("123"); + let str6 = std::str::from_utf8(repr6).unwrap_or("123"); let fe6 = sm2::Scalar::from_str_vartime(str6).unwrap_or(sm2::Scalar::random(&mut rng)); let uint7 = sm2::elliptic_curve::bigint::U256::from_le_slice(&data[128..160]);