wolfcrypt-ring-testing 0.2.1

Tests and benchmarks for wolfcrypt-ring-compat
#![expect(deprecated, dead_code)]

use criterion::{criterion_group, criterion_main, Criterion};
use wolfcrypt_ring_compat::{test, test_file};

#[expect(dead_code)]
pub struct RsaConfig {
    padding: &'static RsaPadding,
    digest: &'static RsaDigest,
    key: Vec<u8>,
    msg: Vec<u8>,
    signature: Vec<u8>,
}

impl RsaConfig {
    fn new(padding: &str, digest: &str, key: &[u8], msg: &[u8], signature: &[u8]) -> RsaConfig {
        RsaConfig {
            padding: RsaPadding::from(padding),
            digest: RsaDigest::from(digest),
            key: Vec::from(key),
            msg: Vec::from(msg),
            signature: Vec::from(signature),
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(PartialEq, Eq, Debug)]
pub enum RsaPadding {
    PSS,
    PKCS1,
}
pub const PSS: RsaPadding = RsaPadding::PSS;
pub const PKCS1: RsaPadding = RsaPadding::PKCS1;

impl RsaPadding {
    fn from(value: &str) -> &'static Self {
        match value.trim() {
            "PSS" => &PSS,
            "PKCS1" => &PKCS1,
            _ => panic!("Unrecognized padding: '{value}'"),
        }
    }
}

#[allow(non_camel_case_types)]
#[derive(PartialEq, Eq, Debug)]
pub enum RsaDigest {
    SHA256,
    SHA384,
    SHA512,
}
pub const SHA256: RsaDigest = RsaDigest::SHA256;
pub const SHA384: RsaDigest = RsaDigest::SHA384;
pub const SHA512: RsaDigest = RsaDigest::SHA512;

impl RsaDigest {
    fn from(value: &str) -> &'static Self {
        match value.trim() {
            "SHA256" => &SHA256,
            "SHA384" => &SHA384,
            "SHA512" => &SHA512,
            _ => panic!("Unrecognize padding: '{value}'"),
        }
    }
}

macro_rules! benchmark_rsa {
    ( $pkg:ident ) => {
        paste::item! {
        mod [<$pkg _benchmarks>]  {

            use $pkg::{signature, rand};

    use super::{RsaDigest, RsaPadding};
    use signature::{RsaKeyPair, RsaParameters, VerificationAlgorithm};

    pub fn create_key_pair(key: &[u8]) -> RsaKeyPair {
        RsaKeyPair::from_der(key).expect("Unable to parse key")
    }

    pub fn encoding(
        padding: &'static RsaPadding,
        digest: &'static RsaDigest,
    ) -> &'static dyn signature::RsaEncoding {
        match (padding, digest) {
            (&crate::PSS, &crate::SHA256) => &signature::RSA_PSS_SHA256,
            (&crate::PSS, &crate::SHA384) => &signature::RSA_PSS_SHA384,
            (&crate::PSS, &crate::SHA512) => &signature::RSA_PSS_SHA512,
            (&crate::PKCS1, &crate::SHA256) => &signature::RSA_PKCS1_SHA256,
            (&crate::PKCS1, &crate::SHA384) => &signature::RSA_PKCS1_SHA384,
            (&crate::PKCS1, &crate::SHA512) => &signature::RSA_PKCS1_SHA512,
        }
    }

    pub fn parameters(
        padding: &'static RsaPadding,
        digest: &'static RsaDigest,
    ) -> &'static RsaParameters {
        match (padding, digest) {
            (&crate::PSS, &crate::SHA256) => &signature::RSA_PSS_2048_8192_SHA256,
            (&crate::PSS, &crate::SHA384) => &signature::RSA_PSS_2048_8192_SHA384,
            (&crate::PSS, &crate::SHA512) => &signature::RSA_PSS_2048_8192_SHA512,
            (&crate::PKCS1, &crate::SHA256) => &signature::RSA_PKCS1_2048_8192_SHA256,
            (&crate::PKCS1, &crate::SHA384) => &signature::RSA_PKCS1_2048_8192_SHA384,
            (&crate::PKCS1, &crate::SHA512) => &signature::RSA_PKCS1_2048_8192_SHA512,
        }
    }

    pub fn get_rng() -> rand::SystemRandom {
        rand::SystemRandom::new()
    }

    pub fn sign(
        key_pair: &RsaKeyPair,
        rng: &dyn rand::SecureRandom,
        msg: &[u8],
        encoding: &'static dyn signature::RsaEncoding,
        signature: &mut [u8],
    ) {
        key_pair
            .sign(encoding, rng, msg, signature)
            .expect("signing failed");
    }

    pub fn verify(rsa_params: &RsaParameters, public_key: &[u8], msg: &[u8], signature: &[u8]) {
        let public_key = untrusted::Input::from(public_key);
        let msg = untrusted::Input::from(msg);
        let signature = untrusted::Input::from(signature);
        rsa_params.verify(public_key, msg, signature).unwrap()
    }
}

}
    };
}

