diff --git a/Cargo.toml b/Cargo.toml index 126bda12..45338d04 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 00000000..3c89704c --- /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 = { version = "0.13.0", features = ["sec1"] } +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/README.md b/fuzz/README.md new file mode 100644 index 00000000..82371f16 --- /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 + + +#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 +~~~ + + +## 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 00000000..039ad6c0 --- /dev/null +++ b/fuzz/fuzz_targets/points.rs @@ -0,0 +1,257 @@ +#![no_main] +// 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 libfuzzer_sys::fuzz_target; +use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; + +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(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(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(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, 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(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(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(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, 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(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(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(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, 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(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(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(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, 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(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(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(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, 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(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(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(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, 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(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(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(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, 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(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(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(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, scalar); +}); diff --git a/fuzz/fuzz_targets/scalars.rs b/fuzz/fuzz_targets/scalars.rs new file mode 100755 index 00000000..7feb7770 --- /dev/null +++ b/fuzz/fuzz_targets/scalars.rs @@ -0,0 +1,400 @@ +#![no_main] +// Targets: bign256, k256, p192, p224, p256, p384, p521, sm2 +// bp256 and bp384 are under construction +use ciborium::de; +use elliptic_curve::{Field, PrimeField}; +use libfuzzer_sys::fuzz_target; +use rand_chacha::{rand_core::SeedableRng, ChaChaRng}; + +static mut I: u64 = 0; + +#[allow(clippy::eq_op)] +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); + + // 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 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)); + } + } + assert_eq!(bool::from(fe1_sq.is_zero()), 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)) + .shr_vartime(99); + + // 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..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()); + 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)) + .shr_vartime(99); + + 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()); + 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)) + .shr_vartime(99); + + 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()); + 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..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()); + 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)) + .shr_vartime(99); + + 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()); + 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)) + .shr_vartime(99); + + 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()); + 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)) + .shr_vartime(99); + + 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()); + 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); +});