use super::{Error, Public, Secret, SECP256K1};
use cfx_types::{BigEndianHash as _, H256, U256};
use secp256k1::{
    constants::{CURVE_ORDER, GENERATOR_X, GENERATOR_Y},
    key,
};
pub fn public_is_valid(public: &Public) -> bool {
    to_secp256k1_public(public)
        .ok()
        .map_or(false, |p| p.is_valid())
}
pub fn public_mul_secret(
    public: &mut Public, secret: &Secret,
) -> Result<(), Error> {
    let key_secret = secret.to_secp256k1_secret()?;
    let mut key_public = to_secp256k1_public(public)?;
    key_public.mul_assign(&SECP256K1, &key_secret)?;
    set_public(public, &key_public);
    Ok(())
}
pub fn public_add(public: &mut Public, other: &Public) -> Result<(), Error> {
    let mut key_public = to_secp256k1_public(public)?;
    let other_public = to_secp256k1_public(other)?;
    key_public.add_assign(&SECP256K1, &other_public)?;
    set_public(public, &key_public);
    Ok(())
}
pub fn public_sub(public: &mut Public, other: &Public) -> Result<(), Error> {
    let mut key_neg_other = to_secp256k1_public(other)?;
    key_neg_other.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
    let mut key_public = to_secp256k1_public(public)?;
    key_public.add_assign(&SECP256K1, &key_neg_other)?;
    set_public(public, &key_public);
    Ok(())
}
pub fn public_negate(public: &mut Public) -> Result<(), Error> {
    let mut key_public = to_secp256k1_public(public)?;
    key_public.mul_assign(&SECP256K1, &key::MINUS_ONE_KEY)?;
    set_public(public, &key_public);
    Ok(())
}
pub fn generation_point() -> Public {
    let mut public_sec_raw = [0u8; 65];
    public_sec_raw[0] = 4;
    public_sec_raw[1..33].copy_from_slice(&GENERATOR_X);
    public_sec_raw[33..65].copy_from_slice(&GENERATOR_Y);
    let public_key = key::PublicKey::from_slice(&SECP256K1, &public_sec_raw)
        .expect("constructing using predefined constants; qed");
    let mut public = Public::default();
    set_public(&mut public, &public_key);
    public
}
pub fn curve_order() -> U256 { H256::from_slice(&CURVE_ORDER).into_uint() }
fn to_secp256k1_public(public: &Public) -> Result<key::PublicKey, Error> {
    let public_data = {
        let mut temp = [4u8; 65];
        (&mut temp[1..65]).copy_from_slice(&public[0..64]);
        temp
    };
    Ok(key::PublicKey::from_slice(&SECP256K1, &public_data)?)
}
fn set_public(public: &mut Public, key_public: &key::PublicKey) {
    let key_public_serialized = key_public.serialize_vec(&SECP256K1, false);
    public
        .as_bytes_mut()
        .copy_from_slice(&key_public_serialized[1..65]);
}
#[cfg(test)]
mod tests {
    use super::{
        super::{KeyPairGenerator, Random},
        public_add, public_sub,
    };
    #[test]
    fn public_addition_is_commutative() {
        let public1 = Random.generate().unwrap().public().clone();
        let public2 = Random.generate().unwrap().public().clone();
        let mut left = public1.clone();
        public_add(&mut left, &public2).unwrap();
        let mut right = public2.clone();
        public_add(&mut right, &public1).unwrap();
        assert_eq!(left, right);
    }
    #[test]
    fn public_addition_is_reversible_with_subtraction() {
        let public1 = Random.generate().unwrap().public().clone();
        let public2 = Random.generate().unwrap().public().clone();
        let mut sum = public1.clone();
        public_add(&mut sum, &public2).unwrap();
        public_sub(&mut sum, &public2).unwrap();
        assert_eq!(sum, public1);
    }
}