use super::*;
use crate::ec::p192::{FieldElement, Point, PointFormat, Scalar};
use dcrypt_params::traditional::ecdsa::NIST_P192;
use rand::{RngCore, SeedableRng};
use rand_chacha::ChaCha20Rng;
mod field_tests {
use super::*;
#[test]
fn test_field_zero_one() {
let zero = FieldElement::zero();
let one = FieldElement::one();
assert!(zero.is_zero());
assert!(!one.is_zero());
let sum = zero.add(&one);
assert_eq!(sum, one);
let diff = one.sub(&one);
assert_eq!(diff, zero);
}
#[test]
fn test_field_addition_commutativity() {
let a_bytes = [
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00,
];
let b_bytes = [
0xFE, 0xDC, 0xBA, 0x98, 0x76, 0x54, 0x32, 0x10, 0x88, 0x77, 0x66, 0x55, 0x44, 0x33,
0x22, 0x11, 0x00, 0xFF, 0xEE, 0xDD, 0xCC, 0xBB, 0xAA, 0x99,
];
let a = FieldElement::from_bytes(&a_bytes).unwrap();
let b = FieldElement::from_bytes(&b_bytes).unwrap();
let sum_ab = a.add(&b);
let sum_ba = b.add(&a);
assert_eq!(sum_ab, sum_ba);
}
#[test]
fn test_field_multiplication() {
let one = FieldElement::one();
let two_bytes = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02,
];
let two = FieldElement::from_bytes(&two_bytes).unwrap();
let product = one.mul(&two);
assert_eq!(product, two);
let four = two.mul(&two);
let four_bytes = [
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04,
];
let expected_four = FieldElement::from_bytes(&four_bytes).unwrap();
assert_eq!(four, expected_four);
}
#[test]
fn test_field_squaring() {
let x_bytes = [
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00,
];
let x = FieldElement::from_bytes(&x_bytes).unwrap();
let square1 = x.square();
let square2 = x.mul(&x);
assert_eq!(square1, square2);
}
#[test]
fn test_field_inversion() {
let x_bytes = [
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00,
];
let x = FieldElement::from_bytes(&x_bytes).unwrap();
let x_inv = x.invert().unwrap();
let product = x.mul(&x_inv);
let one = FieldElement::one();
assert_eq!(product, one);
}
#[test]
fn test_field_inversion_zero_fails() {
let zero = FieldElement::zero();
assert!(zero.invert().is_err());
}
#[test]
fn test_field_serialization() {
let original_bytes = [
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00,
];
let fe = FieldElement::from_bytes(&original_bytes).unwrap();
let serialized = fe.to_bytes();
assert_eq!(serialized, original_bytes);
}
#[test]
fn test_field_modulus_rejection() {
let p_bytes = [
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
];
assert!(FieldElement::from_bytes(&p_bytes).is_err());
let p_minus_1_bytes = [
0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
0xFF, 0xFE, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFE,
];
assert!(FieldElement::from_bytes(&p_minus_1_bytes).is_ok());
}
}
mod point_tests {
use super::*;
#[test]
fn test_base_point() {
let g = base_point_g();
assert!(!g.is_identity());
let x_bytes = g.x_coordinate_bytes();
let y_bytes = g.y_coordinate_bytes();
let recreated = Point::new_uncompressed(&x_bytes, &y_bytes).unwrap();
assert_eq!(g, recreated);
}
#[test]
fn test_point_identity() {
let identity = Point::identity();
assert!(identity.is_identity());
let g = base_point_g();
let sum = g.add(&identity);
assert_eq!(sum, g);
let sum2 = identity.add(&g);
assert_eq!(sum2, g);
}
#[test]
fn test_point_doubling() {
let g = base_point_g();
let double1 = g.double();
let double2 = g.add(&g);
assert_eq!(double1, double2);
}
#[test]
fn test_point_addition_commutativity() {
let g = base_point_g();
let g2 = g.double();
let sum1 = g.add(&g2);
let sum2 = g2.add(&g);
assert_eq!(sum1, sum2);
}
#[test]
fn test_point_uncompressed_serialization() {
let g = base_point_g();
let serialized = g.serialize_uncompressed();
let deserialized = Point::deserialize_uncompressed(&serialized).unwrap();
assert_eq!(g, deserialized);
let format = Point::detect_format(&serialized).unwrap();
assert_eq!(format, PointFormat::Uncompressed);
}
#[test]
fn test_point_compressed_serialization() {
let g = base_point_g();
let compressed = g.serialize_compressed();
let decompressed = Point::deserialize_compressed(&compressed).unwrap();
assert_eq!(g, decompressed);
let format = Point::detect_format(&compressed).unwrap();
assert_eq!(format, PointFormat::Compressed);
}
#[test]
fn test_point_identity_serialization() {
let identity = Point::identity();
let uncompressed = identity.serialize_uncompressed();
assert!(uncompressed.iter().all(|&b| b == 0));
let deserialized = Point::deserialize_uncompressed(&uncompressed).unwrap();
assert_eq!(identity, deserialized);
let compressed = identity.serialize_compressed();
assert!(compressed.iter().all(|&b| b == 0));
let deserialized = Point::deserialize_compressed(&compressed).unwrap();
assert_eq!(identity, deserialized);
}
#[test]
fn test_point_scalar_multiplication() {
let g = base_point_g();
let mut scalar_bytes = [0u8; P192_SCALAR_SIZE];
scalar_bytes[P192_SCALAR_SIZE - 1] = 3; let scalar = Scalar::new(scalar_bytes).unwrap();
let result1 = g.mul(&scalar).unwrap();
let result2 = g.add(&g).add(&g);
assert_eq!(result1, result2);
}
#[test]
fn test_point_invalid_coordinates() {
let invalid_x = [0x12; P192_FIELD_ELEMENT_SIZE];
let invalid_y = [0x34; P192_FIELD_ELEMENT_SIZE];
assert!(Point::new_uncompressed(&invalid_x, &invalid_y).is_err());
}
#[test]
fn test_compressed_point_invalid_prefix() {
let mut invalid_compressed = [0u8; P192_POINT_COMPRESSED_SIZE];
invalid_compressed[0] = 0x05;
assert!(Point::deserialize_compressed(&invalid_compressed).is_err());
}
}
mod scalar_tests {
use super::*;
#[test]
fn test_scalar_creation() {
let scalar_bytes = [
0x12, 0x34, 0x56, 0x78, 0x9A, 0xBC, 0xDE, 0xF0, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66,
0x77, 0x88, 0x99, 0xAA, 0xBB, 0xCC, 0xDD, 0xEE, 0xFF, 0x00,
];
let scalar = Scalar::new(scalar_bytes).unwrap();
assert!(!scalar.is_zero());
let serialized = scalar.serialize();
let deserialized = Scalar::deserialize(&serialized).unwrap();
assert_eq!(scalar.serialize(), deserialized.serialize());
}
#[test]
fn test_scalar_zero_rejection() {
let zero_bytes = [0u8; P192_SCALAR_SIZE];
assert!(Scalar::new(zero_bytes).is_err());
}
#[test]
fn test_scalar_modular_arithmetic() {
let mut a_bytes = [0u8; P192_SCALAR_SIZE];
a_bytes[P192_SCALAR_SIZE - 1] = 5; let a = Scalar::new(a_bytes).unwrap();
let mut b_bytes = [0u8; P192_SCALAR_SIZE];
b_bytes[P192_SCALAR_SIZE - 1] = 3; let b = Scalar::new(b_bytes).unwrap();
let sum = a.add_mod_n(&b).unwrap();
let mut expected_bytes = [0u8; P192_SCALAR_SIZE];
expected_bytes[P192_SCALAR_SIZE - 1] = 8;
let expected = Scalar::new(expected_bytes).unwrap();
assert_eq!(sum.serialize(), expected.serialize());
let diff = a.sub_mod_n(&b).unwrap();
let mut expected_bytes = [0u8; P192_SCALAR_SIZE];
expected_bytes[P192_SCALAR_SIZE - 1] = 2;
let expected = Scalar::new(expected_bytes).unwrap();
assert_eq!(diff.serialize(), expected.serialize());
let product = a.mul_mod_n(&b).unwrap();
let mut expected_bytes = [0u8; P192_SCALAR_SIZE];
expected_bytes[P192_SCALAR_SIZE - 1] = 15;
let expected = Scalar::new(expected_bytes).unwrap();
assert_eq!(product.serialize(), expected.serialize());
}
#[test]
fn test_scalar_inversion() {
let mut scalar_bytes = [0u8; P192_SCALAR_SIZE];
scalar_bytes[P192_SCALAR_SIZE - 1] = 7; let scalar = Scalar::new(scalar_bytes).unwrap();
let inverse = scalar.inv_mod_n().unwrap();
let product = scalar.mul_mod_n(&inverse).unwrap();
let mut one_bytes = [0u8; P192_SCALAR_SIZE];
one_bytes[P192_SCALAR_SIZE - 1] = 1;
let one = Scalar::new(one_bytes).unwrap();
assert_eq!(product.serialize(), one.serialize());
}
#[test]
fn test_scalar_negation() {
let mut scalar_bytes = [0u8; P192_SCALAR_SIZE];
scalar_bytes[P192_SCALAR_SIZE - 1] = 5; let scalar = Scalar::new(scalar_bytes).unwrap();
let negated = scalar.negate();
let _sum = scalar.add_mod_n(&negated).unwrap();
let double_negated = negated.negate();
assert_eq!(scalar.serialize(), double_negated.serialize());
}
#[test]
fn test_scalar_order_reduction() {
let large_bytes = [0xFF; P192_SCALAR_SIZE];
assert!(Scalar::new(large_bytes).is_ok());
}
}
mod integration_tests {
use super::*;
#[test]
fn test_keypair_generation() {
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
let (private_key, public_key) = generate_keypair(&mut rng).unwrap();
assert!(!public_key.is_identity());
let computed_public = scalar_mult_base_g(&private_key).unwrap();
assert_eq!(public_key, computed_public);
}
#[test]
fn test_scalar_base_multiplication() {
let mut scalar_bytes = [0u8; P192_SCALAR_SIZE];
scalar_bytes[P192_SCALAR_SIZE - 1] = 2; let scalar = Scalar::new(scalar_bytes).unwrap();
let result = scalar_mult_base_g(&scalar).unwrap();
let expected = base_point_g().double();
assert_eq!(result, expected);
}
#[test]
fn test_scalar_point_multiplication() {
let g = base_point_g();
let mut scalar_bytes = [0u8; P192_SCALAR_SIZE];
scalar_bytes[P192_SCALAR_SIZE - 1] = 3; let scalar = Scalar::new(scalar_bytes).unwrap();
let result = scalar_mult(&scalar, &g).unwrap();
let expected = g.add(&g).add(&g);
assert_eq!(result, expected);
}
#[test]
fn test_scalar_multiplication_with_identity() {
let identity = Point::identity();
let mut scalar_bytes = [0u8; P192_SCALAR_SIZE];
scalar_bytes[P192_SCALAR_SIZE - 1] = 5; let scalar = Scalar::new(scalar_bytes).unwrap();
let result = scalar_mult(&scalar, &identity).unwrap();
assert_eq!(result, identity);
}
#[test]
fn test_kdf_functionality() {
let input_material = b"test input material";
let info = Some(b"test context info".as_slice());
let derived_key = kdf_hkdf_sha256_for_ecdh_kem(input_material, info).unwrap();
assert_eq!(derived_key.len(), P192_KEM_SHARED_SECRET_KDF_OUTPUT_SIZE);
let different_input = b"different input material";
let different_key = kdf_hkdf_sha256_for_ecdh_kem(different_input, info).unwrap();
assert_ne!(derived_key, different_key);
}
#[test]
fn test_ecdh_compatibility() {
let mut rng = ChaCha20Rng::from_seed([1u8; 32]);
let (alice_private, alice_public) = generate_keypair(&mut rng).unwrap();
let (bob_private, bob_public) = generate_keypair(&mut rng).unwrap();
let alice_shared_point = scalar_mult(&alice_private, &bob_public).unwrap();
let bob_shared_point = scalar_mult(&bob_private, &alice_public).unwrap();
assert_eq!(alice_shared_point, bob_shared_point);
let shared_x = alice_shared_point.x_coordinate_bytes();
let alice_key = kdf_hkdf_sha256_for_ecdh_kem(&shared_x, None).unwrap();
let bob_key = kdf_hkdf_sha256_for_ecdh_kem(&shared_x, None).unwrap();
assert_eq!(alice_key, bob_key);
}
}
mod test_vectors {
use super::*;
#[test]
fn test_nist_p192_parameters() {
let g = base_point_g();
let g_x = g.x_coordinate_bytes();
let g_y = g.y_coordinate_bytes();
assert_eq!(g_x, NIST_P192.g_x);
assert_eq!(g_y, NIST_P192.g_y);
assert!(!g.is_identity());
}
#[test]
fn test_known_scalar_multiplication() {
let mut rng = ChaCha20Rng::from_seed([42u8; 32]);
let mut scalar_bytes = [0u8; P192_SCALAR_SIZE];
rng.fill_bytes(&mut scalar_bytes);
let scalar = Scalar::new(scalar_bytes).unwrap();
let result1 = scalar_mult_base_g(&scalar).unwrap();
let result2 = scalar_mult_base_g(&scalar).unwrap();
assert_eq!(result1, result2);
}
#[test]
fn test_point_order() {
let g = base_point_g();
let g2 = g.double();
assert_ne!(g2, g);
assert!(!g2.is_identity());
let mut current = g.clone();
let mut seen_identity = false;
for _ in 0..10 {
current = current.double();
if current.is_identity() {
seen_identity = true;
break;
}
}
assert!(!seen_identity);
}
}
mod property_tests {
use super::*;
#[test]
fn test_field_element_properties() {
let mut rng = ChaCha20Rng::from_seed([0u8; 32]);
for _ in 0..20 {
let mut a_bytes = [0u8; P192_FIELD_ELEMENT_SIZE];
let mut b_bytes = [0u8; P192_FIELD_ELEMENT_SIZE];
let mut c_bytes = [0u8; P192_FIELD_ELEMENT_SIZE];
rng.fill_bytes(&mut a_bytes);
rng.fill_bytes(&mut b_bytes);
rng.fill_bytes(&mut c_bytes);
if let (Ok(a), Ok(b), Ok(c)) = (
FieldElement::from_bytes(&a_bytes),
FieldElement::from_bytes(&b_bytes),
FieldElement::from_bytes(&c_bytes),
) {
let left = a.add(&b).add(&c);
let right = a.add(&b.add(&c));
assert_eq!(left, right);
let sum1 = a.add(&b);
let sum2 = b.add(&a);
assert_eq!(sum1, sum2);
let left = a.mul(&b.add(&c));
let right = a.mul(&b).add(&a.mul(&c));
assert_eq!(left, right);
}
}
}
#[test]
fn test_point_addition_properties() {
let mut test_points = Vec::new();
for i in 1..=5 {
let mut scalar_bytes = [0u8; P192_SCALAR_SIZE];
scalar_bytes[P192_SCALAR_SIZE - 1] = i;
let scalar = Scalar::new(scalar_bytes).unwrap();
let point = scalar_mult_base_g(&scalar).unwrap();
test_points.push(point);
}
for p in &test_points {
for q in &test_points {
let sum1 = p.add(q);
let sum2 = q.add(p);
assert_eq!(sum1, sum2);
let identity = Point::identity();
let sum_with_identity = p.add(&identity);
assert_eq!(sum_with_identity, *p);
}
}
}
#[test]
fn test_scalar_arithmetic_properties() {
let mut rng = ChaCha20Rng::from_seed([2u8; 32]);
let mut test_scalars = Vec::new();
for _ in 0..5 {
let mut scalar_bytes = [0u8; P192_SCALAR_SIZE];
rng.fill_bytes(&mut scalar_bytes);
if let Ok(scalar) = Scalar::new(scalar_bytes) {
test_scalars.push(scalar);
}
}
for a in &test_scalars {
for b in &test_scalars {
if let (Ok(sum1), Ok(sum2)) = (a.add_mod_n(b), b.add_mod_n(a)) {
assert_eq!(sum1.serialize(), sum2.serialize());
}
if let Ok(product) = a.mul_mod_n(b) {
if let Ok(b_times_g) = scalar_mult_base_g(b) {
if let (Ok(left), Ok(right)) =
(scalar_mult_base_g(&product), scalar_mult(a, &b_times_g))
{
assert_eq!(left, right);
}
}
}
}
}
}
}
mod regression_tests {
use super::*;
#[test]
fn test_serialization_edge_cases() {
let identity = Point::identity();
let uncompressed = identity.serialize_uncompressed();
let compressed = identity.serialize_compressed();
assert!(uncompressed.iter().all(|&b| b == 0));
assert!(compressed.iter().all(|&b| b == 0));
assert!(Point::deserialize_uncompressed(&uncompressed).is_ok());
assert!(Point::deserialize_compressed(&compressed).is_ok());
}
#[test]
fn test_malformed_inputs() {
let too_short = vec![0u8; 10];
let too_long = vec![0u8; 100];
assert!(Point::deserialize_uncompressed(&too_short).is_err());
assert!(Point::deserialize_uncompressed(&too_long).is_err());
assert!(Point::deserialize_compressed(&too_short).is_err());
assert!(Point::deserialize_compressed(&too_long).is_err());
assert!(Scalar::deserialize(&too_short).is_err());
assert!(Scalar::deserialize(&too_long).is_err());
}
#[test]
fn test_zero_and_boundary_handling() {
let zero_bytes = [0u8; P192_SCALAR_SIZE];
assert!(Scalar::new(zero_bytes).is_err());
let large_bytes = [0xFF; P192_SCALAR_SIZE];
assert!(Scalar::new(large_bytes).is_ok());
let mut max_valid = [0xFF; P192_FIELD_ELEMENT_SIZE];
max_valid[16] = 0xFE; assert!(FieldElement::from_bytes(&max_valid).is_ok());
}
}