improve test coverage (#50)

This commit is contained in:
zz-sol 2026-06-17 08:25:25 -04:00 committed by GitHub
parent 7cca75ad6e
commit 06cc7111db
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
4 changed files with 172 additions and 4 deletions

View file

@ -304,6 +304,28 @@ mod test {
assert_eq!(result, expected); assert_eq!(result, expected);
} }
#[test]
fn test_checked_wrapper_accepts_full_width_scalars() {
let mut a1_bytes = [0u8; 32];
a1_bytes[0] = 7;
a1_bytes[16] = 1;
let a1 = Scalar::from_canonical_bytes(a1_bytes).unwrap();
let mut a2_bytes = [0u8; 32];
a2_bytes[0] = 11;
a2_bytes[24] = 1;
let a2 = Scalar::from_canonical_bytes(a2_bytes).unwrap();
let b = random_scalar();
let A1 = constants::ED25519_BASEPOINT_POINT * Scalar::from(23u64);
let A2 = constants::ED25519_BASEPOINT_POINT * Scalar::from(29u64);
let result = crate::backend::vartime_triple_base_mul_128_128_256(&a1, &A1, &a2, &A2, &b);
let expected = (a1 * A1 + a2 * A2) + b * constants::ED25519_BASEPOINT_POINT;
assert_eq!(result, expected);
}
// Proptest for vartime_triple_scalar_mul_basepoint equivalence // Proptest for vartime_triple_scalar_mul_basepoint equivalence
proptest::proptest! { proptest::proptest! {
#[test] #[test]

View file

@ -187,3 +187,50 @@ pub mod spec {
Q.into() Q.into()
} }
} }
#[cfg(all(test, target_arch = "x86_64"))]
mod test {
use super::spec_avx2;
use crate::backend::serial;
use crate::constants;
use crate::scalar::Scalar;
fn scalar_from_low_128(low: [u8; 16]) -> Scalar {
let mut bytes = [0u8; 32];
bytes[..16].copy_from_slice(&low);
Scalar::from_canonical_bytes(bytes).unwrap()
}
#[test]
fn avx2_triple_base_matches_serial_and_naive() {
if !std::is_x86_feature_detected!("avx2") {
return;
}
let a1 = scalar_from_low_128([
0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33, 0x22,
0x11, 0x00,
]);
let a2 = scalar_from_low_128([
0x10, 0x32, 0x54, 0x76, 0x98, 0xba, 0xdc, 0xfe, 0x0f, 0x1e, 0x2d, 0x3c, 0x4b, 0x5a,
0x69, 0x78,
]);
let b = Scalar::from_bytes_mod_order([
0x42, 0x91, 0x0a, 0xbe, 0xef, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99,
0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
0x10, 0x20, 0x30, 0x40,
]);
let A1 = constants::ED25519_BASEPOINT_POINT * Scalar::from(31u64);
let A2 = constants::ED25519_BASEPOINT_POINT * Scalar::from(37u64);
let avx2 = spec_avx2::mul_128_128_256_prechecked(&a1, &A1, &a2, &A2, &b);
let serial = serial::scalar_mul::vartime_triple_base::mul_128_128_256_prechecked(
&a1, &A1, &a2, &A2, &b,
);
let expected = (a1 * A1 + a2 * A2) + b * constants::ED25519_BASEPOINT_POINT;
assert_eq!(avx2, serial);
assert_eq!(avx2, expected);
}
}

View file

