PqcPublicKeyFactory
using Org.BouncyCastle.Asn1;
using Org.BouncyCastle.Asn1.BC;
using Org.BouncyCastle.Asn1.Pkcs;
using Org.BouncyCastle.Asn1.X509;
using Org.BouncyCastle.Crypto;
using Org.BouncyCastle.Crypto.Utilities;
using Org.BouncyCastle.Pqc.Asn1;
using Org.BouncyCastle.Pqc.Crypto.Bike;
using Org.BouncyCastle.Pqc.Crypto.Cmce;
using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
using Org.BouncyCastle.Pqc.Crypto.Falcon;
using Org.BouncyCastle.Pqc.Crypto.Frodo;
using Org.BouncyCastle.Pqc.Crypto.Hqc;
using Org.BouncyCastle.Pqc.Crypto.Lms;
using Org.BouncyCastle.Pqc.Crypto.Ntru;
using Org.BouncyCastle.Pqc.Crypto.Picnic;
using Org.BouncyCastle.Pqc.Crypto.Saber;
using Org.BouncyCastle.Pqc.Crypto.SphincsPlus;
using Org.BouncyCastle.Utilities;
using System;
using System.Collections.Generic;
using System.IO;
namespace Org.BouncyCastle.Pqc.Crypto.Utilities
{
    public static class PqcPublicKeyFactory
    {
        private delegate AsymmetricKeyParameter Converter (SubjectPublicKeyInfo keyInfo, object defaultParams);
        private static Dictionary<DerObjectIdentifier, Converter> Converters;
        static PqcPublicKeyFactory()
        {
            Converters = new Dictionary<DerObjectIdentifier, Converter>();
            Converters[PkcsObjectIdentifiers.IdAlgHssLmsHashsig] = LmsConverter;
            Converters[BCObjectIdentifiers.mceliece348864_r3] = CmceConverter;
            Converters[BCObjectIdentifiers.mceliece348864f_r3] = CmceConverter;
            Converters[BCObjectIdentifiers.mceliece460896_r3] = CmceConverter;
            Converters[BCObjectIdentifiers.mceliece460896f_r3] = CmceConverter;
            Converters[BCObjectIdentifiers.mceliece6688128_r3] = CmceConverter;
            Converters[BCObjectIdentifiers.mceliece6688128f_r3] = CmceConverter;
            Converters[BCObjectIdentifiers.mceliece6960119_r3] = CmceConverter;
            Converters[BCObjectIdentifiers.mceliece6960119f_r3] = CmceConverter;
            Converters[BCObjectIdentifiers.mceliece8192128_r3] = CmceConverter;
            Converters[BCObjectIdentifiers.mceliece8192128f_r3] = CmceConverter;
            Converters[BCObjectIdentifiers.frodokem640aes] = FrodoConverter;
            Converters[BCObjectIdentifiers.frodokem640shake] = FrodoConverter;
            Converters[BCObjectIdentifiers.frodokem976aes] = FrodoConverter;
            Converters[BCObjectIdentifiers.frodokem976shake] = FrodoConverter;
            Converters[BCObjectIdentifiers.frodokem1344aes] = FrodoConverter;
            Converters[BCObjectIdentifiers.frodokem1344shake] = FrodoConverter;
            Converters[BCObjectIdentifiers.lightsaberkem128r3] = SaberConverter;
            Converters[BCObjectIdentifiers.saberkem128r3] = SaberConverter;
            Converters[BCObjectIdentifiers.firesaberkem128r3] = SaberConverter;
            Converters[BCObjectIdentifiers.lightsaberkem192r3] = SaberConverter;
            Converters[BCObjectIdentifiers.saberkem192r3] = SaberConverter;
            Converters[BCObjectIdentifiers.firesaberkem192r3] = SaberConverter;
            Converters[BCObjectIdentifiers.lightsaberkem256r3] = SaberConverter;
            Converters[BCObjectIdentifiers.saberkem256r3] = SaberConverter;
            Converters[BCObjectIdentifiers.firesaberkem256r3] = SaberConverter;
            Converters[BCObjectIdentifiers.ulightsaberkemr3] = SaberConverter;
            Converters[BCObjectIdentifiers.usaberkemr3] = SaberConverter;
            Converters[BCObjectIdentifiers.ufiresaberkemr3] = SaberConverter;
            Converters[BCObjectIdentifiers.lightsaberkem90sr3] = SaberConverter;
            Converters[BCObjectIdentifiers.saberkem90sr3] = SaberConverter;
            Converters[BCObjectIdentifiers.firesaberkem90sr3] = SaberConverter;
            Converters[BCObjectIdentifiers.ulightsaberkem90sr3] = SaberConverter;
            Converters[BCObjectIdentifiers.usaberkem90sr3] = SaberConverter;
            Converters[BCObjectIdentifiers.ufiresaberkem90sr3] = SaberConverter;
            Converters[BCObjectIdentifiers.picnic] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnicl1fs] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnicl1ur] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnicl3fs] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnicl3ur] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnicl5fs] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnicl5ur] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnic3l1] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnic3l3] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnic3l5] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnicl1full] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnicl3full] = PicnicConverter;
            Converters[BCObjectIdentifiers.picnicl5full] = PicnicConverter;
            Converters.Add(BCObjectIdentifiers.ntruhps2048509, NtruConverter);
            Converters.Add(BCObjectIdentifiers.ntruhps2048677, NtruConverter);
            Converters.Add(BCObjectIdentifiers.ntruhps4096821, NtruConverter);
            Converters.Add(BCObjectIdentifiers.ntruhps40961229, NtruConverter);
            Converters.Add(BCObjectIdentifiers.ntruhrss701, NtruConverter);
            Converters.Add(BCObjectIdentifiers.ntruhrss1373, NtruConverter);
            Converters[BCObjectIdentifiers.dilithium2] = DilithiumConverter;
            Converters[BCObjectIdentifiers.dilithium3] = DilithiumConverter;
            Converters[BCObjectIdentifiers.dilithium5] = DilithiumConverter;
            Converters[BCObjectIdentifiers.dilithium2_aes] = DilithiumConverter;
            Converters[BCObjectIdentifiers.dilithium3_aes] = DilithiumConverter;
            Converters[BCObjectIdentifiers.dilithium5_aes] = DilithiumConverter;
            Converters[BCObjectIdentifiers.falcon_512] = FalconConverter;
            Converters[BCObjectIdentifiers.falcon_1024] = FalconConverter;
            Converters[BCObjectIdentifiers.bike128] = BikeConverter;
            Converters[BCObjectIdentifiers.bike192] = BikeConverter;
            Converters[BCObjectIdentifiers.bike256] = BikeConverter;
            Converters[BCObjectIdentifiers.hqc128] = HqcConverter;
            Converters[BCObjectIdentifiers.hqc192] = HqcConverter;
            Converters[BCObjectIdentifiers.hqc256] = HqcConverter;
            Converters[BCObjectIdentifiers.sphincsPlus] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_128s_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_128f_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_128s_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_128f_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_128s_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_128f_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_192s_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_192f_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_192s_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_192f_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_192s_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_192f_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_256s_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_256f_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_256s_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_256f_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_256s_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_256f_r3] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_128f_r3_simple] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_128s_r3_simple] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_192f_r3_simple] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_192s_r3_simple] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_256f_r3_simple] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_haraka_256s_r3_simple] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_128s] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_128f] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_128s] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_128f] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_192s] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_192f] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_192s] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_192f] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_256s] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_sha2_256f] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_256s] = SphincsPlusConverter;
            Converters[BCObjectIdentifiers.sphincsPlus_shake_256f] = SphincsPlusConverter;
        }
        public static AsymmetricKeyParameter CreateKey(byte[] keyInfoData)
        {
            return CreateKey(SubjectPublicKeyInfo.GetInstance(Asn1Object.FromByteArray(keyInfoData)));
        }
        public static AsymmetricKeyParameter CreateKey(Stream inStr)
        {
            return CreateKey(SubjectPublicKeyInfo.GetInstance(new Asn1InputStream(inStr).ReadObject()));
        }
        public static AsymmetricKeyParameter CreateKey(SubjectPublicKeyInfo keyInfo)
        {
            return CreateKey(keyInfo, null);
        }
        public static AsymmetricKeyParameter CreateKey(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            DerObjectIdentifier algorithm = keyInfo.Algorithm.Algorithm;
            if (!Converters.TryGetValue(algorithm, out Converter value))
                throw new IOException("algorithm identifier in public key not recognised: " + algorithm?.ToString());
            return value(keyInfo, defaultParams);
        }
        internal static DilithiumPublicKeyParameters GetDilithiumPublicKey(DilithiumParameters dilithiumParameters, DerBitString publicKeyData)
        {
            byte[] octets = publicKeyData.GetOctets();
            try {
                Asn1Object asn1Object = Asn1Object.FromByteArray(octets);
                Asn1Sequence asn1Sequence = asn1Object as Asn1Sequence;
                if (asn1Sequence == null) {
                    byte[] octets2 = Asn1OctetString.GetInstance(asn1Object).GetOctets();
                    return new DilithiumPublicKeyParameters(dilithiumParameters, octets2);
                }
                return new DilithiumPublicKeyParameters(dilithiumParameters, Asn1OctetString.GetInstance(asn1Sequence[0]).GetOctets(), Asn1OctetString.GetInstance(asn1Sequence[1]).GetOctets());
            } catch (Exception) {
                return new DilithiumPublicKeyParameters(dilithiumParameters, octets);
            }
        }
        private static AsymmetricKeyParameter LmsConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            DerBitString publicKey = keyInfo.PublicKey;
            if (publicKey.IsOctetAligned()) {
                try {
                    Asn1OctetString asn1OctetString = Asn1Object.FromMemoryStream(publicKey.GetOctetMemoryStream()) as Asn1OctetString;
                    if (asn1OctetString != null)
                        return GetLmsKeyParameters(asn1OctetString.GetOctets());
                } catch (Exception) {
                }
                return GetLmsKeyParameters(publicKey.GetOctets());
            }
            throw new ArgumentException("invalid LMS public key");
        }
        private static LmsKeyParameters GetLmsKeyParameters(byte[] keyEnc)
        {
            if (Pack.BE_To_UInt32(keyEnc, 0) == 1)
                return LmsPublicKeyParameters.GetInstance(Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length));
            if (keyEnc.Length == 64)
                keyEnc = Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length);
            return HssPublicKeyParameters.GetInstance(keyEnc);
        }
        private static AsymmetricKeyParameter SphincsPlusConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            try {
                byte[] octets = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
                return new SphincsPlusPublicKeyParameters(PqcUtilities.SphincsPlusParamsLookup(keyInfo.Algorithm.Algorithm), Arrays.CopyOfRange(octets, 4, octets.Length));
            } catch (Exception) {
                byte[] octets2 = keyInfo.PublicKey.GetOctets();
                return new SphincsPlusPublicKeyParameters(PqcUtilities.SphincsPlusParamsLookup(keyInfo.Algorithm.Algorithm), octets2);
            }
        }
        private static AsymmetricKeyParameter CmceConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            byte[] t = CmcePublicKey.GetInstance(keyInfo.ParsePublicKey()).T;
            return new CmcePublicKeyParameters(PqcUtilities.McElieceParamsLookup(keyInfo.Algorithm.Algorithm), t);
        }
        private static AsymmetricKeyParameter FrodoConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            byte[] octets = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
            return new FrodoPublicKeyParameters(PqcUtilities.FrodoParamsLookup(keyInfo.Algorithm.Algorithm), octets);
        }
        private static AsymmetricKeyParameter SaberConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            byte[] octets = Asn1OctetString.GetInstance(Asn1Sequence.GetInstance(keyInfo.ParsePublicKey())[0]).GetOctets();
            return new SaberPublicKeyParameters(PqcUtilities.SaberParamsLookup(keyInfo.Algorithm.Algorithm), octets);
        }
        private static AsymmetricKeyParameter PicnicConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            byte[] octets = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
            return new PicnicPublicKeyParameters(PqcUtilities.PicnicParamsLookup(keyInfo.Algorithm.Algorithm), octets);
        }
        private static AsymmetricKeyParameter DilithiumConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            return GetDilithiumPublicKey(PqcUtilities.DilithiumParamsLookup(keyInfo.Algorithm.Algorithm), keyInfo.PublicKey);
        }
        private static AsymmetricKeyParameter NtruConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            return GetNtruPublicKey(PqcUtilities.NtruParamsLookup(keyInfo.Algorithm.Algorithm), keyInfo.PublicKey);
        }
        private static NtruPublicKeyParameters GetNtruPublicKey(NtruParameters ntruParameters, DerBitString publicKey)
        {
            if (publicKey.IsOctetAligned()) {
                int publicKeyLength = ntruParameters.PublicKeyLength;
                int bytesLength = publicKey.GetBytesLength();
                if (bytesLength == publicKeyLength)
                    return NtruPublicKeyParameters.FromEncoding(ntruParameters, publicKey.GetOctets());
                if (bytesLength > publicKeyLength)
                    try {
                        Asn1OctetString asn1OctetString = Asn1Object.FromMemoryStream(publicKey.GetOctetMemoryStream()) as Asn1OctetString;
                        if (asn1OctetString != null && asn1OctetString.GetOctetsLength() == publicKeyLength)
                            return NtruPublicKeyParameters.FromEncoding(ntruParameters, asn1OctetString.GetOctets());
                    } catch (Exception) {
                    }
            }
            throw new ArgumentException("invalid " + ntruParameters.Name + " public key");
        }
        private static AsymmetricKeyParameter FalconConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            FalconParameters falconParameters = PqcUtilities.FalconParamsLookup(keyInfo.Algorithm.Algorithm);
            try {
                Asn1Object asn1Object = keyInfo.ParsePublicKey();
                if (!(asn1Object is Asn1Sequence)) {
                    byte[] octets = Asn1OctetString.GetInstance(asn1Object).GetOctets();
                    if (octets[0] != (byte)falconParameters.LogN)
                        throw new ArgumentException("byte[] enc of Falcon h value not tagged correctly");
                    return new FalconPublicKeyParameters(falconParameters, Arrays.CopyOfRange(octets, 1, octets.Length));
                }
                byte[] octets2 = Asn1OctetString.GetInstance(Asn1Sequence.GetInstance(asn1Object)[0]).GetOctets();
                return new FalconPublicKeyParameters(falconParameters, octets2);
            } catch (Exception) {
                byte[] octets3 = keyInfo.PublicKey.GetOctets();
                if (octets3[0] != (byte)falconParameters.LogN)
                    throw new ArgumentException("byte[] enc of Falcon h value not tagged correctly");
                return new FalconPublicKeyParameters(falconParameters, Arrays.CopyOfRange(octets3, 1, octets3.Length));
            }
        }
        private static AsymmetricKeyParameter BikeConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            try {
                byte[] octets = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
                return new BikePublicKeyParameters(PqcUtilities.BikeParamsLookup(keyInfo.Algorithm.Algorithm), octets);
            } catch (Exception) {
                byte[] octets2 = keyInfo.PublicKey.GetOctets();
                return new BikePublicKeyParameters(PqcUtilities.BikeParamsLookup(keyInfo.Algorithm.Algorithm), octets2);
            }
        }
        private static AsymmetricKeyParameter HqcConverter(SubjectPublicKeyInfo keyInfo, object defaultParams)
        {
            try {
                byte[] octets = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
                return new HqcPublicKeyParameters(PqcUtilities.HqcParamsLookup(keyInfo.Algorithm.Algorithm), octets);
            } catch (Exception) {
                byte[] octets2 = keyInfo.PublicKey.GetOctets();
                return new HqcPublicKeyParameters(PqcUtilities.HqcParamsLookup(keyInfo.Algorithm.Algorithm), octets2);
            }
        }
    }
}