//! Benchmark suite for the ecmqv-rs library.
//!
//! This benchmark measures the performance of:
//! - Ephemeral-only key exchange (`EphemeralOnly`)
//! - Ephemeral-static key exchange (`EphemeralStatic`)
//! - Ephemeral key generation (`generate_ephemeral`)
//!
//! Currently only Curve25519 is benchmarked by default. To include other curves,
//! uncomment the relevant `#[cfg]` blocks and enable the corresponding features.
//!
//! Run with:
//! ```sh
//! cargo bench
//! ```
//! Or to include all curves:
//! ```sh
//! cargo bench --features "curve25519,secp256k1,secp256r1"
//! ```

use criterion::{criterion_group, criterion_main, Criterion};
use rand::rngs::OsRng;

use ecmqv_rs::{
    EphemeralOnly, EphemeralStatic, KeyExchange, CurveParameters,
    KdfParams, SharedInfo, HashFunction, StaticKey,
};

/// Executes a full EphemeralOnly handshake for the given curve and KDF parameters.
///
/// This helper generates ephemeral keys for both parties, performs the ECMQV
/// agreement, and derives the shared secret using the provided KDF.
///
/// # Parameters
/// - `params`: curve parameters (e.g., `CurveParameters::Curve25519`)
/// - `kdf`: KDF parameters (hash function, output length, etc.)
///
/// # Panics
/// Panics if the handshake fails or the derived secrets do not match.
fn bench_ephemeral_only(params: CurveParameters, kdf: KdfParams) {
    let mut rng = OsRng;
    let (alice_eph, alice_pub) = EphemeralOnly::generate_ephemeral(&mut rng, &params).unwrap();
    let (bob_eph, bob_pub) = EphemeralOnly::generate_ephemeral(&mut rng, &params).unwrap();
    let alice = EphemeralOnly::new(alice_eph, params);
    let bob = EphemeralOnly::new(bob_eph, params);
    let info = SharedInfo {
        id_a: b"alice",
        id_b: b"bob",
        other_data: b"bench",
    };
    let alice_secret = alice.agree(&bob_pub, None, &info, kdf.clone()).unwrap();
    let bob_secret = bob.agree(&alice_pub, None, &info, kdf).unwrap();
    assert_eq!(alice_secret.as_slice(), bob_secret.as_slice());
}

/// Executes a full EphemeralStatic handshake for the given curve and KDF parameters.
///
/// This helper generates static keys from fixed seeds for both parties, generates
/// ephemeral keys, and performs the authenticated ECMQV agreement.
///
/// # Parameters
/// - `params`: curve parameters
/// - `kdf`: KDF parameters
///
/// # Panics
/// Panics if the handshake fails or derived secrets do not match.
fn bench_ephemeral_static(params: CurveParameters, kdf: KdfParams) {
    let mut rng = OsRng;
    // Generate static keys from fixed seeds (simulating loaded certificates)
    let alice_static = StaticKey::from_seed(&[42u8; 32], &mut rng, params).unwrap();
    let bob_static = StaticKey::from_seed(&[43u8; 32], &mut rng, params).unwrap();
    let alice_static_pub = alice_static.public();
    let bob_static_pub = bob_static.public();

    // Generate ephemeral keys
    let (alice_eph, alice_eph_pub) = EphemeralStatic::generate_ephemeral(&mut rng, &params).unwrap();
    let (bob_eph, bob_eph_pub) = EphemeralStatic::generate_ephemeral(&mut rng, &params).unwrap();

    // Create exchangers
    let alice = EphemeralStatic::new(alice_eph, alice_static, params).unwrap();
    let bob = EphemeralStatic::new(bob_eph, bob_static, params).unwrap();

    let info = SharedInfo {
        id_a: b"alice",
        id_b: b"bob",
        other_data: b"bench",
    };
    let kdf2 = kdf.clone();
    let alice_secret = alice.agree(&bob_eph_pub, Some(&bob_static_pub), &info, kdf).unwrap();
    let bob_secret = bob.agree(&alice_eph_pub, Some(&alice_static_pub), &info, kdf2).unwrap();
    assert_eq!(alice_secret.as_slice(), bob_secret.as_slice());
}

/// Benchmark: EphemeralOnly handshake on Curve25519.
///
/// Measures the full two-party ephemeral-only key exchange using SHA-256 as the KDF.
fn bench_ephemeral_only_curve25519(c: &mut Criterion) {
    let params = CurveParameters::Curve25519;
    let kdf = KdfParams {
        hash_fn: HashFunction::Sha256,
        output_len: 32,
        label: None,
        salt: None,
    };
    c.bench_function("ephemeral_only_curve25519", |b| {
        b.iter(|| bench_ephemeral_only(params, kdf.clone()));
    });
}

/// Benchmark: EphemeralStatic handshake on Curve25519.
///
/// Measures the full authenticated key exchange with static keys, using SHA-256 KDF.
fn bench_ephemeral_static_curve25519(c: &mut Criterion) {
    let params = CurveParameters::Curve25519;
    let kdf = KdfParams {
        hash_fn: HashFunction::Sha256,
        output_len: 32,
        label: None,
        salt: None,
    };
    c.bench_function("ephemeral_static_curve25519", |b| {
        b.iter(|| bench_ephemeral_static(params, kdf.clone()));
    });
}

/// Benchmark: Ephemeral key generation on Curve25519.
///
/// Measures the time to generate a single ephemeral key pair without performing
/// the full key exchange or KDF.
fn bench_keygen_ephemeral(c: &mut Criterion) {
    let mut rng = OsRng;
    let params = CurveParameters::Curve25519;
    c.bench_function("keygen_ephemeral_curve25519", |b| {
        b.iter(|| {
            let _ = EphemeralOnly::generate_ephemeral(&mut rng, &params).unwrap();
        });
    });
}

/*
  # Example for secp256k1:
  #[cfg(feature = "secp256k1")]
  fn bench_ephemeral_only_secp256k1(c: &mut Criterion) {
      let params = CurveParameters::Secp256k1;
      let kdf = KdfParams {
          hash_fn: HashFunction::Sha256,
          output_len: 32,
          label: None,
          salt: None,
      };
      c.bench_function("ephemeral_only_secp256k1", |b| {
          b.iter(|| bench_ephemeral_only(params, kdf.clone()));
      });
  }

  // Add similar for secp256r1 and static variants.
*/

criterion_group!(
    benches,
    bench_ephemeral_only_curve25519,
    bench_ephemeral_static_curve25519,
    bench_keygen_ephemeral
    // Uncomment and add other benchmark functions here after enabling features.
);
criterion_main!(benches);