use super::*;
use snarkvm_console_types::prelude::AffineCurve;
impl Blake2Xs {
    #[inline]
    pub fn hash_to_curve<G: AffineCurve>(input: &str) -> (G, String, usize) {
        for k in 0..128 {
            let message = format!("{input} in {k}");
            if let Some(g) = Self::try_hash_to_curve::<G>(&message) {
                return (g, message, k);
            }
        }
        panic!("Unable to hash to curve on {input}")
    }
    #[inline]
    fn try_hash_to_curve<G: AffineCurve>(input: &str) -> Option<G> {
        let serialized_size = G::prime_subgroup_generator().compressed_size();
        let digest = Self::evaluate(input.as_bytes(), u16::try_from(serialized_size).unwrap(), "AleoHtC0".as_bytes());
        debug_assert!(digest.len() == serialized_size); G::from_random_bytes(&digest).and_then(|g| {
            debug_assert!(g.is_on_curve());
            let g = g.mul_by_cofactor();
            debug_assert!(g.is_on_curve());
            debug_assert!(g.is_in_correct_subgroup_assuming_on_curve());
            (!g.is_zero()).then_some(g)
        })
    }
}
#[cfg(test)]
mod bls12_377_g1 {
    use super::*;
    use snarkvm_curves::bls12_377::G1Affine;
    use snarkvm_fields::PrimeField;
    use snarkvm_utilities::{BigInteger384, CanonicalSerialize};
    #[test]
    fn hash_bls12_377_g1() {
        let g1 = Blake2Xs::try_hash_to_curve::<G1Affine>("Aleo BLS12-377 G1 in 0").unwrap();
        assert!(g1.is_on_curve());
        assert!(g1.is_in_correct_subgroup_assuming_on_curve());
        assert_eq!(g1.compressed_size(), 384 / 8);
        assert_eq!(
            Blake2Xs::hash_to_curve::<G1Affine>("Aleo BLS12-377 G1"),
            (g1, "Aleo BLS12-377 G1 in 0".to_string(), 0)
        );
        assert_eq!(
            g1.x.to_string(),
            "89363714989903307245735717098563574705733591463163614225748337416674727625843187853442697973404985688481508350822",
        );
        assert_eq!(
            g1.y.to_string(),
            "3702177272937190650578065972808860481433820514072818216637796320125658674906330993856598323293086021583822603349",
        );
        assert_eq!(
            g1.x.to_bigint(),
            BigInteger384::new([
                1089863619676461926,
                2031922408020517912,
                7605803015099675459,
                5499508099818543095,
                11627353473000952893,
                41837199143568307
            ])
        );
        assert_eq!(
            g1.y.to_bigint(),
            BigInteger384::new([
                8946822147630122069,
                11486725844942458959,
                17739430126876114892,
                5672784675232650440,
                942928816728936680,
                1733239579958889
            ])
        );
        assert_eq!(
            g1.x.0,
            BigInteger384::new([
                1171681672315280277,
                6528257384425852712,
                7514971432460253787,
                2032708395764262463,
                12876543207309632302,
                107509843840671767
            ])
        );
        assert_eq!(
            g1.y.0,
            BigInteger384::new([
                13572190014569192121,
                15344828677741220784,
                17067903700058808083,
                10342263224753415805,
                1083990386877464092,
                21335464879237822
            ])
        );
        assert_eq!(G1Affine::prime_subgroup_generator(), g1);
    }
}
#[cfg(test)]
mod bls12_377_g2 {
    use super::*;
    use snarkvm_curves::bls12_377::G2Affine;
    use snarkvm_fields::PrimeField;
    use snarkvm_utilities::{BigInteger384, CanonicalSerialize};
    #[test]
    fn hash_bls12_377_g2() {
        let g2 = Blake2Xs::try_hash_to_curve::<G2Affine>("Aleo BLS12-377 G2 in 6").unwrap();
        assert!(g2.is_on_curve());
        assert!(g2.is_in_correct_subgroup_assuming_on_curve());
        assert_eq!(g2.compressed_size(), 2 * 384 / 8);
        assert_eq!(
            Blake2Xs::hash_to_curve::<G2Affine>("Aleo BLS12-377 G2"),
            (g2, "Aleo BLS12-377 G2 in 6".to_string(), 6),
        );
        assert_eq!(
            g2.x.to_string(),
            "Fp2(170590608266080109581922461902299092015242589883741236963254737235977648828052995125541529645051927918098146183295 + 83407003718128594709087171351153471074446327721872642659202721143408712182996929763094113874399921859453255070254 * u)",
        );
        assert_eq!(
            g2.y.to_string(),
            "Fp2(1843833842842620867708835993770650838640642469700861403869757682057607397502738488921663703124647238454792872005 + 33145532013610981697337930729788870077912093258611421158732879580766461459275194744385880708057348608045241477209 * u)",
        );
        assert_eq!(
            g2.x.c0.to_bigint(),
            BigInteger384::new([
                6285382596397680767,
                15748827462709656851,
                12106939604663586443,
                15333984969116343459,
                5478119782678835813,
                79865001705186672
            ])
        );
        assert_eq!(
            g2.x.c1.to_bigint(),
            BigInteger384::new([
                16087313950742852142,
                593255854261604337,
                1941199260866950545,
                10849744434273544618,
                2633370935305329371,
                39048459712288691
            ])
        );
        assert_eq!(
            g2.y.c0.to_bigint(),
            BigInteger384::new([
                7702421029866889285,
                16004466681641276576,
                106615717155384672,
                763522394023763305,
                16530696304726864408,
                863223330401754
            ])
        );
        assert_eq!(
            g2.y.c1.to_bigint(),
            BigInteger384::new([
                14642269910726223961,
                418400088670236579,
                13367772290999385514,
                12034951455731096578,
                1807164704891090155,
                15517665349181582
            ])
        );
        assert_eq!(
            g2.x.c0.0,
            BigInteger384::new([
                1394603105513884269,
                11069732150289508451,
                4261960060090787184,
                13457254148541472797,
                3177258746859163322,
                82258727112085846
            ])
        );
        assert_eq!(
            g2.x.c1.0,
            BigInteger384::new([
                12672065269715576738,
                3451530808602826578,
                9486610028138952262,
                5031487885431614078,
                9858745210421513581,
                63301617551232910
            ])
        );
        assert_eq!(
            g2.y.c0.0,
            BigInteger384::new([
                1855632670224768760,
                2989378521406112342,
                9748867374972564648,
                3204895972998458874,
                16520689795595505429,
                61918742406142643
            ])
        );
        assert_eq!(
            g2.y.c1.0,
            BigInteger384::new([
                1532128906028652860,
                14539073382194201855,
                10828918286556702479,
                14664598863867299115,
                483199896405477997,
                73741830940675480
            ])
        );
        assert_eq!(G2Affine::prime_subgroup_generator(), g2);
    }
}
#[cfg(test)]
mod edwards_bls12 {
    use super::*;
    use snarkvm_curves::edwards_bls12::EdwardsAffine;
    use snarkvm_fields::PrimeField;
    use snarkvm_utilities::{BigInteger256, CanonicalSerialize};
    #[test]
    fn hash_edwards_bls12() {
        let group = Blake2Xs::try_hash_to_curve::<EdwardsAffine>("Aleo Edwards BLS12 in 4").unwrap();
        assert!(group.is_on_curve());
        assert!(group.is_in_correct_subgroup_assuming_on_curve());
        assert_eq!(group.compressed_size(), 256 / 8);
        assert_eq!(
            Blake2Xs::hash_to_curve::<EdwardsAffine>("Aleo Edwards BLS12"),
            (group, "Aleo Edwards BLS12 in 4".to_string(), 4)
        );
        assert_eq!(group.x.to_string(), "1540945439182663264862696551825005342995406165131907382295858612069623286213",);
        assert_eq!(group.y.to_string(), "8003546896475222703853313610036801932325312921786952001586936882361378122196",);
        assert_eq!(
            group.x.to_bigint(),
            BigInteger256::new([1404703638504229317, 16672475576000152563, 1635533132911366150, 245486771465834503]),
            "\n\nExpected: {:?}\n\n",
            group.x.to_bigint().0,
        );
        assert_eq!(
            group.y.to_bigint(),
            BigInteger256::new([15352153743387634132, 9180404173643694677, 4017395716581932261, 1275038582114391971]),
            "\n\nExpected: {:?}\n\n",
            group.y.to_bigint().0,
        );
        assert_eq!(
            group.x.0,
            BigInteger256::new([15976313411695170452, 17230178952810798400, 11626259175167078036, 678729006091608048]),
            "\n\nExpected: {:?}\n\n",
            group.x.0,
        );
        assert_eq!(
            group.y.0,
            BigInteger256::new([926786653590077393, 18147000980977651608, 13077459464847727671, 1231472949076376191]),
            "\n\nExpected: {:?}\n\n",
            group.y.0,
        );
        assert_eq!(EdwardsAffine::prime_subgroup_generator(), group);
    }
}