use nettle_sys::{nettle_ecdsa_sign, nettle_ecdsa_verify};
use std::mem::zeroed;

use crate::{
    dsa,
    random::Random,
    ecc::{Point, Scalar},
};

/// Signs `digest` using the key `private`. Returns the signature.
pub fn sign<R: Random>(
    private: &Scalar,
    digest: &[u8],
    random: &mut R,
) -> dsa::Signature {
    unsafe {
        let mut ret = zeroed();

        nettle_ecdsa_sign(
            &private.scalar,
            random.context(),
            Some(R::random_impl),
            digest.len(),
            digest.as_ptr(),
            &mut ret as *mut _,
        );
        dsa::Signature { signature: ret }
    }
}

/// Verify `signature` of `digest` using the key `public`. Returns `true` if the signature is
/// valid.
pub fn verify(
    public: &Point,
    digest: &[u8],
    signature: &dsa::Signature,
) -> bool {
    unsafe {
        nettle_ecdsa_verify(
            &public.point,
            digest.len(),
            digest.as_ptr(),
            &signature.signature as *const _,
        ) == 1
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::ecdsa::generate_keypair;
    use crate::{ecc::Secp192r1, random::Yarrow};

    #[test]
    fn sign_verify() {
        let mut rand = Yarrow::default();
        let (public, private) =
            generate_keypair::<Secp192r1, _>(&mut rand).unwrap();

        for _ in 0..3 {
            let mut msg = [0u8; 160];

            rand.random(&mut msg);
            let sig = sign(&private, &msg, &mut rand);

            assert!(verify(&public, &msg, &sig));
        }

        for _ in 0..3 {
            let mut msg = [0u8; 160];

            rand.random(&mut msg);
            let sig = sign(&private, &msg, &mut rand);
            rand.random(&mut msg);

            assert!(!verify(&public, &msg, &sig));
        }
    }
}