@ -1,11 +1,11 @@
use crate::ed_sigs::SigningKey; use crate::constants;
use crate::ed_sigs::VerificationKey;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use crate::ed_sigs::tests::small_order::SMALL_ORDER_SIGS; use crate::ed_sigs::tests::small_order::SMALL_ORDER_SIGS;
use crate::ed_sigs::{Error, Signature, SigningKey, VerificationKey};
use crate::edwards::CompressedEdwardsY;
use crate::scalar::Scalar;
#[cfg(feature = "std")] #[cfg(feature = "std")]
use core::convert::TryFrom; use core::convert::TryFrom;
#[cfg(feature = "std")]
use ed25519::Signature;
#[test] #[test]
fn test_verify_zebra_invalid_signature() { fn test_verify_zebra_invalid_signature() {
@ -82,6 +82,67 @@ fn test_default_verification_matches_zebra() {
); );
} }
#[test]
fn test_signature_verifier_trait_impl() {
let signing_key = SigningKey::from([3u8; 32]);
let verification_key = VerificationKey::from(&signing_key);
let msg = b"signature::Verifier trait path";
let signature = signing_key.sign(msg);
assert!(
ed25519::signature::Verifier::verify(&verification_key, msg, &signature).is_ok(),
"trait-based verification should accept a valid signature"
);
assert!(
ed25519::signature::Verifier::verify(&verification_key, b"wrong message", &signature)
.is_err(),
"trait-based verification should reject an invalid signature"
);
}
#[test]
fn test_verify_zebra_prehashed_rejects_noncanonical_s() {
let signing_key = SigningKey::from([4u8; 32]);
let verification_key = VerificationKey::from(&signing_key);
let mut sig_bytes: [u8; 64] = signing_key.sign(b"noncanonical s").into();
sig_bytes[32..].copy_from_slice(&constants::BASEPOINT_ORDER.to_bytes());
let signature = Signature::from(sig_bytes);
assert_eq!(
verification_key.verify_zebra_prehashed(&signature, Scalar::from(1u64)),
Err(Error::InvalidSignature)
);
}
#[test]
fn test_verify_zebra_prehashed_rejects_undecodable_r() {
let signing_key = SigningKey::from([5u8; 32]);
let verification_key = VerificationKey::from(&signing_key);
let mut sig_bytes: [u8; 64] = signing_key.sign(b"undecodable r").into();
let invalid_r = first_undecodable_r();
assert!(CompressedEdwardsY(invalid_r).decompress().is_none());
sig_bytes[..32].copy_from_slice(&invalid_r);
let signature = Signature::from(sig_bytes);
assert_eq!(
verification_key.verify_zebra_prehashed(&signature, Scalar::from(1u64)),
Err(Error::InvalidSignature)
);
}
fn first_undecodable_r() -> [u8; 32] {
for candidate in 0u16..=u16::MAX {
let mut bytes = [0u8; 32];
bytes[..2].copy_from_slice(&candidate.to_le_bytes());
if CompressedEdwardsY(bytes).decompress().is_none() {
return bytes;
}
}
panic!("failed to find an undecodable compressed Edwards-Y encoding");
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
#[test] #[test]
fn test_verify_dalek_matches_legacy_edge_cases() { fn test_verify_dalek_matches_legacy_edge_cases() {

View file

@ -241,6 +241,7 @@ mod tests {
use crate::edwards::EdwardsPoint; use crate::edwards::EdwardsPoint;
use crate::field::FieldElement; use crate::field::FieldElement;
use crate::scalar::Scalar; use crate::scalar::Scalar;
use crate::traits::Identity;
use rand::Rng; use rand::Rng;
fn sw_scalar_mul(point: &SwPoint, scalar: &Scalar) -> SwPoint { fn sw_scalar_mul(point: &SwPoint, scalar: &Scalar) -> SwPoint {
@ -413,4 +414,41 @@ mod tests {
Some(SwPoint::Identity) Some(SwPoint::Identity)
); );
} }
#[test]
fn sw_affine_bytes_round_trip_valid_points() {
let mut rng = rand::thread_rng();
for _ in 0..32 {
let scalar = random_scalar(&mut rng);
let point = constants::ED25519_BASEPOINT_POINT * scalar;
let sw = SwPoint::from_edwards(&point);
let encoded = sw.to_affine_le_bytes();
assert_eq!(
SwPoint::from_affine_le_bytes(encoded.0, encoded.1),
Some(sw)
);
}
}
#[test]
fn sw_affine_bytes_reject_off_curve_input() {
let x = FieldElement::ZERO.to_bytes();
let y = FieldElement::ONE.to_bytes();
assert!(SwPoint::from_affine_le_bytes(x, y).is_none());
}
#[test]
fn sw_identity_is_additive_neutral_element() {
let base = SwPoint::from_edwards(&constants::ED25519_BASEPOINT_POINT);
assert_eq!(SwPoint::identity().add(&base), base);
assert_eq!(base.add(&SwPoint::identity()), base);
assert_eq!(
SwPoint::identity().to_edwards(),
Some(EdwardsPoint::identity())
);
}
} }