benchmark_rsa!(wolfcrypt_ring_compat);
#[cfg(feature = "ring-benchmarks")]
benchmark_rsa!(ring);

fn test_rsa_sign(c: &mut Criterion, config: &RsaConfig) {
    let mut buffer = [0u8; 2048];

    let bench_group_name = format!(
        "RSA-{}-{:?}-{:?}-sign-{}-bytes",
        config.key.len(),
        config.padding,
        config.digest,
        config.msg.len()
    );
    let mut group = c.benchmark_group(bench_group_name);
    let wc_rng = wolfcrypt_ring_compat_benchmarks::get_rng();
    let wc_encoding = wolfcrypt_ring_compat_benchmarks::encoding(config.padding, config.digest);
    let wc_key_pair = wolfcrypt_ring_compat_benchmarks::create_key_pair(&config.key);
    let wc_sig = &mut buffer[0..wc_key_pair.public_modulus_len()];
    group.bench_function("wolfcrypt-ring-compat", |b| {
        b.iter(|| {
            wolfcrypt_ring_compat_benchmarks::sign(
                &wc_key_pair,
                &wc_rng,
                &config.msg,
                wc_encoding,
                wc_sig,
            );
        });
    });
    #[cfg(feature = "ring-benchmarks")]
    {
        let ring_rng = ring_benchmarks::get_rng();
        let ring_encoding = ring_benchmarks::encoding(config.padding, config.digest);
        let ring_key_pair = ring_benchmarks::create_key_pair(&config.key);
        let ring_sig = &mut buffer[0..ring_key_pair.public_modulus_len()];

        group.bench_function("Ring", |b| {
            b.iter(|| {
                ring_benchmarks::sign(
                    &ring_key_pair,
                    &ring_rng,
                    &config.msg,
                    ring_encoding,
                    ring_sig,
                );
            });
        });
    }
}

fn test_rsa_verify(c: &mut Criterion, config: &RsaConfig) {
    let bench_group_name = format!(
        "RSA-{}-{:?}-{:?}-verify-{}-bytes",
        config.key.len(),
        config.padding,
        config.digest,
        config.msg.len()
    );
    let mut group = c.benchmark_group(bench_group_name);
    {
        use wolfcrypt_ring_compat::signature::KeyPair;
        let wc_params = wolfcrypt_ring_compat_benchmarks::parameters(config.padding, config.digest);
        let wc_key_pair = wolfcrypt_ring_compat_benchmarks::create_key_pair(&config.key);
        let wc_pub_key = wc_key_pair.public_key().as_ref();
        let wc_sig = config.signature.as_slice();

        group.bench_function("wolfcrypt-ring-compat", |b| {
            b.iter(|| {
                wolfcrypt_ring_compat_benchmarks::verify(
                    wc_params,
                    wc_pub_key,
                    &config.msg,
                    wc_sig,
                );
            });
        });
    }
    #[cfg(feature = "ring-benchmarks")]
    {
        use ring::signature::KeyPair;
        let ring_params = ring_benchmarks::parameters(config.padding, config.digest);
        let ring_key_pair = ring_benchmarks::create_key_pair(&config.key);
        let ring_pub_key = ring_key_pair.public_key().as_ref();
        let ring_sig = config.signature.as_slice();

        group.bench_function("Ring", |b| {
            b.iter(|| {
                ring_benchmarks::verify(ring_params, ring_pub_key, &config.msg, ring_sig);
            });
        });
    }
}

fn test_rsa(c: &mut Criterion) {
    test::run(
        test_file!("data/rsa_benchmarks.txt"),
        |_section, test_case| {
            let config = RsaConfig::new(
                test_case.consume_string("Padding").as_str(),
                test_case.consume_string("Digest").as_str(),
                test_case.consume_bytes("Key").as_slice(),
                test_case.consume_bytes("Msg").as_slice(),
                test_case.consume_bytes("Sig").as_slice(),
            );
            test_rsa_sign(c, &config);
            test_rsa_verify(c, &config);
            Ok(())
        },
    );
}

criterion_group!(benches, test_rsa);
criterion_main!(benches);