summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/asn1/ASN1StreamParser.cs2
-rw-r--r--crypto/src/asn1/Asn1OutputStream.cs10
-rw-r--r--crypto/src/asn1/BERSequenceGenerator.cs8
-rw-r--r--crypto/src/asn1/BERSetGenerator.cs8
-rw-r--r--crypto/src/asn1/DLTaggedObjectParser.cs1
-rw-r--r--crypto/src/asn1/DerObjectIdentifier.cs8
-rw-r--r--crypto/src/asn1/cmp/PKIFreeText.cs10
-rw-r--r--crypto/src/asn1/cmp/PKIHeader.cs21
-rw-r--r--crypto/src/asn1/cmp/PKIHeaderBuilder.cs26
-rw-r--r--crypto/src/asn1/cmp/PKIMessage.cs10
-rw-r--r--crypto/src/asn1/cmp/PKIMessages.cs25
-rw-r--r--crypto/src/asn1/cms/CMSAttributes.cs2
-rw-r--r--crypto/src/asn1/cms/CmsAlgorithmProtection.cs105
-rw-r--r--crypto/src/asn1/cms/ContentInfoParser.cs5
-rw-r--r--crypto/src/asn1/cms/EncryptedContentInfoParser.cs30
-rw-r--r--crypto/src/asn1/cms/EnvelopedDataParser.cs186
-rw-r--r--crypto/src/asn1/cms/KEKIdentifier.cs11
-rw-r--r--crypto/src/asn1/cms/RecipientKeyIdentifier.cs12
-rw-r--r--crypto/src/asn1/cms/SignedData.cs4
-rw-r--r--crypto/src/asn1/cms/SignedDataParser.cs182
-rw-r--r--crypto/src/asn1/cms/Time.cs4
-rw-r--r--crypto/src/asn1/crmf/CertTemplateBuilder.cs30
-rw-r--r--crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs4
-rw-r--r--crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs9
-rw-r--r--crypto/src/asn1/esf/CertificateValues.cs59
-rw-r--r--crypto/src/asn1/esf/CompleteCertificateRefs.cs59
-rw-r--r--crypto/src/asn1/esf/CompleteRevocationRefs.cs59
-rw-r--r--crypto/src/asn1/esf/CrlIdentifier.cs32
-rw-r--r--crypto/src/asn1/esf/CrlListID.cs61
-rw-r--r--crypto/src/asn1/esf/OcspListID.cs61
-rw-r--r--crypto/src/asn1/esf/OtherSigningCertificate.cs84
-rw-r--r--crypto/src/asn1/esf/RevocationValues.cs112
-rw-r--r--crypto/src/asn1/esf/SignaturePolicyId.cs96
-rw-r--r--crypto/src/asn1/esf/SignerLocation.cs16
-rw-r--r--crypto/src/asn1/isismtt/x509/Admissions.cs10
-rw-r--r--crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs79
-rw-r--r--crypto/src/asn1/misc/MiscObjectIdentifiers.cs2
-rw-r--r--crypto/src/asn1/ocsp/CertID.cs30
-rw-r--r--crypto/src/asn1/ocsp/CrlID.cs20
-rw-r--r--crypto/src/asn1/pkcs/CertBag.cs34
-rw-r--r--crypto/src/asn1/pkcs/ContentInfo.cs7
-rw-r--r--crypto/src/asn1/pkcs/CrlBag.cs44
-rw-r--r--crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs20
-rw-r--r--crypto/src/asn1/pkcs/PBEParameter.cs23
-rw-r--r--crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs5
-rw-r--r--crypto/src/asn1/pkcs/SignerInfo.cs24
-rw-r--r--crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs28
-rw-r--r--crypto/src/asn1/tsp/TSTInfo.cs16
-rw-r--r--crypto/src/asn1/x509/AuthorityInformationAccess.cs6
-rw-r--r--crypto/src/asn1/x509/CertificateList.cs23
-rw-r--r--crypto/src/asn1/x509/DistributionPoint.cs92
-rw-r--r--crypto/src/asn1/x509/DistributionPointName.cs82
-rw-r--r--crypto/src/asn1/x509/ExtendedKeyUsage.cs4
-rw-r--r--crypto/src/asn1/x509/GeneralNames.cs45
-rw-r--r--crypto/src/asn1/x509/IssuingDistributionPoint.cs70
-rw-r--r--crypto/src/asn1/x509/KeyUsage.cs8
-rw-r--r--crypto/src/asn1/x509/NameConstraints.cs10
-rw-r--r--crypto/src/asn1/x509/SubjectDirectoryAttributes.cs34
-rw-r--r--crypto/src/asn1/x509/SubjectPublicKeyInfo.cs1
-rw-r--r--crypto/src/asn1/x509/Time.cs4
-rw-r--r--crypto/src/asn1/x509/V2TBSCertListGenerator.cs2
-rw-r--r--crypto/src/asn1/x509/X509CertificateStructure.cs11
-rw-r--r--crypto/src/asn1/x509/X509Extensions.cs4
-rw-r--r--crypto/src/asn1/x509/X509ExtensionsGenerator.cs2
-rw-r--r--crypto/src/bcpg/ArmoredInputStream.cs6
-rw-r--r--crypto/src/cmp/ProtectedPkiMessage.cs9
-rw-r--r--crypto/src/cmp/ProtectedPkiMessageBuilder.cs11
-rw-r--r--crypto/src/cms/CMSAttributeTableGenerator.cs9
-rw-r--r--crypto/src/cms/CMSSignedDataParser.cs1
-rw-r--r--crypto/src/cms/CMSSignedDataStreamGenerator.cs20
-rw-r--r--crypto/src/cms/CMSSignedHelper.cs54
-rw-r--r--crypto/src/cms/DefaultSignedAttributeTableGenerator.cs39
-rw-r--r--crypto/src/cms/OriginatorId.cs4
-rw-r--r--crypto/src/cms/OriginatorInformation.cs2
-rw-r--r--crypto/src/cms/RecipientId.cs2
-rw-r--r--crypto/src/cms/RecipientInformationStore.cs2
-rw-r--r--crypto/src/cms/SignerId.cs2
-rw-r--r--crypto/src/cms/SignerInfoGenerator.cs15
-rw-r--r--crypto/src/cms/SignerInformationStore.cs19
-rw-r--r--crypto/src/crypto/BufferedAeadBlockCipher.cs8
-rw-r--r--crypto/src/crypto/BufferedAeadCipher.cs8
-rw-r--r--crypto/src/crypto/CryptoServicesRegistrar.cs2
-rw-r--r--crypto/src/crypto/IBlockResult.cs1
-rw-r--r--crypto/src/crypto/agreement/DHBasicAgreement.cs11
-rw-r--r--crypto/src/crypto/agreement/ECDHBasicAgreement.cs7
-rw-r--r--crypto/src/crypto/agreement/ECDHCBasicAgreement.cs7
-rw-r--r--crypto/src/crypto/agreement/ECMqvBasicAgreement.cs7
-rw-r--r--crypto/src/crypto/digests/ISAPDigest.cs149
-rw-r--r--crypto/src/crypto/digests/LongDigest.cs2
-rw-r--r--crypto/src/crypto/digests/MD5Digest.cs141
-rw-r--r--crypto/src/crypto/digests/PhotonBeetleDigest.cs247
-rw-r--r--crypto/src/crypto/digests/XoodyakDigest.cs207
-rw-r--r--crypto/src/crypto/encodings/OaepEncoding.cs21
-rw-r--r--crypto/src/crypto/encodings/Pkcs1Encoding.cs20
-rw-r--r--crypto/src/crypto/engines/AesEngine.cs3
-rw-r--r--crypto/src/crypto/engines/AsconEngine.cs694
-rw-r--r--crypto/src/crypto/engines/DesEdeWrapEngine.cs27
-rw-r--r--crypto/src/crypto/engines/ElGamalEngine.cs15
-rw-r--r--crypto/src/crypto/engines/ISAPEngine.cs1036
-rw-r--r--crypto/src/crypto/engines/NaccacheSternEngine.cs8
-rw-r--r--crypto/src/crypto/engines/PhotonBeetleEngine.cs459
-rw-r--r--crypto/src/crypto/engines/RC2WrapEngine.cs256
-rw-r--r--crypto/src/crypto/engines/RFC3211WrapEngine.cs12
-rw-r--r--crypto/src/crypto/engines/RFC3394WrapEngine.cs19
-rw-r--r--crypto/src/crypto/engines/RSABlindingEngine.cs4
-rw-r--r--crypto/src/crypto/engines/RSACoreEngine.cs41
-rw-r--r--crypto/src/crypto/engines/SM2Engine.cs20
-rw-r--r--crypto/src/crypto/engines/Salsa20Engine.cs2
-rw-r--r--crypto/src/crypto/engines/XoodyakEngine.cs450
-rw-r--r--crypto/src/crypto/generators/ECKeyPairGenerator.cs68
-rw-r--r--crypto/src/crypto/macs/Poly1305.cs3
-rw-r--r--crypto/src/crypto/modes/CfbBlockCipher.cs3
-rw-r--r--crypto/src/crypto/modes/EcbBlockCipher.cs5
-rw-r--r--crypto/src/crypto/modes/GCMBlockCipher.cs41
-rw-r--r--crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs1
-rw-r--r--crypto/src/crypto/modes/SicBlockCipher.cs8
-rw-r--r--crypto/src/crypto/modes/gcm/GcmUtilities.cs6
-rw-r--r--crypto/src/crypto/operators/Asn1Signature.cs4
-rw-r--r--crypto/src/crypto/parameters/DHKeyParameters.cs2
-rw-r--r--crypto/src/crypto/parameters/DHParameters.cs2
-rw-r--r--crypto/src/crypto/parameters/DsaKeyParameters.cs2
-rw-r--r--crypto/src/crypto/parameters/ElGamalKeyParameters.cs2
-rw-r--r--crypto/src/crypto/prng/BasicEntropySourceProvider.cs2
-rw-r--r--crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs2
-rw-r--r--crypto/src/crypto/prng/CryptoApiRandomGenerator.cs10
-rw-r--r--crypto/src/crypto/prng/EntropyUtilities.cs17
-rw-r--r--crypto/src/crypto/prng/SP800SecureRandom.cs7
-rw-r--r--crypto/src/crypto/prng/X931SecureRandom.cs7
-rw-r--r--crypto/src/crypto/signers/DsaDigestSigner.cs4
-rw-r--r--crypto/src/crypto/signers/DsaSigner.cs12
-rw-r--r--crypto/src/crypto/signers/ECDsaSigner.cs12
-rw-r--r--crypto/src/crypto/signers/Ed25519phSigner.cs6
-rw-r--r--crypto/src/crypto/signers/Ed448Signer.cs1
-rw-r--r--crypto/src/crypto/signers/Ed448phSigner.cs6
-rw-r--r--crypto/src/crypto/signers/GOST3410DigestSigner.cs9
-rw-r--r--crypto/src/crypto/signers/GenericSigner.cs4
-rw-r--r--crypto/src/crypto/signers/Iso9796d2PssSigner.cs12
-rw-r--r--crypto/src/crypto/signers/IsoTrailers.cs5
-rw-r--r--crypto/src/crypto/signers/PssSigner.cs45
-rw-r--r--crypto/src/crypto/signers/RsaDigestSigner.cs6
-rw-r--r--crypto/src/crypto/signers/SM2Signer.cs15
-rw-r--r--crypto/src/crypto/signers/StandardDsaEncoding.cs4
-rw-r--r--crypto/src/crypto/signers/X931Signer.cs11
-rw-r--r--crypto/src/math/ec/ECCurve.cs146
-rw-r--r--crypto/src/math/ec/ECPoint.cs8
-rw-r--r--crypto/src/math/ec/LongArray.cs1
-rw-r--r--crypto/src/math/ec/abc/Tnaf.cs4
-rw-r--r--crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP128R1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160K1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R2Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1Curve.cs2
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1Curve.cs2
-rw-r--r--crypto/src/math/raw/Interleave.cs2
-rw-r--r--crypto/src/math/raw/Nat.cs2
-rw-r--r--crypto/src/math/raw/Nat128.cs2
-rw-r--r--crypto/src/math/raw/Nat160.cs2
-rw-r--r--crypto/src/math/raw/Nat192.cs2
-rw-r--r--crypto/src/math/raw/Nat224.cs2
-rw-r--r--crypto/src/math/raw/Nat256.cs2
-rw-r--r--crypto/src/math/raw/Nat320.cs2
-rw-r--r--crypto/src/math/raw/Nat384.cs2
-rw-r--r--crypto/src/math/raw/Nat448.cs2
-rw-r--r--crypto/src/math/raw/Nat512.cs2
-rw-r--r--crypto/src/math/raw/Nat576.cs2
-rw-r--r--crypto/src/ocsp/BasicOCSPResp.cs9
-rw-r--r--crypto/src/ocsp/OCSPReq.cs5
-rw-r--r--crypto/src/ocsp/OCSPReqGenerator.cs54
-rw-r--r--crypto/src/openpgp/PgpSignatureGenerator.cs24
-rw-r--r--crypto/src/openpgp/PgpUtilities.cs268
-rw-r--r--crypto/src/openpgp/PgpV3SignatureGenerator.cs23
-rw-r--r--crypto/src/openssl/MiscPemGenerator.cs10
-rw-r--r--crypto/src/openssl/PEMReader.cs30
-rw-r--r--crypto/src/openssl/PEMWriter.cs30
-rw-r--r--crypto/src/pkix/CertStatus.cs2
-rw-r--r--crypto/src/pkix/PkixCertPath.cs31
-rw-r--r--crypto/src/pkix/PkixCertPathBuilderResult.cs24
-rw-r--r--crypto/src/pkix/PkixCertPathChecker.cs2
-rw-r--r--crypto/src/pkix/PkixCertPathValidator.cs4
-rw-r--r--crypto/src/pkix/PkixCertPathValidatorException.cs9
-rw-r--r--crypto/src/pkix/PkixCertPathValidatorResult.cs17
-rw-r--r--crypto/src/pkix/PkixCertPathValidatorUtilities.cs69
-rw-r--r--crypto/src/pkix/PkixCrlUtilities.cs54
-rw-r--r--crypto/src/pkix/PkixNameConstraintValidator.cs27
-rw-r--r--crypto/src/pkix/PkixParameters.cs33
-rw-r--r--crypto/src/pkix/Rfc3280CertPathUtilities.cs51
-rw-r--r--crypto/src/pkix/Rfc3281CertPathUtilities.cs19
-rw-r--r--crypto/src/pqc/crypto/bike/BikeEngine.cs3
-rw-r--r--crypto/src/pqc/crypto/bike/BikeUtilities.cs39
-rw-r--r--crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs10
-rw-r--r--crypto/src/pqc/crypto/falcon/FalconNIST.cs15
-rw-r--r--crypto/src/pqc/crypto/falcon/FalconSigner.cs49
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcEngine.cs6
-rw-r--r--crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusSigner.cs10
-rw-r--r--crypto/src/security/SecureRandom.cs2
-rw-r--r--crypto/src/security/SignerUtilities.cs121
-rw-r--r--crypto/src/tls/TlsClientProtocol.cs3
-rw-r--r--crypto/src/tls/TlsExtensionsUtilities.cs5
-rw-r--r--crypto/src/tls/TlsUtilities.cs16
-rw-r--r--crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs10
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.cs2
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.cs2
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.cs2
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs12
-rw-r--r--crypto/src/util/Arrays.cs8
-rw-r--r--crypto/src/util/BigIntegers.cs40
-rw-r--r--crypto/src/util/Platform.cs7
-rw-r--r--crypto/src/util/collections/CollectionUtilities.cs13
-rw-r--r--crypto/src/util/io/LimitedInputStream.cs3
-rw-r--r--crypto/src/util/io/pem/PemHeader.cs4
-rw-r--r--crypto/src/util/io/pem/PemObject.cs18
-rw-r--r--crypto/src/util/io/pem/PemReader.cs253
-rw-r--r--crypto/src/util/io/pem/PemWriter.cs42
-rw-r--r--crypto/src/x509/AttributeCertificateHolder.cs36
-rw-r--r--crypto/src/x509/AttributeCertificateIssuer.cs15
-rw-r--r--crypto/src/x509/X509AttrCertParser.cs4
-rw-r--r--crypto/src/x509/X509Certificate.cs15
-rw-r--r--crypto/src/x509/X509CertificatePair.cs85
-rw-r--r--crypto/src/x509/X509Crl.cs10
-rw-r--r--crypto/src/x509/X509CrlEntry.cs2
-rw-r--r--crypto/src/x509/X509V1CertificateGenerator.cs2
-rw-r--r--crypto/src/x509/X509V2AttributeCertificate.cs6
-rw-r--r--crypto/src/x509/X509V2AttributeCertificateGenerator.cs2
-rw-r--r--crypto/src/x509/X509V2CRLGenerator.cs3
-rw-r--r--crypto/src/x509/X509V3CertificateGenerator.cs2
-rw-r--r--crypto/src/x509/store/X509AttrCertStoreSelector.cs24
233 files changed, 5621 insertions, 2799 deletions
diff --git a/crypto/src/asn1/ASN1StreamParser.cs b/crypto/src/asn1/ASN1StreamParser.cs
index 490b20ccf..85b890a8c 100644
--- a/crypto/src/asn1/ASN1StreamParser.cs
+++ b/crypto/src/asn1/ASN1StreamParser.cs
@@ -205,7 +205,7 @@ namespace Org.BouncyCastle.Asn1
         internal Asn1TaggedObjectParser ParseTaggedObject()
         {
             int tagHdr = _in.ReadByte();
-            if (tagHdr< 0)
+            if (tagHdr < 0)
                 return null;
 
             int tagClass = tagHdr & Asn1Tags.Private;
diff --git a/crypto/src/asn1/Asn1OutputStream.cs b/crypto/src/asn1/Asn1OutputStream.cs
index 163e3848c..1363aa676 100644
--- a/crypto/src/asn1/Asn1OutputStream.cs
+++ b/crypto/src/asn1/Asn1OutputStream.cs
@@ -1,6 +1,6 @@
 using System;
-using System.IO;
 using System.Diagnostics;
+using System.IO;
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
 using System.Buffers.Binary;
 using System.Numerics;
@@ -24,13 +24,9 @@ namespace Org.BouncyCastle.Asn1
         public static Asn1OutputStream Create(Stream output, string encoding)
         {
             if (Asn1Encodable.Der.Equals(encoding))
-            {
                 return new DerOutputStream(output);
-            }
-            else
-            {
-                return new Asn1OutputStream(output);
-            }
+
+            return new Asn1OutputStream(output);
         }
 
         internal Asn1OutputStream(Stream os)
diff --git a/crypto/src/asn1/BERSequenceGenerator.cs b/crypto/src/asn1/BERSequenceGenerator.cs
index 5ea2c9b82..64ac23c57 100644
--- a/crypto/src/asn1/BERSequenceGenerator.cs
+++ b/crypto/src/asn1/BERSequenceGenerator.cs
@@ -5,17 +5,13 @@ namespace Org.BouncyCastle.Asn1
 	public class BerSequenceGenerator
 		: BerGenerator
 	{
-		public BerSequenceGenerator(
-			Stream outStream)
+		public BerSequenceGenerator(Stream outStream)
 			: base(outStream)
 		{
 			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Sequence);
 		}
 
-		public BerSequenceGenerator(
-			Stream	outStream,
-			int		tagNo,
-			bool	isExplicit)
+		public BerSequenceGenerator(Stream outStream, int tagNo, bool isExplicit)
 			: base(outStream, tagNo, isExplicit)
 		{
 			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Sequence);
diff --git a/crypto/src/asn1/BERSetGenerator.cs b/crypto/src/asn1/BERSetGenerator.cs
index 72b1f903a..29fc37b93 100644
--- a/crypto/src/asn1/BERSetGenerator.cs
+++ b/crypto/src/asn1/BERSetGenerator.cs
@@ -5,17 +5,13 @@ namespace Org.BouncyCastle.Asn1
 	public class BerSetGenerator
 		: BerGenerator
 	{
-		public BerSetGenerator(
-			Stream outStream)
+		public BerSetGenerator(Stream outStream)
 			: base(outStream)
 		{
 			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Set);
 		}
 
-		public BerSetGenerator(
-			Stream	outStream,
-			int		tagNo,
-			bool	isExplicit)
+		public BerSetGenerator(Stream outStream, int tagNo, bool isExplicit)
 			: base(outStream, tagNo, isExplicit)
 		{
 			WriteBerHeader(Asn1Tags.Constructed | Asn1Tags.Set);
diff --git a/crypto/src/asn1/DLTaggedObjectParser.cs b/crypto/src/asn1/DLTaggedObjectParser.cs
index 3a89a69cd..75e8995be 100644
--- a/crypto/src/asn1/DLTaggedObjectParser.cs
+++ b/crypto/src/asn1/DLTaggedObjectParser.cs
@@ -71,4 +71,3 @@ namespace Org.BouncyCastle.Asn1
 		}
     }
 }
-
diff --git a/crypto/src/asn1/DerObjectIdentifier.cs b/crypto/src/asn1/DerObjectIdentifier.cs
index cb5771958..06a7b25f3 100644
--- a/crypto/src/asn1/DerObjectIdentifier.cs
+++ b/crypto/src/asn1/DerObjectIdentifier.cs
@@ -80,7 +80,7 @@ namespace Org.BouncyCastle.Asn1
 
         private const long LongLimit = (long.MaxValue >> 7) - 0x7F;
 
-        private static readonly DerObjectIdentifier[] cache = new DerObjectIdentifier[1024];
+        private static readonly DerObjectIdentifier[] Cache = new DerObjectIdentifier[1024];
 
         private readonly string identifier;
         private byte[] contents;
@@ -208,15 +208,15 @@ namespace Org.BouncyCastle.Asn1
             int hashCode = Arrays.GetHashCode(contents);
             int first = hashCode & 1023;
 
-            lock (cache)
+            lock (Cache)
             {
-                DerObjectIdentifier entry = cache[first];
+                DerObjectIdentifier entry = Cache[first];
                 if (entry != null && Arrays.AreEqual(contents, entry.GetContents()))
                 {
                     return entry;
                 }
 
-                return cache[first] = new DerObjectIdentifier(contents, clone);
+                return Cache[first] = new DerObjectIdentifier(contents, clone);
             }
         }
 
diff --git a/crypto/src/asn1/cmp/PKIFreeText.cs b/crypto/src/asn1/cmp/PKIFreeText.cs
index f3a4b8a81..f4d7e0967 100644
--- a/crypto/src/asn1/cmp/PKIFreeText.cs
+++ b/crypto/src/asn1/cmp/PKIFreeText.cs
@@ -7,13 +7,11 @@ namespace Org.BouncyCastle.Asn1.Cmp
 	{
 		public static PkiFreeText GetInstance(object obj)
 		{
+			if (obj == null)
+				return null;
 			if (obj is PkiFreeText pkiFreeText)
 				return pkiFreeText;
-
-			if (obj != null)
-                return new PkiFreeText(Asn1Sequence.GetInstance(obj));
-
-            return null;
+            return new PkiFreeText(Asn1Sequence.GetInstance(obj));
 		}
 
         public static PkiFreeText GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
@@ -21,7 +19,7 @@ namespace Org.BouncyCastle.Asn1.Cmp
             return GetInstance(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
         }
 
-        internal Asn1Sequence m_strings;
+        private readonly Asn1Sequence m_strings;
 
         internal PkiFreeText(Asn1Sequence seq)
 		{
diff --git a/crypto/src/asn1/cmp/PKIHeader.cs b/crypto/src/asn1/cmp/PKIHeader.cs
index 7ed914e6a..7db9cde1d 100644
--- a/crypto/src/asn1/cmp/PKIHeader.cs
+++ b/crypto/src/asn1/cmp/PKIHeader.cs
@@ -76,13 +76,13 @@ namespace Org.BouncyCastle.Asn1.Cmp
 
         public static PkiHeader GetInstance(object obj)
         {
-            if (obj is PkiHeader)
-                return (PkiHeader)obj;
+            if (obj is PkiHeader pkiHeader)
+                return pkiHeader;
 
-            if (obj is Asn1Sequence)
-                return new PkiHeader((Asn1Sequence)obj);
+            if (obj is Asn1Sequence asn1Sequence)
+                return new PkiHeader(asn1Sequence);
 
-            throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+            throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), nameof(obj));
         }
 
         public PkiHeader(
@@ -160,16 +160,7 @@ namespace Org.BouncyCastle.Asn1.Cmp
 
         public virtual InfoTypeAndValue[] GetGeneralInfo()
         {
-            if (generalInfo == null)
-            {
-                return null;
-            }
-            InfoTypeAndValue[] results = new InfoTypeAndValue[generalInfo.Count];
-            for (int i = 0; i < results.Length; i++)
-            {
-                results[i] = InfoTypeAndValue.GetInstance(generalInfo[i]);
-            }
-            return results;
+            return generalInfo?.MapElements(InfoTypeAndValue.GetInstance);
         }
 
         /**
diff --git a/crypto/src/asn1/cmp/PKIHeaderBuilder.cs b/crypto/src/asn1/cmp/PKIHeaderBuilder.cs
index cbefc73b8..ab8db958a 100644
--- a/crypto/src/asn1/cmp/PKIHeaderBuilder.cs
+++ b/crypto/src/asn1/cmp/PKIHeaderBuilder.cs
@@ -189,15 +189,15 @@ namespace Org.BouncyCastle.Asn1.Cmp
 		public virtual PkiHeader Build()
 		{
 			Asn1EncodableVector v = new Asn1EncodableVector(pvno, sender, recipient);
-			AddOptional(v, 0, messageTime);
-			AddOptional(v, 1, protectionAlg);
-			AddOptional(v, 2, senderKID);
-			AddOptional(v, 3, recipKID);
-			AddOptional(v, 4, transactionID);
-			AddOptional(v, 5, senderNonce);
-			AddOptional(v, 6, recipNonce);
-			AddOptional(v, 7, freeText);
-			AddOptional(v, 8, generalInfo);
+            v.AddOptionalTagged(true, 0, messageTime);
+            v.AddOptionalTagged(true, 1, protectionAlg);
+			v.AddOptionalTagged(true, 2, senderKID);
+			v.AddOptionalTagged(true, 3, recipKID);
+			v.AddOptionalTagged(true, 4, transactionID);
+			v.AddOptionalTagged(true, 5, senderNonce);
+			v.AddOptionalTagged(true, 6, recipNonce);
+			v.AddOptionalTagged(true, 7, freeText);
+			v.AddOptionalTagged(true, 8, generalInfo);
 
 			messageTime = null;
 			protectionAlg = null;
@@ -211,13 +211,5 @@ namespace Org.BouncyCastle.Asn1.Cmp
 
 			return PkiHeader.GetInstance(new DerSequence(v));
 		}
-
-		private void AddOptional(Asn1EncodableVector v, int tagNo, Asn1Encodable obj)
-		{
-			if (obj != null)
-			{
-				v.Add(new DerTaggedObject(true, tagNo, obj));
-			}
-		}
 	}
 }
diff --git a/crypto/src/asn1/cmp/PKIMessage.cs b/crypto/src/asn1/cmp/PKIMessage.cs
index c87bf2126..9ac54b3da 100644
--- a/crypto/src/asn1/cmp/PKIMessage.cs
+++ b/crypto/src/asn1/cmp/PKIMessage.cs
@@ -96,15 +96,7 @@ namespace Org.BouncyCastle.Asn1.Cmp
 
         public virtual CmpCertificate[] GetExtraCerts()
         {
-            if (extraCerts == null)
-                return null;
-
-            CmpCertificate[] results = new CmpCertificate[extraCerts.Count];
-            for (int i = 0; i < results.Length; ++i)
-            {
-                results[i] = CmpCertificate.GetInstance(extraCerts[i]);
-            }
-            return results;
+            return extraCerts?.MapElements(CmpCertificate.GetInstance);
         }
 
         /**
diff --git a/crypto/src/asn1/cmp/PKIMessages.cs b/crypto/src/asn1/cmp/PKIMessages.cs
index 0008f476a..8e2e8a1ed 100644
--- a/crypto/src/asn1/cmp/PKIMessages.cs
+++ b/crypto/src/asn1/cmp/PKIMessages.cs
@@ -7,37 +7,32 @@ namespace Org.BouncyCastle.Asn1.Cmp
     public class PkiMessages
         : Asn1Encodable
     {
-        private Asn1Sequence content;
+        private Asn1Sequence m_content;
 
         internal PkiMessages(Asn1Sequence seq)
         {
-            content = seq;
+            m_content = seq;
         }
 
         public static PkiMessages GetInstance(object obj)
         {
-            if (obj is PkiMessages)
-                return (PkiMessages)obj;
+            if (obj is PkiMessages pkiMessages)
+                return pkiMessages;
 
-            if (obj is Asn1Sequence)
-                return new PkiMessages((Asn1Sequence)obj);
+            if (obj is Asn1Sequence asn1Sequence)
+                return new PkiMessages(asn1Sequence);
 
-            throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), "obj");
+            throw new ArgumentException("Invalid object: " + Platform.GetTypeName(obj), nameof(obj));
         }
 
 		public PkiMessages(params PkiMessage[] msgs)
         {
-            content = new DerSequence(msgs);
+            m_content = new DerSequence(msgs);
         }
 
         public virtual PkiMessage[] ToPkiMessageArray()
         {
-            PkiMessage[] result = new PkiMessage[content.Count];
-            for (int i = 0; i != result.Length; ++i)
-            {
-                result[i] = PkiMessage.GetInstance(content[i]);
-            }
-            return result;
+            return m_content.MapElements(PkiMessage.GetInstance);
         }
 
         /**
@@ -48,7 +43,7 @@ namespace Org.BouncyCastle.Asn1.Cmp
          */
         public override Asn1Object ToAsn1Object()
         {
-            return content;
+            return m_content;
         }
     }
 }
diff --git a/crypto/src/asn1/cms/CMSAttributes.cs b/crypto/src/asn1/cms/CMSAttributes.cs
index fca2b6738..a3e11db84 100644
--- a/crypto/src/asn1/cms/CMSAttributes.cs
+++ b/crypto/src/asn1/cms/CMSAttributes.cs
@@ -10,5 +10,7 @@ namespace Org.BouncyCastle.Asn1.Cms
         public static readonly DerObjectIdentifier SigningTime		= PkcsObjectIdentifiers.Pkcs9AtSigningTime;
 		public static readonly DerObjectIdentifier CounterSignature = PkcsObjectIdentifiers.Pkcs9AtCounterSignature;
 		public static readonly DerObjectIdentifier ContentHint		= PkcsObjectIdentifiers.IdAAContentHint;
+        public static readonly DerObjectIdentifier CmsAlgorithmProtect = PkcsObjectIdentifiers.id_aa_cmsAlgorithmProtect;
+
 	}
 }
diff --git a/crypto/src/asn1/cms/CmsAlgorithmProtection.cs b/crypto/src/asn1/cms/CmsAlgorithmProtection.cs
new file mode 100644
index 000000000..9d21e53ff
--- /dev/null
+++ b/crypto/src/asn1/cms/CmsAlgorithmProtection.cs
@@ -0,0 +1,105 @@
+using System;
+
+using Org.BouncyCastle.Asn1.X509;
+
+namespace Org.BouncyCastle.Asn1.Cms
+{
+
+    /**
+     * From RFC 6211
+     * <pre>
+     * CMSAlgorithmProtection ::= SEQUENCE {
+     *    digestAlgorithm         DigestAlgorithmIdentifier,
+     *    signatureAlgorithm  [1] SignatureAlgorithmIdentifier OPTIONAL,
+     *    macAlgorithm        [2] MessageAuthenticationCodeAlgorithm
+     *                                     OPTIONAL
+     * }
+     * (WITH COMPONENTS { signatureAlgorithm PRESENT,
+     *                    macAlgorithm ABSENT } |
+     *  WITH COMPONENTS { signatureAlgorithm ABSENT,
+     *                    macAlgorithm PRESENT })
+     * </pre>
+     */
+    public class CmsAlgorithmProtection
+        : Asn1Encodable
+    {
+        public static readonly int Signature = 1;
+        public static readonly int Mac = 2;
+
+        private readonly AlgorithmIdentifier digestAlgorithm;
+        private readonly AlgorithmIdentifier signatureAlgorithm;
+        private readonly AlgorithmIdentifier macAlgorithm;
+
+        public CmsAlgorithmProtection(AlgorithmIdentifier digestAlgorithm, int type, AlgorithmIdentifier algorithmIdentifier)
+        {
+            if (digestAlgorithm == null || algorithmIdentifier == null)
+                throw new ArgumentException("AlgorithmIdentifiers cannot be null");
+
+            this.digestAlgorithm = digestAlgorithm;
+
+            if (type == 1)
+            {
+                this.signatureAlgorithm = algorithmIdentifier;
+                this.macAlgorithm = null;
+            }
+            else if (type == 2)
+            {
+                this.signatureAlgorithm = null;
+                this.macAlgorithm = algorithmIdentifier;
+            }
+            else
+            {
+                throw new ArgumentException("Unknown type: " + type);
+            }
+        }
+
+        private CmsAlgorithmProtection(Asn1Sequence sequence)
+        {
+            if (sequence.Count != 2)
+                throw new ArgumentException("Sequence wrong size: One of signatureAlgorithm or macAlgorithm must be present");
+
+            this.digestAlgorithm = AlgorithmIdentifier.GetInstance(sequence[0]);
+
+            Asn1TaggedObject tagged = Asn1TaggedObject.GetInstance(sequence[1]);
+            if (tagged.TagNo == 1)
+            {
+                this.signatureAlgorithm = AlgorithmIdentifier.GetInstance(tagged, false);
+                this.macAlgorithm = null;
+            }
+            else if (tagged.TagNo == 2)
+            {
+                this.signatureAlgorithm = null;
+
+                this.macAlgorithm = AlgorithmIdentifier.GetInstance(tagged, false);
+            }
+            else
+            {
+                throw new ArgumentException("Unknown tag found: " + tagged.TagNo);
+            }
+        }
+
+        public static CmsAlgorithmProtection GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is CmsAlgorithmProtection cmsAlgorithmProtection)
+                return cmsAlgorithmProtection;
+            return new CmsAlgorithmProtection(Asn1Sequence.GetInstance(obj));
+        }
+
+        public AlgorithmIdentifier DigestAlgorithm => digestAlgorithm;
+
+        public AlgorithmIdentifier MacAlgorithm => macAlgorithm;
+
+        public AlgorithmIdentifier SignatureAlgorithm => signatureAlgorithm;
+
+        public override Asn1Object ToAsn1Object()
+        {
+            Asn1EncodableVector v = new Asn1EncodableVector(3);
+            v.Add(digestAlgorithm);
+            v.AddOptionalTagged(false, 1, signatureAlgorithm);
+            v.AddOptionalTagged(false, 2, macAlgorithm);
+            return new DerSequence(v);
+        }
+    }
+}
diff --git a/crypto/src/asn1/cms/ContentInfoParser.cs b/crypto/src/asn1/cms/ContentInfoParser.cs
index 750d8ba7a..e423be848 100644
--- a/crypto/src/asn1/cms/ContentInfoParser.cs
+++ b/crypto/src/asn1/cms/ContentInfoParser.cs
@@ -22,10 +22,7 @@ namespace Org.BouncyCastle.Asn1.Cms
 			m_content = (Asn1TaggedObjectParser)seq.ReadObject();
 		}
 
-		public DerObjectIdentifier ContentType
-		{
-			get { return m_contentType; }
-		}
+		public DerObjectIdentifier ContentType => m_contentType;
 
 		public IAsn1Convertible GetContent(int tag)
 		{
diff --git a/crypto/src/asn1/cms/EncryptedContentInfoParser.cs b/crypto/src/asn1/cms/EncryptedContentInfoParser.cs
index 09434d7ef..42f72164a 100644
--- a/crypto/src/asn1/cms/EncryptedContentInfoParser.cs
+++ b/crypto/src/asn1/cms/EncryptedContentInfoParser.cs
@@ -15,32 +15,24 @@ namespace Org.BouncyCastle.Asn1.Cms
 	*/
 	public class EncryptedContentInfoParser
 	{
-		private DerObjectIdentifier		_contentType;
-		private AlgorithmIdentifier		_contentEncryptionAlgorithm;
-		private Asn1TaggedObjectParser	_encryptedContent;
+		private readonly DerObjectIdentifier m_contentType;
+		private readonly AlgorithmIdentifier m_contentEncryptionAlgorithm;
+		private readonly Asn1TaggedObjectParser	m_encryptedContent;
 
-		public EncryptedContentInfoParser(
-			Asn1SequenceParser seq)
+		public EncryptedContentInfoParser(Asn1SequenceParser seq)
 		{
-			_contentType = (DerObjectIdentifier)seq.ReadObject();
-			_contentEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq.ReadObject().ToAsn1Object());
-			_encryptedContent = (Asn1TaggedObjectParser)seq.ReadObject();
+			m_contentType = (DerObjectIdentifier)seq.ReadObject();
+			m_contentEncryptionAlgorithm = AlgorithmIdentifier.GetInstance(seq.ReadObject().ToAsn1Object());
+			m_encryptedContent = (Asn1TaggedObjectParser)seq.ReadObject();
 		}
 
-		public DerObjectIdentifier ContentType
-		{
-			get { return _contentType; }
-		}
+		public DerObjectIdentifier ContentType => m_contentType;
 
-		public AlgorithmIdentifier ContentEncryptionAlgorithm
-		{
-			get { return _contentEncryptionAlgorithm; }
-		}
+		public AlgorithmIdentifier ContentEncryptionAlgorithm => m_contentEncryptionAlgorithm;
 
-		public IAsn1Convertible GetEncryptedContent(
-			int tag)
+		public IAsn1Convertible GetEncryptedContent(int tag)
 		{
-			return Asn1Utilities.ParseContextBaseUniversal(_encryptedContent, 0, false, tag);
+			return Asn1Utilities.ParseContextBaseUniversal(m_encryptedContent, 0, false, tag);
 		}
 	}
 }
diff --git a/crypto/src/asn1/cms/EnvelopedDataParser.cs b/crypto/src/asn1/cms/EnvelopedDataParser.cs
index a86608bb4..06e10c104 100644
--- a/crypto/src/asn1/cms/EnvelopedDataParser.cs
+++ b/crypto/src/asn1/cms/EnvelopedDataParser.cs
@@ -2,7 +2,7 @@ using System;
 
 namespace Org.BouncyCastle.Asn1.Cms
 {
-	/**
+    /**
 	* Produce an object suitable for an Asn1OutputStream.
 	* <pre>
 	* EnvelopedData ::= SEQUENCE {
@@ -14,96 +14,96 @@ namespace Org.BouncyCastle.Asn1.Cms
 	* }
 	* </pre>
 	*/
-	public class EnvelopedDataParser
-	{
-		private Asn1SequenceParser	_seq;
-		private DerInteger			_version;
-		private IAsn1Convertible	_nextObject;
-		private bool				_originatorInfoCalled;
-
-		public EnvelopedDataParser(
-			Asn1SequenceParser seq)
-		{
-			this._seq = seq;
-			this._version = (DerInteger)seq.ReadObject();
-		}
-
-		public DerInteger Version
-		{
-			get { return _version; }
-		}
-
-		public OriginatorInfo GetOriginatorInfo() 
-		{
-			_originatorInfoCalled = true; 
-
-			if (_nextObject == null)
-			{
-				_nextObject = _seq.ReadObject();
-			}
-
-			if (_nextObject is Asn1TaggedObjectParser o)
-			{
-				if (o.HasContextTag(0))
-				{
-					Asn1SequenceParser originatorInfo = (Asn1SequenceParser)o.ParseBaseUniversal(false, Asn1Tags.Sequence);
-					_nextObject = null;
-					return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
-				}
-			}
-
-			return null;
-		}
-
-		public Asn1SetParser GetRecipientInfos()
-		{
-			if (!_originatorInfoCalled)
-			{
-				GetOriginatorInfo();
-			}
-
-			if (_nextObject == null)
-			{
-				_nextObject = _seq.ReadObject();
-			}
-
-			Asn1SetParser recipientInfos = (Asn1SetParser)_nextObject;
-			_nextObject = null;
-			return recipientInfos;
-		}
-
-		public EncryptedContentInfoParser GetEncryptedContentInfo()
-		{
-			if (_nextObject == null)
-			{
-				_nextObject = _seq.ReadObject();
-			}
-
-			if (_nextObject != null)
-			{
-				Asn1SequenceParser o = (Asn1SequenceParser) _nextObject;
-				_nextObject = null;
-				return new EncryptedContentInfoParser(o);
-			}
-
-			return null;
-		}
-
-		public Asn1SetParser GetUnprotectedAttrs()
-		{
-			if (_nextObject == null)
-			{
-				_nextObject = _seq.ReadObject();
-			}
-
-			if (_nextObject != null)
-			{
-				Asn1TaggedObjectParser o = (Asn1TaggedObjectParser)_nextObject;
-				_nextObject = null;
-				return (Asn1SetParser)Asn1Utilities.ParseContextBaseUniversal(o, 1, false, Asn1Tags.SetOf);
-			}
-
-			return null;
-		}
-	}
+    public class EnvelopedDataParser
+    {
+        private Asn1SequenceParser _seq;
+        private DerInteger _version;
+        private IAsn1Convertible _nextObject;
+        private bool _originatorInfoCalled;
+
+        public EnvelopedDataParser(
+            Asn1SequenceParser seq)
+        {
+            this._seq = seq;
+            this._version = (DerInteger)seq.ReadObject();
+        }
+
+        public DerInteger Version
+        {
+            get { return _version; }
+        }
+
+        public OriginatorInfo GetOriginatorInfo()
+        {
+            _originatorInfoCalled = true;
+
+            if (_nextObject == null)
+            {
+                _nextObject = _seq.ReadObject();
+            }
+
+            if (_nextObject is Asn1TaggedObjectParser o)
+            {
+                if (o.HasContextTag(0))
+                {
+                    Asn1SequenceParser originatorInfo = (Asn1SequenceParser)o.ParseBaseUniversal(false, Asn1Tags.Sequence);
+                    _nextObject = null;
+                    return OriginatorInfo.GetInstance(originatorInfo.ToAsn1Object());
+                }
+            }
+
+            return null;
+        }
+
+        public Asn1SetParser GetRecipientInfos()
+        {
+            if (!_originatorInfoCalled)
+            {
+                GetOriginatorInfo();
+            }
+
+            if (_nextObject == null)
+            {
+                _nextObject = _seq.ReadObject();
+            }
+
+            Asn1SetParser recipientInfos = (Asn1SetParser)_nextObject;
+            _nextObject = null;
+            return recipientInfos;
+        }
+
+        public EncryptedContentInfoParser GetEncryptedContentInfo()
+        {
+            if (_nextObject == null)
+            {
+                _nextObject = _seq.ReadObject();
+            }
+
+            if (_nextObject != null)
+            {
+                Asn1SequenceParser o = (Asn1SequenceParser)_nextObject;
+                _nextObject = null;
+                return new EncryptedContentInfoParser(o);
+            }
+
+            return null;
+        }
+
+        public Asn1SetParser GetUnprotectedAttrs()
+        {
+            if (_nextObject == null)
+            {
+                _nextObject = _seq.ReadObject();
+            }
+
+            if (_nextObject != null)
+            {
+                Asn1TaggedObjectParser o = (Asn1TaggedObjectParser)_nextObject;
+                _nextObject = null;
+                return (Asn1SetParser)Asn1Utilities.ParseContextBaseUniversal(o, 1, false, Asn1Tags.SetOf);
+            }
+
+            return null;
+        }
+    }
 }
diff --git a/crypto/src/asn1/cms/KEKIdentifier.cs b/crypto/src/asn1/cms/KEKIdentifier.cs
index 36ab94f52..70ae8c438 100644
--- a/crypto/src/asn1/cms/KEKIdentifier.cs
+++ b/crypto/src/asn1/cms/KEKIdentifier.cs
@@ -21,19 +21,18 @@ namespace Org.BouncyCastle.Asn1.Cms
             this.other = other;
         }
 
-		public KekIdentifier(
-            Asn1Sequence seq)
+		public KekIdentifier(Asn1Sequence seq)
         {
-            keyIdentifier = (Asn1OctetString) seq[0];
+            keyIdentifier = (Asn1OctetString)seq[0];
 
 			switch (seq.Count)
             {
             case 1:
 				break;
             case 2:
-				if (seq[1] is Asn1GeneralizedTime)
+				if (seq[1] is Asn1GeneralizedTime asn1GeneralizedTime)
 				{
-					date = (Asn1GeneralizedTime) seq[1];
+					date = asn1GeneralizedTime;
 				}
 				else
 				{
@@ -41,7 +40,7 @@ namespace Org.BouncyCastle.Asn1.Cms
 				}
 				break;
             case 3:
-				date  = (Asn1GeneralizedTime) seq[1];
+				date = (Asn1GeneralizedTime)seq[1];
 				other = OtherKeyAttribute.GetInstance(seq[2]);
 				break;
             default:
diff --git a/crypto/src/asn1/cms/RecipientKeyIdentifier.cs b/crypto/src/asn1/cms/RecipientKeyIdentifier.cs
index dea9ce09d..512025808 100644
--- a/crypto/src/asn1/cms/RecipientKeyIdentifier.cs
+++ b/crypto/src/asn1/cms/RecipientKeyIdentifier.cs
@@ -37,20 +37,18 @@ namespace Org.BouncyCastle.Asn1.Cms
 			this.other = other;
 		}
 
-		public RecipientKeyIdentifier(
-            Asn1Sequence seq)
+		public RecipientKeyIdentifier(Asn1Sequence seq)
         {
-            subjectKeyIdentifier = Asn1OctetString.GetInstance(
-				seq[0]);
+            subjectKeyIdentifier = Asn1OctetString.GetInstance(seq[0]);
 
 			switch(seq.Count)
             {
 				case 1:
 					break;
 				case 2:
-					if (seq[1] is Asn1GeneralizedTime)
+					if (seq[1] is Asn1GeneralizedTime asn1GeneralizedTime)
 					{
-						date = (Asn1GeneralizedTime)seq[1];
+						date = asn1GeneralizedTime;
 					}
 					else
 					{
@@ -58,7 +56,7 @@ namespace Org.BouncyCastle.Asn1.Cms
 					}
 					break;
 				case 3:
-					date  = (Asn1GeneralizedTime)seq[1];
+					date = (Asn1GeneralizedTime)seq[1];
 					other = OtherKeyAttribute.GetInstance(seq[2]);
 					break;
 				default:
diff --git a/crypto/src/asn1/cms/SignedData.cs b/crypto/src/asn1/cms/SignedData.cs
index 789f8bd72..6b07e5128 100644
--- a/crypto/src/asn1/cms/SignedData.cs
+++ b/crypto/src/asn1/cms/SignedData.cs
@@ -24,8 +24,8 @@ namespace Org.BouncyCastle.Asn1.Cms
 
         public static SignedData GetInstance(object obj)
         {
-            if (obj is SignedData)
-                return (SignedData)obj;
+            if (obj is SignedData signedData)
+                return signedData;
             if (obj == null)
                 return null;
             return new SignedData(Asn1Sequence.GetInstance(obj));
diff --git a/crypto/src/asn1/cms/SignedDataParser.cs b/crypto/src/asn1/cms/SignedDataParser.cs
index 64114f292..3afbe09f4 100644
--- a/crypto/src/asn1/cms/SignedDataParser.cs
+++ b/crypto/src/asn1/cms/SignedDataParser.cs
@@ -5,7 +5,7 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Cms
 {
-	/**
+    /**
 	* <pre>
 	* SignedData ::= SEQUENCE {
 	*     version CMSVersion,
@@ -17,102 +17,102 @@ namespace Org.BouncyCastle.Asn1.Cms
 	*   }
 	* </pre>
 	*/
-	public class SignedDataParser
-	{
-		private Asn1SequenceParser	_seq;
-		private DerInteger			_version;
-		private object				_nextObject;
-		private bool				_certsCalled;
-		private bool				_crlsCalled;
-
-		public static SignedDataParser GetInstance(
-			object o)
-		{
-			if (o is Asn1Sequence)
-				return new SignedDataParser(((Asn1Sequence)o).Parser);
-
-			if (o is Asn1SequenceParser)
-				return new SignedDataParser((Asn1SequenceParser)o);
+    public class SignedDataParser
+    {
+        private Asn1SequenceParser _seq;
+        private DerInteger _version;
+        private object _nextObject;
+        private bool _certsCalled;
+        private bool _crlsCalled;
+
+        public static SignedDataParser GetInstance(
+            object o)
+        {
+            if (o is Asn1Sequence)
+                return new SignedDataParser(((Asn1Sequence)o).Parser);
+
+            if (o is Asn1SequenceParser)
+                return new SignedDataParser((Asn1SequenceParser)o);
 
             throw new IOException("unknown object encountered: " + Platform.GetTypeName(o));
-		}
-
-		public SignedDataParser(
-			Asn1SequenceParser seq)
-		{
-			this._seq = seq;
-			this._version = (DerInteger)seq.ReadObject();
-		}
-
-		public DerInteger Version
-		{
-			get { return _version; }
-		}
-
-		public Asn1SetParser GetDigestAlgorithms()
-		{
-			return (Asn1SetParser)_seq.ReadObject();
-		}
-
-		public ContentInfoParser GetEncapContentInfo()
-		{
-			return new ContentInfoParser((Asn1SequenceParser)_seq.ReadObject());
-		}
-
-		public Asn1SetParser GetCertificates()
-		{
-			_certsCalled = true;
-			_nextObject = _seq.ReadObject();
-
-			if (_nextObject is Asn1TaggedObjectParser o)
-			{
-				if (o.HasContextTag(0))
-				{
-					Asn1SetParser certs = (Asn1SetParser)o.ParseBaseUniversal(false, Asn1Tags.SetOf);
-					_nextObject = null;
-					return certs;
-				}
-			}
-
-			return null;
-		}
-
-		public Asn1SetParser GetCrls()
-		{
-			if (!_certsCalled)
-				throw new IOException("GetCerts() has not been called.");
-
-			_crlsCalled = true;
-
-			if (_nextObject == null)
-			{
-				_nextObject = _seq.ReadObject();
-			}
-
-			if (_nextObject is Asn1TaggedObjectParser o)
-			{
-				if (o.HasContextTag(1))
-				{
-					Asn1SetParser crls = (Asn1SetParser)o.ParseBaseUniversal(false, Asn1Tags.SetOf);
-					_nextObject = null;
-					return crls;
-				}
-			}
+        }
+
+        public SignedDataParser(
+            Asn1SequenceParser seq)
+        {
+            this._seq = seq;
+            this._version = (DerInteger)seq.ReadObject();
+        }
+
+        public DerInteger Version
+        {
+            get { return _version; }
+        }
+
+        public Asn1SetParser GetDigestAlgorithms()
+        {
+            return (Asn1SetParser)_seq.ReadObject();
+        }
+
+        public ContentInfoParser GetEncapContentInfo()
+        {
+            return new ContentInfoParser((Asn1SequenceParser)_seq.ReadObject());
+        }
+
+        public Asn1SetParser GetCertificates()
+        {
+            _certsCalled = true;
+            _nextObject = _seq.ReadObject();
+
+            if (_nextObject is Asn1TaggedObjectParser o)
+            {
+                if (o.HasContextTag(0))
+                {
+                    Asn1SetParser certs = (Asn1SetParser)o.ParseBaseUniversal(false, Asn1Tags.SetOf);
+                    _nextObject = null;
+                    return certs;
+                }
+            }
 
             return null;
         }
 
-		public Asn1SetParser GetSignerInfos()
-		{
-			if (!_certsCalled || !_crlsCalled)
-				throw new IOException("GetCerts() and/or GetCrls() has not been called.");
+        public Asn1SetParser GetCrls()
+        {
+            if (!_certsCalled)
+                throw new IOException("GetCerts() has not been called.");
+
+            _crlsCalled = true;
+
+            if (_nextObject == null)
+            {
+                _nextObject = _seq.ReadObject();
+            }
 
-			if (_nextObject == null)
-			{
-				_nextObject = _seq.ReadObject();
-			}
+            if (_nextObject is Asn1TaggedObjectParser o)
+            {
+                if (o.HasContextTag(1))
+                {
+                    Asn1SetParser crls = (Asn1SetParser)o.ParseBaseUniversal(false, Asn1Tags.SetOf);
+                    _nextObject = null;
+                    return crls;
+                }
+            }
 
-			return (Asn1SetParser)_nextObject;
-		}
-	}
+            return null;
+        }
+
+        public Asn1SetParser GetSignerInfos()
+        {
+            if (!_certsCalled || !_crlsCalled)
+                throw new IOException("GetCerts() and/or GetCrls() has not been called.");
+
+            if (_nextObject == null)
+            {
+                _nextObject = _seq.ReadObject();
+            }
+
+            return (Asn1SetParser)_nextObject;
+        }
+    }
 }
diff --git a/crypto/src/asn1/cms/Time.cs b/crypto/src/asn1/cms/Time.cs
index 7b6b49c30..19bc1a633 100644
--- a/crypto/src/asn1/cms/Time.cs
+++ b/crypto/src/asn1/cms/Time.cs
@@ -31,7 +31,7 @@ namespace Org.BouncyCastle.Asn1.Cms
 
         public Time(Asn1GeneralizedTime generalizedTime)
         {
-            this.m_timeObject = generalizedTime ?? throw new ArgumentNullException(nameof(generalizedTime));
+            m_timeObject = generalizedTime ?? throw new ArgumentNullException(nameof(generalizedTime));
         }
 
         public Time(Asn1UtcTime utcTime)
@@ -42,7 +42,7 @@ namespace Org.BouncyCastle.Asn1.Cms
             // Validate utcTime is in the appropriate year range
             utcTime.ToDateTime(2049);
 
-            this.m_timeObject = utcTime;
+            m_timeObject = utcTime;
         }
 
 		/**
diff --git a/crypto/src/asn1/crmf/CertTemplateBuilder.cs b/crypto/src/asn1/crmf/CertTemplateBuilder.cs
index 51c73c4e1..d26e6399c 100644
--- a/crypto/src/asn1/crmf/CertTemplateBuilder.cs
+++ b/crypto/src/asn1/crmf/CertTemplateBuilder.cs
@@ -99,27 +99,17 @@ namespace Org.BouncyCastle.Asn1.Crmf
         public virtual CertTemplate Build()
         {
             Asn1EncodableVector v = new Asn1EncodableVector();
-
-            AddOptional(v, 0, false, version);
-            AddOptional(v, 1, false, serialNumber);
-            AddOptional(v, 2, false, signingAlg);
-            AddOptional(v, 3, true, issuer); // CHOICE
-            AddOptional(v, 4, false, validity);
-            AddOptional(v, 5, true, subject); // CHOICE
-            AddOptional(v, 6, false, publicKey);
-            AddOptional(v, 7, false, issuerUID);
-            AddOptional(v, 8, false, subjectUID);
-            AddOptional(v, 9, false, extensions);
-
+            v.AddOptionalTagged(false, 0, version);
+            v.AddOptionalTagged(false, 1, serialNumber);
+            v.AddOptionalTagged(false, 2, signingAlg);
+            v.AddOptionalTagged(true, 3, issuer); // CHOICE
+            v.AddOptionalTagged(false, 4, validity);
+            v.AddOptionalTagged(true, 5, subject); // CHOICE
+            v.AddOptionalTagged(false, 6, publicKey);
+            v.AddOptionalTagged(false, 7, issuerUID);
+            v.AddOptionalTagged(false, 8, subjectUID);
+            v.AddOptionalTagged(false, 9, extensions);
             return CertTemplate.GetInstance(new DerSequence(v));
         }
-
-        private void AddOptional(Asn1EncodableVector v, int tagNo, bool isExplicit, Asn1Encodable obj)
-        {
-            if (obj != null)
-            {
-                v.Add(new DerTaggedObject(isExplicit, tagNo, obj));
-            }
-        }
     }
 }
diff --git a/crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs b/crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs
index 87df3c4a9..2c494c526 100644
--- a/crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs
+++ b/crypto/src/asn1/cryptopro/ECGOST3410ParamSetParameters.cs
@@ -18,9 +18,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
         public static ECGost3410ParamSetParameters GetInstance(object obj)
         {
             if (obj == null || obj is ECGost3410ParamSetParameters)
-            {
-                return (ECGost3410ParamSetParameters) obj;
-            }
+                return (ECGost3410ParamSetParameters)obj;
 
             if (obj is Asn1Sequence seq)
                 return new ECGost3410ParamSetParameters(seq);
diff --git a/crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs b/crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs
index c82e4248a..ae0cd4f83 100644
--- a/crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs
+++ b/crypto/src/asn1/cryptopro/GOST3410ParamSetParameters.cs
@@ -27,11 +27,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
             throw new ArgumentException("Invalid GOST3410Parameter: " + Platform.GetTypeName(obj));
         }
 
-		public Gost3410ParamSetParameters(
-            int			keySize,
-            BigInteger	p,
-            BigInteger	q,
-            BigInteger	a)
+		public Gost3410ParamSetParameters(int keySize, BigInteger p, BigInteger q, BigInteger a)
         {
             this.keySize = keySize;
             this.p = new DerInteger(p);
@@ -39,8 +35,7 @@ namespace Org.BouncyCastle.Asn1.CryptoPro
             this.a = new DerInteger(a);
         }
 
-		private Gost3410ParamSetParameters(
-            Asn1Sequence seq)
+		private Gost3410ParamSetParameters(Asn1Sequence seq)
         {
 			if (seq.Count != 4)
 				throw new ArgumentException("Wrong number of elements in sequence", "seq");
diff --git a/crypto/src/asn1/esf/CertificateValues.cs b/crypto/src/asn1/esf/CertificateValues.cs
index ee0d2830c..8329e45f8 100644
--- a/crypto/src/asn1/esf/CertificateValues.cs
+++ b/crypto/src/asn1/esf/CertificateValues.cs
@@ -15,69 +15,58 @@ namespace Org.BouncyCastle.Asn1.Esf
 	public class CertificateValues
 		: Asn1Encodable
 	{
-		private readonly Asn1Sequence certificates;
+		private readonly Asn1Sequence m_certificates;
 
-		public static CertificateValues GetInstance(
-			object obj)
+		public static CertificateValues GetInstance(object obj)
 		{
-			if (obj == null || obj is CertificateValues)
-				return (CertificateValues) obj;
+			if (obj == null)
+				return null;
 
-			if (obj is Asn1Sequence)
-				return new CertificateValues((Asn1Sequence) obj);
+			if (obj is CertificateValues certificateValues)
+				return certificateValues;
 
-			throw new ArgumentException(
-				"Unknown object in 'CertificateValues' factory: "
-                    + Platform.GetTypeName(obj),
-				"obj");
+			if (obj is Asn1Sequence asn1Sequence)
+				return new CertificateValues(asn1Sequence);
+
+			throw new ArgumentException("Unknown object in 'CertificateValues' factory: " + Platform.GetTypeName(obj),
+				nameof(obj));
 		}
 
-		private CertificateValues(
-			Asn1Sequence seq)
+		private CertificateValues(Asn1Sequence seq)
 		{
 			if (seq == null)
-				throw new ArgumentNullException("seq");
+				throw new ArgumentNullException(nameof(seq));
 
-			foreach (Asn1Encodable ae in seq)
-			{
-				X509CertificateStructure.GetInstance(ae.ToAsn1Object());
-			}
+			// Validate
+            seq.MapElements(element => X509CertificateStructure.GetInstance(element.ToAsn1Object()));
 
-			this.certificates = seq;
+			m_certificates = seq;
 		}
 
-		public CertificateValues(
-			params X509CertificateStructure[] certificates)
+		public CertificateValues(params X509CertificateStructure[] certificates)
 		{
 			if (certificates == null)
-				throw new ArgumentNullException("certificates");
+				throw new ArgumentNullException(nameof(certificates));
 
-			this.certificates = new DerSequence(certificates);
+			m_certificates = new DerSequence(certificates);
 		}
 
-		public CertificateValues(
-			IEnumerable<X509CertificateStructure> certificates)
+		public CertificateValues(IEnumerable<X509CertificateStructure> certificates)
 		{
 			if (certificates == null)
-				throw new ArgumentNullException("certificates");
+                throw new ArgumentNullException(nameof(certificates));
 
-			this.certificates = new DerSequence(
-				Asn1EncodableVector.FromEnumerable(certificates));
+            m_certificates = new DerSequence(Asn1EncodableVector.FromEnumerable(certificates));
 		}
 
 		public X509CertificateStructure[] GetCertificates()
 		{
-			X509CertificateStructure[] result = new X509CertificateStructure[certificates.Count];
-			for (int i = 0; i < certificates.Count; ++i)
-			{
-				result[i] = X509CertificateStructure.GetInstance(certificates[i]);
-			}
-			return result;
+			return m_certificates.MapElements(element => X509CertificateStructure.GetInstance(element.ToAsn1Object()));
 		}
 
 		public override Asn1Object ToAsn1Object()
 		{
-			return certificates;
+			return m_certificates;
 		}
  	}
 }
diff --git a/crypto/src/asn1/esf/CompleteCertificateRefs.cs b/crypto/src/asn1/esf/CompleteCertificateRefs.cs
index 2ed66e3dc..24727dc25 100644
--- a/crypto/src/asn1/esf/CompleteCertificateRefs.cs
+++ b/crypto/src/asn1/esf/CompleteCertificateRefs.cs
@@ -14,69 +14,58 @@ namespace Org.BouncyCastle.Asn1.Esf
 	public class CompleteCertificateRefs
 		: Asn1Encodable
 	{
-		private readonly Asn1Sequence otherCertIDs;
+		private readonly Asn1Sequence m_otherCertIDs;
 
-		public static CompleteCertificateRefs GetInstance(
-			object obj)
+		public static CompleteCertificateRefs GetInstance(object obj)
 		{
-			if (obj == null || obj is CompleteCertificateRefs)
-				return (CompleteCertificateRefs) obj;
+			if (obj == null)
+				return null;
 
-			if (obj is Asn1Sequence)
-				return new CompleteCertificateRefs((Asn1Sequence) obj);
+            if (obj is CompleteCertificateRefs completeCertificateRefs)
+				return completeCertificateRefs;
 
-			throw new ArgumentException(
-				"Unknown object in 'CompleteCertificateRefs' factory: "
-                    + Platform.GetTypeName(obj),
-				"obj");
+			if (obj is Asn1Sequence asn1Sequence)
+				return new CompleteCertificateRefs(asn1Sequence);
+
+			throw new ArgumentException("Unknown object in 'CompleteCertificateRefs' factory: " + Platform.GetTypeName(obj),
+				nameof(obj));
 		}
 
-		private CompleteCertificateRefs(
-			Asn1Sequence seq)
+		private CompleteCertificateRefs(Asn1Sequence seq)
 		{
 			if (seq == null)
-				throw new ArgumentNullException("seq");
+				throw new ArgumentNullException(nameof(seq));
 
-			foreach (Asn1Encodable ae in seq)
-			{
-				OtherCertID.GetInstance(ae.ToAsn1Object());
-			}
+            // Validate
+            seq.MapElements(element => OtherCertID.GetInstance(element.ToAsn1Object()));
 
-			this.otherCertIDs = seq;
+            m_otherCertIDs = seq;
 		}
 
-		public CompleteCertificateRefs(
-			params OtherCertID[] otherCertIDs)
+		public CompleteCertificateRefs(params OtherCertID[] otherCertIDs)
 		{
 			if (otherCertIDs == null)
-				throw new ArgumentNullException("otherCertIDs");
+				throw new ArgumentNullException(nameof(otherCertIDs));
 
-			this.otherCertIDs = new DerSequence(otherCertIDs);
+			m_otherCertIDs = new DerSequence(otherCertIDs);
 		}
 
-		public CompleteCertificateRefs(
-			IEnumerable<OtherCertID> otherCertIDs)
+		public CompleteCertificateRefs(IEnumerable<OtherCertID> otherCertIDs)
 		{
 			if (otherCertIDs == null)
-				throw new ArgumentNullException("otherCertIDs");
+                throw new ArgumentNullException(nameof(otherCertIDs));
 
-			this.otherCertIDs = new DerSequence(
-				Asn1EncodableVector.FromEnumerable(otherCertIDs));
+            m_otherCertIDs = new DerSequence(Asn1EncodableVector.FromEnumerable(otherCertIDs));
 		}
 
 		public OtherCertID[] GetOtherCertIDs()
 		{
-			OtherCertID[] result = new OtherCertID[otherCertIDs.Count];
-			for (int i = 0; i < otherCertIDs.Count; ++i)
-			{
-				result[i] = OtherCertID.GetInstance(otherCertIDs[i].ToAsn1Object());
-			}
-			return result;
+            return m_otherCertIDs.MapElements(element => OtherCertID.GetInstance(element.ToAsn1Object()));
 		}
 
 		public override Asn1Object ToAsn1Object()
 		{
-			return otherCertIDs;
+			return m_otherCertIDs;
 		}
 	}
 }
diff --git a/crypto/src/asn1/esf/CompleteRevocationRefs.cs b/crypto/src/asn1/esf/CompleteRevocationRefs.cs
index 9942cec8f..2c120f0f9 100644
--- a/crypto/src/asn1/esf/CompleteRevocationRefs.cs
+++ b/crypto/src/asn1/esf/CompleteRevocationRefs.cs
@@ -14,69 +14,58 @@ namespace Org.BouncyCastle.Asn1.Esf
 	public class CompleteRevocationRefs
 		: Asn1Encodable
 	{
-		private readonly Asn1Sequence crlOcspRefs;
+		private readonly Asn1Sequence m_crlOcspRefs;
 
-		public static CompleteRevocationRefs GetInstance(
-			object obj)
+		public static CompleteRevocationRefs GetInstance(object obj)
 		{
-			if (obj == null || obj is CompleteRevocationRefs)
-				return (CompleteRevocationRefs) obj;
+			if (obj == null)
+				return null;
 
-			if (obj is Asn1Sequence)
-				return new CompleteRevocationRefs((Asn1Sequence) obj);
+			if (obj is CompleteRevocationRefs completeRevocationRefs)
+				return completeRevocationRefs;
 
-			throw new ArgumentException(
-				"Unknown object in 'CompleteRevocationRefs' factory: "
-                    + Platform.GetTypeName(obj),
-				"obj");
+			if (obj is Asn1Sequence asn1Sequence)
+				return new CompleteRevocationRefs(asn1Sequence);
+
+			throw new ArgumentException("Unknown object in 'CompleteRevocationRefs' factory: " + Platform.GetTypeName(obj),
+				nameof(obj));
 		}
 
-		private CompleteRevocationRefs(
-			Asn1Sequence seq)
+		private CompleteRevocationRefs(Asn1Sequence seq)
 		{
 			if (seq == null)
-				throw new ArgumentNullException("seq");
+				throw new ArgumentNullException(nameof(seq));
 
-			foreach (Asn1Encodable ae in seq)
-			{
-				CrlOcspRef.GetInstance(ae.ToAsn1Object());
-			}
+            // Validate
+            seq.MapElements(element => CrlOcspRef.GetInstance(element.ToAsn1Object()));
 
-			this.crlOcspRefs = seq;
+			m_crlOcspRefs = seq;
 		}
 
-		public CompleteRevocationRefs(
-			params CrlOcspRef[] crlOcspRefs)
+		public CompleteRevocationRefs(params CrlOcspRef[] crlOcspRefs)
 		{
 			if (crlOcspRefs == null)
-				throw new ArgumentNullException("crlOcspRefs");
+				throw new ArgumentNullException(nameof(crlOcspRefs));
 
-			this.crlOcspRefs = new DerSequence(crlOcspRefs);
+			m_crlOcspRefs = new DerSequence(crlOcspRefs);
 		}
 
-		public CompleteRevocationRefs(
-			IEnumerable<CrlOcspRef> crlOcspRefs)
+		public CompleteRevocationRefs(IEnumerable<CrlOcspRef> crlOcspRefs)
 		{
 			if (crlOcspRefs == null)
-				throw new ArgumentNullException("crlOcspRefs");
+                throw new ArgumentNullException(nameof(crlOcspRefs));
 
-			this.crlOcspRefs = new DerSequence(
-				Asn1EncodableVector.FromEnumerable(crlOcspRefs));
+            m_crlOcspRefs = new DerSequence(Asn1EncodableVector.FromEnumerable(crlOcspRefs));
 		}
 
 		public CrlOcspRef[] GetCrlOcspRefs()
 		{
-			CrlOcspRef[] result = new CrlOcspRef[crlOcspRefs.Count];
-			for (int i = 0; i < crlOcspRefs.Count; ++i)
-			{
-				result[i] = CrlOcspRef.GetInstance(crlOcspRefs[i].ToAsn1Object());
-			}
-			return result;
+            return m_crlOcspRefs.MapElements(element => CrlOcspRef.GetInstance(element.ToAsn1Object()));
 		}
 
 		public override Asn1Object ToAsn1Object()
 		{
-			return crlOcspRefs;
+			return m_crlOcspRefs;
 		}
 	}
 }
diff --git a/crypto/src/asn1/esf/CrlIdentifier.cs b/crypto/src/asn1/esf/CrlIdentifier.cs
index 54e930acc..29003260a 100644
--- a/crypto/src/asn1/esf/CrlIdentifier.cs
+++ b/crypto/src/asn1/esf/CrlIdentifier.cs
@@ -20,9 +20,9 @@ namespace Org.BouncyCastle.Asn1.Esf
 	public class CrlIdentifier
 		: Asn1Encodable
 	{
-		private readonly X509Name crlIssuer;
-		private readonly Asn1UtcTime crlIssuedTime;
-		private readonly DerInteger crlNumber;
+		private readonly X509Name m_crlIssuer;
+		private readonly Asn1UtcTime m_crlIssuedTime;
+		private readonly DerInteger m_crlNumber;
 
 		public static CrlIdentifier GetInstance(object obj)
 		{
@@ -46,15 +46,15 @@ namespace Org.BouncyCastle.Asn1.Esf
 			if (seq.Count < 2 || seq.Count > 3)
 				throw new ArgumentException("Bad sequence size: " + seq.Count, nameof(seq));
 
-			this.crlIssuer = X509Name.GetInstance(seq[0]);
-			this.crlIssuedTime = Asn1UtcTime.GetInstance(seq[1]);
+			this.m_crlIssuer = X509Name.GetInstance(seq[0]);
+			this.m_crlIssuedTime = Asn1UtcTime.GetInstance(seq[1]);
 
             // Validate crlIssuedTime is in the appropriate year range
-            crlIssuedTime.ToDateTime(2049);
+            m_crlIssuedTime.ToDateTime(2049);
 
 			if (seq.Count > 2)
 			{
-				this.crlNumber = DerInteger.GetInstance(seq[2]);
+				this.m_crlNumber = DerInteger.GetInstance(seq[2]);
 			}
 		}
 
@@ -75,37 +75,37 @@ namespace Org.BouncyCastle.Asn1.Esf
 
         public CrlIdentifier(X509Name crlIssuer, Asn1UtcTime crlIssuedTime, BigInteger crlNumber)
         {
-            this.crlIssuer = crlIssuer ?? throw new ArgumentNullException(nameof(crlIssuer));
-            this.crlIssuedTime = crlIssuedTime ?? throw new ArgumentNullException(nameof(crlIssuedTime));
+            m_crlIssuer = crlIssuer ?? throw new ArgumentNullException(nameof(crlIssuer));
+            m_crlIssuedTime = crlIssuedTime ?? throw new ArgumentNullException(nameof(crlIssuedTime));
 
             if (null != crlNumber)
             {
-                this.crlNumber = new DerInteger(crlNumber);
+                m_crlNumber = new DerInteger(crlNumber);
             }
 
             // Validate crlIssuedTime is in the appropriate year range
-            this.crlIssuedTime.ToDateTime(2049);
+            m_crlIssuedTime.ToDateTime(2049);
         }
 
         public X509Name CrlIssuer
 		{
-			get { return crlIssuer; }
+			get { return m_crlIssuer; }
 		}
 
 		public DateTime CrlIssuedTime
 		{
-			get { return crlIssuedTime.ToDateTime(2049); }
+			get { return m_crlIssuedTime.ToDateTime(2049); }
 		}
 
 		public BigInteger CrlNumber
 		{
-			get { return crlNumber?.Value; }
+			get { return m_crlNumber?.Value; }
 		}
 
 		public override Asn1Object ToAsn1Object()
 		{
-			var v = new Asn1EncodableVector(crlIssuer.ToAsn1Object(), crlIssuedTime);
-            v.AddOptional(crlNumber);
+			var v = new Asn1EncodableVector(m_crlIssuer.ToAsn1Object(), m_crlIssuedTime);
+            v.AddOptional(m_crlNumber);
 			return new DerSequence(v);
 		}
 	}
diff --git a/crypto/src/asn1/esf/CrlListID.cs b/crypto/src/asn1/esf/CrlListID.cs
index d3c4365c5..1ee58aebc 100644
--- a/crypto/src/asn1/esf/CrlListID.cs
+++ b/crypto/src/asn1/esf/CrlListID.cs
@@ -17,71 +17,60 @@ namespace Org.BouncyCastle.Asn1.Esf
 	public class CrlListID
 		: Asn1Encodable
 	{
-		private readonly Asn1Sequence crls;
+		private readonly Asn1Sequence m_crls;
 
-		public static CrlListID GetInstance(
-			object obj)
+		public static CrlListID GetInstance(object obj)
 		{
-			if (obj == null || obj is CrlListID)
-				return (CrlListID) obj;
+			if (obj == null)
+				return null;
 
-			if (obj is Asn1Sequence)
-				return new CrlListID((Asn1Sequence) obj);
+			if (obj is CrlListID crlListID)
+				return crlListID;
 
-			throw new ArgumentException(
-				"Unknown object in 'CrlListID' factory: "
-                    + Platform.GetTypeName(obj),
-				"obj");
+			if (obj is Asn1Sequence asn1Sequence)
+				return new CrlListID(asn1Sequence);
+
+			throw new ArgumentException("Unknown object in 'CrlListID' factory: " + Platform.GetTypeName(obj),
+				nameof(obj));
 		}
 
-		private CrlListID(
-			Asn1Sequence seq)
+		private CrlListID(Asn1Sequence seq)
 		{
 			if (seq == null)
-				throw new ArgumentNullException("seq");
+				throw new ArgumentNullException(nameof(seq));
 			if (seq.Count != 1)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+				throw new ArgumentException("Bad sequence size: " + seq.Count, nameof(seq));
 
-			this.crls = (Asn1Sequence) seq[0].ToAsn1Object();
+			m_crls = (Asn1Sequence)seq[0].ToAsn1Object();
 
-			foreach (Asn1Encodable ae in this.crls)
-			{
-				CrlValidatedID.GetInstance(ae.ToAsn1Object());
-			}
+			// Validate
+			m_crls.MapElements(element => CrlValidatedID.GetInstance(element.ToAsn1Object()));
 		}
 
-		public CrlListID(
-			params CrlValidatedID[] crls)
+		public CrlListID(params CrlValidatedID[] crls)
 		{
 			if (crls == null)
-				throw new ArgumentNullException("crls");
+				throw new ArgumentNullException(nameof(crls));
 
-			this.crls = new DerSequence(crls);
+			this.m_crls = new DerSequence(crls);
 		}
 
-		public CrlListID(
-			IEnumerable<CrlValidatedID> crls)
+		public CrlListID(IEnumerable<CrlValidatedID> crls)
 		{
 			if (crls == null)
-				throw new ArgumentNullException("crls");
+                throw new ArgumentNullException(nameof(crls));
 
-			this.crls = new DerSequence(
-				Asn1EncodableVector.FromEnumerable(crls));
+            this.m_crls = new DerSequence(Asn1EncodableVector.FromEnumerable(crls));
 		}
 
 		public CrlValidatedID[] GetCrls()
 		{
-			CrlValidatedID[] result = new CrlValidatedID[crls.Count];
-			for (int i = 0; i < crls.Count; ++i)
-			{
-				result[i] = CrlValidatedID.GetInstance(crls[i].ToAsn1Object());
-			}
-			return result;
+            return m_crls.MapElements(element => CrlValidatedID.GetInstance(element.ToAsn1Object()));
 		}
 
 		public override Asn1Object ToAsn1Object()
 		{
-			return new DerSequence(crls);
+			return new DerSequence(m_crls);
 		}
 	}
 }
diff --git a/crypto/src/asn1/esf/OcspListID.cs b/crypto/src/asn1/esf/OcspListID.cs
index 3918dfd42..974962571 100644
--- a/crypto/src/asn1/esf/OcspListID.cs
+++ b/crypto/src/asn1/esf/OcspListID.cs
@@ -16,71 +16,60 @@ namespace Org.BouncyCastle.Asn1.Esf
 	public class OcspListID
 		: Asn1Encodable
 	{
-		private readonly Asn1Sequence ocspResponses;
+		private readonly Asn1Sequence m_ocspResponses;
 
-		public static OcspListID GetInstance(
-			object obj)
+		public static OcspListID GetInstance(object obj)
 		{
-			if (obj == null || obj is OcspListID)
-				return (OcspListID) obj;
+			if (obj == null)
+				return null;
 
-			if (obj is Asn1Sequence)
-				return new OcspListID((Asn1Sequence) obj);
+			if (obj is OcspListID ocspListID)
+				return ocspListID;
 
-			throw new ArgumentException(
-				"Unknown object in 'OcspListID' factory: "
-                    + Platform.GetTypeName(obj),
-				"obj");
+			if (obj is Asn1Sequence asn1Sequence)
+				return new OcspListID(asn1Sequence);
+
+			throw new ArgumentException("Unknown object in 'OcspListID' factory: " + Platform.GetTypeName(obj),
+				nameof(obj));
 		}
 
-		private OcspListID(
-			Asn1Sequence seq)
+		private OcspListID(Asn1Sequence seq)
 		{
 			if (seq == null)
-				throw new ArgumentNullException("seq");
+				throw new ArgumentNullException(nameof(seq));
 			if (seq.Count != 1)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+				throw new ArgumentException("Bad sequence size: " + seq.Count, nameof(seq));
 
-			this.ocspResponses = (Asn1Sequence) seq[0].ToAsn1Object();
+			m_ocspResponses = (Asn1Sequence)seq[0].ToAsn1Object();
 
-			foreach (Asn1Encodable ae in this.ocspResponses)
-			{
-				OcspResponsesID.GetInstance(ae.ToAsn1Object());
-			}
+            // Validate
+            m_ocspResponses.MapElements(element => OcspResponsesID.GetInstance(element.ToAsn1Object()));
 		}
 
-		public OcspListID(
-			params OcspResponsesID[] ocspResponses)
+		public OcspListID(params OcspResponsesID[] ocspResponses)
 		{
 			if (ocspResponses == null)
-				throw new ArgumentNullException("ocspResponses");
+				throw new ArgumentNullException(nameof(ocspResponses));
 
-			this.ocspResponses = new DerSequence(ocspResponses);
+			m_ocspResponses = new DerSequence(ocspResponses);
 		}
 
-		public OcspListID(
-			IEnumerable<OcspResponsesID> ocspResponses)
+		public OcspListID(IEnumerable<OcspResponsesID> ocspResponses)
 		{
 			if (ocspResponses == null)
-				throw new ArgumentNullException("ocspResponses");
+                throw new ArgumentNullException(nameof(ocspResponses));
 
-			this.ocspResponses = new DerSequence(
-				Asn1EncodableVector.FromEnumerable(ocspResponses));
+            m_ocspResponses = new DerSequence(Asn1EncodableVector.FromEnumerable(ocspResponses));
 		}
 
 		public OcspResponsesID[] GetOcspResponses()
 		{
-			OcspResponsesID[] result = new OcspResponsesID[ocspResponses.Count];
-			for (int i = 0; i < ocspResponses.Count; ++i)
-			{
-				result[i] = OcspResponsesID.GetInstance(ocspResponses[i].ToAsn1Object());
-			}
-			return result;
+            return m_ocspResponses.MapElements(element => OcspResponsesID.GetInstance(element.ToAsn1Object()));
 		}
 
 		public override Asn1Object ToAsn1Object()
 		{
-			return new DerSequence(ocspResponses);
+			return new DerSequence(m_ocspResponses);
 		}
 	}
 }
diff --git a/crypto/src/asn1/esf/OtherSigningCertificate.cs b/crypto/src/asn1/esf/OtherSigningCertificate.cs
index a4f4a0727..aa1dcbf99 100644
--- a/crypto/src/asn1/esf/OtherSigningCertificate.cs
+++ b/crypto/src/asn1/esf/OtherSigningCertificate.cs
@@ -17,111 +17,89 @@ namespace Org.BouncyCastle.Asn1.Esf
 	public class OtherSigningCertificate
 		: Asn1Encodable
 	{
-		private readonly Asn1Sequence	certs;
-		private readonly Asn1Sequence	policies;
+		private readonly Asn1Sequence m_certs;
+		private readonly Asn1Sequence m_policies;
 
-		public static OtherSigningCertificate GetInstance(
-			object obj)
+		public static OtherSigningCertificate GetInstance(object obj)
 		{
-			if (obj == null || obj is OtherSigningCertificate)
-				return (OtherSigningCertificate) obj;
+			if (obj == null)
+				return null;
+
+			if (obj is OtherSigningCertificate otherSigningCertificate)
+				return otherSigningCertificate;
 
-			if (obj is Asn1Sequence)
-				return new OtherSigningCertificate((Asn1Sequence) obj);
+			if (obj is Asn1Sequence asn1Sequence)
+				return new OtherSigningCertificate(asn1Sequence);
 
-			throw new ArgumentException(
-				"Unknown object in 'OtherSigningCertificate' factory: "
-                    + Platform.GetTypeName(obj),
-				"obj");
+			throw new ArgumentException("Unknown object in 'OtherSigningCertificate' factory: " + Platform.GetTypeName(obj),
+				nameof(obj));
 		}
 
-		private OtherSigningCertificate(
-			Asn1Sequence seq)
+		private OtherSigningCertificate(Asn1Sequence seq)
 		{
 			if (seq == null)
-				throw new ArgumentNullException("seq");
+				throw new ArgumentNullException(nameof(seq));
 			if (seq.Count < 1 || seq.Count > 2)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+				throw new ArgumentException("Bad sequence size: " + seq.Count, nameof(seq));
 
-			this.certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object());
+			m_certs = Asn1Sequence.GetInstance(seq[0].ToAsn1Object());
 
 			if (seq.Count > 1)
 			{
-				this.policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object());
+				m_policies = Asn1Sequence.GetInstance(seq[1].ToAsn1Object());
 			}
 		}
 
-		public OtherSigningCertificate(
-			params OtherCertID[] certs)
+		public OtherSigningCertificate(params OtherCertID[] certs)
 			: this(certs, null)
 		{
 		}
 
-		public OtherSigningCertificate(
-			OtherCertID[]				certs,
-			params PolicyInformation[]	policies)
+		public OtherSigningCertificate(OtherCertID[] certs, params PolicyInformation[] policies)
 		{
 			if (certs == null)
-				throw new ArgumentNullException("certs");
+                throw new ArgumentNullException(nameof(certs));
 
-			this.certs = new DerSequence(certs);
+            m_certs = new DerSequence(certs);
 
 			if (policies != null)
 			{
-				this.policies = new DerSequence(policies);
+				m_policies = new DerSequence(policies);
 			}
 		}
 
-		public OtherSigningCertificate(
-			IEnumerable<OtherCertID> certs)
+		public OtherSigningCertificate(IEnumerable<OtherCertID> certs)
 			: this(certs, null)
 		{
 		}
 
-		public OtherSigningCertificate(
-			IEnumerable<OtherCertID> certs,
-			IEnumerable<PolicyInformation> policies)
+		public OtherSigningCertificate(IEnumerable<OtherCertID> certs, IEnumerable<PolicyInformation> policies)
 		{
 			if (certs == null)
-				throw new ArgumentNullException("certs");
+                throw new ArgumentNullException(nameof(certs));
 
-			this.certs = new DerSequence(
-				Asn1EncodableVector.FromEnumerable(certs));
+            m_certs = new DerSequence(Asn1EncodableVector.FromEnumerable(certs));
 
 			if (policies != null)
 			{
-				this.policies = new DerSequence(
-					Asn1EncodableVector.FromEnumerable(policies));
+				m_policies = new DerSequence(Asn1EncodableVector.FromEnumerable(policies));
 			}
 		}
 
 		public OtherCertID[] GetCerts()
 		{
-			OtherCertID[] cs = new OtherCertID[certs.Count];
-			for (int i = 0; i < certs.Count; ++i)
-			{
-				cs[i] = OtherCertID.GetInstance(certs[i].ToAsn1Object());
-			}
-			return cs;
+			return m_certs.MapElements(element => OtherCertID.GetInstance(element.ToAsn1Object()));
 		}
 
 		public PolicyInformation[] GetPolicies()
 		{
-			if (policies == null)
-				return null;
-
-			PolicyInformation[] ps = new PolicyInformation[policies.Count];
-			for (int i = 0; i < policies.Count; ++i)
-			{
-				ps[i] = PolicyInformation.GetInstance(policies[i].ToAsn1Object());
-			}
-			return ps;
+            return m_policies?.MapElements(element => PolicyInformation.GetInstance(element.ToAsn1Object()));
 		}
 
 		public override Asn1Object ToAsn1Object()
 		{
-			Asn1EncodableVector v = new Asn1EncodableVector(certs);
-            v.AddOptional(policies);
+			Asn1EncodableVector v = new Asn1EncodableVector(m_certs);
+            v.AddOptional(m_policies);
 			return new DerSequence(v);
 		}
 	}
diff --git a/crypto/src/asn1/esf/RevocationValues.cs b/crypto/src/asn1/esf/RevocationValues.cs
index 682728dde..61bfd0be1 100644
--- a/crypto/src/asn1/esf/RevocationValues.cs
+++ b/crypto/src/asn1/esf/RevocationValues.cs
@@ -19,129 +19,113 @@ namespace Org.BouncyCastle.Asn1.Esf
 	public class RevocationValues
 		: Asn1Encodable
 	{
-		private readonly Asn1Sequence	crlVals;
-		private readonly Asn1Sequence	ocspVals;
-		private readonly OtherRevVals	otherRevVals;
+		private readonly Asn1Sequence m_crlVals;
+		private readonly Asn1Sequence m_ocspVals;
+		private readonly OtherRevVals m_otherRevVals;
 
-		public static RevocationValues GetInstance(
-			object obj)
+		public static RevocationValues GetInstance(object obj)
 		{
-			if (obj == null || obj is RevocationValues)
-				return (RevocationValues) obj;
+            if (obj == null)
+                return null;
+
+            if (obj is RevocationValues revocationValues)
+				return revocationValues;
 
 			return new RevocationValues(Asn1Sequence.GetInstance(obj));
 		}
 
-		private RevocationValues(
-			Asn1Sequence seq)
+		private RevocationValues(Asn1Sequence seq)
 		{
 			if (seq == null)
-				throw new ArgumentNullException("seq");
+				throw new ArgumentNullException(nameof(seq));
 			if (seq.Count > 3)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+				throw new ArgumentException("Bad sequence size: " + seq.Count, nameof(seq));
 
 			foreach (Asn1TaggedObject taggedObj in seq)
 			{
 				Asn1Object asn1Obj = taggedObj.GetObject();
 				switch (taggedObj.TagNo)
 				{
-					case 0:
-						Asn1Sequence crlValsSeq = (Asn1Sequence) asn1Obj;
-						foreach (Asn1Encodable ae in crlValsSeq)
-						{
-							CertificateList.GetInstance(ae.ToAsn1Object());
-						}
-						this.crlVals = crlValsSeq;
-						break;
-					case 1:
-						Asn1Sequence ocspValsSeq = (Asn1Sequence) asn1Obj;
-						foreach (Asn1Encodable ae in ocspValsSeq)
-						{
-							BasicOcspResponse.GetInstance(ae.ToAsn1Object());
-						}
-						this.ocspVals = ocspValsSeq;
-						break;
-					case 2:
-						this.otherRevVals = OtherRevVals.GetInstance(asn1Obj);
-						break;
-					default:
-						throw new ArgumentException("Illegal tag in RevocationValues", "seq");
+				case 0:
+					Asn1Sequence crlValsSeq = (Asn1Sequence)asn1Obj;
+
+					// Validate
+					crlValsSeq.MapElements(element => CertificateList.GetInstance(element.ToAsn1Object()));
+
+					m_crlVals = crlValsSeq;
+					break;
+				case 1:
+					Asn1Sequence ocspValsSeq = (Asn1Sequence)asn1Obj;
+
+					// Validate
+					ocspValsSeq.MapElements(element => BasicOcspResponse.GetInstance(element.ToAsn1Object()));
+
+					m_ocspVals = ocspValsSeq;
+					break;
+				case 2:
+					m_otherRevVals = OtherRevVals.GetInstance(asn1Obj);
+					break;
+				default:
+					throw new ArgumentException("Illegal tag in RevocationValues", nameof(seq));
 				}
 			}
 		}
 
-		public RevocationValues(
-			CertificateList[]	crlVals,
-			BasicOcspResponse[]	ocspVals,
-			OtherRevVals		otherRevVals)
+		public RevocationValues(CertificateList[] crlVals, BasicOcspResponse[] ocspVals, OtherRevVals otherRevVals)
 		{
 			if (crlVals != null)
 			{
-				this.crlVals = new DerSequence(crlVals);
+				m_crlVals = new DerSequence(crlVals);
 			}
 
 			if (ocspVals != null)
 			{
-				this.ocspVals = new DerSequence(ocspVals);
+				m_ocspVals = new DerSequence(ocspVals);
 			}
 
-			this.otherRevVals = otherRevVals;
+			m_otherRevVals = otherRevVals;
 		}
 
-		public RevocationValues(
-			IEnumerable<CertificateList> crlVals,
-			IEnumerable<BasicOcspResponse> ocspVals,
+		public RevocationValues(IEnumerable<CertificateList> crlVals, IEnumerable<BasicOcspResponse> ocspVals,
 			OtherRevVals otherRevVals)
 		{
 			if (crlVals != null)
 			{
-				this.crlVals = new DerSequence(
-					Asn1EncodableVector.FromEnumerable(crlVals));
+				m_crlVals = new DerSequence(Asn1EncodableVector.FromEnumerable(crlVals));
 			}
 
 			if (ocspVals != null)
 			{
-				this.ocspVals = new DerSequence(
-					Asn1EncodableVector.FromEnumerable(ocspVals));
+				m_ocspVals = new DerSequence(Asn1EncodableVector.FromEnumerable(ocspVals));
 			}
 
-			this.otherRevVals = otherRevVals;
+			m_otherRevVals = otherRevVals;
 		}
 
 		public CertificateList[] GetCrlVals()
 		{
-			CertificateList[] result = new CertificateList[crlVals.Count];
-			for (int i = 0; i < crlVals.Count; ++i)
-			{
-				result[i] = CertificateList.GetInstance(crlVals[i].ToAsn1Object());
-			}
-			return result;
+			return m_crlVals.MapElements(element => CertificateList.GetInstance(element.ToAsn1Object()));
 		}
 
 		public BasicOcspResponse[] GetOcspVals()
 		{
-			BasicOcspResponse[] result = new BasicOcspResponse[ocspVals.Count];
-			for (int i = 0; i < ocspVals.Count; ++i)
-			{
-				result[i] = BasicOcspResponse.GetInstance(ocspVals[i].ToAsn1Object());
-			}
-			return result;
+            return m_ocspVals.MapElements(element => BasicOcspResponse.GetInstance(element.ToAsn1Object()));
 		}
 
 		public OtherRevVals OtherRevVals
 		{
-			get { return otherRevVals; }
+			get { return m_otherRevVals; }
 		}
 
 		public override Asn1Object ToAsn1Object()
 		{
 			Asn1EncodableVector v = new Asn1EncodableVector();
-            v.AddOptionalTagged(true, 0, crlVals);
-            v.AddOptionalTagged(true, 1, ocspVals);
+            v.AddOptionalTagged(true, 0, m_crlVals);
+            v.AddOptionalTagged(true, 1, m_ocspVals);
 
-            if (otherRevVals != null)
+            if (m_otherRevVals != null)
 			{
-				v.Add(new DerTaggedObject(true, 2, otherRevVals.ToAsn1Object()));
+				v.Add(new DerTaggedObject(true, 2, m_otherRevVals.ToAsn1Object()));
 			}
 
             return new DerSequence(v);
diff --git a/crypto/src/asn1/esf/SignaturePolicyId.cs b/crypto/src/asn1/esf/SignaturePolicyId.cs
index 21bb40560..84e9f8c62 100644
--- a/crypto/src/asn1/esf/SignaturePolicyId.cs
+++ b/crypto/src/asn1/esf/SignaturePolicyId.cs
@@ -21,119 +21,103 @@ namespace Org.BouncyCastle.Asn1.Esf
 	public class SignaturePolicyId
 		: Asn1Encodable
 	{
-		private readonly DerObjectIdentifier	sigPolicyIdentifier;
-		private readonly OtherHashAlgAndValue	sigPolicyHash;
-		private readonly Asn1Sequence			sigPolicyQualifiers;
+		private readonly DerObjectIdentifier m_sigPolicyIdentifier;
+		private readonly OtherHashAlgAndValue m_sigPolicyHash;
+		private readonly Asn1Sequence m_sigPolicyQualifiers;
 
-		public static SignaturePolicyId GetInstance(
-			object obj)
+		public static SignaturePolicyId GetInstance(object obj)
 		{
-			if (obj == null || obj is SignaturePolicyId)
-				return (SignaturePolicyId) obj;
+			if (obj == null)
+				return null;
+
+			if (obj is SignaturePolicyId signaturePolicyId)
+				return signaturePolicyId;
 
-			if (obj is Asn1Sequence)
-				return new SignaturePolicyId((Asn1Sequence) obj);
+			if (obj is Asn1Sequence asn1Sequence)
+				return new SignaturePolicyId(asn1Sequence);
 
-			throw new ArgumentException(
-				"Unknown object in 'SignaturePolicyId' factory: "
-                    + Platform.GetTypeName(obj),
-				"obj");
+			throw new ArgumentException("Unknown object in 'SignaturePolicyId' factory: " + Platform.GetTypeName(obj),
+				nameof(obj));
 		}
 
-		private SignaturePolicyId(
-			Asn1Sequence seq)
+		private SignaturePolicyId(Asn1Sequence seq)
 		{
 			if (seq == null)
-				throw new ArgumentNullException("seq");
+				throw new ArgumentNullException(nameof(seq));
 			if (seq.Count < 2 || seq.Count > 3)
-				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
+				throw new ArgumentException("Bad sequence size: " + seq.Count, nameof(seq));
 
-			this.sigPolicyIdentifier = (DerObjectIdentifier) seq[0].ToAsn1Object();
-			this.sigPolicyHash = OtherHashAlgAndValue.GetInstance(seq[1].ToAsn1Object());
+			m_sigPolicyIdentifier = (DerObjectIdentifier)seq[0].ToAsn1Object();
+			m_sigPolicyHash = OtherHashAlgAndValue.GetInstance(seq[1].ToAsn1Object());
 
 			if (seq.Count > 2)
 			{
-				this.sigPolicyQualifiers = (Asn1Sequence) seq[2].ToAsn1Object();
+				m_sigPolicyQualifiers = (Asn1Sequence)seq[2].ToAsn1Object();
 			}
 		}
 
-		public SignaturePolicyId(
-			DerObjectIdentifier		sigPolicyIdentifier,
-			OtherHashAlgAndValue	sigPolicyHash)
+		public SignaturePolicyId(DerObjectIdentifier sigPolicyIdentifier, OtherHashAlgAndValue sigPolicyHash)
 			: this(sigPolicyIdentifier, sigPolicyHash, null)
 		{
 		}
 
-		public SignaturePolicyId(
-			DerObjectIdentifier				sigPolicyIdentifier,
-			OtherHashAlgAndValue			sigPolicyHash,
+		public SignaturePolicyId(DerObjectIdentifier sigPolicyIdentifier, OtherHashAlgAndValue sigPolicyHash,
 			params SigPolicyQualifierInfo[]	sigPolicyQualifiers)
 		{
 			if (sigPolicyIdentifier == null)
-				throw new ArgumentNullException("sigPolicyIdentifier");
+				throw new ArgumentNullException(nameof(sigPolicyIdentifier));
 			if (sigPolicyHash == null)
-				throw new ArgumentNullException("sigPolicyHash");
+				throw new ArgumentNullException(nameof(sigPolicyHash));
 
-			this.sigPolicyIdentifier = sigPolicyIdentifier;
-			this.sigPolicyHash = sigPolicyHash;
+			m_sigPolicyIdentifier = sigPolicyIdentifier;
+			m_sigPolicyHash = sigPolicyHash;
 
 			if (sigPolicyQualifiers != null)
 			{
-				this.sigPolicyQualifiers = new DerSequence(sigPolicyQualifiers);
+				m_sigPolicyQualifiers = new DerSequence(sigPolicyQualifiers);
 			}
 		}
 
-		public SignaturePolicyId(
-			DerObjectIdentifier sigPolicyIdentifier,
-			OtherHashAlgAndValue sigPolicyHash,
+		public SignaturePolicyId(DerObjectIdentifier sigPolicyIdentifier, OtherHashAlgAndValue sigPolicyHash,
 			IEnumerable<SigPolicyQualifierInfo> sigPolicyQualifiers)
 		{
-			if (sigPolicyIdentifier == null)
-				throw new ArgumentNullException("sigPolicyIdentifier");
-			if (sigPolicyHash == null)
-				throw new ArgumentNullException("sigPolicyHash");
+            if (sigPolicyIdentifier == null)
+                throw new ArgumentNullException(nameof(sigPolicyIdentifier));
+            if (sigPolicyHash == null)
+                throw new ArgumentNullException(nameof(sigPolicyHash));
 
-			this.sigPolicyIdentifier = sigPolicyIdentifier;
-			this.sigPolicyHash = sigPolicyHash;
+			m_sigPolicyIdentifier = sigPolicyIdentifier;
+			m_sigPolicyHash = sigPolicyHash;
 
 			if (sigPolicyQualifiers != null)
 			{
-				this.sigPolicyQualifiers = new DerSequence(
-					Asn1EncodableVector.FromEnumerable(sigPolicyQualifiers));
+				m_sigPolicyQualifiers = new DerSequence(Asn1EncodableVector.FromEnumerable(sigPolicyQualifiers));
 			}
 		}
 
 		public DerObjectIdentifier SigPolicyIdentifier
 		{
-			get { return sigPolicyIdentifier; }
+			get { return m_sigPolicyIdentifier; }
 		}
 
 		public OtherHashAlgAndValue SigPolicyHash
 		{
-			get { return sigPolicyHash; }
+			get { return m_sigPolicyHash; }
 		}
 
 		public SigPolicyQualifierInfo[] GetSigPolicyQualifiers()
 		{
-			if (sigPolicyQualifiers == null)
-				return null;
-
-			SigPolicyQualifierInfo[] infos = new SigPolicyQualifierInfo[sigPolicyQualifiers.Count];
-			for (int i = 0; i < sigPolicyQualifiers.Count; ++i)
-			{
-				infos[i] = SigPolicyQualifierInfo.GetInstance(sigPolicyQualifiers[i]);
-			}
-			return infos;
+			return m_sigPolicyQualifiers?.MapElements(SigPolicyQualifierInfo.GetInstance);
 		}
 
 		public override Asn1Object ToAsn1Object()
 		{
 			Asn1EncodableVector v = new Asn1EncodableVector(
-				sigPolicyIdentifier, sigPolicyHash.ToAsn1Object());
+				m_sigPolicyIdentifier, m_sigPolicyHash.ToAsn1Object());
 
-			if (sigPolicyQualifiers != null)
+			if (m_sigPolicyQualifiers != null)
 			{
-				v.Add(sigPolicyQualifiers.ToAsn1Object());
+				v.Add(m_sigPolicyQualifiers.ToAsn1Object());
 			}
 
 			return new DerSequence(v);
diff --git a/crypto/src/asn1/esf/SignerLocation.cs b/crypto/src/asn1/esf/SignerLocation.cs
index 0e87812be..106a32c59 100644
--- a/crypto/src/asn1/esf/SignerLocation.cs
+++ b/crypto/src/asn1/esf/SignerLocation.cs
@@ -19,9 +19,9 @@ namespace Org.BouncyCastle.Asn1.Esf
 	public class SignerLocation
 		: Asn1Encodable
 	{
-        private DirectoryString countryName;
-        private DirectoryString localityName;
-        private Asn1Sequence postalAddress;
+        private readonly DirectoryString countryName;
+        private readonly DirectoryString localityName;
+        private readonly Asn1Sequence postalAddress;
 
 		public SignerLocation(Asn1Sequence seq)
 		{
@@ -99,13 +99,7 @@ namespace Org.BouncyCastle.Asn1.Esf
             if (postalAddress == null)
                 return null;
 
-            DirectoryString[] dirStrings = new DirectoryString[postalAddress.Count];
-            for (int i = 0; i != dirStrings.Length; i++)
-            {
-                dirStrings[i] = DirectoryString.GetInstance(postalAddress[i]);
-            }
-
-            return dirStrings;
+			return postalAddress.MapElements(element => DirectoryString.GetInstance(element.ToAsn1Object()));
         }
 
 		public Asn1Sequence PostalAddress
@@ -132,7 +126,7 @@ namespace Org.BouncyCastle.Asn1.Esf
 		*/
 		public override Asn1Object ToAsn1Object()
 		{
-			Asn1EncodableVector v = new Asn1EncodableVector();
+			Asn1EncodableVector v = new Asn1EncodableVector(3);
             v.AddOptionalTagged(true, 0, countryName);
             v.AddOptionalTagged(true, 1, localityName);
             v.AddOptionalTagged(true, 2, postalAddress);
diff --git a/crypto/src/asn1/isismtt/x509/Admissions.cs b/crypto/src/asn1/isismtt/x509/Admissions.cs
index 42ebceb1c..1ade6093f 100644
--- a/crypto/src/asn1/isismtt/x509/Admissions.cs
+++ b/crypto/src/asn1/isismtt/x509/Admissions.cs
@@ -70,13 +70,13 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 				switch (tagged1.TagNo)
 				{
 				case 0:
-					admissionAuthority = GeneralName.GetInstance((Asn1TaggedObject)o, true);
+					admissionAuthority = GeneralName.GetInstance(tagged1, true);
 					break;
 				case 1:
-					namingAuthority = NamingAuthority.GetInstance((Asn1TaggedObject)o, true);
+					namingAuthority = NamingAuthority.GetInstance(tagged1, true);
 					break;
 				default:
-					throw new ArgumentException("Bad tag number: " + ((Asn1TaggedObject)o).TagNo);
+					throw new ArgumentException("Bad tag number: " + tagged1.TagNo);
 				}
 				e.MoveNext();
 				o = e.Current;
@@ -86,10 +86,10 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 				switch (tagged2.TagNo)
 				{
 				case 1:
-					namingAuthority = NamingAuthority.GetInstance((Asn1TaggedObject)o, true);
+					namingAuthority = NamingAuthority.GetInstance(tagged2, true);
 					break;
 				default:
-					throw new ArgumentException("Bad tag number: " + ((Asn1TaggedObject)o).TagNo);
+					throw new ArgumentException("Bad tag number: " + tagged2.TagNo);
 				}
 				e.MoveNext();
 				o = e.Current;
diff --git a/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs b/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
index c9c96cbda..471776630 100644
--- a/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
+++ b/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
@@ -33,20 +33,17 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 			DateOfBirth = 2
 		};
 
-		private readonly Asn1TaggedObject declaration;
+		private readonly Asn1TaggedObject m_declaration;
 
-		public DeclarationOfMajority(
-			int notYoungerThan)
+		public DeclarationOfMajority(int notYoungerThan)
 		{
-			declaration = new DerTaggedObject(false, 0, new DerInteger(notYoungerThan));
+			m_declaration = new DerTaggedObject(false, 0, new DerInteger(notYoungerThan));
 		}
 
-		public DeclarationOfMajority(
-			bool	fullAge,
-			string	country)
+		public DeclarationOfMajority(bool fullAge, string country)
 		{
 			if (country.Length > 2)
-				throw new ArgumentException("country can only be 2 characters");
+				throw new ArgumentException("country can only be 2 characters", nameof(country));
 
 			DerPrintableString countryString = new DerPrintableString(country, true);
 
@@ -60,38 +57,34 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 				seq = new DerSequence(DerBoolean.False, countryString);
 			}
 
-			this.declaration = new DerTaggedObject(false, 1, seq);
+			m_declaration = new DerTaggedObject(false, 1, seq);
 		}
 
-		public DeclarationOfMajority(
-            Asn1GeneralizedTime dateOfBirth)
+		public DeclarationOfMajority(Asn1GeneralizedTime dateOfBirth)
 		{
-			this.declaration = new DerTaggedObject(false, 2, dateOfBirth);
+			m_declaration = new DerTaggedObject(false, 2, dateOfBirth);
 		}
 
-		public static DeclarationOfMajority GetInstance(
-			object obj)
+		public static DeclarationOfMajority GetInstance(object obj)
 		{
-			if (obj == null || obj is DeclarationOfMajority)
-			{
-				return (DeclarationOfMajority) obj;
-			}
+			if (obj == null)
+				return null;
 
-			if (obj is Asn1TaggedObject)
-			{
-				return new DeclarationOfMajority((Asn1TaggedObject) obj);
-			}
+			if (obj is DeclarationOfMajority declarationOfMajority)
+				return declarationOfMajority;
+
+			if (obj is Asn1TaggedObject asn1TaggedObject)
+				return new DeclarationOfMajority(asn1TaggedObject);
 
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), nameof(obj));
 		}
 
-		private DeclarationOfMajority(
-			Asn1TaggedObject o)
+		private DeclarationOfMajority(Asn1TaggedObject o)
 		{
 			if (o.TagNo > 2)
 				throw new ArgumentException("Bad tag number: " + o.TagNo);
 
-			this.declaration = o;
+			m_declaration = o;
 		}
 
 		/**
@@ -116,12 +109,12 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		*/
 		public override Asn1Object ToAsn1Object()
 		{
-			return declaration;
+			return m_declaration;
 		}
 
 		public Choice Type
 		{
-			get { return (Choice) declaration.TagNo; }
+			get { return (Choice)m_declaration.TagNo; }
 		}
 
 		/**
@@ -131,12 +124,12 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		{
 			get
 			{
-				switch ((Choice) declaration.TagNo)
+				switch (Type)
 				{
-					case Choice.NotYoungerThan:
-                        return DerInteger.GetInstance(declaration, false).IntValueExact;
-					default:
-						return -1;
+				case Choice.NotYoungerThan:
+                    return DerInteger.GetInstance(m_declaration, false).IntValueExact;
+				default:
+					return -1;
 				}
 			}
 		}
@@ -145,12 +138,12 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		{
 			get
 			{
-				switch ((Choice) declaration.TagNo)
+				switch (Type)
 				{
-					case Choice.FullAgeAtCountry:
-						return Asn1Sequence.GetInstance(declaration, false);
-					default:
-						return null;
+				case Choice.FullAgeAtCountry:
+					return Asn1Sequence.GetInstance(m_declaration, false);
+				default:
+					return null;
 				}
 			}
 		}
@@ -159,12 +152,12 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		{
 			get
 			{
-				switch ((Choice) declaration.TagNo)
+				switch (Type)
 				{
-					case Choice.DateOfBirth:
-						return Asn1GeneralizedTime.GetInstance(declaration, false);
-					default:
-						return null;
+				case Choice.DateOfBirth:
+					return Asn1GeneralizedTime.GetInstance(m_declaration, false);
+				default:
+					return null;
 				}
 			}
 		}
diff --git a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
index 693c0eaba..ebf107dd6 100644
--- a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
+++ b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
@@ -50,7 +50,7 @@ namespace Org.BouncyCastle.Asn1.Misc
         public static readonly DerObjectIdentifier Entrust = new DerObjectIdentifier("1.2.840.113533.7");
         public static readonly DerObjectIdentifier EntrustVersionExtension = Entrust.Branch("65.0");
 
-        public static readonly DerObjectIdentifier cast5CBC = new DerObjectIdentifier(Entrust+ ".66.10");
+        public static readonly DerObjectIdentifier cast5CBC = Entrust.Branch("66.10");
 
         //
         // HMAC-SHA1       hMAC-SHA1 OBJECT IDENTIFIER ::= { iso(1) identified-organization(3)
diff --git a/crypto/src/asn1/ocsp/CertID.cs b/crypto/src/asn1/ocsp/CertID.cs
index 523f6b87c..12a111ec9 100644
--- a/crypto/src/asn1/ocsp/CertID.cs
+++ b/crypto/src/asn1/ocsp/CertID.cs
@@ -1,12 +1,10 @@
 using System;
 
-using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Ocsp
 {
-    public class CertID
+	public class CertID
         : Asn1Encodable
     {
         private readonly AlgorithmIdentifier    hashAlgorithm;
@@ -14,27 +12,18 @@ namespace Org.BouncyCastle.Asn1.Ocsp
         private readonly Asn1OctetString        issuerKeyHash;
         private readonly DerInteger             serialNumber;
 
-		public static CertID GetInstance(
-			Asn1TaggedObject	obj,
-			bool				explicitly)
+		public static CertID GetInstance(Asn1TaggedObject obj, bool explicitly)
 		{
 			return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
 		}
 
-		public static CertID GetInstance(
-			object obj)
+		public static CertID GetInstance(object obj)
 		{
-			if (obj == null || obj is CertID)
-			{
-				return (CertID)obj;
-			}
-
-			if (obj is Asn1Sequence)
-			{
-				return new CertID((Asn1Sequence)obj);
-			}
-
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+			if (obj == null)
+				return null;
+			if (obj is CertID certID)
+				return certID;
+			return new CertID(Asn1Sequence.GetInstance(obj));
 		}
 
 		public CertID(
@@ -49,8 +38,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
             this.serialNumber = serialNumber;
         }
 
-		private CertID(
-            Asn1Sequence seq)
+		private CertID(Asn1Sequence seq)
         {
 			if (seq.Count != 4)
 				throw new ArgumentException("Wrong number of elements in sequence", "seq");
diff --git a/crypto/src/asn1/ocsp/CrlID.cs b/crypto/src/asn1/ocsp/CrlID.cs
index 24dda4edf..8736b83ab 100644
--- a/crypto/src/asn1/ocsp/CrlID.cs
+++ b/crypto/src/asn1/ocsp/CrlID.cs
@@ -9,8 +9,24 @@ namespace Org.BouncyCastle.Asn1.Ocsp
         private readonly DerInteger			crlNum;
         private readonly Asn1GeneralizedTime crlTime;
 
-		// TODO Add GetInstance method(s) and make this private?
-		public CrlID(Asn1Sequence seq)
+        public static CrlID GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return GetInstance(Asn1Sequence.GetInstance(taggedObject, declaredExplicit));
+        }
+
+        public static CrlID GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is CrlID crlID)
+                return crlID;
+#pragma warning disable CS0618 // Type or member is obsolete
+            return new CrlID(Asn1Sequence.GetInstance(obj));
+#pragma warning restore CS0618 // Type or member is obsolete
+        }
+
+        [Obsolete("Use 'GetInstance' instead")]
+        public CrlID(Asn1Sequence seq)
         {
 			foreach (Asn1TaggedObject o in seq)
 			{
diff --git a/crypto/src/asn1/pkcs/CertBag.cs b/crypto/src/asn1/pkcs/CertBag.cs
index ddaa353fb..81868fef6 100644
--- a/crypto/src/asn1/pkcs/CertBag.cs
+++ b/crypto/src/asn1/pkcs/CertBag.cs
@@ -7,46 +7,38 @@ namespace Org.BouncyCastle.Asn1.Pkcs
     {
         public static CertBag GetInstance(object obj)
         {
-            if (obj is CertBag)
-                return (CertBag)obj;
+            if (obj is CertBag certBag)
+                return certBag;
             if (obj == null)
                 return null;
             return new CertBag(Asn1Sequence.GetInstance(obj));
         }
 
-        private readonly DerObjectIdentifier certID;
-        private readonly Asn1Object certValue;
+        private readonly DerObjectIdentifier m_certID;
+        private readonly Asn1Object m_certValue;
 
 		private CertBag(Asn1Sequence seq)
         {
 			if (seq.Count != 2)
-				throw new ArgumentException("Wrong number of elements in sequence", "seq");
+				throw new ArgumentException("Wrong number of elements in sequence", nameof(seq));
 
-            this.certID = DerObjectIdentifier.GetInstance(seq[0]);
-            this.certValue = Asn1TaggedObject.GetInstance(seq[1]).GetObject();
+            this.m_certID = DerObjectIdentifier.GetInstance(seq[0]);
+            this.m_certValue = Asn1TaggedObject.GetInstance(seq[1]).GetObject();
         }
 
-		public CertBag(
-            DerObjectIdentifier	certID,
-            Asn1Object			certValue)
+		public CertBag(DerObjectIdentifier certID, Asn1Object certValue)
         {
-            this.certID = certID;
-            this.certValue = certValue;
+            m_certID = certID;
+            m_certValue = certValue;
         }
 
-		public virtual DerObjectIdentifier CertID
-		{
-			get { return certID; }
-		}
+        public virtual DerObjectIdentifier CertID => m_certID;
 
-		public virtual Asn1Object CertValue
-		{
-			get { return certValue; }
-		}
+        public virtual Asn1Object CertValue => m_certValue;
 
 		public override Asn1Object ToAsn1Object()
         {
-			return new DerSequence(certID, new DerTaggedObject(0, certValue));
+			return new DerSequence(m_certID, new DerTaggedObject(0, m_certValue));
         }
     }
 }
diff --git a/crypto/src/asn1/pkcs/ContentInfo.cs b/crypto/src/asn1/pkcs/ContentInfo.cs
index d19b4659c..05d9a2033 100644
--- a/crypto/src/asn1/pkcs/ContentInfo.cs
+++ b/crypto/src/asn1/pkcs/ContentInfo.cs
@@ -1,5 +1,3 @@
-using System;
-
 namespace Org.BouncyCastle.Asn1.Pkcs
 {
     public class ContentInfo
@@ -12,9 +10,8 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         {
             if (obj == null)
                 return null;
-            ContentInfo existing = obj as ContentInfo;
-            if (existing != null)
-                return existing;
+            if (obj is ContentInfo contentInfo)
+                return contentInfo;
             return new ContentInfo(Asn1Sequence.GetInstance(obj));
         }
 
diff --git a/crypto/src/asn1/pkcs/CrlBag.cs b/crypto/src/asn1/pkcs/CrlBag.cs
new file mode 100644
index 000000000..5cc68ace4
--- /dev/null
+++ b/crypto/src/asn1/pkcs/CrlBag.cs
@@ -0,0 +1,44 @@
+using System;
+
+namespace Org.BouncyCastle.Asn1.Pkcs
+{
+    public class CrlBag
+        : Asn1Encodable
+    {
+        public static CrlBag GetInstance(object obj)
+        {
+            if (obj is CrlBag crlBag)
+                return crlBag;
+            if (obj == null)
+                return null;
+            return new CrlBag(Asn1Sequence.GetInstance(obj));
+        }
+
+        private readonly DerObjectIdentifier m_crlID;
+        private readonly Asn1Encodable m_crlValue;
+
+        private CrlBag(Asn1Sequence seq)
+        {
+            if (seq.Count != 2)
+                throw new ArgumentException("Wrong number of elements in sequence", nameof(seq));
+
+            m_crlID = DerObjectIdentifier.GetInstance(seq[0]);
+            m_crlValue = Asn1TaggedObject.GetInstance(seq[1]).GetObject();
+        }
+
+        public CrlBag(DerObjectIdentifier crlID, Asn1Encodable crlValue)
+        {
+            m_crlID = crlID;
+            m_crlValue = crlValue;
+        }
+
+        public virtual DerObjectIdentifier CrlID => m_crlID;
+
+        public virtual Asn1Encodable CrlValue => m_crlValue;
+
+        public override Asn1Object ToAsn1Object()
+        {
+            return new DerSequence(m_crlID, new DerTaggedObject(0, m_crlValue));
+        }
+    }
+}
diff --git a/crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs b/crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs
index 5ca612f27..bf0e1aaeb 100644
--- a/crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs
+++ b/crypto/src/asn1/pkcs/EncryptedPrivateKeyInfo.cs
@@ -1,7 +1,6 @@
 using System;
 
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Pkcs
 {
@@ -28,19 +27,14 @@ namespace Org.BouncyCastle.Asn1.Pkcs
             this.data = new DerOctetString(encoding);
         }
 
-		public static EncryptedPrivateKeyInfo GetInstance(
-             object obj)
+        public static EncryptedPrivateKeyInfo GetInstance(object obj)
         {
-			if (obj is EncryptedPrivateKeyInfo)
-			{
-				return (EncryptedPrivateKeyInfo) obj;
-			}
-
-			if (obj is Asn1Sequence seq)
-				return new EncryptedPrivateKeyInfo(seq);
-
-			throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+            if (obj == null)
+                return null;
+            if (obj is EncryptedPrivateKeyInfo encryptedPrivateKeyInfo)
+                return encryptedPrivateKeyInfo;
+            return new EncryptedPrivateKeyInfo(Asn1Sequence.GetInstance(obj));
+        }
 
 		public AlgorithmIdentifier EncryptionAlgorithm
 		{
diff --git a/crypto/src/asn1/pkcs/PBEParameter.cs b/crypto/src/asn1/pkcs/PBEParameter.cs
index e8e7c5a82..31d9ad1f3 100644
--- a/crypto/src/asn1/pkcs/PBEParameter.cs
+++ b/crypto/src/asn1/pkcs/PBEParameter.cs
@@ -1,7 +1,6 @@
 using System;
 
 using Org.BouncyCastle.Math;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Pkcs
 {
@@ -11,20 +10,14 @@ namespace Org.BouncyCastle.Asn1.Pkcs
 		private readonly Asn1OctetString	salt;
 		private readonly DerInteger			iterationCount;
 
-		public static PbeParameter GetInstance(object obj)
-		{
-			if (obj is PbeParameter || obj == null)
-			{
-				return (PbeParameter) obj;
-			}
-
-			if (obj is Asn1Sequence)
-			{
-				return new PbeParameter((Asn1Sequence) obj);
-			}
-
-			throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+        public static PbeParameter GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is PbeParameter pbeParameter)
+                return pbeParameter;
+            return new PbeParameter(Asn1Sequence.GetInstance(obj));
+        }
 
 		private PbeParameter(Asn1Sequence seq)
 		{
diff --git a/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs b/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
index 570e0ded7..5d5f67127 100644
--- a/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
+++ b/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
@@ -145,6 +145,11 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         public static readonly DerObjectIdentifier IdAlgPwriKek         = IdAlg.Branch("9");
         public static readonly DerObjectIdentifier IdAlgSsdh            = IdAlg.Branch("10");
 
+        /** RFC 6211 -  id-aa-cmsAlgorithmProtect OBJECT IDENTIFIER ::= {
+iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1)
+pkcs9(9) 52 }  */
+        public static readonly DerObjectIdentifier id_aa_cmsAlgorithmProtect = new DerObjectIdentifier(Pkcs9 + ".52");
+
         /*
          * <pre>
          * -- RSA-KEM Key Transport Algorithm
diff --git a/crypto/src/asn1/pkcs/SignerInfo.cs b/crypto/src/asn1/pkcs/SignerInfo.cs
index 7abd8e5c6..777251e84 100644
--- a/crypto/src/asn1/pkcs/SignerInfo.cs
+++ b/crypto/src/asn1/pkcs/SignerInfo.cs
@@ -1,7 +1,4 @@
-using System;
-
 using Org.BouncyCastle.Asn1.X509;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1.Pkcs
 {
@@ -19,21 +16,14 @@ namespace Org.BouncyCastle.Asn1.Pkcs
         private Asn1OctetString         encryptedDigest;
         private Asn1Set                 unauthenticatedAttributes;
 
-		public static SignerInfo GetInstance(
-            object obj)
+        public static SignerInfo GetInstance(object obj)
         {
-            if (obj is SignerInfo)
-            {
-                return (SignerInfo) obj;
-            }
-
-			if (obj is Asn1Sequence)
-            {
-                return new SignerInfo((Asn1Sequence) obj);
-            }
-
-			throw new ArgumentException("Unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+            if (obj == null)
+                return null;
+            if (obj is SignerInfo signerInfo)
+                return signerInfo;
+            return new SignerInfo(Asn1Sequence.GetInstance(obj));
+        }
 
 		public SignerInfo(
             DerInteger              version,
diff --git a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
index 5edb24045..d022ab8a5 100644
--- a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
+++ b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
@@ -47,7 +47,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("E95E4A5F737059DC60DFC7AD95B3D8139515620F"), // q
                     FromHex("340E7BE2A280EB74E2BE61BADA745D97E8F7C300"), // a
                     FromHex("1E589A8595423412134FAA2DBDEC95C8D8675E58"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -78,7 +78,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("E95E4A5F737059DC60DFC7AD95B3D8139515620F"), // q
                     FromHex("E95E4A5F737059DC60DFC7AD95B3D8139515620C"), // a
                     FromHex("7A556B6DAE535B7B51ED2C4D7DAA7A0B5C55F380"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -108,7 +108,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297"), // q
                     FromHex("6A91174076B1E0E19C39C031FE8685C1CAE040E5C69A28EF"), // a
                     FromHex("469A28EF7C28CCA3DC721D044F4496BCCA7EF4146FBF25C9"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -139,7 +139,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86297"), // q
                     FromHex("C302F41D932A36CDA7A3463093D18DB78FCE476DE1A86294"), // a
                     FromHex("13D56FFAEC78681E68F9DEB43B35BEC2FB68542E27897B79"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -169,7 +169,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF"), // q
                     FromHex("68A5E62CA9CE6C1C299803A6C1530B514E182AD8B0042A59CAD29F43"), // a
                     FromHex("2580F63CCFE44138870713B1A92369E33E2135D266DBB372386C400B"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -200,7 +200,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FF"), // q
                     FromHex("D7C134AA264366862A18302575D1D787B09F075797DA89F57EC8C0FC"), // a
                     FromHex("4B337D934104CD7BEF271BF60CED1ED20DA14C08B3BB64F18A60888D"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -230,7 +230,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377"), // q
                     FromHex("7D5A0975FC2C3057EEF67530417AFFE7FB8055C126DC5C6CE94A4B44F330B5D9"), // a
                     FromHex("26DC5C6CE94A4B44F330B5D9BBD77CBF958416295CF7E1CE6BCCDC18FF8C07B6"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -261,7 +261,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5377"), // q
                     FromHex("A9FB57DBA1EEA9BC3E660A909D838D726E3BF623D52620282013481D1F6E5374"), // a
                     FromHex("662C61C430D84EA4FE66A7733D0B76B7BF93EBC4AF2F49256AE58101FEE92B04"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -291,7 +291,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27"), // q
                     FromHex("3EE30B568FBAB0F883CCEBD46D3F3BB8A2A73513F5EB79DA66190EB085FFA9F492F375A97D860EB4"), // a
                     FromHex("520883949DFDBC42D3AD198640688A6FE13F41349554B49ACC31DCCD884539816F5EB4AC8FB1F1A6"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -322,7 +322,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E27"), // q
                     FromHex("D35E472036BC4FB7E13C785ED201E065F98FCFA6F6F40DEF4F92B9EC7893EC28FCD412B1F1B32E24"), // a
                     FromHex("A7F561E038EB1ED560B3D147DB782013064C19F27ED27C6780AAF77FB8A547CEB5B4FEF422340353"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -352,7 +352,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53"), // q
                     FromHex("7BC382C63D8C150C3C72080ACE05AFA0C2BEA28E4FB22787139165EFBA91F90F8AA5814A503AD4EB04A8C7DD22CE2826"), // a
                     FromHex("04A8C7DD22CE28268B39B55416F0447C2FB77DE107DCD2A62E880EA53EEB62D57CB4390295DBC9943AB78696FA504C11"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -383,7 +383,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC53"), // q
                     FromHex("8CB91E82A3386D280F5D6F7E50E641DF152F7109ED5456B412B1DA197FB71123ACD3A729901D1A71874700133107EC50"), // a
                     FromHex("7F519EADA7BDA81BD826DBA647910F8C4B9346ED8CCDC64E4B1ABD11756DCE1D2074AA263B88805CED70355A33B471EE"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -413,7 +413,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3"), // q
                     FromHex("7830A3318B603B89E2327145AC234CC594CBDD8D3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CA"), // a
                     FromHex("3DF91610A83441CAEA9863BC2DED5D5AA8253AA10A2EF1C98B9AC8B57F1117A72BF2C7B9E7C1AC4D77FC94CADC083E67984050B75EBAE5DD2809BD638016F723"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
@@ -444,7 +444,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
                     FromHex("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F3"), // q
                     FromHex("AADD9DB8DBE9C48B3FD4E6AE33C9FC07CB308DB3B3C9D20ED6639CCA703308717D4D9B009BC66842AECDA12AE6A380E62881FF2F2D82C68528AA6056583A48F0"), // a
                     FromHex("7CBBBCF9441CFAB76E1890E46884EAE321F70C0BCB4981527897504BEC3E36A62BCDFA2304976540F6450085F2DAE145C22553B465763689180EA2571867423E"), // b
-                    n, h));
+                    n, h, true));
             }
 
             protected override X9ECParameters CreateParameters()
diff --git a/crypto/src/asn1/tsp/TSTInfo.cs b/crypto/src/asn1/tsp/TSTInfo.cs
index dde11494c..c37208d3c 100644
--- a/crypto/src/asn1/tsp/TSTInfo.cs
+++ b/crypto/src/asn1/tsp/TSTInfo.cs
@@ -64,14 +64,14 @@ namespace Org.BouncyCastle.Asn1.Tsp
 
 					switch (tagged.TagNo)
 					{
-						case 0:
-							tsa = GeneralName.GetInstance(tagged, true);
-							break;
-						case 1:
-							extensions = X509Extensions.GetInstance(tagged, false);
-							break;
-						default:
-							throw new ArgumentException("Unknown tag value " + tagged.TagNo);
+					case 0:
+						tsa = GeneralName.GetInstance(tagged, true);
+						break;
+					case 1:
+						extensions = X509Extensions.GetInstance(tagged, false);
+						break;
+					default:
+						throw new ArgumentException("Unknown tag value " + tagged.TagNo);
 					}
 				}
 
diff --git a/crypto/src/asn1/x509/AuthorityInformationAccess.cs b/crypto/src/asn1/x509/AuthorityInformationAccess.cs
index 382513674..c601322c5 100644
--- a/crypto/src/asn1/x509/AuthorityInformationAccess.cs
+++ b/crypto/src/asn1/x509/AuthorityInformationAccess.cs
@@ -1,8 +1,6 @@
 using System;
 using System.Text;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.X509
 {
     /**
@@ -31,10 +29,10 @@ namespace Org.BouncyCastle.Asn1.X509
 
         public static AuthorityInformationAccess GetInstance(object obj)
         {
-            if (obj is AuthorityInformationAccess)
-                return (AuthorityInformationAccess)obj;
             if (obj == null)
                 return null;
+            if (obj is AuthorityInformationAccess authorityInformationAccess)
+                return authorityInformationAccess;
             return new AuthorityInformationAccess(Asn1Sequence.GetInstance(obj));
         }
 
diff --git a/crypto/src/asn1/x509/CertificateList.cs b/crypto/src/asn1/x509/CertificateList.cs
index 3d5d2e557..5d73cf411 100644
--- a/crypto/src/asn1/x509/CertificateList.cs
+++ b/crypto/src/asn1/x509/CertificateList.cs
@@ -23,26 +23,21 @@ namespace Org.BouncyCastle.Asn1.X509
         private readonly AlgorithmIdentifier sigAlgID;
         private readonly DerBitString sig;
 
-		public static CertificateList GetInstance(
-            Asn1TaggedObject	obj,
-            bool				explicitly)
+        public static CertificateList GetInstance(Asn1TaggedObject obj, bool explicitly)
         {
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		public static CertificateList GetInstance(
-            object obj)
+        public static CertificateList GetInstance(object obj)
         {
-            if (obj is CertificateList)
-                return (CertificateList) obj;
-
-			if (obj != null)
-				return new CertificateList(Asn1Sequence.GetInstance(obj));
-
-			return null;
-		}
+            if (obj == null)
+                return null;
+            if (obj is CertificateList certificateList)
+                return certificateList;
+            return new CertificateList(Asn1Sequence.GetInstance(obj));
+        }
 
-		private CertificateList(
+        private CertificateList(
             Asn1Sequence seq)
         {
 			if (seq.Count != 3)
diff --git a/crypto/src/asn1/x509/DistributionPoint.cs b/crypto/src/asn1/x509/DistributionPoint.cs
index f35586016..077c9321e 100644
--- a/crypto/src/asn1/x509/DistributionPoint.cs
+++ b/crypto/src/asn1/x509/DistributionPoint.cs
@@ -1,8 +1,5 @@
-using System;
 using System.Text;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.X509
 {
     /**
@@ -18,35 +15,25 @@ namespace Org.BouncyCastle.Asn1.X509
     public class DistributionPoint
         : Asn1Encodable
     {
-        internal readonly DistributionPointName	distributionPoint;
-        internal readonly ReasonFlags			reasons;
-        internal readonly GeneralNames			cRLIssuer;
-
-		public static DistributionPoint GetInstance(
-            Asn1TaggedObject	obj,
-            bool				explicitly)
+		public static DistributionPoint GetInstance(object obj)
         {
-            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
+            if (obj == null)
+                return null;
+            if (obj is DistributionPoint distributionPoint)
+                return distributionPoint;
+            return new DistributionPoint(Asn1Sequence.GetInstance(obj));
         }
 
-		public static DistributionPoint GetInstance(
-            object obj)
+        public static DistributionPoint GetInstance(Asn1TaggedObject obj, bool explicitly)
         {
-            if(obj == null || obj is DistributionPoint)
-            {
-                return (DistributionPoint) obj;
-            }
-
-			if(obj is Asn1Sequence)
-            {
-                return new DistributionPoint((Asn1Sequence) obj);
-            }
-
-            throw new ArgumentException("Invalid DistributionPoint: " + Platform.GetTypeName(obj));
+            return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		private DistributionPoint(
-            Asn1Sequence seq)
+        private readonly DistributionPointName m_distributionPoint;
+        private readonly ReasonFlags m_reasons;
+        private readonly GeneralNames m_crlIssuer;
+
+        private DistributionPoint(Asn1Sequence seq)
         {
             for (int i = 0; i != seq.Count; i++)
             {
@@ -55,52 +42,41 @@ namespace Org.BouncyCastle.Asn1.X509
 				switch (t.TagNo)
                 {
                 case 0:
-                    distributionPoint = DistributionPointName.GetInstance(t, true);
+                    m_distributionPoint = DistributionPointName.GetInstance(t, true);
                     break;
                 case 1:
-                    reasons = new ReasonFlags(DerBitString.GetInstance(t, false));
+                    m_reasons = new ReasonFlags(DerBitString.GetInstance(t, false));
                     break;
                 case 2:
-                    cRLIssuer = GeneralNames.GetInstance(t, false);
+                    m_crlIssuer = GeneralNames.GetInstance(t, false);
                     break;
                 }
             }
         }
 
-		public DistributionPoint(
-            DistributionPointName	distributionPointName,
-            ReasonFlags				reasons,
-            GeneralNames			crlIssuer)
+		public DistributionPoint(DistributionPointName distributionPointName, ReasonFlags reasons,
+            GeneralNames crlIssuer)
         {
-            this.distributionPoint = distributionPointName;
-            this.reasons = reasons;
-            this.cRLIssuer = crlIssuer;
+            m_distributionPoint = distributionPointName;
+            m_reasons = reasons;
+            m_crlIssuer = crlIssuer;
         }
 
-		public DistributionPointName DistributionPointName
-        {
-			get { return distributionPoint; }
-        }
+        public DistributionPointName DistributionPointName => m_distributionPoint;
 
-		public ReasonFlags Reasons
-        {
-			get { return reasons; }
-        }
+		public ReasonFlags Reasons => m_reasons;
 
-		public GeneralNames CrlIssuer
-        {
-			get { return cRLIssuer; }
-        }
+		public GeneralNames CrlIssuer => m_crlIssuer;
 
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector();
+            Asn1EncodableVector v = new Asn1EncodableVector(3);
 
             // As this is a CHOICE it must be explicitly tagged
-            v.AddOptionalTagged(true, 0, distributionPoint);
+            v.AddOptionalTagged(true, 0, m_distributionPoint);
 
-            v.AddOptionalTagged(false, 1, reasons);
-            v.AddOptionalTagged(false, 2, cRLIssuer);
+            v.AddOptionalTagged(false, 1, m_reasons);
+            v.AddOptionalTagged(false, 2, m_crlIssuer);
             return new DerSequence(v);
         }
 
@@ -108,17 +84,17 @@ namespace Org.BouncyCastle.Asn1.X509
 		{
 			StringBuilder buf = new StringBuilder();
 			buf.AppendLine("DistributionPoint: [");
-			if (distributionPoint != null)
+			if (m_distributionPoint != null)
 			{
-                AppendObject(buf, "distributionPoint", distributionPoint.ToString());
+                AppendObject(buf, "distributionPoint", m_distributionPoint.ToString());
 			}
-			if (reasons != null)
+			if (m_reasons != null)
 			{
-                AppendObject(buf, "reasons", reasons.ToString());
+                AppendObject(buf, "reasons", m_reasons.ToString());
 			}
-			if (cRLIssuer != null)
+			if (m_crlIssuer != null)
 			{
-                AppendObject(buf, "cRLIssuer", cRLIssuer.ToString());
+                AppendObject(buf, "cRLIssuer", m_crlIssuer.ToString());
 			}
 			buf.AppendLine("]");
 			return buf.ToString();
diff --git a/crypto/src/asn1/x509/DistributionPointName.cs b/crypto/src/asn1/x509/DistributionPointName.cs
index bca54fa06..bdb7219be 100644
--- a/crypto/src/asn1/x509/DistributionPointName.cs
+++ b/crypto/src/asn1/x509/DistributionPointName.cs
@@ -1,8 +1,5 @@
-using System;
 using System.Text;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.X509
 {
     /**
@@ -17,90 +14,71 @@ namespace Org.BouncyCastle.Asn1.X509
     public class DistributionPointName
         : Asn1Encodable, IAsn1Choice
     {
-        internal readonly Asn1Encodable	name;
-        internal readonly int			type;
-
-		public const int FullName					= 0;
-        public const int NameRelativeToCrlIssuer	= 1;
+        public const int FullName = 0;
+        public const int NameRelativeToCrlIssuer = 1;
 
-		public static DistributionPointName GetInstance(
-            Asn1TaggedObject	obj,
-            bool				explicitly)
+		public static DistributionPointName GetInstance(object obj)
         {
-            return GetInstance(Asn1TaggedObject.GetInstance(obj, true));
-        }
-
-		public static DistributionPointName GetInstance(
-            object obj)
-        {
-            if (obj == null || obj is DistributionPointName)
-            {
-                return (DistributionPointName) obj;
-            }
-
-			if (obj is Asn1TaggedObject)
-            {
-                return new DistributionPointName((Asn1TaggedObject) obj);
-            }
-
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+            if (obj == null)
+                return null;
+            if (obj is DistributionPointName distributionPointName)
+                return distributionPointName;
+            return new DistributionPointName(Asn1TaggedObject.GetInstance(obj));
 		}
 
-        public DistributionPointName(
-            int				type,
-            Asn1Encodable	name)
+		public static DistributionPointName GetInstance(Asn1TaggedObject obj, bool explicitly)
         {
-            this.type = type;
-            this.name = name;
+            return GetInstance(Asn1TaggedObject.GetInstance(obj, true));
         }
 
-		public DistributionPointName(
-			GeneralNames name)
-			:	this(FullName, name)
-		{
-		}
+        private readonly Asn1Encodable m_name;
+        private readonly int m_type;
 
-		public int PointType
+        public DistributionPointName(GeneralNames name)
+            : this(FullName, name)
         {
-			get { return type; }
         }
 
-		public Asn1Encodable Name
+        public DistributionPointName(int type, Asn1Encodable name)
         {
-			get { return name; }
+            m_type = type;
+            m_name = name;
         }
 
-		public DistributionPointName(
-            Asn1TaggedObject obj)
+		public int PointType => m_type;
+
+		public Asn1Encodable Name => m_name;
+
+		public DistributionPointName(Asn1TaggedObject obj)
         {
-            this.type = obj.TagNo;
+            m_type = obj.TagNo;
 
-			if (type == FullName)
+			if (m_type == FullName)
             {
-                this.name = GeneralNames.GetInstance(obj, false);
+                m_name = GeneralNames.GetInstance(obj, false);
             }
             else
             {
-                this.name = Asn1Set.GetInstance(obj, false);
+                m_name = Asn1Set.GetInstance(obj, false);
             }
         }
 
 		public override Asn1Object ToAsn1Object()
         {
-            return new DerTaggedObject(false, type, name);
+            return new DerTaggedObject(false, m_type, m_name);
         }
 
 		public override string ToString()
 		{
 			StringBuilder buf = new StringBuilder();
 			buf.AppendLine("DistributionPointName: [");
-			if (type == FullName)
+			if (m_type == FullName)
 			{
-				AppendObject(buf, "fullName", name.ToString());
+				AppendObject(buf, "fullName", m_name.ToString());
 			}
 			else
 			{
-				AppendObject(buf, "nameRelativeToCRLIssuer", name.ToString());
+				AppendObject(buf, "nameRelativeToCRLIssuer", m_name.ToString());
 			}
 			buf.AppendLine("]");
 			return buf.ToString();
diff --git a/crypto/src/asn1/x509/ExtendedKeyUsage.cs b/crypto/src/asn1/x509/ExtendedKeyUsage.cs
index f812c308d..08962ab72 100644
--- a/crypto/src/asn1/x509/ExtendedKeyUsage.cs
+++ b/crypto/src/asn1/x509/ExtendedKeyUsage.cs
@@ -67,10 +67,8 @@ namespace Org.BouncyCastle.Asn1.X509
         {
             Asn1EncodableVector v = new Asn1EncodableVector();
 
-            foreach (object usage in usages)
+            foreach (var oid in usages)
             {
-                DerObjectIdentifier oid = DerObjectIdentifier.GetInstance(usage);
-
                 v.Add(oid);
                 m_usageTable.Add(oid);
             }
diff --git a/crypto/src/asn1/x509/GeneralNames.cs b/crypto/src/asn1/x509/GeneralNames.cs
index acf263f84..3937b3279 100644
--- a/crypto/src/asn1/x509/GeneralNames.cs
+++ b/crypto/src/asn1/x509/GeneralNames.cs
@@ -1,24 +1,16 @@
-using System;
 using System.Text;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.X509
 {
 	public class GeneralNames
 		: Asn1Encodable
 	{
-        private static GeneralName[] Copy(GeneralName[] names)
-        {
-            return (GeneralName[])names.Clone();
-        }
-
         public static GeneralNames GetInstance(object obj)
 		{
-            if (obj is GeneralNames)
-                return (GeneralNames)obj;
             if (obj == null)
                 return null;
+            if (obj is GeneralNames generalNames)
+                return generalNames;
             return new GeneralNames(Asn1Sequence.GetInstance(obj));
 		}
 
@@ -32,36 +24,33 @@ namespace Org.BouncyCastle.Asn1.X509
             return GetInstance(X509Extensions.GetExtensionParsedValue(extensions, extOid));
         }
 
-        private readonly GeneralName[] names;
+        private static GeneralName[] Copy(GeneralName[] names)
+        {
+            return (GeneralName[])names.Clone();
+        }
+
+        private readonly GeneralName[] m_names;
 
         /// <summary>Construct a GeneralNames object containing one GeneralName.</summary>
 		/// <param name="name">The name to be contained.</param>
-		public GeneralNames(
-			GeneralName name)
+		public GeneralNames(GeneralName name)
 		{
-			names = new GeneralName[]{ name };
+			m_names = new GeneralName[]{ name };
 		}
 
-        public GeneralNames(
-            GeneralName[] names)
+        public GeneralNames(GeneralName[] names)
         {
-            this.names = Copy(names);
+            m_names = Copy(names);
         }
 
-		private GeneralNames(
-			Asn1Sequence seq)
+		private GeneralNames(Asn1Sequence seq)
 		{
-			this.names = new GeneralName[seq.Count];
-
-			for (int i = 0; i != seq.Count; i++)
-			{
-				names[i] = GeneralName.GetInstance(seq[i]);
-			}
+			m_names = seq.MapElements(GeneralName.GetInstance);
 		}
 
 		public GeneralName[] GetNames()
 		{
-            return Copy(names);
+            return Copy(m_names);
 		}
 
 		/**
@@ -72,14 +61,14 @@ namespace Org.BouncyCastle.Asn1.X509
 		 */
 		public override Asn1Object ToAsn1Object()
 		{
-			return new DerSequence(names);
+			return new DerSequence(m_names);
 		}
 
 		public override string ToString()
 		{
 			StringBuilder buf = new StringBuilder();
 			buf.AppendLine("GeneralNames:");
-			foreach (GeneralName name in names)
+			foreach (GeneralName name in m_names)
 			{
 				buf.Append("    ")
 				   .Append(name)
diff --git a/crypto/src/asn1/x509/IssuingDistributionPoint.cs b/crypto/src/asn1/x509/IssuingDistributionPoint.cs
index a05efffa4..0287fd8f5 100644
--- a/crypto/src/asn1/x509/IssuingDistributionPoint.cs
+++ b/crypto/src/asn1/x509/IssuingDistributionPoint.cs
@@ -1,8 +1,6 @@
 using System;
 using System.Text;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.X509
 {
 	/**
@@ -28,27 +26,18 @@ namespace Org.BouncyCastle.Asn1.X509
 
 		private readonly Asn1Sequence seq;
 
-		public static IssuingDistributionPoint GetInstance(
-            Asn1TaggedObject	obj,
-            bool				explicitly)
+		public static IssuingDistributionPoint GetInstance(Asn1TaggedObject	obj, bool explicitly)
         {
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-		public static IssuingDistributionPoint GetInstance(
-            object obj)
+		public static IssuingDistributionPoint GetInstance(object obj)
         {
-            if (obj == null || obj is IssuingDistributionPoint)
-            {
-                return (IssuingDistributionPoint) obj;
-            }
-
-			if (obj is Asn1Sequence)
-            {
-                return new IssuingDistributionPoint((Asn1Sequence) obj);
-            }
-
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
+			if (obj == null)
+				return null;
+            if (obj is IssuingDistributionPoint issuingDistributionPoint)
+                return issuingDistributionPoint;
+            return new IssuingDistributionPoint(Asn1Sequence.GetInstance(obj));
 		}
 
 		/**
@@ -113,8 +102,7 @@ namespace Org.BouncyCastle.Asn1.X509
 		/**
          * Constructor from Asn1Sequence
          */
-        private IssuingDistributionPoint(
-            Asn1Sequence seq)
+        private IssuingDistributionPoint(Asn1Sequence seq)
         {
             this.seq = seq;
 
@@ -124,27 +112,27 @@ namespace Org.BouncyCastle.Asn1.X509
 
 				switch (o.TagNo)
                 {
-					case 0:
-						// CHOICE so explicit
-						_distributionPoint = DistributionPointName.GetInstance(o, true);
-						break;
-					case 1:
-						_onlyContainsUserCerts = DerBoolean.GetInstance(o, false).IsTrue;
-						break;
-					case 2:
-						_onlyContainsCACerts = DerBoolean.GetInstance(o, false).IsTrue;
-						break;
-					case 3:
-						_onlySomeReasons = new ReasonFlags(ReasonFlags.GetInstance(o, false));
-						break;
-					case 4:
-						_indirectCRL = DerBoolean.GetInstance(o, false).IsTrue;
-						break;
-					case 5:
-						_onlyContainsAttributeCerts = DerBoolean.GetInstance(o, false).IsTrue;
-						break;
-					default:
-						throw new ArgumentException("unknown tag in IssuingDistributionPoint");
+				case 0:
+					// CHOICE so explicit
+					_distributionPoint = DistributionPointName.GetInstance(o, true);
+					break;
+				case 1:
+					_onlyContainsUserCerts = DerBoolean.GetInstance(o, false).IsTrue;
+					break;
+				case 2:
+					_onlyContainsCACerts = DerBoolean.GetInstance(o, false).IsTrue;
+					break;
+				case 3:
+					_onlySomeReasons = new ReasonFlags(ReasonFlags.GetInstance(o, false));
+					break;
+				case 4:
+					_indirectCRL = DerBoolean.GetInstance(o, false).IsTrue;
+					break;
+				case 5:
+					_onlyContainsAttributeCerts = DerBoolean.GetInstance(o, false).IsTrue;
+					break;
+				default:
+					throw new ArgumentException("unknown tag in IssuingDistributionPoint");
                 }
             }
         }
diff --git a/crypto/src/asn1/x509/KeyUsage.cs b/crypto/src/asn1/x509/KeyUsage.cs
index b31b54341..dd69cc63b 100644
--- a/crypto/src/asn1/x509/KeyUsage.cs
+++ b/crypto/src/asn1/x509/KeyUsage.cs
@@ -32,10 +32,10 @@ namespace Org.BouncyCastle.Asn1.X509
 
 		public static new KeyUsage GetInstance(object obj)
 		{
-			if (obj is KeyUsage)
-				return (KeyUsage)obj;
-            if (obj is X509Extension)
-				return GetInstance(X509Extension.ConvertValueToObject((X509Extension)obj));
+			if (obj is KeyUsage keyUsage)
+				return keyUsage;
+            if (obj is X509Extension x509Extension)
+				return GetInstance(X509Extension.ConvertValueToObject(x509Extension));
             if (obj == null)
                 return null;
 			return new KeyUsage(DerBitString.GetInstance(obj));
diff --git a/crypto/src/asn1/x509/NameConstraints.cs b/crypto/src/asn1/x509/NameConstraints.cs
index 9fe4fdd01..590b14aa0 100644
--- a/crypto/src/asn1/x509/NameConstraints.cs
+++ b/crypto/src/asn1/x509/NameConstraints.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Collections.Generic;
+using System.Linq;
 
 using Org.BouncyCastle.Utilities;
 
@@ -68,12 +69,7 @@ namespace Org.BouncyCastle.Asn1.X509
 
 		private DerSequence CreateSequence(IList<GeneralSubtree> subtrees)
 		{
-            GeneralSubtree[] gsts = new GeneralSubtree[subtrees.Count];
-            for (int i = 0; i < subtrees.Count; ++i)
-            {
-                gsts[i] = subtrees[i];
-            }
-            return new DerSequence(gsts);
+            return new DerSequence(subtrees.ToArray());
 		}
 
 		public Asn1Sequence PermittedSubtrees
@@ -92,7 +88,7 @@ namespace Org.BouncyCastle.Asn1.X509
 		 */
         public override Asn1Object ToAsn1Object()
         {
-            Asn1EncodableVector v = new Asn1EncodableVector();
+            Asn1EncodableVector v = new Asn1EncodableVector(2);
             v.AddOptionalTagged(false, 0, permitted);
             v.AddOptionalTagged(false, 1, excluded);
             return new DerSequence(v);
diff --git a/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs b/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
index 6ebd35e21..c8f24ecd5 100644
--- a/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
+++ b/crypto/src/asn1/x509/SubjectDirectoryAttributes.cs
@@ -1,7 +1,5 @@
-using System;
 using System.Collections.Generic;
 
-using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
 
 namespace Org.BouncyCastle.Asn1.X509
@@ -28,23 +26,16 @@ namespace Org.BouncyCastle.Asn1.X509
 	public class SubjectDirectoryAttributes
 		: Asn1Encodable
 	{
-		private readonly IList<AttributeX509> m_attributes;
+		private readonly List<AttributeX509> m_attributes;
 
-		public static SubjectDirectoryAttributes GetInstance(
-			object obj)
-		{
-			if (obj == null || obj is SubjectDirectoryAttributes)
-			{
-				return (SubjectDirectoryAttributes) obj;
-			}
-
-			if (obj is Asn1Sequence)
-			{
-				return new SubjectDirectoryAttributes((Asn1Sequence) obj);
-			}
-
-            throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
-		}
+        public static SubjectDirectoryAttributes GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+            if (obj is SubjectDirectoryAttributes subjectDirectoryAttributes)
+                return subjectDirectoryAttributes;
+            return new SubjectDirectoryAttributes(Asn1Sequence.GetInstance(obj));
+        }
 
 		/**
 		 * Constructor from Asn1Sequence.
@@ -114,12 +105,7 @@ namespace Org.BouncyCastle.Asn1.X509
 		 */
 		public override Asn1Object ToAsn1Object()
 		{
-            AttributeX509[] v = new AttributeX509[m_attributes.Count];
-            for (int i = 0; i < m_attributes.Count; ++i)
-            {
-                v[i] = m_attributes[i];
-            }
-            return new DerSequence(v);
+            return new DerSequence(m_attributes.ToArray());
 		}
 
         /**
diff --git a/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs b/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
index 52f977e91..4875152eb 100644
--- a/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
+++ b/crypto/src/asn1/x509/SubjectPublicKeyInfo.cs
@@ -1,5 +1,4 @@
 using System;
-using System.IO;
 
 namespace Org.BouncyCastle.Asn1.X509
 {
diff --git a/crypto/src/asn1/x509/Time.cs b/crypto/src/asn1/x509/Time.cs
index e03055f6d..f7746257c 100644
--- a/crypto/src/asn1/x509/Time.cs
+++ b/crypto/src/asn1/x509/Time.cs
@@ -31,7 +31,7 @@ namespace Org.BouncyCastle.Asn1.X509
 
         public Time(Asn1GeneralizedTime generalizedTime)
         {
-            this.m_timeObject = generalizedTime ?? throw new ArgumentNullException(nameof(generalizedTime));
+            m_timeObject = generalizedTime ?? throw new ArgumentNullException(nameof(generalizedTime));
         }
 
         public Time(Asn1UtcTime utcTime)
@@ -42,7 +42,7 @@ namespace Org.BouncyCastle.Asn1.X509
             // Validate utcTime is in the appropriate year range
             utcTime.ToDateTime(2049);
 
-            this.m_timeObject = utcTime;
+            m_timeObject = utcTime;
         }
 
         /**
diff --git a/crypto/src/asn1/x509/V2TBSCertListGenerator.cs b/crypto/src/asn1/x509/V2TBSCertListGenerator.cs
index aa1a0b95d..bf016c22d 100644
--- a/crypto/src/asn1/x509/V2TBSCertListGenerator.cs
+++ b/crypto/src/asn1/x509/V2TBSCertListGenerator.cs
@@ -2,8 +2,6 @@ using System;
 using System.Collections.Generic;
 using System.IO;
 
-using Org.BouncyCastle.Utilities;
-
 namespace Org.BouncyCastle.Asn1.X509
 {
     /**
diff --git a/crypto/src/asn1/x509/X509CertificateStructure.cs b/crypto/src/asn1/x509/X509CertificateStructure.cs
index 6e7c85de6..5394b2be3 100644
--- a/crypto/src/asn1/x509/X509CertificateStructure.cs
+++ b/crypto/src/asn1/x509/X509CertificateStructure.cs
@@ -21,20 +21,17 @@ namespace Org.BouncyCastle.Asn1.X509
         private readonly AlgorithmIdentifier		sigAlgID;
         private readonly DerBitString				sig;
 
-        public static X509CertificateStructure GetInstance(
-            Asn1TaggedObject	obj,
-            bool				explicitly)
+        public static X509CertificateStructure GetInstance(Asn1TaggedObject obj, bool explicitly)
         {
             return GetInstance(Asn1Sequence.GetInstance(obj, explicitly));
         }
 
-        public static X509CertificateStructure GetInstance(
-            object obj)
+        public static X509CertificateStructure GetInstance(object obj)
         {
-            if (obj is X509CertificateStructure)
-                return (X509CertificateStructure)obj;
             if (obj == null)
                 return null;
+            if (obj is X509CertificateStructure x509CertificateStructure)
+                return x509CertificateStructure;
             return new X509CertificateStructure(Asn1Sequence.GetInstance(obj));
         }
 
diff --git a/crypto/src/asn1/x509/X509Extensions.cs b/crypto/src/asn1/x509/X509Extensions.cs
index a399058c2..aa5205800 100644
--- a/crypto/src/asn1/x509/X509Extensions.cs
+++ b/crypto/src/asn1/x509/X509Extensions.cs
@@ -175,12 +175,12 @@ namespace Org.BouncyCastle.Asn1.X509
 
         public static X509Extension GetExtension(X509Extensions extensions, DerObjectIdentifier oid)
         {
-            return null == extensions ? null : extensions.GetExtension(oid);
+            return extensions?.GetExtension(oid);
         }
 
         public static Asn1Encodable GetExtensionParsedValue(X509Extensions extensions, DerObjectIdentifier oid)
         {
-            return null == extensions ? null : extensions.GetExtensionParsedValue(oid);
+            return extensions?.GetExtensionParsedValue(oid);
         }
 
 		public static X509Extensions GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
diff --git a/crypto/src/asn1/x509/X509ExtensionsGenerator.cs b/crypto/src/asn1/x509/X509ExtensionsGenerator.cs
index 53d18ecff..7ea6084af 100644
--- a/crypto/src/asn1/x509/X509ExtensionsGenerator.cs
+++ b/crypto/src/asn1/x509/X509ExtensionsGenerator.cs
@@ -90,8 +90,6 @@ namespace Org.BouncyCastle.Asn1.X509
             }
         }
 
-
-
         /// <summary>Return true if there are no extension present in this generator.</summary>
         /// <returns>True if empty, false otherwise</returns>
         public bool IsEmpty
diff --git a/crypto/src/bcpg/ArmoredInputStream.cs b/crypto/src/bcpg/ArmoredInputStream.cs
index 7bd7b5c04..348f0bc32 100644
--- a/crypto/src/bcpg/ArmoredInputStream.cs
+++ b/crypto/src/bcpg/ArmoredInputStream.cs
@@ -243,7 +243,7 @@ namespace Org.BouncyCastle.Bcpg
 
 			if (headerList.Count > 0)
             {
-                header = (string)headerList[0];
+                header = headerList[0];
             }
 
 			clearText = "-----BEGIN PGP SIGNED MESSAGE-----".Equals(header);
@@ -290,7 +290,7 @@ namespace Org.BouncyCastle.Bcpg
 			string[] hdrs = new string[headerList.Count - 1];
             for (int i = 0; i != hdrs.Length; i++)
             {
-                hdrs[i] = (string)headerList[i + 1];
+                hdrs[i] = headerList[i + 1];
             }
 
 			return hdrs;
@@ -303,7 +303,7 @@ namespace Org.BouncyCastle.Bcpg
             {
                 c = input.ReadByte();
             }
-            while (c == ' ' || c == '\t' || c == '\f' || c == '\u000B') ; // \u000B ~ \v
+            while (c == ' ' || c == '\t' || c == '\f' || c == '\u000B'); // \u000B ~ \v
 
             if (c >= 128)
                 throw new IOException("invalid armor");
diff --git a/crypto/src/cmp/ProtectedPkiMessage.cs b/crypto/src/cmp/ProtectedPkiMessage.cs
index df4c45143..8bc9e4f4d 100644
--- a/crypto/src/cmp/ProtectedPkiMessage.cs
+++ b/crypto/src/cmp/ProtectedPkiMessage.cs
@@ -137,14 +137,9 @@ namespace Org.BouncyCastle.Cmp
 
         private TResult Process<TResult>(IStreamCalculator<TResult> streamCalculator)
         {
-            Asn1EncodableVector avec = new Asn1EncodableVector();
-            avec.Add(m_pkiMessage.Header);
-            avec.Add(m_pkiMessage.Body);
-            byte[] enc = new DerSequence(avec).GetDerEncoded();
-
-            using (var stream = streamCalculator.Stream)
+            using (var s = streamCalculator.Stream)
             {
-                stream.Write(enc, 0, enc.Length);
+                new DerSequence(m_pkiMessage.Header, m_pkiMessage.Body).EncodeTo(s, Asn1Encodable.Der);
             }
 
             return streamCalculator.GetResult();
diff --git a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
index 505747960..508b00ff5 100644
--- a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
+++ b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
@@ -3,7 +3,6 @@ using System.Collections.Generic;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Cmp;
-using Org.BouncyCastle.Asn1.Cms;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.X509;
@@ -98,7 +97,7 @@ namespace Org.BouncyCastle.Cmp
             if (null == body)
                 throw new InvalidOperationException("body must be set before building");
 
-            IStreamCalculator<IBlockResult> calculator = signatureFactory.CreateCalculator();
+            var calculator = signatureFactory.CreateCalculator();
 
             if (!(signatureFactory.AlgorithmDetails is AlgorithmIdentifier algorithmDetails))
                 throw new ArgumentException("AlgorithmDetails is not AlgorithmIdentifier");
@@ -114,7 +113,7 @@ namespace Org.BouncyCastle.Cmp
             if (null == body)
                 throw new InvalidOperationException("body must be set before building");
 
-            IStreamCalculator<IBlockResult> calculator = macFactory.CreateCalculator();
+            var calculator = macFactory.CreateCalculator();
 
             if (!(macFactory.AlgorithmDetails is AlgorithmIdentifier algorithmDetails))
                 throw new ArgumentException("AlgorithmDetails is not AlgorithmIdentifier");
@@ -150,7 +149,11 @@ namespace Org.BouncyCastle.Cmp
 
         private byte[] CalculateSignature(IStreamCalculator<IBlockResult> signer, PkiHeader header, PkiBody body)
         {
-            new DerSequence(header, body).EncodeTo(signer.Stream);
+            using (var s = signer.Stream)
+            {
+                new DerSequence(header, body).EncodeTo(s);
+            }
+
             return signer.GetResult().Collect();
         }
     }
diff --git a/crypto/src/cms/CMSAttributeTableGenerator.cs b/crypto/src/cms/CMSAttributeTableGenerator.cs
index a113bd8d4..36d1bdcff 100644
--- a/crypto/src/cms/CMSAttributeTableGenerator.cs
+++ b/crypto/src/cms/CMSAttributeTableGenerator.cs
@@ -9,13 +9,8 @@ namespace Org.BouncyCastle.Cms
 	/// </remarks>
 	public enum CmsAttributeTableParameter
 	{
-//		const string ContentType = "contentType";
-//		const string Digest = "digest";
-//		const string Signature = "encryptedDigest";
-//		const string DigestAlgorithmIdentifier = "digestAlgID";
-
-		ContentType, Digest, Signature, DigestAlgorithmIdentifier
-	}
+		ContentType, Digest, Signature, DigestAlgorithmIdentifier, SignatureAlgorithmIdentifier
+    }
 
 	public interface CmsAttributeTableGenerator
 	{
diff --git a/crypto/src/cms/CMSSignedDataParser.cs b/crypto/src/cms/CMSSignedDataParser.cs
index 83f87718f..8b02770d6 100644
--- a/crypto/src/cms/CMSSignedDataParser.cs
+++ b/crypto/src/cms/CMSSignedDataParser.cs
@@ -8,7 +8,6 @@ using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.IO;
 using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
 using Org.BouncyCastle.Utilities.IO;
 using Org.BouncyCastle.X509;
diff --git a/crypto/src/cms/CMSSignedDataStreamGenerator.cs b/crypto/src/cms/CMSSignedDataStreamGenerator.cs
index 33b661761..48abfbfa2 100644
--- a/crypto/src/cms/CMSSignedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSSignedDataStreamGenerator.cs
@@ -102,18 +102,18 @@ namespace Org.BouncyCastle.Cms
 
 				if (_sAttr != null)
 				{
-            		_sig = Helper.GetSignatureInstance(signatureName);
-				}
-				else
+                    _sig = SignerUtilities.InitSigner(signatureName, true, key, outer.m_random);
+                }
+                else
 				{
 					// Note: Need to use raw signatures here since we have already calculated the digest
 					if (_encName.Equals("RSA"))
 					{
-						_sig = Helper.GetSignatureInstance("RSA");
-					}
-					else if (_encName.Equals("DSA"))
+                        _sig = SignerUtilities.InitSigner("RSA", true, key, outer.m_random);
+                    }
+                    else if (_encName.Equals("DSA"))
 					{
-						_sig = Helper.GetSignatureInstance("NONEwithDSA");
+                        _sig = SignerUtilities.InitSigner("NONEwithDSA", true, key, outer.m_random);
 					}
 					// TODO Add support for raw PSS
 //					else if (_encName.equals("RSAandMGF1"))
@@ -135,10 +135,8 @@ namespace Org.BouncyCastle.Cms
 					{
 						throw new SignatureException("algorithm: " + _encName + " not supported in base signatures.");
 					}
-				}
-
-				_sig.Init(true, new ParametersWithRandom(key, outer.m_random));
-			}
+                }
+            }
 
 			public SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm,
         		byte[] calculatedDigest)
diff --git a/crypto/src/cms/CMSSignedHelper.cs b/crypto/src/cms/CMSSignedHelper.cs
index 9db39549b..37fefe140 100644
--- a/crypto/src/cms/CMSSignedHelper.cs
+++ b/crypto/src/cms/CMSSignedHelper.cs
@@ -35,7 +35,7 @@ namespace Org.BouncyCastle.Cms
 		private static readonly IDictionary<string, string> m_digestAlgs = new Dictionary<string, string>();
 		private static readonly IDictionary<string, string[]> m_digestAliases = new Dictionary<string, string[]>();
 
-        private static readonly HashSet<string> noParams = new HashSet<string>();
+        private static readonly HashSet<string> m_noParams = new HashSet<string>();
 		private static readonly IDictionary<string, string> m_ecAlgorithms = new Dictionary<string, string>();
 
 		private static void AddEntries(DerObjectIdentifier oid, string digest, string encryption)
@@ -130,13 +130,13 @@ namespace Org.BouncyCastle.Cms
 			m_digestAliases.Add("SHA384", new string[]{ "SHA-384" });
 			m_digestAliases.Add("SHA512", new string[]{ "SHA-512" });
 
-            noParams.Add(CmsSignedGenerator.EncryptionDsa);
-            //noParams.Add(EncryptionECDsa);
-            noParams.Add(EncryptionECDsaWithSha1);
-            noParams.Add(EncryptionECDsaWithSha224);
-            noParams.Add(EncryptionECDsaWithSha256);
-            noParams.Add(EncryptionECDsaWithSha384);
-            noParams.Add(EncryptionECDsaWithSha512);
+            m_noParams.Add(CmsSignedGenerator.EncryptionDsa);
+            //m_noParams.Add(EncryptionECDsa);
+            m_noParams.Add(EncryptionECDsaWithSha1);
+            m_noParams.Add(EncryptionECDsaWithSha224);
+            m_noParams.Add(EncryptionECDsaWithSha256);
+            m_noParams.Add(EncryptionECDsaWithSha384);
+            m_noParams.Add(EncryptionECDsaWithSha512);
 
 			m_ecAlgorithms.Add(CmsSignedGenerator.DigestSha1, EncryptionECDsaWithSha1);
 			m_ecAlgorithms.Add(CmsSignedGenerator.DigestSha224, EncryptionECDsaWithSha224);
@@ -151,13 +151,13 @@ namespace Org.BouncyCastle.Cms
         */
 		internal string GetDigestAlgName(string digestAlgOid)
         {
-			return m_digestAlgs.TryGetValue(digestAlgOid, out var algName) ? algName : digestAlgOid;
+            return CollectionUtilities.GetValueOrKey(m_digestAlgs, digestAlgOid);
         }
 
-		internal AlgorithmIdentifier GetEncAlgorithmIdentifier(DerObjectIdentifier encOid,
+        internal AlgorithmIdentifier GetEncAlgorithmIdentifier(DerObjectIdentifier encOid,
 			Asn1Encodable sigX509Parameters)
 		{
-			if (noParams.Contains(encOid.Id))
+			if (m_noParams.Contains(encOid.Id))
 			{
 				return new AlgorithmIdentifier(encOid);
 			}
@@ -177,10 +177,10 @@ namespace Org.BouncyCastle.Cms
         */
         internal string GetEncryptionAlgName(string encryptionAlgOid)
         {
-			return m_encryptionAlgs.TryGetValue(encryptionAlgOid, out var algName) ? algName : encryptionAlgOid;
+            return CollectionUtilities.GetValueOrKey(m_encryptionAlgs, encryptionAlgOid);
         }
 
-		internal IDigest GetDigestInstance(
+        internal IDigest GetDigestInstance(
 			string algorithm)
 		{
 			try
@@ -326,10 +326,17 @@ namespace Org.BouncyCastle.Cms
             {
 				foreach (Asn1Encodable ae in certSet)
 				{
-					if (ae != null && ae.ToAsn1Object() is Asn1Sequence s)
+					if (ae == null)
+						continue;
+
+					if (ae is X509CertificateStructure c)
 					{
-						contents.Add(new X509Certificate(X509CertificateStructure.GetInstance(s)));
-					}
+                        contents.Add(new X509Certificate(c));
+                    }
+					else if (ae.ToAsn1Object() is Asn1Sequence s)
+					{
+                        contents.Add(new X509Certificate(X509CertificateStructure.GetInstance(s)));
+                    }
 				}
 			}
 			return CollectionUtilities.CreateStore(contents);
@@ -342,10 +349,17 @@ namespace Org.BouncyCastle.Cms
 			{
 				foreach (Asn1Encodable ae in crlSet)
 				{
-					if (ae != null && ae.ToAsn1Object() is Asn1Sequence s)
-					{
-						contents.Add(new X509Crl(CertificateList.GetInstance(s)));
-					}
+                    if (ae == null)
+                        continue;
+
+                    if (ae is CertificateList c)
+                    {
+                        contents.Add(new X509Crl(c));
+                    }
+                    else if (ae.ToAsn1Object() is Asn1Sequence s)
+                    {
+                        contents.Add(new X509Crl(CertificateList.GetInstance(s)));
+                    }
 				}
 			}
 			return CollectionUtilities.CreateStore(contents);
diff --git a/crypto/src/cms/DefaultSignedAttributeTableGenerator.cs b/crypto/src/cms/DefaultSignedAttributeTableGenerator.cs
index d8b668c4e..dea4de0a3 100644
--- a/crypto/src/cms/DefaultSignedAttributeTableGenerator.cs
+++ b/crypto/src/cms/DefaultSignedAttributeTableGenerator.cs
@@ -60,23 +60,22 @@ namespace Org.BouncyCastle.Cms
         private void DoCreateStandardAttributeTable(IDictionary<CmsAttributeTableParameter, object> parameters,
 			IDictionary<DerObjectIdentifier, object> std)
         {
-            // contentType will be absent if we're trying to generate a counter signature.
-
-            if (parameters.ContainsKey(CmsAttributeTableParameter.ContentType))
+            if (!std.ContainsKey(CmsAttributes.ContentType))
             {
-                if (!std.ContainsKey(CmsAttributes.ContentType))
+                // contentType will be absent if we're trying to generate a counter signature.
+                if (parameters.TryGetValue(CmsAttributeTableParameter.ContentType, out var contentType))
                 {
-                    DerObjectIdentifier contentType = (DerObjectIdentifier)
-                        parameters[CmsAttributeTableParameter.ContentType];
-                    Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.ContentType,
-                        new DerSet(contentType));
+                    Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(
+						CmsAttributes.ContentType,
+                        new DerSet((DerObjectIdentifier)contentType));
                     std[attr.AttrType] = attr;
                 }
             }
 
             if (!std.ContainsKey(CmsAttributes.SigningTime))
             {
-                Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.SigningTime,
+                Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(
+					CmsAttributes.SigningTime,
                     new DerSet(new Time(DateTime.UtcNow)));
                 std[attr.AttrType] = attr;
             }
@@ -84,17 +83,35 @@ namespace Org.BouncyCastle.Cms
             if (!std.ContainsKey(CmsAttributes.MessageDigest))
             {
                 byte[] messageDigest = (byte[])parameters[CmsAttributeTableParameter.Digest];
-                Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(CmsAttributes.MessageDigest,
+
+                Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(
+					CmsAttributes.MessageDigest,
                     new DerSet(new DerOctetString(messageDigest)));
                 std[attr.AttrType] = attr;
             }
+
+			// TODO CmsAlgorithmProtect support (see bc-fips-csharp)
+            //if (!std.ContainsKey(CmsAttributes.CmsAlgorithmProtect))
+            //{
+            //    var digestAlgorithmIdentifier = (Asn1.X509.AlgorithmIdentifier)
+            //        parameters[CmsAttributeTableParameter.DigestAlgorithmIdentifier];
+            //    var signatureAlgorithmIdentifier = (Asn1.X509.AlgorithmIdentifier)
+            //        parameters[CmsAttributeTableParameter.SignatureAlgorithmIdentifier];
+            //    var cmsAlgorithmProtection = new CmsAlgorithmProtection(
+            //        digestAlgorithmIdentifier, CmsAlgorithmProtection.Signature, signatureAlgorithmIdentifier);
+
+            //    Asn1.Cms.Attribute attr = new Asn1.Cms.Attribute(
+            //        CmsAttributes.CmsAlgorithmProtect,
+            //        new DerSet(cmsAlgorithmProtection));
+            //    std[attr.AttrType] = attr;
+            //}
         }
 
         /**
 		 * @param parameters source parameters
 		 * @return the populated attribute table
 		 */
-		public virtual AttributeTable GetAttributes(IDictionary<CmsAttributeTableParameter, object> parameters)
+        public virtual AttributeTable GetAttributes(IDictionary<CmsAttributeTableParameter, object> parameters)
 		{
             var table = CreateStandardAttributeTable(parameters);
 			return new AttributeTable(table);
diff --git a/crypto/src/cms/OriginatorId.cs b/crypto/src/cms/OriginatorId.cs
index 5a3b7374d..6ae64c503 100644
--- a/crypto/src/cms/OriginatorId.cs
+++ b/crypto/src/cms/OriginatorId.cs
@@ -1,5 +1,3 @@
-using System;
-
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Utilities;
@@ -44,7 +42,7 @@ namespace Org.BouncyCastle.Cms
 				return false;
 
 			return Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier)
-				&& Platform.Equals(SerialNumber, id.SerialNumber)
+				&& Objects.Equals(SerialNumber, id.SerialNumber)
 				&& IssuersMatch(Issuer, id.Issuer);
         }
     }
diff --git a/crypto/src/cms/OriginatorInformation.cs b/crypto/src/cms/OriginatorInformation.cs
index 7186fafc3..6307cbc1f 100644
--- a/crypto/src/cms/OriginatorInformation.cs
+++ b/crypto/src/cms/OriginatorInformation.cs
@@ -10,7 +10,7 @@ namespace Org.BouncyCastle.Cms
 	{
 		private readonly OriginatorInfo originatorInfo;
 
-		internal OriginatorInformation(OriginatorInfo originatorInfo)
+        public OriginatorInformation(OriginatorInfo originatorInfo)
 		{
 			this.originatorInfo = originatorInfo;
 		}
diff --git a/crypto/src/cms/RecipientId.cs b/crypto/src/cms/RecipientId.cs
index 9b6eb093b..815f3ff90 100644
--- a/crypto/src/cms/RecipientId.cs
+++ b/crypto/src/cms/RecipientId.cs
@@ -51,7 +51,7 @@ namespace Org.BouncyCastle.Cms
 
 			return Arrays.AreEqual(keyIdentifier, id.keyIdentifier)
 				&& Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier)
-				&& Platform.Equals(SerialNumber, id.SerialNumber)
+				&& Objects.Equals(SerialNumber, id.SerialNumber)
 				&& IssuersMatch(Issuer, id.Issuer);
         }
     }
diff --git a/crypto/src/cms/RecipientInformationStore.cs b/crypto/src/cms/RecipientInformationStore.cs
index 06d093805..281b51c79 100644
--- a/crypto/src/cms/RecipientInformationStore.cs
+++ b/crypto/src/cms/RecipientInformationStore.cs
@@ -25,7 +25,7 @@ namespace Org.BouncyCastle.Cms
 				list.Add(recipientInformation);
 			}
 
-            this.m_all = new List<RecipientInformation>(recipientInfos);
+            m_all = new List<RecipientInformation>(recipientInfos);
 		}
 
 		public RecipientInformation this[RecipientID selector]
diff --git a/crypto/src/cms/SignerId.cs b/crypto/src/cms/SignerId.cs
index baac9369b..8023ca280 100644
--- a/crypto/src/cms/SignerId.cs
+++ b/crypto/src/cms/SignerId.cs
@@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Cms
 				return false;
 
 			return Arrays.AreEqual(SubjectKeyIdentifier, id.SubjectKeyIdentifier)
-				&& Platform.Equals(SerialNumber, id.SerialNumber)
+				&& Objects.Equals(SerialNumber, id.SerialNumber)
 				&& IssuersMatch(Issuer, id.Issuer);
         }
     }
diff --git a/crypto/src/cms/SignerInfoGenerator.cs b/crypto/src/cms/SignerInfoGenerator.cs
index 786749cb5..2fa185885 100644
--- a/crypto/src/cms/SignerInfoGenerator.cs
+++ b/crypto/src/cms/SignerInfoGenerator.cs
@@ -1,5 +1,3 @@
-using System;
-
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Cms;
 using Org.BouncyCastle.Asn1.X509;
@@ -23,7 +21,8 @@ namespace Org.BouncyCastle.Cms
         internal CmsAttributeTableGenerator unsignedGen;
         private bool isDirectSignature;
 
-        internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureFactory signerFactory): this(sigId, signerFactory, false)
+        internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureFactory signerFactory)
+            : this(sigId, signerFactory, false)
         {
 
         }
@@ -45,7 +44,8 @@ namespace Org.BouncyCastle.Cms
             }
         }
 
-        internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureFactory contentSigner, CmsAttributeTableGenerator signedGen, CmsAttributeTableGenerator unsignedGen)
+        internal SignerInfoGenerator(SignerIdentifier sigId, ISignatureFactory contentSigner,
+            CmsAttributeTableGenerator signedGen, CmsAttributeTableGenerator unsignedGen)
         {
             this.sigId = sigId;
             this.contentSigner = contentSigner;
@@ -54,7 +54,7 @@ namespace Org.BouncyCastle.Cms
             this.isDirectSignature = false;
         }
 
-        internal void setAssociatedCertificate(X509Certificate certificate)
+        internal void SetAssociatedCertificate(X509Certificate certificate)
         {
             this.certificate = certificate;
         }
@@ -130,11 +130,12 @@ namespace Org.BouncyCastle.Cms
          */
         public SignerInfoGenerator Build(ISignatureFactory contentSigner, X509Certificate certificate)
         {
-            SignerIdentifier sigId = new SignerIdentifier(new IssuerAndSerialNumber(certificate.IssuerDN, new DerInteger(certificate.SerialNumber)));
+            SignerIdentifier sigId = new SignerIdentifier(new IssuerAndSerialNumber(certificate.IssuerDN,
+                new DerInteger(certificate.SerialNumber)));
 
             SignerInfoGenerator sigInfoGen = CreateGenerator(contentSigner, sigId);
 
-            sigInfoGen.setAssociatedCertificate(certificate);
+            sigInfoGen.SetAssociatedCertificate(certificate);
 
             return sigInfoGen;
         }
diff --git a/crypto/src/cms/SignerInformationStore.cs b/crypto/src/cms/SignerInformationStore.cs
index 7fa3ef678..bc21f9d39 100644
--- a/crypto/src/cms/SignerInformationStore.cs
+++ b/crypto/src/cms/SignerInformationStore.cs
@@ -5,7 +5,7 @@ namespace Org.BouncyCastle.Cms
 {
     public class SignerInformationStore
     {
-        private readonly IList<SignerInformation> all;
+        private readonly IList<SignerInformation> m_all;
         private readonly IDictionary<SignerID, IList<SignerInformation>> m_table =
             new Dictionary<SignerID, IList<SignerInformation>>();
 
@@ -16,12 +16,12 @@ namespace Org.BouncyCastle.Cms
          */
         public SignerInformationStore(SignerInformation signerInfo)
         {
-            this.all = new List<SignerInformation>(1);
-            this.all.Add(signerInfo);
+            m_all = new List<SignerInformation>(1);
+            m_all.Add(signerInfo);
 
             SignerID sid = signerInfo.SignerID;
 
-            m_table[sid] = all;
+            m_table[sid] = m_all;
         }
 
         /**
@@ -31,19 +31,20 @@ namespace Org.BouncyCastle.Cms
          */
         public SignerInformationStore(IEnumerable<SignerInformation> signerInfos)
         {
+            m_all = new List<SignerInformation>(signerInfos);
+
             foreach (SignerInformation signer in signerInfos)
             {
                 SignerID sid = signer.SignerID;
 
                 if (!m_table.TryGetValue(sid, out var list))
                 {
-                    m_table[sid] = list = new List<SignerInformation>(1);
+                    list = new List<SignerInformation>(1);
+                    m_table[sid] = list;
                 }
 
                 list.Add(signer);
             }
-
-            this.all = new List<SignerInformation>(signerInfos);
         }
 
         /**
@@ -64,13 +65,13 @@ namespace Org.BouncyCastle.Cms
         /// <summary>The number of signers in the collection.</summary>
         public int Count
         {
-            get { return all.Count; }
+            get { return m_all.Count; }
         }
 
         /// <returns>An ICollection of all signers in the collection</returns>
         public IList<SignerInformation> GetSigners()
         {
-            return new List<SignerInformation>(all);
+            return new List<SignerInformation>(m_all);
         }
 
         /**
diff --git a/crypto/src/crypto/BufferedAeadBlockCipher.cs b/crypto/src/crypto/BufferedAeadBlockCipher.cs
index bf453feea..f822e393e 100644
--- a/crypto/src/crypto/BufferedAeadBlockCipher.cs
+++ b/crypto/src/crypto/BufferedAeadBlockCipher.cs
@@ -37,13 +37,11 @@ namespace Org.BouncyCastle.Crypto
 		* @exception ArgumentException if the parameters argument is
 		* inappropriate.
 		*/
-		public override void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
+		public override void Init(bool forEncryption, ICipherParameters parameters)
 		{
-			if (parameters is ParametersWithRandom)
+			if (parameters is ParametersWithRandom withRandom)
 			{
-				parameters = ((ParametersWithRandom) parameters).Parameters;
+				parameters = withRandom.Parameters;
 			}
 
 			cipher.Init(forEncryption, parameters);
diff --git a/crypto/src/crypto/BufferedAeadCipher.cs b/crypto/src/crypto/BufferedAeadCipher.cs
index fb3408e12..05bf6e25b 100644
--- a/crypto/src/crypto/BufferedAeadCipher.cs
+++ b/crypto/src/crypto/BufferedAeadCipher.cs
@@ -36,13 +36,11 @@ namespace Org.BouncyCastle.Crypto
         * @exception ArgumentException if the parameters argument is
         * inappropriate.
         */
-        public override void Init(
-            bool forEncryption,
-            ICipherParameters parameters)
+        public override void Init(bool forEncryption, ICipherParameters parameters)
         {
-            if (parameters is ParametersWithRandom)
+            if (parameters is ParametersWithRandom withRandom)
             {
-                parameters = ((ParametersWithRandom)parameters).Parameters;
+                parameters = withRandom.Parameters;
             }
 
             cipher.Init(forEncryption, parameters);
diff --git a/crypto/src/crypto/CryptoServicesRegistrar.cs b/crypto/src/crypto/CryptoServicesRegistrar.cs
index 33bf47386..a2784108e 100644
--- a/crypto/src/crypto/CryptoServicesRegistrar.cs
+++ b/crypto/src/crypto/CryptoServicesRegistrar.cs
@@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto
 
         public static SecureRandom GetSecureRandom(SecureRandom secureRandom)
         {
-            return secureRandom ?? new SecureRandom();
+            return secureRandom ?? GetSecureRandom();
         }
     }
 }
diff --git a/crypto/src/crypto/IBlockResult.cs b/crypto/src/crypto/IBlockResult.cs
index f3b73e59f..2a62e26de 100644
--- a/crypto/src/crypto/IBlockResult.cs
+++ b/crypto/src/crypto/IBlockResult.cs
@@ -31,6 +31,7 @@ namespace Org.BouncyCastle.Crypto
         int Collect(Span<byte> output);
 #endif
 
+        /// <summary>Return an upper limit for the size of the result.</summary>
         int GetMaxResultLength();
     }
 }
diff --git a/crypto/src/crypto/agreement/DHBasicAgreement.cs b/crypto/src/crypto/agreement/DHBasicAgreement.cs
index 6c3fe6595..ca298dd27 100644
--- a/crypto/src/crypto/agreement/DHBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/DHBasicAgreement.cs
@@ -19,20 +19,17 @@ namespace Org.BouncyCastle.Crypto.Agreement
         private DHPrivateKeyParameters	key;
         private DHParameters			dhParams;
 
-        public virtual void Init(
-            ICipherParameters parameters)
+        public virtual void Init(ICipherParameters parameters)
         {
-            if (parameters is ParametersWithRandom)
+            if (parameters is ParametersWithRandom withRandom)
             {
-                parameters = ((ParametersWithRandom) parameters).Parameters;
+                parameters = withRandom.Parameters;
             }
 
             if (!(parameters is DHPrivateKeyParameters))
-            {
                 throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
-            }
 
-            this.key = (DHPrivateKeyParameters) parameters;
+            this.key = (DHPrivateKeyParameters)parameters;
             this.dhParams = key.Parameters;
         }
 
diff --git a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
index 1358db0cf..b3b1ab5c7 100644
--- a/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHBasicAgreement.cs
@@ -26,12 +26,11 @@ namespace Org.BouncyCastle.Crypto.Agreement
     {
         protected internal ECPrivateKeyParameters privKey;
 
-        public virtual void Init(
-            ICipherParameters parameters)
+        public virtual void Init(ICipherParameters parameters)
         {
-            if (parameters is ParametersWithRandom)
+            if (parameters is ParametersWithRandom withRandom)
             {
-                parameters = ((ParametersWithRandom)parameters).Parameters;
+                parameters = withRandom.Parameters;
             }
 
             this.privKey = (ECPrivateKeyParameters)parameters;
diff --git a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
index f0b5d1e02..1bcb259c6 100644
--- a/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECDHCBasicAgreement.cs
@@ -31,12 +31,11 @@ namespace Org.BouncyCastle.Crypto.Agreement
     {
         private ECPrivateKeyParameters privKey;
 
-        public virtual void Init(
-            ICipherParameters parameters)
+        public virtual void Init(ICipherParameters parameters)
         {
-            if (parameters is ParametersWithRandom)
+            if (parameters is ParametersWithRandom withRandom)
             {
-                parameters = ((ParametersWithRandom) parameters).Parameters;
+                parameters = withRandom.Parameters;
             }
 
             this.privKey = (ECPrivateKeyParameters)parameters;
diff --git a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
index b71f5a7d2..984d66587 100644
--- a/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
+++ b/crypto/src/crypto/agreement/ECMqvBasicAgreement.cs
@@ -12,12 +12,11 @@ namespace Org.BouncyCastle.Crypto.Agreement
     {
         protected internal MqvPrivateParameters privParams;
 
-        public virtual void Init(
-            ICipherParameters parameters)
+        public virtual void Init(ICipherParameters parameters)
         {
-            if (parameters is ParametersWithRandom)
+            if (parameters is ParametersWithRandom withRandom)
             {
-                parameters = ((ParametersWithRandom)parameters).Parameters;
+                parameters = withRandom.Parameters;
             }
 
             this.privParams = (MqvPrivateParameters)parameters;
diff --git a/crypto/src/crypto/digests/ISAPDigest.cs b/crypto/src/crypto/digests/ISAPDigest.cs
new file mode 100644
index 000000000..3be28e4e2
--- /dev/null
+++ b/crypto/src/crypto/digests/ISAPDigest.cs
@@ -0,0 +1,149 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    public class ISAPDigest : IDigest
+    {
+        private ulong x0, x1, x2, x3, x4;
+        private ulong t0, t1, t2, t3, t4;
+        private MemoryStream buffer = new MemoryStream();
+
+        private void ROUND(ulong C)
+        {
+            t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
+            t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
+            t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
+            t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
+            t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
+            x0 = t0 ^ ROTR(t0, 19) ^ ROTR(t0, 28);
+            x1 = t1 ^ ROTR(t1, 39) ^ ROTR(t1, 61);
+            x2 = ~(t2 ^ ROTR(t2, 1) ^ ROTR(t2, 6));
+            x3 = t3 ^ ROTR(t3, 10) ^ ROTR(t3, 17);
+            x4 = t4 ^ ROTR(t4, 7) ^ ROTR(t4, 41);
+        }
+
+        private void P12()
+        {
+            ROUND(0xf0);
+            ROUND(0xe1);
+            ROUND(0xd2);
+            ROUND(0xc3);
+            ROUND(0xb4);
+            ROUND(0xa5);
+            ROUND(0x96);
+            ROUND(0x87);
+            ROUND(0x78);
+            ROUND(0x69);
+            ROUND(0x5a);
+            ROUND(0x4b);
+        }
+
+        private ulong ROTR(ulong x, int n)
+        {
+            return (x >> n) | (x << (64 - n));
+        }
+
+        protected ulong U64BIG(ulong x)
+        {
+            return ((ROTR(x, 8) & (0xFF000000FF000000UL)) | (ROTR(x, 24) & (0x00FF000000FF0000UL)) |
+                (ROTR(x, 40) & (0x0000FF000000FF00UL)) | (ROTR(x, 56) & (0x000000FF000000FFUL)));
+        }
+
+        public string AlgorithmName
+        {
+            get { return "ISAP Hash"; }
+        }
+
+        public void BlockUpdate(byte[] input, int inOff, int inLen)
+        {
+            if (inOff + inLen > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            buffer.Write(input, inOff, inLen);
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            buffer.Write(input.ToArray(), 0, input.Length);
+        }
+
+        public int DoFinal(Span<byte> output)
+        {
+            byte[] rv = new byte[32];
+            int rlt = DoFinal(rv, 0);
+            rv.AsSpan(0, 32).CopyTo(output);
+            return rlt;
+        }
+
+#endif
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (32 + outOff > output.Length)
+            {
+                throw new OutputLengthException("output buffer is too short");
+            }
+            t0 = t1 = t2 = t3 = t4 = 0;
+            /* init state */
+            x0 = 17191252062196199485UL;
+            x1 = 10066134719181819906UL;
+            x2 = 13009371945472744034UL;
+            x3 = 4834782570098516968UL;
+            x4 = 3787428097924915520UL;
+            /* absorb */
+            byte[] input = buffer.GetBuffer();
+            int len = (int)buffer.Length;
+            ulong[] in64 = new ulong[len >> 3];
+            Pack.LE_To_UInt64(input, 0, in64, 0, in64.Length);
+            int idx = 0;
+            while (len >= 8)
+            {
+                x0 ^= U64BIG(in64[idx++]);
+                P12();
+                len -= 8;
+            }
+            /* absorb final input block */
+            x0 ^= 0x80UL << ((7 - len) << 3);
+            while (len > 0)
+            {
+                x0 ^= (input[(idx << 3) + --len] & 0xFFUL) << ((7 - len) << 3);
+            }
+            P12();
+            // squeeze
+            ulong[] out64 = new ulong[4];
+            for (idx = 0; idx < 3; ++idx)
+            {
+                out64[idx] = U64BIG(x0);
+                P12();
+            }
+            /* squeeze final output block */
+            out64[idx] = U64BIG(x0);
+            Pack.UInt64_To_LE(out64, output, outOff);
+            return 32;
+        }
+
+        public int GetByteLength()
+        {
+            throw new NotImplementedException();
+        }
+
+        public int GetDigestSize()
+        {
+            return 32;
+        }
+
+        public void Reset()
+        {
+            buffer.SetLength(0);
+        }
+
+        public void Update(byte input)
+        {
+            buffer.Write(new byte[] { input }, 0, 1);
+        }
+    }
+}
diff --git a/crypto/src/crypto/digests/LongDigest.cs b/crypto/src/crypto/digests/LongDigest.cs
index 6a2f94ece..df48c4889 100644
--- a/crypto/src/crypto/digests/LongDigest.cs
+++ b/crypto/src/crypto/digests/LongDigest.cs
@@ -12,7 +12,7 @@ namespace Org.BouncyCastle.Crypto.Digests
     public abstract class LongDigest
         : IDigest, IMemoable
     {
-        private int MyByteLength = 128;
+        private const int MyByteLength = 128;
 
         private byte[] xBuf;
         private int xBufOff;
diff --git a/crypto/src/crypto/digests/MD5Digest.cs b/crypto/src/crypto/digests/MD5Digest.cs
index 062d7bb46..3a0967bc3 100644
--- a/crypto/src/crypto/digests/MD5Digest.cs
+++ b/crypto/src/crypto/digests/MD5Digest.cs
@@ -182,16 +182,6 @@ namespace Org.BouncyCastle.Crypto.Digests
         private static readonly int S44 = 21;
 
         /*
-        * rotate int x left n bits.
-        */
-        private static uint RotateLeft(
-            uint x,
-            int n)
-        {
-            return (x << n) | (x >> (32 - n));
-        }
-
-        /*
         * F, G, H and I are the basic MD5 functions.
         */
         private static uint F(
@@ -236,82 +226,82 @@ namespace Org.BouncyCastle.Crypto.Digests
             //
             // Round 1 - F cycle, 16 times.
             //
-            a = RotateLeft((a + F(b, c, d) + X[0] + 0xd76aa478), S11) + b;
-            d = RotateLeft((d + F(a, b, c) + X[1] + 0xe8c7b756), S12) + a;
-            c = RotateLeft((c + F(d, a, b) + X[2] + 0x242070db), S13) + d;
-            b = RotateLeft((b + F(c, d, a) + X[3] + 0xc1bdceee), S14) + c;
-            a = RotateLeft((a + F(b, c, d) + X[4] + 0xf57c0faf), S11) + b;
-            d = RotateLeft((d + F(a, b, c) + X[5] + 0x4787c62a), S12) + a;
-            c = RotateLeft((c + F(d, a, b) + X[6] + 0xa8304613), S13) + d;
-            b = RotateLeft((b + F(c, d, a) + X[7] + 0xfd469501), S14) + c;
-            a = RotateLeft((a + F(b, c, d) + X[8] + 0x698098d8), S11) + b;
-            d = RotateLeft((d + F(a, b, c) + X[9] + 0x8b44f7af), S12) + a;
-            c = RotateLeft((c + F(d, a, b) + X[10] + 0xffff5bb1), S13) + d;
-            b = RotateLeft((b + F(c, d, a) + X[11] + 0x895cd7be), S14) + c;
-            a = RotateLeft((a + F(b, c, d) + X[12] + 0x6b901122), S11) + b;
-            d = RotateLeft((d + F(a, b, c) + X[13] + 0xfd987193), S12) + a;
-            c = RotateLeft((c + F(d, a, b) + X[14] + 0xa679438e), S13) + d;
-            b = RotateLeft((b + F(c, d, a) + X[15] + 0x49b40821), S14) + c;
+            a = Integers.RotateLeft((a + F(b, c, d) + X[0] + 0xd76aa478), S11) + b;
+            d = Integers.RotateLeft((d + F(a, b, c) + X[1] + 0xe8c7b756), S12) + a;
+            c = Integers.RotateLeft((c + F(d, a, b) + X[2] + 0x242070db), S13) + d;
+            b = Integers.RotateLeft((b + F(c, d, a) + X[3] + 0xc1bdceee), S14) + c;
+            a = Integers.RotateLeft((a + F(b, c, d) + X[4] + 0xf57c0faf), S11) + b;
+            d = Integers.RotateLeft((d + F(a, b, c) + X[5] + 0x4787c62a), S12) + a;
+            c = Integers.RotateLeft((c + F(d, a, b) + X[6] + 0xa8304613), S13) + d;
+            b = Integers.RotateLeft((b + F(c, d, a) + X[7] + 0xfd469501), S14) + c;
+            a = Integers.RotateLeft((a + F(b, c, d) + X[8] + 0x698098d8), S11) + b;
+            d = Integers.RotateLeft((d + F(a, b, c) + X[9] + 0x8b44f7af), S12) + a;
+            c = Integers.RotateLeft((c + F(d, a, b) + X[10] + 0xffff5bb1), S13) + d;
+            b = Integers.RotateLeft((b + F(c, d, a) + X[11] + 0x895cd7be), S14) + c;
+            a = Integers.RotateLeft((a + F(b, c, d) + X[12] + 0x6b901122), S11) + b;
+            d = Integers.RotateLeft((d + F(a, b, c) + X[13] + 0xfd987193), S12) + a;
+            c = Integers.RotateLeft((c + F(d, a, b) + X[14] + 0xa679438e), S13) + d;
+            b = Integers.RotateLeft((b + F(c, d, a) + X[15] + 0x49b40821), S14) + c;
 
             //
             // Round 2 - G cycle, 16 times.
             //
-            a = RotateLeft((a + G(b, c, d) + X[1] + 0xf61e2562), S21) + b;
-            d = RotateLeft((d + G(a, b, c) + X[6] + 0xc040b340), S22) + a;
-            c = RotateLeft((c + G(d, a, b) + X[11] + 0x265e5a51), S23) + d;
-            b = RotateLeft((b + G(c, d, a) + X[0] + 0xe9b6c7aa), S24) + c;
-            a = RotateLeft((a + G(b, c, d) + X[5] + 0xd62f105d), S21) + b;
-            d = RotateLeft((d + G(a, b, c) + X[10] + 0x02441453), S22) + a;
-            c = RotateLeft((c + G(d, a, b) + X[15] + 0xd8a1e681), S23) + d;
-            b = RotateLeft((b + G(c, d, a) + X[4] + 0xe7d3fbc8), S24) + c;
-            a = RotateLeft((a + G(b, c, d) + X[9] + 0x21e1cde6), S21) + b;
-            d = RotateLeft((d + G(a, b, c) + X[14] + 0xc33707d6), S22) + a;
-            c = RotateLeft((c + G(d, a, b) + X[3] + 0xf4d50d87), S23) + d;
-            b = RotateLeft((b + G(c, d, a) + X[8] + 0x455a14ed), S24) + c;
-            a = RotateLeft((a + G(b, c, d) + X[13] + 0xa9e3e905), S21) + b;
-            d = RotateLeft((d + G(a, b, c) + X[2] + 0xfcefa3f8), S22) + a;
-            c = RotateLeft((c + G(d, a, b) + X[7] + 0x676f02d9), S23) + d;
-            b = RotateLeft((b + G(c, d, a) + X[12] + 0x8d2a4c8a), S24) + c;
+            a = Integers.RotateLeft((a + G(b, c, d) + X[1] + 0xf61e2562), S21) + b;
+            d = Integers.RotateLeft((d + G(a, b, c) + X[6] + 0xc040b340), S22) + a;
+            c = Integers.RotateLeft((c + G(d, a, b) + X[11] + 0x265e5a51), S23) + d;
+            b = Integers.RotateLeft((b + G(c, d, a) + X[0] + 0xe9b6c7aa), S24) + c;
+            a = Integers.RotateLeft((a + G(b, c, d) + X[5] + 0xd62f105d), S21) + b;
+            d = Integers.RotateLeft((d + G(a, b, c) + X[10] + 0x02441453), S22) + a;
+            c = Integers.RotateLeft((c + G(d, a, b) + X[15] + 0xd8a1e681), S23) + d;
+            b = Integers.RotateLeft((b + G(c, d, a) + X[4] + 0xe7d3fbc8), S24) + c;
+            a = Integers.RotateLeft((a + G(b, c, d) + X[9] + 0x21e1cde6), S21) + b;
+            d = Integers.RotateLeft((d + G(a, b, c) + X[14] + 0xc33707d6), S22) + a;
+            c = Integers.RotateLeft((c + G(d, a, b) + X[3] + 0xf4d50d87), S23) + d;
+            b = Integers.RotateLeft((b + G(c, d, a) + X[8] + 0x455a14ed), S24) + c;
+            a = Integers.RotateLeft((a + G(b, c, d) + X[13] + 0xa9e3e905), S21) + b;
+            d = Integers.RotateLeft((d + G(a, b, c) + X[2] + 0xfcefa3f8), S22) + a;
+            c = Integers.RotateLeft((c + G(d, a, b) + X[7] + 0x676f02d9), S23) + d;
+            b = Integers.RotateLeft((b + G(c, d, a) + X[12] + 0x8d2a4c8a), S24) + c;
 
             //
             // Round 3 - H cycle, 16 times.
             //
-            a = RotateLeft((a + H(b, c, d) + X[5] + 0xfffa3942), S31) + b;
-            d = RotateLeft((d + H(a, b, c) + X[8] + 0x8771f681), S32) + a;
-            c = RotateLeft((c + H(d, a, b) + X[11] + 0x6d9d6122), S33) + d;
-            b = RotateLeft((b + H(c, d, a) + X[14] + 0xfde5380c), S34) + c;
-            a = RotateLeft((a + H(b, c, d) + X[1] + 0xa4beea44), S31) + b;
-            d = RotateLeft((d + H(a, b, c) + X[4] + 0x4bdecfa9), S32) + a;
-            c = RotateLeft((c + H(d, a, b) + X[7] + 0xf6bb4b60), S33) + d;
-            b = RotateLeft((b + H(c, d, a) + X[10] + 0xbebfbc70), S34) + c;
-            a = RotateLeft((a + H(b, c, d) + X[13] + 0x289b7ec6), S31) + b;
-            d = RotateLeft((d + H(a, b, c) + X[0] + 0xeaa127fa), S32) + a;
-            c = RotateLeft((c + H(d, a, b) + X[3] + 0xd4ef3085), S33) + d;
-            b = RotateLeft((b + H(c, d, a) + X[6] + 0x04881d05), S34) + c;
-            a = RotateLeft((a + H(b, c, d) + X[9] + 0xd9d4d039), S31) + b;
-            d = RotateLeft((d + H(a, b, c) + X[12] + 0xe6db99e5), S32) + a;
-            c = RotateLeft((c + H(d, a, b) + X[15] + 0x1fa27cf8), S33) + d;
-            b = RotateLeft((b + H(c, d, a) + X[2] + 0xc4ac5665), S34) + c;
+            a = Integers.RotateLeft((a + H(b, c, d) + X[5] + 0xfffa3942), S31) + b;
+            d = Integers.RotateLeft((d + H(a, b, c) + X[8] + 0x8771f681), S32) + a;
+            c = Integers.RotateLeft((c + H(d, a, b) + X[11] + 0x6d9d6122), S33) + d;
+            b = Integers.RotateLeft((b + H(c, d, a) + X[14] + 0xfde5380c), S34) + c;
+            a = Integers.RotateLeft((a + H(b, c, d) + X[1] + 0xa4beea44), S31) + b;
+            d = Integers.RotateLeft((d + H(a, b, c) + X[4] + 0x4bdecfa9), S32) + a;
+            c = Integers.RotateLeft((c + H(d, a, b) + X[7] + 0xf6bb4b60), S33) + d;
+            b = Integers.RotateLeft((b + H(c, d, a) + X[10] + 0xbebfbc70), S34) + c;
+            a = Integers.RotateLeft((a + H(b, c, d) + X[13] + 0x289b7ec6), S31) + b;
+            d = Integers.RotateLeft((d + H(a, b, c) + X[0] + 0xeaa127fa), S32) + a;
+            c = Integers.RotateLeft((c + H(d, a, b) + X[3] + 0xd4ef3085), S33) + d;
+            b = Integers.RotateLeft((b + H(c, d, a) + X[6] + 0x04881d05), S34) + c;
+            a = Integers.RotateLeft((a + H(b, c, d) + X[9] + 0xd9d4d039), S31) + b;
+            d = Integers.RotateLeft((d + H(a, b, c) + X[12] + 0xe6db99e5), S32) + a;
+            c = Integers.RotateLeft((c + H(d, a, b) + X[15] + 0x1fa27cf8), S33) + d;
+            b = Integers.RotateLeft((b + H(c, d, a) + X[2] + 0xc4ac5665), S34) + c;
 
             //
             // Round 4 - K cycle, 16 times.
             //
-            a = RotateLeft((a + K(b, c, d) + X[0] + 0xf4292244), S41) + b;
-            d = RotateLeft((d + K(a, b, c) + X[7] + 0x432aff97), S42) + a;
-            c = RotateLeft((c + K(d, a, b) + X[14] + 0xab9423a7), S43) + d;
-            b = RotateLeft((b + K(c, d, a) + X[5] + 0xfc93a039), S44) + c;
-            a = RotateLeft((a + K(b, c, d) + X[12] + 0x655b59c3), S41) + b;
-            d = RotateLeft((d + K(a, b, c) + X[3] + 0x8f0ccc92), S42) + a;
-            c = RotateLeft((c + K(d, a, b) + X[10] + 0xffeff47d), S43) + d;
-            b = RotateLeft((b + K(c, d, a) + X[1] + 0x85845dd1), S44) + c;
-            a = RotateLeft((a + K(b, c, d) + X[8] + 0x6fa87e4f), S41) + b;
-            d = RotateLeft((d + K(a, b, c) + X[15] + 0xfe2ce6e0), S42) + a;
-            c = RotateLeft((c + K(d, a, b) + X[6] + 0xa3014314), S43) + d;
-            b = RotateLeft((b + K(c, d, a) + X[13] + 0x4e0811a1), S44) + c;
-            a = RotateLeft((a + K(b, c, d) + X[4] + 0xf7537e82), S41) + b;
-            d = RotateLeft((d + K(a, b, c) + X[11] + 0xbd3af235), S42) + a;
-            c = RotateLeft((c + K(d, a, b) + X[2] + 0x2ad7d2bb), S43) + d;
-            b = RotateLeft((b + K(c, d, a) + X[9] + 0xeb86d391), S44) + c;
+            a = Integers.RotateLeft((a + K(b, c, d) + X[0] + 0xf4292244), S41) + b;
+            d = Integers.RotateLeft((d + K(a, b, c) + X[7] + 0x432aff97), S42) + a;
+            c = Integers.RotateLeft((c + K(d, a, b) + X[14] + 0xab9423a7), S43) + d;
+            b = Integers.RotateLeft((b + K(c, d, a) + X[5] + 0xfc93a039), S44) + c;
+            a = Integers.RotateLeft((a + K(b, c, d) + X[12] + 0x655b59c3), S41) + b;
+            d = Integers.RotateLeft((d + K(a, b, c) + X[3] + 0x8f0ccc92), S42) + a;
+            c = Integers.RotateLeft((c + K(d, a, b) + X[10] + 0xffeff47d), S43) + d;
+            b = Integers.RotateLeft((b + K(c, d, a) + X[1] + 0x85845dd1), S44) + c;
+            a = Integers.RotateLeft((a + K(b, c, d) + X[8] + 0x6fa87e4f), S41) + b;
+            d = Integers.RotateLeft((d + K(a, b, c) + X[15] + 0xfe2ce6e0), S42) + a;
+            c = Integers.RotateLeft((c + K(d, a, b) + X[6] + 0xa3014314), S43) + d;
+            b = Integers.RotateLeft((b + K(c, d, a) + X[13] + 0x4e0811a1), S44) + c;
+            a = Integers.RotateLeft((a + K(b, c, d) + X[4] + 0xf7537e82), S41) + b;
+            d = Integers.RotateLeft((d + K(a, b, c) + X[11] + 0xbd3af235), S42) + a;
+            c = Integers.RotateLeft((c + K(d, a, b) + X[2] + 0x2ad7d2bb), S43) + d;
+            b = Integers.RotateLeft((b + K(c, d, a) + X[9] + 0xeb86d391), S44) + c;
 
             H1 += a;
             H2 += b;
@@ -332,8 +322,5 @@ namespace Org.BouncyCastle.Crypto.Digests
 
 			CopyIn(d);
 		}
-
 	}
-
 }
-
diff --git a/crypto/src/crypto/digests/PhotonBeetleDigest.cs b/crypto/src/crypto/digests/PhotonBeetleDigest.cs
new file mode 100644
index 000000000..e0961cc3f
--- /dev/null
+++ b/crypto/src/crypto/digests/PhotonBeetleDigest.cs
@@ -0,0 +1,247 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+
+/**
+ * Photon-Beetle, https://www.isical.ac.in/~lightweight/beetle/
+ * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/readonlyist-round/updated-spec-doc/photon-beetle-spec-readonly.pdf
+ * <p>
+ * Photon-Beetle with reference to C Reference Impl from: https://github.com/PHOTON-Beetle/Software
+ * </p>
+ */
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    public class PhotonBeetleDigest : IDigest
+    {
+        private byte[] state;
+        private byte[][] state_2d;
+        private MemoryStream buffer = new MemoryStream();
+        private const int INITIAL_RATE_INBYTES = 16;
+        private int RATE_INBYTES = 4;
+        private int SQUEEZE_RATE_INBYTES = 16;
+        private int STATE_INBYTES = 32;
+        private int TAG_INBYTES = 32;
+        private int LAST_THREE_BITS_OFFSET = 5;
+        private int ROUND = 12;
+        private int D = 8;
+        private int Dq = 3;
+        private int Dr = 7;
+        private int DSquare = 64;
+        private int S = 4;
+        private int S_1 = 3;
+        private byte[][] RC = {//[D][12]
+        new byte[]{1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10},
+        new byte[]{0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11},
+        new byte[]{2, 0, 4, 13, 14, 8, 5, 15, 10, 1, 6, 9},
+        new byte[]{6, 4, 0, 9, 10, 12, 1, 11, 14, 5, 2, 13},
+        new byte[]{14, 12, 8, 1, 2, 4, 9, 3, 6, 13, 10, 5},
+        new byte[]{15, 13, 9, 0, 3, 5, 8, 2, 7, 12, 11, 4},
+        new byte[]{13, 15, 11, 2, 1, 7, 10, 0, 5, 14, 9, 6},
+        new byte[]{9, 11, 15, 6, 5, 3, 14, 4, 1, 10, 13, 2}
+    };
+        private byte[][] MixColMatrix = { //[D][D]
+        new byte[]{2, 4, 2, 11, 2, 8, 5, 6},
+        new byte[]{12, 9, 8, 13, 7, 7, 5, 2},
+        new byte[]{4, 4, 13, 13, 9, 4, 13, 9},
+       new byte[] {1, 6, 5, 1, 12, 13, 15, 14},
+        new byte[]{15, 12, 9, 13, 14, 5, 14, 13},
+        new byte[]{9, 14, 5, 15, 4, 12, 9, 6},
+        new byte[]{12, 2, 2, 10, 3, 1, 1, 14},
+        new byte[]{15, 1, 13, 10, 5, 10, 2, 3}
+    };
+
+        private byte[] sbox = { 12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2 };
+
+        public PhotonBeetleDigest()
+        {
+            state = new byte[STATE_INBYTES];
+            state_2d = new byte[D][];
+            for (int i = 0; i < D; ++i)
+            {
+                state_2d[i] = new byte[D];
+            }
+        }
+
+
+        public String AlgorithmName => "Photon-Beetle Hash";
+
+
+        public int GetDigestSize()
+        {
+            return TAG_INBYTES;
+        }
+
+
+        public void Update(byte input)
+        {
+            buffer.Write(new byte[] { input }, 0, 1);
+        }
+
+
+        public void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            if ((inOff + len) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            buffer.Write(input, inOff, len);
+        }
+
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (32 + outOff > output.Length)
+            {
+                throw new OutputLengthException("output buffer is too short");
+            }
+            byte[] input = buffer.GetBuffer();
+            int inlen = (int)buffer.Length;
+            if (inlen == 0)
+            {
+                state[STATE_INBYTES - 1] ^= (byte)(1 << LAST_THREE_BITS_OFFSET);
+            }
+            else if (inlen <= INITIAL_RATE_INBYTES)
+            {
+                Array.Copy(input, 0, state, 0, inlen);
+                if (inlen < INITIAL_RATE_INBYTES)
+                {
+                    state[inlen] ^= 0x01; // ozs
+                }
+                state[STATE_INBYTES - 1] ^= (byte)((inlen < INITIAL_RATE_INBYTES ? 1 : 2) << LAST_THREE_BITS_OFFSET);
+            }
+            else
+            {
+                Array.Copy(input, 0, state, 0, INITIAL_RATE_INBYTES);
+                inlen -= INITIAL_RATE_INBYTES;
+                int Dlen_inblocks = (inlen + RATE_INBYTES - 1) / RATE_INBYTES;
+                int i, LastDBlocklen;
+                for (i = 0; i < Dlen_inblocks - 1; i++)
+                {
+                    PHOTON_Permutation();
+                    XOR(input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, RATE_INBYTES);
+                }
+                PHOTON_Permutation();
+                LastDBlocklen = inlen - i * RATE_INBYTES;
+                XOR(input, INITIAL_RATE_INBYTES + i * RATE_INBYTES, LastDBlocklen);
+                if (LastDBlocklen < RATE_INBYTES)
+                {
+                    state[LastDBlocklen] ^= 0x01; // ozs
+                }
+                state[STATE_INBYTES - 1] ^= (byte)((inlen % RATE_INBYTES == 0 ? 1 : 2) << LAST_THREE_BITS_OFFSET);
+            }
+            PHOTON_Permutation();
+            Array.Copy(state, 0, output, outOff, SQUEEZE_RATE_INBYTES);
+            PHOTON_Permutation();
+            Array.Copy(state, 0, output, outOff + SQUEEZE_RATE_INBYTES, TAG_INBYTES - SQUEEZE_RATE_INBYTES);
+            return TAG_INBYTES;
+        }
+
+        void XOR(byte[] in_right, int rOff, int iolen_inbytes)
+        {
+            for (int i = 0; i < iolen_inbytes; i++)
+            {
+                state[i] ^= in_right[i + rOff];
+            }
+        }
+
+
+        public void Reset()
+        {
+            buffer.SetLength(0);
+            Arrays.Fill(state, (byte)0);
+        }
+
+        void PHOTON_Permutation()
+        {
+            int i, j, k, l;
+            for (i = 0; i < DSquare; i++)
+            {
+                state_2d[i >> Dq][i & Dr] = (byte)(((state[i >> 1] & 0xFF) >> (4 * (i & 1))) & 0xf);
+            }
+            for (int round = 0; round < ROUND; round++)
+            {
+                //AddKey
+                for (i = 0; i < D; i++)
+                {
+                    state_2d[i][0] ^= RC[i][round];
+                }
+                //SubCell
+                for (i = 0; i < D; i++)
+                {
+                    for (j = 0; j < D; j++)
+                    {
+                        state_2d[i][j] = sbox[state_2d[i][j]];
+                    }
+                }
+                //ShiftRow
+                for (i = 1; i < D; i++)
+                {
+                    Array.Copy(state_2d[i], 0, state, 0, D);
+                    Array.Copy(state, i, state_2d[i], 0, D - i);
+                    Array.Copy(state, 0, state_2d[i], D - i, i);
+                }
+                //MixColumn
+                for (j = 0; j < D; j++)
+                {
+                    for (i = 0; i < D; i++)
+                    {
+                        byte sum = 0;
+                        for (k = 0; k < D; k++)
+                        {
+                            int x = MixColMatrix[i][k], ret = 0, b = state_2d[k][j];
+                            for (l = 0; l < S; l++)
+                            {
+                                if (((b >> l) & 1) != 0)
+                                {
+                                    ret ^= x;
+                                }
+                                if (((x >> S_1) & 1) != 0)
+                                {
+                                    x <<= 1;
+                                    x ^= 0x3;
+                                }
+                                else
+                                {
+                                    x <<= 1;
+                                }
+                            }
+                            sum ^= (byte)(ret & 15);
+                        }
+                        state[i] = sum;
+                    }
+                    for (i = 0; i < D; i++)
+                    {
+                        state_2d[i][j] = state[i];
+                    }
+                }
+            }
+            for (i = 0; i < DSquare; i += 2)
+            {
+                state[i >> 1] = (byte)(((state_2d[i >> Dq][i & Dr] & 0xf)) | ((state_2d[i >> Dq][(i + 1) & Dr] & 0xf) << 4));
+            }
+        }
+
+        public int GetByteLength()
+        {
+            throw new NotImplementedException();
+        }
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+
+        public int DoFinal(Span<byte> output)
+        {
+            byte[] rv = new byte[32];
+            int rlt = DoFinal(rv, 0);
+            rv.AsSpan(0, 32).CopyTo(output);
+            return rlt;
+        }
+
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            buffer.Write(input.ToArray(), 0, input.Length);
+        }
+
+#endif
+    }
+}
diff --git a/crypto/src/crypto/digests/XoodyakDigest.cs b/crypto/src/crypto/digests/XoodyakDigest.cs
new file mode 100644
index 000000000..cf1afcc10
--- /dev/null
+++ b/crypto/src/crypto/digests/XoodyakDigest.cs
@@ -0,0 +1,207 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    public class XoodyakDigest : IDigest
+    {
+        private byte[] state;
+        private int phase;
+        private MODE mode;
+        private int Rabsorb;
+        private const int f_bPrime = 48;
+        private const int Rkout = 24;
+        private const int PhaseDown = 1;
+        private const int PhaseUp = 2;
+        private const int NLANES = 12;
+        private const int NROWS = 3;
+        private const int NCOLUMS = 4;
+        private const int MAXROUNDS = 12;
+        private const int TAGLEN = 16;
+        private const int Rhash = 16;
+        const int Rkin = 44;
+        private readonly uint[] RC = {0x00000058, 0x00000038, 0x000003C0, 0x000000D0, 0x00000120, 0x00000014, 0x00000060,
+        0x0000002C, 0x00000380, 0x000000F0, 0x000001A0, 0x00000012};
+        private MemoryStream buffer = new MemoryStream();
+        enum MODE
+        {
+            ModeHash,
+            ModeKeyed
+        }
+
+        public XoodyakDigest()
+        {
+            state = new byte[48];
+            Reset();
+        }
+
+        public string AlgorithmName => "Xoodyak Hash";
+
+        private void Up(byte[] Yi, int YiOff, int YiLen, uint Cu)
+        {
+            if (mode != MODE.ModeHash)
+            {
+                state[f_bPrime - 1] ^= (byte)Cu;
+            }
+            uint[] a = new uint[NLANES];
+            Pack.LE_To_UInt32(state, 0, a, 0, a.Length);
+            uint x, y;
+            uint[] b = new uint[NLANES];
+            uint[] p = new uint[NCOLUMS];
+            uint[] e = new uint[NCOLUMS];
+            for (int i = 0; i < MAXROUNDS; ++i)
+            {
+                /* Theta: Column Parity Mixer */
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    p[x] = a[index(x, 0)] ^ a[index(x, 1)] ^ a[index(x, 2)];
+                }
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    y = p[(x + 3) & 3];
+                    e[x] = ROTL32(y, 5) ^ ROTL32(y, 14);
+                }
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    for (y = 0; y < NROWS; ++y)
+                    {
+                        a[index(x, y)] ^= e[x];
+                    }
+                }
+                /* Rho-west: plane shift */
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    b[index(x, 0)] = a[index(x, 0)];
+                    b[index(x, 1)] = a[index(x + 3, 1)];
+                    b[index(x, 2)] = ROTL32(a[index(x, 2)], 11);
+                }
+                /* Iota: round ant */
+                b[0] ^= RC[i];
+                /* Chi: non linear layer */
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    for (y = 0; y < NROWS; ++y)
+                    {
+                        a[index(x, y)] = b[index(x, y)] ^ (~b[index(x, y + 1)] & b[index(x, y + 2)]);
+                    }
+                }
+                /* Rho-east: plane shift */
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    b[index(x, 0)] = a[index(x, 0)];
+                    b[index(x, 1)] = ROTL32(a[index(x, 1)], 1);
+                    b[index(x, 2)] = ROTL32(a[index(x + 2, 2)], 8);
+                }
+                Array.Copy(b, 0, a, 0, NLANES);
+            }
+            Pack.UInt32_To_LE(a, 0, a.Length, state, 0);
+            phase = PhaseUp;
+            if (Yi != null)
+            {
+                Array.Copy(state, 0, Yi, YiOff, YiLen);
+            }
+        }
+
+        void Down(byte[] Xi, int XiOff, int XiLen, uint Cd)
+        {
+            for (int i = 0; i < XiLen; i++)
+            {
+                state[i] ^= Xi[XiOff++];
+            }
+            state[XiLen] ^= 0x01;
+            state[f_bPrime - 1] ^= (byte)((mode == MODE.ModeHash) ? (Cd & 0x01) : Cd);
+            phase = PhaseDown;
+        }
+
+        private uint index(uint x, uint y)
+        {
+            return (((y % NROWS) * NCOLUMS) + ((x) % NCOLUMS));
+        }
+
+        private uint ROTL32(uint a, int offset)
+        {
+            return (a << (offset & 31)) ^ (a >> ((32 - (offset)) & 31));
+        }
+
+        public void BlockUpdate(byte[] input, int inOff, int inLen)
+        {
+            if (inOff + inLen > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            buffer.Write(input, inOff, inLen);
+        }
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (32 + outOff > output.Length)
+            {
+                throw new OutputLengthException("output buffer is too short");
+            }
+            byte[] input = buffer.GetBuffer();
+            int inLen = (int)buffer.Length;
+            int inOff = 0;
+            uint Cd = 0x03;
+            int splitLen;
+            do
+            {
+                if (phase != PhaseUp)
+                {
+                    Up(null, 0, 0, 0);
+                }
+                splitLen = System.Math.Min(inLen, Rabsorb);
+                Down(input, inOff, splitLen, Cd);
+                Cd = 0;
+                inOff += splitLen;
+                inLen -= splitLen;
+            }
+            while (inLen != 0);
+            Up(output, outOff, TAGLEN, 0x40);
+            Down(null, 0, 0, 0);
+            Up(output, outOff + TAGLEN, TAGLEN, 0);
+            return 32;
+        }
+
+        public int GetByteLength()
+        {
+            throw new NotImplementedException();
+        }
+
+        public int GetDigestSize()
+        {
+            return 32;
+        }
+
+        public void Reset()
+        {
+            for (int i = 0; i < state.Length; ++i)
+            {
+                state[i] = 0;
+            }
+            phase = PhaseUp;
+            mode = MODE.ModeHash;
+            Rabsorb = Rhash;
+            buffer.SetLength(0);
+        }
+
+        public void Update(byte input)
+        {
+            buffer.Write(new byte[] { input }, 0, 1);
+        }
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public int DoFinal(Span<byte> output)
+        {
+            byte[] rv = new byte[32];
+            int rlt = DoFinal(rv, 0);
+            rv.AsSpan(0, 32).CopyTo(output);
+            return rlt;
+        }
+
+        public void BlockUpdate(ReadOnlySpan<byte> input)
+        {
+            buffer.Write(input.ToArray(), 0, input.Length);
+        }
+#endif
+    }
+}
diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs
index 6871a039a..9ddaec779 100644
--- a/crypto/src/crypto/encodings/OaepEncoding.cs
+++ b/crypto/src/crypto/encodings/OaepEncoding.cs
@@ -74,7 +74,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
             }
             else
             {
-                this.random = CryptoServicesRegistrar.GetSecureRandom();
+                this.random = forEncryption ? CryptoServicesRegistrar.GetSecureRandom() : null;
             }
 
             engine.Init(forEncryption, parameters);
@@ -285,24 +285,17 @@ namespace Org.BouncyCastle.Crypto.Encodings
             return output;
         }
 
-        private byte[] MaskGeneratorFunction(
-            byte[] Z,
-            int zOff,
-            int zLen,
-            int length)
+        private byte[] MaskGeneratorFunction(byte[] Z, int zOff, int zLen, int length)
         {
-            if (mgf1Hash is IXof)
+            if (mgf1Hash is IXof xof)
             {
                 byte[] mask = new byte[length];
-                mgf1Hash.BlockUpdate(Z, zOff, zLen);
-                ((IXof)mgf1Hash).OutputFinal(mask, 0, mask.Length);
-
+                xof.BlockUpdate(Z, zOff, zLen);
+                xof.OutputFinal(mask, 0, length);
                 return mask;
             }
-            else
-            {
-                return MaskGeneratorFunction1(Z, zOff, zLen, length);
-            }
+
+            return MaskGeneratorFunction1(Z, zOff, zLen, length);
         }
 
         /**
diff --git a/crypto/src/crypto/encodings/Pkcs1Encoding.cs b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
index 06e59d4f3..299d0ddb0 100644
--- a/crypto/src/crypto/encodings/Pkcs1Encoding.cs
+++ b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
@@ -105,13 +105,13 @@ namespace Org.BouncyCastle.Crypto.Encodings
             AsymmetricKeyParameter kParam;
             if (parameters is ParametersWithRandom withRandom)
             {
-                this.random = withRandom.Random;
                 kParam = (AsymmetricKeyParameter)withRandom.Parameters;
+                this.random = withRandom.Random;
             }
             else
             {
-                this.random = CryptoServicesRegistrar.GetSecureRandom();
                 kParam = (AsymmetricKeyParameter)parameters;
+                this.random = forEncryption && !kParam.IsPrivate ? CryptoServicesRegistrar.GetSecureRandom() : null;
             }
 
             engine.Init(forEncryption, parameters);
@@ -119,9 +119,6 @@ namespace Org.BouncyCastle.Crypto.Encodings
             this.forPrivateKey = kParam.IsPrivate;
             this.forEncryption = forEncryption;
             this.blockBuffer = new byte[engine.GetOutputBlockSize()];
-
-            if (pLen > 0 && fallback == null && random == null)
-                throw new ArgumentException("encoder requires random");
         }
 
         public int GetInputBlockSize()
@@ -259,15 +256,10 @@ namespace Org.BouncyCastle.Crypto.Encodings
                 throw new InvalidCipherTextException("sorry, this method is only for decryption, not for signing");
 
             byte[] block = engine.ProcessBlock(input, inOff, inLen);
-            byte[] random;
-            if (this.fallback == null)
-            {
-                random = new byte[this.pLen];
-                this.random.NextBytes(random);
-            }
-            else
+            byte[] fallbackResult = fallback;
+            if (fallbackResult == null)
             {
-                random = fallback;
+                fallbackResult = SecureRandom.GetNextBytes(SecureRandom.ArbitraryRandom, pLen);
             }
 
             byte[] data = (useStrictLength & (block.Length != engine.GetOutputBlockSize())) ? blockBuffer : block;
@@ -284,7 +276,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
             byte[] result = new byte[this.pLen];
             for (int i = 0; i < this.pLen; i++)
             {
-                result[i] = (byte)((data[i + (data.Length - pLen)] & (~correct)) | (random[i] & correct));
+                result[i] = (byte)((data[i + (data.Length - pLen)] & (~correct)) | (fallbackResult[i] & correct));
             }
 
             Arrays.Fill(data, 0);
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index 914550d6d..3977cb893 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -1,5 +1,4 @@
 using System;
-using System.Diagnostics;
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
@@ -37,7 +36,7 @@ namespace Org.BouncyCastle.Crypto.Engines
         // The S box
         private static readonly byte[] S =
         {
-            99,	124, 119, 123, 242, 107, 111, 197,
+            99, 124, 119, 123, 242, 107, 111, 197,
             48, 1, 103, 43, 254, 215, 171, 118,
             202, 130, 201, 125, 250, 89, 71, 240,
             173, 212, 162, 175, 156, 164, 114, 192,
diff --git a/crypto/src/crypto/engines/AsconEngine.cs b/crypto/src/crypto/engines/AsconEngine.cs
new file mode 100644
index 000000000..c3091b9ef
--- /dev/null
+++ b/crypto/src/crypto/engines/AsconEngine.cs
@@ -0,0 +1,694 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+using static Org.BouncyCastle.Tls.DtlsReliableHandshake;
+
+/**
+* ASCON AEAD v1.2, https://ascon.iaik.tugraz.at/
+* https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/ascon-spec-final.pdf
+* <p>
+* ASCON AEAD v1.2 with reference to C Reference Impl from: https://github.com/ascon/ascon-c
+* </p>
+*/
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    public class AsconEngine : IAeadBlockCipher
+    {
+        public enum AsconParameters
+        {
+            ascon80pq,
+            ascon128a,
+            ascon128
+        }
+
+        private readonly AsconParameters asconParameters;
+        private readonly MemoryStream aadData = new MemoryStream();
+        private readonly MemoryStream message = new MemoryStream();
+        private bool encrypted;
+        private bool initialised;
+        private bool forEncryption;
+        private bool aadFinished;
+        private readonly int CRYPTO_KEYBYTES;
+        private readonly int CRYPTO_ABYTES;
+        private readonly int ASCON_AEAD_RATE;
+        private readonly int nr;
+        private byte[] mac;
+        private ulong K0;
+        private ulong K1;
+        private ulong K2;
+        private ulong N0;
+        private ulong N1;
+        private readonly ulong ASCON_IV;
+        private ulong x0;
+        private ulong x1;
+        private ulong x2;
+        private ulong x3;
+        private ulong x4;
+        private String algorithmName;
+
+        public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
+
+        public string AlgorithmName => algorithmName;
+
+        public AsconEngine(AsconParameters asconParameters)
+        {
+            this.asconParameters = asconParameters;
+            switch (asconParameters)
+            {
+                case AsconParameters.ascon80pq:
+                    CRYPTO_KEYBYTES = 20;
+                    CRYPTO_ABYTES = 16;
+                    ASCON_AEAD_RATE = 8;
+                    ASCON_IV = 0xa0400c0600000000UL;
+                    algorithmName = "Ascon-80pq AEAD";
+                    break;
+                case AsconParameters.ascon128a:
+                    CRYPTO_KEYBYTES = 16;
+                    CRYPTO_ABYTES = 16;
+                    ASCON_AEAD_RATE = 16;
+                    ASCON_IV = 0x80800c0800000000UL;
+                    algorithmName = "Ascon-128a AEAD";
+                    break;
+                case AsconParameters.ascon128:
+                    CRYPTO_KEYBYTES = 16;
+                    CRYPTO_ABYTES = 16;
+                    ASCON_AEAD_RATE = 8;
+                    ASCON_IV = 0x80400c0600000000UL;
+                    algorithmName = "Ascon-128 AEAD";
+                    break;
+                default:
+                    throw new ArgumentException("invalid parameter setting for ASCON AEAD");
+            }
+            nr = (ASCON_AEAD_RATE == 8) ? 6 : 8;
+            initialised = false;
+        }
+
+        private ulong U64BIG(ulong x)
+        {
+            return (((0x00000000000000FFUL & x) << 56) |
+            ((0x000000000000FF00UL & x) << 40) |
+            ((0x0000000000FF0000UL & x) << 24) |
+            ((0x00000000FF000000UL & x) << 8) |
+            ((0x000000FF00000000UL & x) >> 8) |
+            ((0x0000FF0000000000UL & x) >> 24) |
+            ((0x00FF000000000000UL & x) >> 40) |
+            ((0xFF00000000000000UL & x) >> 56));
+        }
+
+        private ulong ROR(ulong x, int n)
+        {
+            return x >> n | x << (64 - n);
+        }
+
+        private ulong KEYROT(ulong lo2hi, ulong hi2lo)
+        {
+            return lo2hi << 32 | hi2lo >> 32;
+        }
+
+        private ulong PAD(int i)
+        {
+            return 0x80UL << (56 - (i << 3));
+        }
+
+        private ulong MASK(int n)
+        {
+            /* undefined for n == 0 */
+            return ~0UL >> (64 - (n << 3));
+        }
+
+        private ulong LOAD(byte[] bytes, int inOff, int n)
+        {
+            ulong x = 0;
+            int len = System.Math.Min(8, bytes.Length - inOff);
+            for (int i = 0; i < len; ++i)
+            {
+                x |= (bytes[i + inOff] & 0xFFUL) << (i << 3);
+            }
+            return U64BIG(x & MASK(n));
+        }
+
+        private void STORE(byte[] bytes, int inOff, ulong w, int n)
+        {
+            ulong x = 0;
+            for (int i = 0; i < n; ++i)
+            {
+                x |= (bytes[i + inOff] & 0xFFUL) << (i << 3);
+            }
+            x &= ~MASK(n);
+            x |= U64BIG(w);
+            for (int i = 0; i < n; ++i)
+            {
+                bytes[i + inOff] = (byte)(x >> (i << 3));
+            }
+        }
+
+        private ulong LOADBYTES(byte[] bytes, int inOff, int n)
+        {
+            ulong x = 0;
+            for (int i = 0; i < n; ++i)
+            {
+                x |= (bytes[i + inOff] & 0xFFUL) << ((7 - i) << 3);
+            }
+            return x;
+        }
+
+        private void STOREBYTES(byte[] bytes, int inOff, ulong w, int n)
+        {
+            for (int i = 0; i < n; ++i)
+            {
+                bytes[i + inOff] = (byte)(w >> ((7 - i) << 3));
+            }
+        }
+
+        private void ROUND(ulong C)
+        {
+            ulong t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
+            ulong t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
+            ulong t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
+            ulong t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
+            ulong t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
+            x0 = t0 ^ ROR(t0, 19) ^ ROR(t0, 28);
+            x1 = t1 ^ ROR(t1, 39) ^ ROR(t1, 61);
+            x2 = ~(t2 ^ ROR(t2, 1) ^ ROR(t2, 6));
+            x3 = t3 ^ ROR(t3, 10) ^ ROR(t3, 17);
+            x4 = t4 ^ ROR(t4, 7) ^ ROR(t4, 41);
+        }
+
+        private void P(int nr)
+        {
+            if (nr == 12)
+            {
+                ROUND(0xf0UL);
+                ROUND(0xe1UL);
+                ROUND(0xd2UL);
+                ROUND(0xc3UL);
+            }
+            if (nr >= 8)
+            {
+                ROUND(0xb4UL);
+                ROUND(0xa5UL);
+            }
+            ROUND(0x96UL);
+            ROUND(0x87UL);
+            ROUND(0x78UL);
+            ROUND(0x69UL);
+            ROUND(0x5aUL);
+            ROUND(0x4bUL);
+        }
+
+        private void ascon_aeadinit()
+        {
+            /* initialize */
+            x0 ^= ASCON_IV;
+            if (CRYPTO_KEYBYTES == 20)
+            {
+                x0 ^= K0;
+            }
+            x1 ^= K1;
+            x2 ^= K2;
+            x3 ^= N0;
+            x4 ^= N1;
+            P(12);
+            if (CRYPTO_KEYBYTES == 20)
+            {
+                x2 ^= K0;
+            }
+            x3 ^= K1;
+            x4 ^= K2;
+        }
+
+        private void ascon_adata(byte[] ad, int adOff, int adlen)
+        {
+            if (adlen != 0)
+            {
+                /* full associated data blocks */
+                while (adlen >= ASCON_AEAD_RATE)
+                {
+                    x0 ^= LOAD(ad, adOff, 8);
+                    if (ASCON_AEAD_RATE == 16)
+                    {
+                        x1 ^= LOAD(ad, adOff + 8, 8);
+                    }
+                    P(nr);
+                    adOff += ASCON_AEAD_RATE;
+                    adlen -= ASCON_AEAD_RATE;
+                }
+                /* readonly associated data block */
+                if (ASCON_AEAD_RATE == 16 && adlen >= 8)
+                {
+                    x0 ^= LOAD(ad, adOff, 8);
+                    adOff += 8;
+                    adlen -= 8;
+                    x1 ^= PAD(adlen);
+                    if (adlen != 0)
+                    {
+                        x1 ^= LOAD(ad, adOff, adlen);
+                    }
+                }
+                else
+                {
+                    x0 ^= PAD(adlen);
+                    if (adlen != 0)
+                    {
+                        x0 ^= LOAD(ad, adOff, adlen);
+                    }
+                }
+                P(nr);
+            }
+            /* domain separation */
+            x4 ^= 1UL;
+        }
+
+        private void ascon_encrypt(byte[] c, int cOff, byte[] m, int mOff, int mlen)
+        {
+            /* full plaintext blocks */
+            while (mlen >= ASCON_AEAD_RATE)
+            {
+                x0 ^= LOAD(m, mOff, 8);
+                STORE(c, cOff, x0, 8);
+                if (ASCON_AEAD_RATE == 16)
+                {
+                    x1 ^= LOAD(m, mOff + 8, 8);
+                    STORE(c, cOff + 8, x1, 8);
+                }
+                P(nr);
+                mOff += ASCON_AEAD_RATE;
+                cOff += ASCON_AEAD_RATE;
+                mlen -= ASCON_AEAD_RATE;
+            }
+        }
+
+        private void ascon_decrypt(byte[] m, int mOff, byte[] c, int cOff, int clen)
+        {
+            /* full ciphertext blocks */
+            while (clen >= ASCON_AEAD_RATE)
+            {
+                ulong cx = LOAD(c, cOff, 8);
+                x0 ^= cx;
+                STORE(m, mOff, x0, 8);
+                x0 = cx;
+                if (ASCON_AEAD_RATE == 16)
+                {
+                    cx = LOAD(c, cOff + 8, 8);
+                    x1 ^= cx;
+                    STORE(m, mOff + 8, x1, 8);
+                    x1 = cx;
+                }
+                P(nr);
+                mOff += ASCON_AEAD_RATE;
+                cOff += ASCON_AEAD_RATE;
+                clen -= ASCON_AEAD_RATE;
+            }
+        }
+
+        private ulong CLEAR(ulong w, int n)
+        {
+            /* undefined for n == 0 */
+            ulong mask = 0x00ffffffffffffffUL >> (n * 8 - 8);
+            return w & mask;
+        }
+
+        private void ascon_final(byte[] c, int cOff, byte[] m, int mOff, int mlen)
+        {
+            if (forEncryption)
+            {
+                /* final plaintext block */
+                if (ASCON_AEAD_RATE == 16 && mlen >= 8)
+                {
+                    x0 ^= LOAD(m, mOff, 8);
+                    STORE(c, cOff, x0, 8);
+                    mOff += 8;
+                    cOff += 8;
+                    mlen -= 8;
+                    x1 ^= PAD(mlen);
+                    if (mlen != 0)
+                    {
+                        x1 ^= LOAD(m, mOff, mlen);
+                        STORE(c, cOff, x1, mlen);
+                    }
+                }
+                else
+                {
+                    x0 ^= PAD(mlen);
+                    if (mlen != 0)
+                    {
+                        x0 ^= LOAD(m, mOff, mlen);
+                        STORE(c, cOff, x0, mlen);
+                    }
+                }
+            }
+            else
+            {
+                /* final ciphertext block */
+                if (ASCON_AEAD_RATE == 16 && mlen >= 8)
+                {
+                    ulong cx = LOAD(m, mOff, 8);
+                    x0 ^= cx;
+                    STORE(c, cOff, x0, 8);
+                    x0 = cx;
+                    mOff += 8;
+                    cOff += 8;
+                    mlen -= 8;
+                    x1 ^= PAD(mlen);
+                    if (mlen != 0)
+                    {
+                        cx = LOAD(m, mOff, mlen);
+                        x1 ^= cx;
+                        STORE(c, cOff, x1, mlen);
+                        x1 = CLEAR(x1, mlen);
+                        x1 ^= cx;
+                    }
+                }
+                else
+                {
+                    x0 ^= PAD(mlen);
+                    if (mlen != 0)
+                    {
+                        ulong cx = LOAD(m, mOff, mlen);
+                        x0 ^= cx;
+                        STORE(c, cOff, x0, mlen);
+                        x0 = CLEAR(x0, mlen);
+                        x0 ^= cx;
+                    }
+                }
+            }
+            /* finalize */
+            switch (asconParameters)
+            {
+                case AsconParameters.ascon128:
+                    x1 ^= K1;
+                    x2 ^= K2;
+                    break;
+                case AsconParameters.ascon128a:
+                    x2 ^= K1;
+                    x3 ^= K2;
+                    break;
+                case AsconParameters.ascon80pq:
+                    x1 ^= KEYROT(K0, K1);
+                    x2 ^= KEYROT(K1, K2);
+                    x3 ^= KEYROT(K2, 0UL);
+                    break;
+            }
+            P(12);
+            x3 ^= K1;
+            x4 ^= K2;
+        }
+
+        public void Init(bool forEncryption, ICipherParameters param)
+        {
+            this.forEncryption = forEncryption;
+            if (!(param is ParametersWithIV))
+            {
+                throw new ArgumentException(
+                "ASCON init parameters must include an IV");
+            }
+            ParametersWithIV ivParams = (ParametersWithIV)param;
+            byte[] npub = ivParams.GetIV();
+            if (npub == null || npub.Length != CRYPTO_ABYTES)
+            {
+                throw new ArgumentException(asconParameters + " requires exactly " + CRYPTO_ABYTES + " bytes of IV");
+            }
+            if (!(ivParams.Parameters is KeyParameter))
+            {
+                throw new ArgumentException(
+                "ASCON init parameters must include a key");
+            }
+            KeyParameter key = (KeyParameter)ivParams.Parameters;
+            byte[] k = key.GetKey();
+            if (k.Length != CRYPTO_KEYBYTES)
+            {
+                throw new ArgumentException(asconParameters + " key must be " + CRYPTO_KEYBYTES + " bytes long");
+            }
+            N0 = LOAD(npub, 0, 8);
+            N1 = LOAD(npub, 8, 8);
+            if (CRYPTO_KEYBYTES == 16)
+            {
+                K1 = LOAD(k, 0, 8);
+                K2 = LOAD(k, 8, 8);
+            }
+            else if (CRYPTO_KEYBYTES == 20)
+            {
+                K0 = KEYROT(0, LOADBYTES(k, 0, 4));
+                K1 = LOADBYTES(k, 4, 8);
+                K2 = LOADBYTES(k, 12, 8);
+            }
+            initialised = true;
+            /*Mask-Gen*/
+            reset(false);
+        }
+
+        public void ProcessAadByte(byte input)
+        {
+            if (aadFinished)
+            {
+                throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+                    " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+            }
+            aadData.Write(new byte[] { input }, 0, 1);
+        }
+
+
+        public void ProcessAadBytes(byte[] input, int inOff, int len)
+        {
+            if (aadFinished)
+            {
+                throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+                    " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+            }
+            if ((inOff + len) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            aadData.Write(input, inOff, len);
+        }
+
+
+        public int ProcessByte(byte input, byte[] output, int outOff)
+        {
+            return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+        }
+
+
+        public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            if ((inOff + len) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            message.Write(input, inOff, len);
+            int rv = processBytes(output, outOff);
+            encrypted = true;
+            return rv;
+        }
+
+        private void processAAD()
+        {
+            if (!aadFinished)
+            {
+                byte[] ad = aadData.GetBuffer();
+                int adlen = (int)aadData.Length;
+                /* perform ascon computation */
+                ascon_adata(ad, 0, adlen);
+                aadFinished = true;
+            }
+        }
+
+        private int processBytes(byte[] output, int outOff)
+        {
+            int len = 0;
+            if (forEncryption)
+            {
+                if ((int)message.Length >= ASCON_AEAD_RATE)
+                {
+                    processAAD();
+                    byte[] input = message.GetBuffer();
+                    len = ((int)message.Length / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
+                    if (len + outOff > output.Length)
+                    {
+                        throw new OutputLengthException("output buffer is too short");
+                    }
+                    ascon_encrypt(output, outOff, input, 0, len);
+                    int len_orig = (int)message.Length;
+                    message.SetLength(0);
+                    message.Write(input, len, len_orig - len);
+                }
+            }
+            else
+            {
+                if ((int)message.Length - CRYPTO_ABYTES >= ASCON_AEAD_RATE)
+                {
+                    processAAD();
+                    byte[] input = message.GetBuffer();
+                    len = (((int)message.Length - CRYPTO_ABYTES) / ASCON_AEAD_RATE) * ASCON_AEAD_RATE;
+                    if (len + outOff > output.Length)
+                    {
+                        throw new OutputLengthException("output buffer is too short");
+                    }
+                    ascon_decrypt(output, outOff, input, 0, len);
+                    int len_orig = (int)message.Length;
+                    message.SetLength(0);
+                    message.Write(input, len, len_orig - len);
+                }
+            }
+            return len;
+        }
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            if (!aadFinished)
+            {
+                processAAD();
+            }
+            if (!encrypted)
+            {
+                ProcessBytes(new byte[] { }, 0, 0, new byte[] { }, 0);
+            }
+            byte[] input = message.GetBuffer();
+            int len = (int)message.Length;
+            if ((forEncryption && outOff + len + CRYPTO_ABYTES > output.Length) ||
+                (!forEncryption && outOff + len - CRYPTO_ABYTES > output.Length))
+            {
+                throw new OutputLengthException("output buffer too short");
+            }
+            if (forEncryption)
+            {
+                ascon_final(output, outOff, input, 0, len);
+                /* set tag */
+                mac = new byte[16];
+                STOREBYTES(mac, 0, x3, 8);
+                STOREBYTES(mac, 8, x4, 8);
+                Array.Copy(mac, 0, output, len + outOff, 16);
+                reset(false);
+                return len + CRYPTO_ABYTES;
+            }
+            else
+            {
+                len -= CRYPTO_ABYTES;
+                ascon_final(output, outOff, input, 0, len);
+                x3 ^= LOADBYTES(input, len, 8);
+                x4 ^= LOADBYTES(input, len + 8, 8);
+                ulong result = x3 | x4;
+                result |= result >> 32;
+                result |= result >> 16;
+                result |= result >> 8;
+                reset(true);
+                if ((((((int)(result & 0xffUL) - 1) >> 8) & 1) - 1) != 0)
+                {
+                    throw new ArgumentException("Mac does not match");
+                }
+                return len;
+            }
+        }
+
+
+        public byte[] GetMac()
+        {
+            return mac;
+        }
+
+
+        public int GetUpdateOutputSize(int len)
+        {
+            return len;
+        }
+
+        public int GetOutputSize(int len)
+        {
+            return len + CRYPTO_ABYTES;
+        }
+
+        public void Reset()
+        {
+            reset(true);
+        }
+
+        private void reset(bool clearMac)
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            x0 = x1 = x2 = x3 = x4 = 0;
+            ascon_aeadinit();
+            aadData.SetLength(0);
+            message.SetLength(0);
+            encrypted = false;
+            aadFinished = false;
+            if (clearMac)
+            {
+                mac = null;
+            }
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void ProcessAadBytes(ReadOnlySpan<byte> input)
+        {
+            if (aadFinished)
+            {
+                throw new ArgumentException("AAD cannot be added after reading a full block(" + ASCON_AEAD_RATE +
+                    " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+            }
+            aadData.Write(input);
+        }
+
+        public int ProcessByte(byte input, Span<byte> output)
+        {
+            byte[] rv = new byte[1];
+            int len = ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return len;
+        }
+
+        public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            byte[] rv = new byte[input.Length];
+            int len = ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return len;
+        }
+
+        public int DoFinal(Span<byte> output)
+        {
+            byte[] rv;
+            if (forEncryption)
+            {
+                rv = new byte[message.Length + 16];
+            }
+            else
+            {
+                rv = new byte[message.Length];
+            }
+            int len = DoFinal(rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return rv.Length;
+        }
+#endif
+        public int GetBlockSize()
+        {
+            return ASCON_AEAD_RATE;
+        }
+
+        public int GetKeyBytesSize()
+        {
+            return CRYPTO_KEYBYTES;
+        }
+
+        public int GetIVBytesSize()
+        {
+            return CRYPTO_ABYTES;
+        }
+    }
+}
+
+
diff --git a/crypto/src/crypto/engines/DesEdeWrapEngine.cs b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
index 07f751ab9..3115f65dc 100644
--- a/crypto/src/crypto/engines/DesEdeWrapEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
@@ -52,45 +52,40 @@ namespace Org.BouncyCastle.Crypto.Engines
         * @param forWrapping
         * @param param
         */
-        public virtual void Init(
-			bool				forWrapping,
-			ICipherParameters	parameters)
+        public virtual void Init(bool forWrapping, ICipherParameters parameters)
         {
             this.forWrapping = forWrapping;
             this.engine = new CbcBlockCipher(new DesEdeEngine());
 
-			SecureRandom sr;
+			SecureRandom random = null;
 			if (parameters is ParametersWithRandom pr)
 			{
 				parameters = pr.Parameters;
-				sr = pr.Random;
-			}
-			else
-			{
-				sr = CryptoServicesRegistrar.GetSecureRandom();
+                random = pr.Random;
 			}
 
-			if (parameters is KeyParameter)
+			if (parameters is KeyParameter keyParameter)
             {
-                this.param = (KeyParameter) parameters;
+                this.param = keyParameter;
                 if (this.forWrapping)
 				{
                     // Hm, we have no IV but we want to wrap ?!?
                     // well, then we have to create our own IV.
                     this.iv = new byte[8];
-					sr.NextBytes(iv);
+
+                    CryptoServicesRegistrar.GetSecureRandom(random).NextBytes(iv);
 
 					this.paramPlusIV = new ParametersWithIV(this.param, this.iv);
                 }
             }
-            else if (parameters is ParametersWithIV)
+            else if (parameters is ParametersWithIV withIV)
             {
 				if (!forWrapping)
 					throw new ArgumentException("You should not supply an IV for unwrapping");
 
-				this.paramPlusIV = (ParametersWithIV) parameters;
-                this.iv = this.paramPlusIV.GetIV();
-                this.param = (KeyParameter) this.paramPlusIV.Parameters;
+				this.paramPlusIV = withIV;
+                this.iv = withIV.GetIV();
+                this.param = (KeyParameter)withIV.Parameters;
 
 				if (this.iv.Length != 8)
 					throw new ArgumentException("IV is not 8 octets", "parameters");
diff --git a/crypto/src/crypto/engines/ElGamalEngine.cs b/crypto/src/crypto/engines/ElGamalEngine.cs
index ea5e5bc30..8903f495e 100644
--- a/crypto/src/crypto/engines/ElGamalEngine.cs
+++ b/crypto/src/crypto/engines/ElGamalEngine.cs
@@ -3,6 +3,7 @@ using System;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
@@ -38,7 +39,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 			else
 			{
 				this.key = (ElGamalKeyParameters)parameters;
-				this.random = CryptoServicesRegistrar.GetSecureRandom();
+				this.random = forEncryption ? CryptoServicesRegistrar.GetSecureRandom() : null;
             }
 
 			this.forEncryption = forEncryption;
@@ -157,14 +158,12 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 				output = new byte[this.GetOutputBlockSize()];
 
-				// TODO Add methods to allow writing BigInteger to existing byte array?
-				byte[] out1 = gamma.ToByteArrayUnsigned();
-				byte[] out2 = phi.ToByteArrayUnsigned();
-				out1.CopyTo(output, output.Length / 2 - out1.Length);
-				out2.CopyTo(output, output.Length - out2.Length);
-			}
+				int mid = output.Length / 2;
+                BigIntegers.AsUnsignedByteArray(gamma, output, 0, mid);
+                BigIntegers.AsUnsignedByteArray(phi, output, mid, output.Length - mid);
+            }
 
-			return output;
+            return output;
 		}
 	}
 }
diff --git a/crypto/src/crypto/engines/ISAPEngine.cs b/crypto/src/crypto/engines/ISAPEngine.cs
new file mode 100644
index 000000000..3745f3ae9
--- /dev/null
+++ b/crypto/src/crypto/engines/ISAPEngine.cs
@@ -0,0 +1,1036 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+using static Org.BouncyCastle.Tls.DtlsReliableHandshake;
+
+
+/**
+ * ISAP AEAD v2, https://isap.iaik.tugraz.at/
+ * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/constist-round/updated-spec-doc/isap-spec-const.pdf
+ * <p>
+ * ISAP AEAD v2 with reference to C Reference Impl from: https://github.com/isap-lwc/isap-code-package
+ * </p>
+ */
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    public class ISAPEngine : IAeadBlockCipher
+    {
+        public enum IsapType
+        {
+            ISAP_A_128A,
+            ISAP_K_128A,
+            ISAP_A_128,
+            ISAP_K_128
+        }
+
+        public ISAPEngine(IsapType isapType)
+        {
+            switch (isapType)
+            {
+                case IsapType.ISAP_A_128A:
+                    ISAPAEAD = new ISAPAEAD_A_128A();
+                    ISAP_rH = 64;
+                    algorithmName = "ISAP-A-128A AEAD";
+                    break;
+                case IsapType.ISAP_K_128A:
+                    ISAPAEAD = new ISAPAEAD_K_128A();
+                    ISAP_rH = 144;
+                    algorithmName = "ISAP-K-128A AEAD";
+                    break;
+                case IsapType.ISAP_A_128:
+                    ISAPAEAD = new ISAPAEAD_A_128();
+                    ISAP_rH = 64;
+                    algorithmName = "ISAP-A-128 AEAD";
+                    break;
+                case IsapType.ISAP_K_128:
+                    ISAPAEAD = new ISAPAEAD_K_128();
+                    ISAP_rH = 144;
+                    algorithmName = "ISAP-K-128 AEAD";
+                    break;
+            }
+            ISAP_rH_SZ = (ISAP_rH + 7) >> 3;
+        }
+
+        private string algorithmName;
+        private bool forEncryption;
+        private bool initialised;
+        const int CRYPTO_KEYBYTES = 16;
+        const int CRYPTO_NPUBBYTES = 16;
+        const int ISAP_STATE_SZ = 40;
+        private byte[] c;
+        private byte[] ad;
+        private byte[] mac;
+        private MemoryStream aadData = new MemoryStream();
+        private MemoryStream message = new MemoryStream();
+        private MemoryStream outputStream = new MemoryStream();
+        private ISAP_AEAD ISAPAEAD;
+        private int ISAP_rH;
+        private int ISAP_rH_SZ;
+
+        public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
+
+        public string AlgorithmName => algorithmName;
+
+        protected abstract class ISAP_AEAD
+        {
+            protected byte[] k;
+            protected byte[] npub;
+            protected int ISAP_rH;
+            protected int ISAP_rH_SZ;
+
+            public abstract void isap_enc(byte[] m, int mOff, int mlen, byte[] c, int cOff, int clen);
+
+            public abstract void init(byte[] k, byte[] npub, int ISAP_rH, int ISAP_rH_SZ);
+
+            public abstract void isap_mac(byte[] ad, int adlen, byte[] c, int clen, byte[] tag, int tagOff);
+
+            public abstract void reset();
+        }
+
+        protected abstract class ISAPAEAD_A : ISAP_AEAD
+        {
+            protected ulong[] k64;
+            protected ulong[] npub64;
+            protected ulong ISAP_IV1_64;
+            protected ulong ISAP_IV2_64;
+            protected ulong ISAP_IV3_64;
+            protected ulong x0, x1, x2, x3, x4, t0, t1, t2, t3, t4;
+
+            public override void init(byte[] k, byte[] npub, int ISAP_rH, int ISAP_rH_SZ)
+            {
+                this.k = k;
+                this.npub = npub;
+                this.ISAP_rH = ISAP_rH;
+                this.ISAP_rH_SZ = ISAP_rH_SZ;
+                npub64 = new ulong[getulongSize(npub.Length)];
+                Pack.LE_To_UInt64(npub, 0, npub64, 0, npub64.Length);
+                npub64[0] = U64BIG(npub64[0]);
+                npub64[1] = U64BIG(npub64[1]);
+                k64 = new ulong[getulongSize(k.Length)];
+                Pack.LE_To_UInt64(k, 0, k64, 0, k64.Length);
+                k64[0] = U64BIG(k64[0]);
+                k64[1] = U64BIG(k64[1]);
+                reset();
+            }
+
+            protected abstract void PX1();
+
+            protected abstract void PX2();
+
+            protected void ABSORB_MAC(byte[] src, int len)
+            {
+                ulong[] src64 = new ulong[src.Length >> 3];
+                Pack.LE_To_UInt64(src, 0, src64, 0, src64.Length);
+                int idx = 0;
+                while (len >= ISAP_rH_SZ)
+                {
+                    x0 ^= U64BIG(src64[idx++]);
+                    P12();
+                    len -= ISAP_rH_SZ;
+                }
+                /* Absorb const ad block */
+                for (int i = 0; i < len; ++i)
+                {
+                    x0 ^= (src[(idx << 3) + i] & 0xFFUL) << ((7 - i) << 3);
+                }
+                x0 ^= 0x80UL << ((7 - len) << 3);
+                P12();
+            }
+
+            public override void isap_mac(byte[] ad, int adlen, byte[] c, int clen, byte[] tag, int tagOff)
+            {
+                // Init State
+                x0 = npub64[0];
+                x1 = npub64[1];
+                x2 = ISAP_IV1_64;
+                x3 = x4 = 0;
+                P12();
+                ABSORB_MAC(ad, adlen);
+                // Domain seperation
+                x4 ^= 1L;
+                ABSORB_MAC(c, clen);
+                // Derive K*
+                Pack.UInt64_To_LE(U64BIG(x0), tag, 0);
+                Pack.UInt64_To_LE(U64BIG(x1), tag, 8);
+                ulong tmp_x2 = x2, tmp_x3 = x3, tmp_x4 = x4;
+                isap_rk(ISAP_IV2_64, tag, CRYPTO_KEYBYTES);
+                x2 = tmp_x2;
+                x3 = tmp_x3;
+                x4 = tmp_x4;
+                // Squeeze tag
+                P12();
+                Pack.UInt64_To_LE(U64BIG(x0), tag, tagOff);
+                Pack.UInt64_To_LE(U64BIG(x1), tag, tagOff + 8);
+            }
+
+            public void isap_rk(ulong iv64, byte[] y, int ylen)
+            {
+                // Init state
+                x0 = k64[0];
+                x1 = k64[1];
+                x2 = iv64;
+                x3 = x4 = 0;
+                P12();
+                // Absorb Y
+                for (int i = 0; i < (ylen << 3) - 1; i++)
+                {
+                    x0 ^= (((((ulong)y[i >> 3] >> (7 - (i & 7))) & 0x01UL) << 7) & 0xFFUL) << 56;
+                    PX2();
+                }
+                x0 ^= (((y[ylen - 1]) & 0x01UL) << 7) << 56;
+                P12();
+            }
+
+            public override void isap_enc(byte[] m, int mOff, int mlen, byte[] c, int cOff, int clen)
+            {
+                /* Encrypt m */
+                ulong[] m64 = new ulong[mlen >> 3];
+                Pack.LE_To_UInt64(m, mOff, m64, 0, m64.Length);
+                ulong[] c64 = new ulong[m64.Length];
+                int idx = 0;
+                while (mlen >= ISAP_rH_SZ)
+                {
+                    c64[idx] = U64BIG(x0) ^ m64[idx];
+                    PX1();
+                    idx++;
+                    mlen -= ISAP_rH_SZ;
+                }
+                Pack.UInt64_To_LE(c64, 0, c64.Length, c, cOff);
+                /* Encrypt const m block */
+                byte[] xo = Pack.UInt64_To_LE(x0);
+                while (mlen > 0)
+                {
+                    c[(idx << 3) + cOff + mlen - 1] = (byte)(xo[ISAP_rH_SZ - mlen] ^ m[(idx << 3) + mOff + --mlen]);
+                }
+            }
+
+            public override void reset()
+            {
+                // Init state
+                isap_rk(ISAP_IV3_64, npub, CRYPTO_NPUBBYTES);
+                x3 = npub64[0];
+                x4 = npub64[1];
+                PX1();
+            }
+
+            private int getulongSize(int x)
+            {
+                return (x >> 3) + ((x & 7) != 0 ? 1 : 0);
+            }
+
+            private ulong ROTR(ulong x, int n)
+            {
+                return (x >> n) | (x << (64 - n));
+            }
+
+            protected ulong U64BIG(ulong x)
+            {
+                return ((ROTR(x, 8) & (0xFF000000FF000000UL)) | (ROTR(x, 24) & (0x00FF000000FF0000UL)) |
+                    (ROTR(x, 40) & (0x0000FF000000FF00UL)) | (ROTR(x, 56) & (0x000000FF000000FFUL)));
+            }
+
+            protected void ROUND(ulong C)
+            {
+                t0 = x0 ^ x1 ^ x2 ^ x3 ^ C ^ (x1 & (x0 ^ x2 ^ x4 ^ C));
+                t1 = x0 ^ x2 ^ x3 ^ x4 ^ C ^ ((x1 ^ x2 ^ C) & (x1 ^ x3));
+                t2 = x1 ^ x2 ^ x4 ^ C ^ (x3 & x4);
+                t3 = x0 ^ x1 ^ x2 ^ C ^ ((~x0) & (x3 ^ x4));
+                t4 = x1 ^ x3 ^ x4 ^ ((x0 ^ x4) & x1);
+                x0 = t0 ^ ROTR(t0, 19) ^ ROTR(t0, 28);
+                x1 = t1 ^ ROTR(t1, 39) ^ ROTR(t1, 61);
+                x2 = ~(t2 ^ ROTR(t2, 1) ^ ROTR(t2, 6));
+                x3 = t3 ^ ROTR(t3, 10) ^ ROTR(t3, 17);
+                x4 = t4 ^ ROTR(t4, 7) ^ ROTR(t4, 41);
+            }
+
+            public void P12()
+            {
+                ROUND(0xf0);
+                ROUND(0xe1);
+                ROUND(0xd2);
+                ROUND(0xc3);
+                ROUND(0xb4);
+                ROUND(0xa5);
+                P6();
+            }
+
+            protected void P6()
+            {
+                ROUND(0x96);
+                ROUND(0x87);
+                ROUND(0x78);
+                ROUND(0x69);
+                ROUND(0x5a);
+                ROUND(0x4b);
+            }
+        }
+
+        private class ISAPAEAD_A_128A : ISAPAEAD_A
+        {
+            public ISAPAEAD_A_128A()
+            {
+                ISAP_IV1_64 = 108156764297430540UL;
+                ISAP_IV2_64 = 180214358335358476UL;
+                ISAP_IV3_64 = 252271952373286412UL;
+            }
+
+            protected override void PX1()
+            {
+                P6();
+            }
+
+            protected override void PX2()
+            {
+                ROUND(0x4b);
+            }
+        }
+
+        private class ISAPAEAD_A_128 : ISAPAEAD_A
+        {
+            public ISAPAEAD_A_128()
+            {
+                ISAP_IV1_64 = 108156764298152972L;
+                ISAP_IV2_64 = 180214358336080908L;
+                ISAP_IV3_64 = 252271952374008844L;
+            }
+
+            protected override void PX1()
+            {
+                P12();
+            }
+
+            protected override void PX2()
+            {
+                P12();
+            }
+        }
+
+        private abstract class ISAPAEAD_K : ISAP_AEAD
+        {
+            const int ISAP_STATE_SZ_CRYPTO_NPUBBYTES = ISAP_STATE_SZ - CRYPTO_NPUBBYTES;
+            protected ushort[] ISAP_IV1_16;
+            protected ushort[] ISAP_IV2_16;
+            protected ushort[] ISAP_IV3_16;
+            protected ushort[] k16;
+            protected ushort[] iv16;
+            private readonly int[] KeccakF400RoundConstants = {0x0001, 0x8082, 0x808a, 0x8000, 0x808b, 0x0001, 0x8081, 0x8009,
+            0x008a, 0x0088, 0x8009, 0x000a, 0x808b, 0x008b, 0x8089, 0x8003, 0x8002, 0x0080, 0x800a, 0x000a};
+            protected ushort[] SX = new ushort[25];
+            protected ushort[] E = new ushort[25];
+            protected ushort[] C = new ushort[5];
+
+            public override void init(byte[] k, byte[] npub, int ISAP_rH, int ISAP_rH_SZ)
+            {
+                this.k = k;
+                this.npub = npub;
+                this.ISAP_rH = ISAP_rH;
+                this.ISAP_rH_SZ = ISAP_rH_SZ;
+                k16 = new ushort[k.Length >> 1];
+                byteToushort(k, k16, k16.Length);
+                iv16 = new ushort[npub.Length >> 1];
+                byteToushort(npub, iv16, iv16.Length);
+                reset();
+            }
+
+            public override void reset()
+            {
+                // Init state
+                SX = new ushort[25];
+                E = new ushort[25];
+                C = new ushort[5];
+                isap_rk(ISAP_IV3_16, npub, CRYPTO_NPUBBYTES, SX, ISAP_STATE_SZ_CRYPTO_NPUBBYTES, C);
+                Array.Copy(iv16, 0, SX, 17, 8);
+                PermuteRoundsKX(SX, E, C);
+            }
+
+            protected abstract void PermuteRoundsHX(ushort[] SX, ushort[] E, ushort[] C);
+
+            protected abstract void PermuteRoundsKX(ushort[] SX, ushort[] E, ushort[] C);
+
+            protected abstract void PermuteRoundsBX(ushort[] SX, ushort[] E, ushort[] C);
+
+            protected void ABSORB_MAC(ushort[] SX, byte[] src, int len, ushort[] E, ushort[] C)
+            {
+                int rem_bytes = len;
+                int idx = 0;
+                while (true)
+                {
+                    if (rem_bytes > ISAP_rH_SZ)
+                    {
+                        byteToushortXor(src, SX, ISAP_rH_SZ >> 1);
+                        idx += ISAP_rH_SZ;
+                        rem_bytes -= ISAP_rH_SZ;
+                        PermuteRoundsHX(SX, E, C);
+                    }
+                    else if (rem_bytes == ISAP_rH_SZ)
+                    {
+                        byteToushortXor(src, SX, ISAP_rH_SZ >> 1);
+                        PermuteRoundsHX(SX, E, C);
+                        SX[0] ^= 0x80;
+                        PermuteRoundsHX(SX, E, C);
+                        break;
+                    }
+                    else
+                    {
+                        for (int i = 0; i < rem_bytes; i++)
+                        {
+                            SX[i >> 1] ^= (ushort)((src[idx++] & 0xFFU) << ((i & 1) << 3));
+                        }
+                        SX[rem_bytes >> 1] ^= (ushort)(0x80U << ((rem_bytes & 1) << 3));
+                        PermuteRoundsHX(SX, E, C);
+                        break;
+                    }
+                }
+            }
+
+            public void isap_rk(ushort[] iv16, byte[] y, int ylen, ushort[] out16, int outlen, ushort[] C)
+            {
+                // Init state
+                ushort[] SX = new ushort[25];
+                ushort[] E = new ushort[25];
+                Array.Copy(k16, 0, SX, 0, 8);
+                Array.Copy(iv16, 0, SX, 8, 4);
+                PermuteRoundsKX(SX, E, C);
+                // Absorb all bits of Y
+                for (int i = 0; i < (ylen << 3) - 1; i++)
+                {
+                    SX[0] ^= (ushort)(((y[i >> 3] >> (7 - (i & 7))) & 0x01) << 7);
+                    PermuteRoundsBX(SX, E, C);
+                }
+                SX[0] ^= (ushort)(((y[ylen - 1]) & 0x01) << 7);
+                PermuteRoundsKX(SX, E, C);
+                // Extract K*
+                Array.Copy(SX, 0, out16, 0, outlen == ISAP_STATE_SZ_CRYPTO_NPUBBYTES ? 17 : 8);
+            }
+
+            public override void isap_mac(byte[] ad, int adlen, byte[] c, int clen, byte[] tag, int tagOff)
+            {
+                SX = new ushort[25];
+                // Init state
+                Array.Copy(iv16, 0, SX, 0, 8);
+                Array.Copy(ISAP_IV1_16, 0, SX, 8, 4);
+                PermuteRoundsHX(SX, E, C);
+                // Absorb AD
+                ABSORB_MAC(SX, ad, adlen, E, C);
+                // Domain seperation
+                SX[24] ^= 0x0100;
+                // Absorb C
+                ABSORB_MAC(SX, c, clen, E, C);
+                // Derive K*
+                ushortToByte(SX, tag, tagOff);
+                isap_rk(ISAP_IV2_16, tag, CRYPTO_KEYBYTES, SX, CRYPTO_KEYBYTES, C);
+                // Squeeze tag
+                PermuteRoundsHX(SX, E, C);
+                ushortToByte(SX, tag, tagOff);
+            }
+
+            public override void isap_enc(byte[] m, int mOff, int mlen, byte[] c, int cOff, int clen)
+            {
+                // Squeeze key stream
+                while (true)
+                {
+                    if (mlen >= ISAP_rH_SZ)
+                    {
+                        // Squeeze full lane and continue
+                        for (int i = 0; i < ISAP_rH_SZ; ++i)
+                        {
+                            c[cOff++] = (byte)((SX[i >> 1] >> ((i & 1) << 3)) ^ m[mOff++]);
+                        }
+                        mlen -= ISAP_rH_SZ;
+                        PermuteRoundsKX(SX, E, C);
+                    }
+                    else
+                    {
+                        // Squeeze full or partial lane and stop
+                        for (int i = 0; i < mlen; ++i)
+                        {
+                            c[cOff++] = (byte)((SX[i >> 1] >> ((i & 1) << 3)) ^ m[mOff++]);
+                        }
+                        break;
+                    }
+                }
+            }
+
+            private void byteToushortXor(byte[] input, ushort[] output, int outLen)
+            {
+                for (int i = 0; i < outLen; ++i)
+                {
+                    output[i] ^= Pack.LE_To_UInt16(input, (i << 1));
+                }
+            }
+
+            private void byteToushort(byte[] input, ushort[] output, int outLen)
+            {
+                for (int i = 0; i < outLen; ++i)
+                {
+                    output[i] = Pack.LE_To_UInt16(input, (i << 1));
+                }
+            }
+
+            private void ushortToByte(ushort[] input, byte[] output, int outOff)
+            {
+                for (int i = 0; i < 8; ++i)
+                {
+                    shortToLittleEndian(input[i], output, outOff + (i << 1));
+                }
+            }
+
+            protected void rounds12X(ushort[] SX, ushort[] E, ushort[] C)
+            {
+                prepareThetaX(SX, C);
+                rounds_8_18(SX, E, C);
+            }
+
+            protected void rounds_4_18(ushort[] SX, ushort[] E, ushort[] C)
+            {
+                thetaRhoPiChiIotaPrepareTheta(4, SX, E, C);
+                thetaRhoPiChiIotaPrepareTheta(5, E, SX, C);
+                thetaRhoPiChiIotaPrepareTheta(6, SX, E, C);
+                thetaRhoPiChiIotaPrepareTheta(7, E, SX, C);
+                rounds_8_18(SX, E, C);
+            }
+
+            protected void rounds_8_18(ushort[] SX, ushort[] E, ushort[] C)
+            {
+                thetaRhoPiChiIotaPrepareTheta(8, SX, E, C);
+                thetaRhoPiChiIotaPrepareTheta(9, E, SX, C);
+                thetaRhoPiChiIotaPrepareTheta(10, SX, E, C);
+                thetaRhoPiChiIotaPrepareTheta(11, E, SX, C);
+                rounds_12_18(SX, E, C);
+            }
+
+            protected void rounds_12_18(ushort[] SX, ushort[] E, ushort[] C)
+            {
+                thetaRhoPiChiIotaPrepareTheta(12, SX, E, C);
+                thetaRhoPiChiIotaPrepareTheta(13, E, SX, C);
+                thetaRhoPiChiIotaPrepareTheta(14, SX, E, C);
+                thetaRhoPiChiIotaPrepareTheta(15, E, SX, C);
+                thetaRhoPiChiIotaPrepareTheta(16, SX, E, C);
+                thetaRhoPiChiIotaPrepareTheta(17, E, SX, C);
+                thetaRhoPiChiIotaPrepareTheta(18, SX, E, C);
+                thetaRhoPiChiIota(E, SX, C);
+            }
+
+            protected void prepareThetaX(ushort[] SX, ushort[] C)
+            {
+                C[0] = (ushort)(SX[0] ^ SX[5] ^ SX[10] ^ SX[15] ^ SX[20]);
+                C[1] = (ushort)(SX[1] ^ SX[6] ^ SX[11] ^ SX[16] ^ SX[21]);
+                C[2] = (ushort)(SX[2] ^ SX[7] ^ SX[12] ^ SX[17] ^ SX[22]);
+                C[3] = (ushort)(SX[3] ^ SX[8] ^ SX[13] ^ SX[18] ^ SX[23]);
+                C[4] = (ushort)(SX[4] ^ SX[9] ^ SX[14] ^ SX[19] ^ SX[24]);
+            }
+
+            private ushort ROL16(ushort a, int offset)
+            {
+                return (ushort)(((a & 0xFFFF) << offset) ^ ((a & 0xFFFF) >> (16 - offset)));
+            }
+
+            protected void thetaRhoPiChiIotaPrepareTheta(int i, ushort[] A, ushort[] E, ushort[] C)
+            {
+                ushort Da = (ushort)(C[4] ^ ROL16(C[1], 1));
+                ushort De = (ushort)(C[0] ^ ROL16(C[2], 1));
+                ushort Di = (ushort)(C[1] ^ ROL16(C[3], 1));
+                ushort Do = (ushort)(C[2] ^ ROL16(C[4], 1));
+                ushort Du = (ushort)(C[3] ^ ROL16(C[0], 1));
+
+                ushort Ba = A[0] ^= Da;
+                A[6] ^= De;
+                ushort Be = ROL16(A[6], 12);
+                A[12] ^= Di;
+                ushort Bi = ROL16(A[12], 11);
+                A[18] ^= Do;
+                ushort Bo = ROL16(A[18], 5);
+                A[24] ^= Du;
+                ushort Bu = ROL16(A[24], 14);
+                C[0] = E[0] = (ushort)(Ba ^ ((~Be) & Bi) ^ KeccakF400RoundConstants[i]);
+                C[1] = E[1] = (ushort)(Be ^ ((~Bi) & Bo));
+                C[2] = E[2] = (ushort)(Bi ^ ((~Bo) & Bu));
+                C[3] = E[3] = (ushort)(Bo ^ ((~Bu) & Ba));
+                C[4] = E[4] = (ushort)(Bu ^ ((~Ba) & Be));
+
+                A[3] ^= Do;
+                Ba = ROL16(A[3], 12);
+                A[9] ^= Du;
+                Be = ROL16(A[9], 4);
+                A[10] ^= Da;
+                Bi = ROL16(A[10], 3);
+                A[16] ^= De;
+                Bo = ROL16(A[16], 13);
+                A[22] ^= Di;
+                Bu = ROL16(A[22], 13);
+                E[5] = (ushort)(Ba ^ ((~Be) & Bi));
+                C[0] ^= E[5];
+                E[6] = (ushort)(Be ^ ((~Bi) & Bo));
+                C[1] ^= E[6];
+                E[7] = (ushort)(Bi ^ ((~Bo) & Bu));
+                C[2] ^= E[7];
+                E[8] = (ushort)(Bo ^ ((~Bu) & Ba));
+                C[3] ^= E[8];
+                E[9] = (ushort)(Bu ^ ((~Ba) & Be));
+                C[4] ^= E[9];
+
+                A[1] ^= De;
+                Ba = ROL16(A[1], 1);
+                A[7] ^= Di;
+                Be = ROL16(A[7], 6);
+                A[13] ^= Do;
+                Bi = ROL16(A[13], 9);
+                A[19] ^= Du;
+                Bo = ROL16(A[19], 8);
+                A[20] ^= Da;
+                Bu = ROL16(A[20], 2);
+                E[10] = (ushort)(Ba ^ ((~Be) & Bi));
+                C[0] ^= E[10];
+                E[11] = (ushort)(Be ^ ((~Bi) & Bo));
+                C[1] ^= E[11];
+                E[12] = (ushort)(Bi ^ ((~Bo) & Bu));
+                C[2] ^= E[12];
+                E[13] = (ushort)(Bo ^ ((~Bu) & Ba));
+                C[3] ^= E[13];
+                E[14] = (ushort)(Bu ^ ((~Ba) & Be));
+                C[4] ^= E[14];
+
+                A[4] ^= Du;
+                Ba = ROL16(A[4], 11);
+                A[5] ^= Da;
+                Be = ROL16(A[5], 4);
+                A[11] ^= De;
+                Bi = ROL16(A[11], 10);
+                A[17] ^= Di;
+                Bo = ROL16(A[17], 15);
+                A[23] ^= Do;
+                Bu = ROL16(A[23], 8);
+                E[15] = (ushort)(Ba ^ ((~Be) & Bi));
+                C[0] ^= E[15];
+                E[16] = (ushort)(Be ^ ((~Bi) & Bo));
+                C[1] ^= E[16];
+                E[17] = (ushort)(Bi ^ ((~Bo) & Bu));
+                C[2] ^= E[17];
+                E[18] = (ushort)(Bo ^ ((~Bu) & Ba));
+                C[3] ^= E[18];
+                E[19] = (ushort)(Bu ^ ((~Ba) & Be));
+                C[4] ^= E[19];
+
+                A[2] ^= Di;
+                Ba = ROL16(A[2], 14);
+                A[8] ^= Do;
+                Be = ROL16(A[8], 7);
+                A[14] ^= Du;
+                Bi = ROL16(A[14], 7);
+                A[15] ^= Da;
+                Bo = ROL16(A[15], 9);
+                A[21] ^= De;
+                Bu = ROL16(A[21], 2);
+                E[20] = (ushort)(Ba ^ ((~Be) & Bi));
+                C[0] ^= E[20];
+                E[21] = (ushort)(Be ^ ((~Bi) & Bo));
+                C[1] ^= E[21];
+                E[22] = (ushort)(Bi ^ ((~Bo) & Bu));
+                C[2] ^= E[22];
+                E[23] = (ushort)(Bo ^ ((~Bu) & Ba));
+                C[3] ^= E[23];
+                E[24] = (ushort)(Bu ^ ((~Ba) & Be));
+                C[4] ^= E[24];
+            }
+
+            protected void thetaRhoPiChiIota(ushort[] A, ushort[] E, ushort[] C)
+            {
+                ushort Da = (ushort)(C[4] ^ ROL16(C[1], 1));
+                ushort De = (ushort)(C[0] ^ ROL16(C[2], 1));
+                ushort Di = (ushort)(C[1] ^ ROL16(C[3], 1));
+                ushort Do = (ushort)(C[2] ^ ROL16(C[4], 1));
+                ushort Du = (ushort)(C[3] ^ ROL16(C[0], 1));
+
+                ushort Ba = A[0] ^= Da;
+                A[6] ^= De;
+                ushort Be = ROL16(A[6], 12);
+                A[12] ^= Di;
+                ushort Bi = ROL16(A[12], 11);
+                A[18] ^= Do;
+                ushort Bo = ROL16(A[18], 5);
+                A[24] ^= Du;
+                ushort Bu = ROL16(A[24], 14);
+                E[0] = (ushort)(Ba ^ ((~Be) & Bi) ^ KeccakF400RoundConstants[19]);
+                E[1] = (ushort)(Be ^ ((~Bi) & Bo));
+                E[2] = (ushort)(Bi ^ ((~Bo) & Bu));
+                E[3] = (ushort)(Bo ^ ((~Bu) & Ba));
+                E[4] = (ushort)(Bu ^ ((~Ba) & Be));
+
+                A[3] ^= Do;
+                Ba = ROL16(A[3], 12);
+                A[9] ^= Du;
+                Be = ROL16(A[9], 4);
+                A[10] ^= Da;
+                Bi = ROL16(A[10], 3);
+                A[16] ^= De;
+                Bo = ROL16(A[16], 13);
+                A[22] ^= Di;
+                Bu = ROL16(A[22], 13);
+                E[5] = (ushort)(Ba ^ ((~Be) & Bi));
+                E[6] = (ushort)(Be ^ ((~Bi) & Bo));
+                E[7] = (ushort)(Bi ^ ((~Bo) & Bu));
+                E[8] = (ushort)(Bo ^ ((~Bu) & Ba));
+                E[9] = (ushort)(Bu ^ ((~Ba) & Be));
+
+                A[1] ^= De;
+                Ba = ROL16(A[1], 1);
+                A[7] ^= Di;
+                Be = ROL16(A[7], 6);
+                A[13] ^= Do;
+                Bi = ROL16(A[13], 9);
+                A[19] ^= Du;
+                Bo = ROL16(A[19], 8);
+                A[20] ^= Da;
+                Bu = ROL16(A[20], 2);
+                E[10] = (ushort)(Ba ^ ((~Be) & Bi));
+                E[11] = (ushort)(Be ^ ((~Bi) & Bo));
+                E[12] = (ushort)(Bi ^ ((~Bo) & Bu));
+                E[13] = (ushort)(Bo ^ ((~Bu) & Ba));
+                E[14] = (ushort)(Bu ^ ((~Ba) & Be));
+
+                A[4] ^= Du;
+                Ba = ROL16(A[4], 11);
+                A[5] ^= Da;
+                Be = ROL16(A[5], 4);
+                A[11] ^= De;
+                Bi = ROL16(A[11], 10);
+                A[17] ^= Di;
+                Bo = ROL16(A[17], 15);
+                A[23] ^= Do;
+                Bu = ROL16(A[23], 8);
+                E[15] = (ushort)(Ba ^ ((~Be) & Bi));
+                E[16] = (ushort)(Be ^ ((~Bi) & Bo));
+                E[17] = (ushort)(Bi ^ ((~Bo) & Bu));
+                E[18] = (ushort)(Bo ^ ((~Bu) & Ba));
+                E[19] = (ushort)(Bu ^ ((~Ba) & Be));
+
+                A[2] ^= Di;
+                Ba = ROL16(A[2], 14);
+                A[8] ^= Do;
+                Be = ROL16(A[8], 7);
+                A[14] ^= Du;
+                Bi = ROL16(A[14], 7);
+                A[15] ^= Da;
+                Bo = ROL16(A[15], 9);
+                A[21] ^= De;
+                Bu = ROL16(A[21], 2);
+                E[20] = (ushort)(Ba ^ ((~Be) & Bi));
+                E[21] = (ushort)(Be ^ ((~Bi) & Bo));
+                E[22] = (ushort)(Bi ^ ((~Bo) & Bu));
+                E[23] = (ushort)(Bo ^ ((~Bu) & Ba));
+                E[24] = (ushort)(Bu ^ ((~Ba) & Be));
+            }
+        }
+
+        private class ISAPAEAD_K_128A : ISAPAEAD_K
+        {
+            public ISAPAEAD_K_128A()
+            {
+                ISAP_IV1_16 = new ushort[] { 32769, 400, 272, 2056 };
+                ISAP_IV2_16 = new ushort[] { 32770, 400, 272, 2056 };
+                ISAP_IV3_16 = new ushort[] { 32771, 400, 272, 2056 };
+            }
+
+            protected override void PermuteRoundsHX(ushort[] SX, ushort[] E, ushort[] C)
+            {
+                prepareThetaX(SX, C);
+                rounds_4_18(SX, E, C);
+            }
+
+            protected override void PermuteRoundsKX(ushort[] SX, ushort[] E, ushort[] C)
+            {
+                prepareThetaX(SX, C);
+                rounds_12_18(SX, E, C);
+            }
+
+            protected override void PermuteRoundsBX(ushort[] SX, ushort[] E, ushort[] C)
+            {
+                prepareThetaX(SX, C);
+                thetaRhoPiChiIotaPrepareTheta(19, SX, E, C);
+                Array.Copy(E, 0, SX, 0, E.Length);
+            }
+        }
+
+        private class ISAPAEAD_K_128
+            : ISAPAEAD_K
+        {
+            public ISAPAEAD_K_128()
+            {
+                ISAP_IV1_16 = new ushort[] { 32769, 400, 3092, 3084 };
+                ISAP_IV2_16 = new ushort[] { 32770, 400, 3092, 3084 };
+                ISAP_IV3_16 = new ushort[] { 32771, 400, 3092, 3084 };
+            }
+
+            protected override void PermuteRoundsHX(ushort[] SX, ushort[] E, ushort[] C)
+            {
+                prepareThetaX(SX, C);
+                thetaRhoPiChiIotaPrepareTheta(0, SX, E, C);
+                thetaRhoPiChiIotaPrepareTheta(1, E, SX, C);
+                thetaRhoPiChiIotaPrepareTheta(2, SX, E, C);
+                thetaRhoPiChiIotaPrepareTheta(3, E, SX, C);
+                rounds_4_18(SX, E, C);
+            }
+
+            protected override void PermuteRoundsKX(ushort[] SX, ushort[] E, ushort[] C)
+            {
+                rounds12X(SX, E, C);
+            }
+
+            protected override void PermuteRoundsBX(ushort[] SX, ushort[] E, ushort[] C)
+            {
+                rounds12X(SX, E, C);
+            }
+        }
+
+
+
+        public void Init(bool forEncryption, ICipherParameters param)
+        {
+            this.forEncryption = forEncryption;
+            if (!(param is ParametersWithIV))
+            {
+                throw new ArgumentException(
+                    "ISAP AEAD init parameters must include an IV");
+            }
+
+            ParametersWithIV ivParams = (ParametersWithIV)param;
+
+            byte[] iv = ivParams.GetIV();
+
+            if (iv == null || iv.Length != 16)
+            {
+                throw new ArgumentException(
+                    "ISAP AEAD requires exactly 12 bytes of IV");
+            }
+
+            if (!(ivParams.Parameters is KeyParameter))
+            {
+                throw new ArgumentException(
+                    "ISAP AEAD init parameters must include a key");
+            }
+
+            KeyParameter key = (KeyParameter)ivParams.Parameters;
+            byte[] keyBytes = key.GetKey();
+            if (keyBytes.Length != 16)
+            {
+                throw new ArgumentException(
+                    "ISAP AEAD key must be 128 bits ulong");
+            }
+
+            /**
+             * Initialize variables.
+             */
+            byte[] npub = new byte[iv.Length];
+            byte[] k = new byte[keyBytes.Length];
+            Array.Copy(iv, 0, npub, 0, iv.Length);
+            Array.Copy(keyBytes, 0, k, 0, keyBytes.Length);
+            initialised = true;
+            ISAPAEAD.init(k, npub, ISAP_rH, ISAP_rH_SZ);
+            Reset();
+        }
+
+        public void ProcessAadByte(byte input)
+        {
+            aadData.Write(new byte[] { input }, 0, 1);
+        }
+
+
+        public void ProcessAadBytes(byte[] input, int inOff, int len)
+        {
+            if ((inOff + len) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short" + (forEncryption ? "encryption" : "decryption"));
+            }
+            aadData.Write(input, inOff, len);
+        }
+
+
+        public int ProcessByte(byte input, byte[] output, int outOff)
+        {
+
+            return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+        }
+
+
+        public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            if ((inOff + len) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            message.Write(input, inOff, len);
+            if (forEncryption)
+            {
+                if (message.Length >= ISAP_rH_SZ)
+                {
+                    len = (int)message.Length / ISAP_rH_SZ * ISAP_rH_SZ;
+                    if (outOff + len > output.Length)
+                    {
+                        throw new OutputLengthException("output buffer is too short");
+                    }
+                    byte[] enc_input = message.GetBuffer();
+                    ISAPAEAD.isap_enc(enc_input, 0, len, output, outOff, output.Length);
+                    outputStream.Write(output, outOff, len);
+                    int enc_input_len = (int)message.Length;
+                    message.SetLength(0);
+                    message.Write(enc_input, len, enc_input_len - len);
+                    return len;
+                }
+            }
+            return 0;
+        }
+
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            int len;
+            if (forEncryption)
+            {
+                byte[] enc_input = message.GetBuffer();
+                len = (int)message.Length;
+                if (outOff + len + 16 > output.Length)
+                {
+                    throw new OutputLengthException("output buffer is too short");
+                }
+                ISAPAEAD.isap_enc(enc_input, 0, len, output, outOff, output.Length);
+                outputStream.Write(output, outOff, len);
+                outOff += len;
+                ad = aadData.GetBuffer();
+                c = outputStream.GetBuffer();
+                mac = new byte[16];
+                ISAPAEAD.isap_mac(ad, (int)aadData.Length, c, (int)outputStream.Length, mac, 0);
+                Array.Copy(mac, 0, output, outOff, 16);
+                len += 16;
+            }
+            else
+            {
+                ad = aadData.GetBuffer();
+                int adlen = (int)aadData.Length;
+                c = message.GetBuffer();
+                int clen = (int)message.Length;
+                mac = new byte[16];
+                len = clen - mac.Length;
+                if (len + outOff > output.Length)
+                {
+                    throw new OutputLengthException("output buffer is too short");
+                }
+                ISAPAEAD.isap_mac(ad, adlen, c, len, mac, 0);
+                ISAPAEAD.reset();
+                for (int i = 0; i < 16; ++i)
+                {
+                    if (mac[i] != c[len + i])
+                    {
+                        throw new ArgumentException("Mac does not match");
+                    }
+                }
+                ISAPAEAD.isap_enc(c, 0, len, output, outOff, output.Length);
+            }
+            return len;
+        }
+
+
+        public byte[] GetMac()
+        {
+            return mac;
+        }
+
+
+        public int GetUpdateOutputSize(int len)
+        {
+            return len;
+        }
+
+
+        public int GetOutputSize(int len)
+        {
+            return len + 16;
+        }
+
+
+        public void Reset()
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            aadData.SetLength(0);
+            ISAPAEAD.reset();
+            message.SetLength(0);
+            outputStream.SetLength(0);
+        }
+
+        private static void shortToLittleEndian(ushort n, byte[] bs, int off)
+        {
+            bs[off] = (byte)(n);
+            bs[++off] = (byte)(n >> 8);
+        }
+
+        public int GetBlockSize()
+        {
+            return ISAP_rH_SZ;
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void ProcessAadBytes(ReadOnlySpan<byte> input)
+        {
+            aadData.Write(input);
+        }
+
+        public int ProcessByte(byte input, Span<byte> output)
+        {
+            byte[] rv = new byte[1];
+            int len = ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return len;
+        }
+
+        public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            byte[] rv = new byte[input.Length];
+            int len = ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return len;
+        }
+
+        public int DoFinal(Span<byte> output)
+        {
+            byte[] rv;
+            if (forEncryption)
+            {
+                rv = new byte[message.Length + 16];
+            }
+            else
+            {
+                rv = new byte[message.Length];
+            }
+            int len = DoFinal(rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return rv.Length;
+        }
+#endif
+
+        public int GetKeyBytesSize()
+        {
+            return CRYPTO_KEYBYTES;
+        }
+
+        public int GetIVBytesSize()
+        {
+            return CRYPTO_NPUBBYTES;
+        }
+    }
+}
+
+
diff --git a/crypto/src/crypto/engines/NaccacheSternEngine.cs b/crypto/src/crypto/engines/NaccacheSternEngine.cs
index 39fb7c9ec..16f62a4e5 100644
--- a/crypto/src/crypto/engines/NaccacheSternEngine.cs
+++ b/crypto/src/crypto/engines/NaccacheSternEngine.cs
@@ -31,15 +31,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @see org.bouncycastle.crypto.AsymmetricBlockCipher#init(bool,
 		*      org.bouncycastle.crypto.CipherParameters)
 		*/
-		public virtual void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
+		public virtual void Init(bool forEncryption, ICipherParameters parameters)
 		{
 			this.forEncryption = forEncryption;
 
-			if (parameters is ParametersWithRandom)
+			if (parameters is ParametersWithRandom withRandom)
 			{
-				parameters = ((ParametersWithRandom) parameters).Parameters;
+				parameters = withRandom.Parameters;
 			}
 
 			key = (NaccacheSternKeyParameters)parameters;
diff --git a/crypto/src/crypto/engines/PhotonBeetleEngine.cs b/crypto/src/crypto/engines/PhotonBeetleEngine.cs
new file mode 100644
index 000000000..9245faa27
--- /dev/null
+++ b/crypto/src/crypto/engines/PhotonBeetleEngine.cs
@@ -0,0 +1,459 @@
+using System;
+using System.IO;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+
+/**
+ * Photon-Beetle, https://www.isical.ac.in/~lightweight/beetle/
+ * https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/readonlyist-round/updated-spec-doc/photon-beetle-spec-readonly.pdf
+ * <p>
+ * Photon-Beetle with reference to C Reference Impl from: https://github.com/PHOTON-Beetle/Software
+ * </p>
+ */
+
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    public class PhotonBeetleEngine : IAeadBlockCipher
+    {
+        public enum PhotonBeetleParameters
+        {
+            pb32,
+            pb128
+        }
+        private bool input_empty;
+        private bool forEncryption;
+        private bool initialised;
+        private byte[] K;
+        private byte[] N;
+        private byte[] state;
+        private byte[][] state_2d;
+        private byte[] A;
+        private byte[] T;
+        private MemoryStream aadData = new MemoryStream();
+        private MemoryStream message = new MemoryStream();
+        private readonly int CRYPTO_KEYBYTES = 16;
+        private readonly int CRYPTO_NPUBBYTES = 16;
+        private readonly int RATE_INBYTES;
+        private readonly int RATE_INBYTES_HALF;
+        private int STATE_INBYTES;
+        private int TAG_INBYTES = 16;
+        private int LAST_THREE_BITS_OFFSET;
+        private int ROUND = 12;
+        private int D = 8;
+        private int Dq = 3;
+        private int Dr = 7;
+        private int DSquare = 64;
+        private int S = 4;
+        private int S_1 = 3;
+        private byte[][] RC = {
+            new byte[]{1, 3, 7, 14, 13, 11, 6, 12, 9, 2, 5, 10},
+            new byte[]{0, 2, 6, 15, 12, 10, 7, 13, 8, 3, 4, 11},
+            new byte[]{2, 0, 4, 13, 14, 8, 5, 15, 10, 1, 6, 9},
+            new byte[]{6, 4, 0, 9, 10, 12, 1, 11, 14, 5, 2, 13},
+            new byte[]{14, 12, 8, 1, 2, 4, 9, 3, 6, 13, 10, 5},
+            new byte[]{15, 13, 9, 0, 3, 5, 8, 2, 7, 12, 11, 4},
+            new byte[]{13, 15, 11, 2, 1, 7, 10, 0, 5, 14, 9, 6},
+            new byte[]{9, 11, 15, 6, 5, 3, 14, 4, 1, 10, 13, 2}
+    };
+        private byte[][] MixColMatrix = {
+            new byte[]{2, 4, 2, 11, 2, 8, 5, 6},
+            new byte[]{12, 9, 8, 13, 7, 7, 5, 2},
+            new byte[]{4, 4, 13, 13, 9, 4, 13, 9},
+            new byte[]{1, 6, 5, 1, 12, 13, 15, 14},
+            new byte[]{15, 12, 9, 13, 14, 5, 14, 13},
+            new byte[]{9, 14, 5, 15, 4, 12, 9, 6},
+            new byte[]{12, 2, 2, 10, 3, 1, 1, 14},
+            new byte[]{15, 1, 13, 10, 5, 10, 2, 3}
+    };
+
+        private byte[] sbox = { 12, 5, 6, 11, 9, 0, 10, 13, 3, 14, 15, 8, 4, 7, 1, 2 };
+        public PhotonBeetleEngine(PhotonBeetleParameters pbp)
+        {
+            int CAPACITY_INBITS = 0, RATE_INBITS = 0;
+            switch (pbp)
+            {
+                case PhotonBeetleParameters.pb32:
+                    RATE_INBITS = 32;
+                    CAPACITY_INBITS = 224;
+                    break;
+                case PhotonBeetleParameters.pb128:
+                    RATE_INBITS = 128;
+                    CAPACITY_INBITS = 128;
+                    break;
+            }
+            RATE_INBYTES = (RATE_INBITS + 7) >> 3;
+            RATE_INBYTES_HALF = RATE_INBYTES >> 1;
+            int STATE_INBITS = RATE_INBITS + CAPACITY_INBITS;
+            STATE_INBYTES = (STATE_INBITS + 7) >> 3;
+            LAST_THREE_BITS_OFFSET = (STATE_INBITS - ((STATE_INBYTES - 1) << 3) - 3);
+            initialised = false;
+        }
+
+        public string AlgorithmName => "Photon-Beetle AEAD";
+
+        public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
+
+        public byte[] GetMac()
+        {
+            return T;
+        }
+
+        public int GetOutputSize(int len)
+        {
+            return len + TAG_INBYTES;
+        }
+
+        public int GetUpdateOutputSize(int len)
+        {
+            return len;
+        }
+
+        public void Init(bool forEncryption, ICipherParameters parameters)
+        {
+            this.forEncryption = forEncryption;
+            if (!(parameters is ParametersWithIV param))
+            {
+                throw new ArgumentException("Photon-Beetle AEAD init parameters must include an IV");
+            }
+            ParametersWithIV ivParams = param;
+            N = ivParams.GetIV();
+            if (N == null || N.Length != CRYPTO_NPUBBYTES)
+            {
+                throw new ArgumentException("Photon-Beetle AEAD requires exactly 16 bytes of IV");
+            }
+            if (!(ivParams.Parameters is KeyParameter))
+            {
+                throw new ArgumentException("Photon-Beetle AEAD init parameters must include a key");
+            }
+            KeyParameter key = (KeyParameter)ivParams.Parameters;
+            K = key.GetKey();
+            if (K.Length != CRYPTO_KEYBYTES)
+            {
+                throw new ArgumentException("Photon-Beetle AEAD key must be 128 bits long");
+            }
+
+            state = new byte[STATE_INBYTES];
+            state_2d = new byte[D][];
+            for (int i = 0; i < D; ++i)
+            {
+                state_2d[i] = new byte[D];
+            }
+            T = new byte[TAG_INBYTES];
+            initialised = true;
+            reset(false);
+        }
+
+        public void ProcessAadByte(byte input)
+        {
+            aadData.Write(new byte[] { input }, 0, 1);
+        }
+
+        public void ProcessAadBytes(byte[] input, int inOff, int len)
+        {
+            if (inOff + len > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            aadData.Write(input, inOff, len);
+        }
+
+        public int ProcessByte(byte input, byte[] output, int outOff)
+        {
+            message.Write(new byte[] { input }, 0, 1);
+            return 0;
+        }
+
+        public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+        {
+            if (inOff + len > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            message.Write(input, inOff, len);
+            return 0;
+        }
+
+        public void Reset()
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            reset(true);
+        }
+
+        private void reset(bool clearMac)
+        {
+            if (clearMac)
+            {
+                T = null;
+            }
+            input_empty = true;
+            aadData.SetLength(0);
+            message.SetLength(0);
+            Array.Copy(K, 0, state, 0, K.Length);
+            Array.Copy(N, 0, state, K.Length, N.Length);
+        }
+
+        void PHOTON_Permutation()
+        {
+            int i, j, k, l;
+            for (i = 0; i < DSquare; i++)
+            {
+                state_2d[i >> Dq][i & Dr] = (byte)(((state[i >> 1] & 0xFF) >> (4 * (i & 1))) & 0xf);
+            }
+            for (int round = 0; round < ROUND; round++)
+            {
+                //AddKey
+                for (i = 0; i < D; i++)
+                {
+                    state_2d[i][0] ^= RC[i][round];
+                }
+                //SubCell
+                for (i = 0; i < D; i++)
+                {
+                    for (j = 0; j < D; j++)
+                    {
+                        state_2d[i][j] = sbox[state_2d[i][j]];
+                    }
+                }
+                //ShiftRow
+                for (i = 1; i < D; i++)
+                {
+                    Array.Copy(state_2d[i], 0, state, 0, D);
+                    Array.Copy(state, i, state_2d[i], 0, D - i);
+                    Array.Copy(state, 0, state_2d[i], D - i, i);
+                }
+                //MixColumn
+                for (j = 0; j < D; j++)
+                {
+                    for (i = 0; i < D; i++)
+                    {
+                        byte sum = 0;
+                        for (k = 0; k < D; k++)
+                        {
+                            int x = MixColMatrix[i][k], ret = 0, b = state_2d[k][j];
+                            for (l = 0; l < S; l++)
+                            {
+                                if (((b >> l) & 1) != 0)
+                                {
+                                    ret ^= x;
+                                }
+                                if (((x >> S_1) & 1) != 0)
+                                {
+                                    x <<= 1;
+                                    x ^= 0x3;
+                                }
+                                else
+                                {
+                                    x <<= 1;
+                                }
+                            }
+                            sum ^= (byte)(ret & 15);
+                        }
+                        state[i] = sum;
+                    }
+                    for (i = 0; i < D; i++)
+                    {
+                        state_2d[i][j] = state[i];
+                    }
+                }
+            }
+            for (i = 0; i < DSquare; i += 2)
+            {
+                state[i >> 1] = (byte)(((state_2d[i >> Dq][i & Dr] & 0xf)) | ((state_2d[i >> Dq][(i + 1) & Dr] & 0xf) << 4));
+            }
+        }
+
+        private byte select(bool condition1, bool condition2, byte option3, byte option4)
+        {
+            if (condition1 && condition2)
+            {
+                return 1;
+            }
+            if (condition1)
+            {
+                return 2;
+            }
+            if (condition2)
+            {
+                return option3;
+            }
+            return option4;
+        }
+
+        void rhoohr(byte[] ciphertext, int offset, byte[] plaintext, int inOff, int DBlen_inbytes)
+        {
+            byte[] OuterState_part1_ROTR1 = state_2d[0];
+            int i, loop_end = System.Math.Min(DBlen_inbytes, RATE_INBYTES_HALF);
+            for (i = 0; i < RATE_INBYTES_HALF - 1; i++)
+            {
+                OuterState_part1_ROTR1[i] = (byte)(((state[i] & 0xFF) >> 1) | ((state[(i + 1)] & 1) << 7));
+            }
+            OuterState_part1_ROTR1[RATE_INBYTES_HALF - 1] = (byte)(((state[i] & 0xFF) >> 1) | ((state[0] & 1) << 7));
+            i = 0;
+            while (i < loop_end)
+            {
+                ciphertext[i + offset] = (byte)(state[i + RATE_INBYTES_HALF] ^ plaintext[i++ + inOff]);
+            }
+            while (i < DBlen_inbytes)
+            {
+                ciphertext[i + offset] = (byte)(OuterState_part1_ROTR1[i - RATE_INBYTES_HALF] ^ plaintext[i++ + inOff]);
+            }
+            if (forEncryption)
+            {
+                XOR(plaintext, inOff, DBlen_inbytes);
+            }
+            else
+            {
+                XOR(ciphertext, inOff, DBlen_inbytes);
+            }
+        }
+
+        void XOR(byte[] in_right, int rOff, int iolen_inbytes)
+        {
+            for (int i = 0; i < iolen_inbytes; i++)
+            {
+                state[i] ^= in_right[rOff++];
+            }
+        }
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            int len = (int)message.Length - (forEncryption ? 0 : TAG_INBYTES);
+            if ((forEncryption && len + TAG_INBYTES + outOff > output.Length) ||
+                (!forEncryption && len + outOff > output.Length))
+            {
+                throw new OutputLengthException("output buffer too short");
+            }
+            byte[] input = message.GetBuffer();
+            int inOff = 0;
+            A = aadData.GetBuffer();
+            int adlen = (int)aadData.Length, i;
+            if (adlen != 0 || len != 0)
+            {
+                input_empty = false;
+            }
+            byte c0 = select((len != 0), ((adlen % RATE_INBYTES) == 0), (byte)3, (byte)4);
+            byte c1 = select((adlen != 0), ((len % RATE_INBYTES) == 0), (byte)5, (byte)6);
+            int Dlen_inblocks, LastDBlocklen;
+            if (adlen != 0)
+            {
+                Dlen_inblocks = (adlen + RATE_INBYTES - 1) / RATE_INBYTES;
+                for (i = 0; i < Dlen_inblocks - 1; i++)
+                {
+                    PHOTON_Permutation();
+                    XOR(A, i * RATE_INBYTES, RATE_INBYTES);
+                }
+                PHOTON_Permutation();
+                LastDBlocklen = adlen - i * RATE_INBYTES;
+                XOR(A, i * RATE_INBYTES, LastDBlocklen);
+                if (LastDBlocklen < RATE_INBYTES)
+                {
+                    state[LastDBlocklen] ^= 0x01; // ozs
+                }
+                state[STATE_INBYTES - 1] ^= (byte)(c0 << LAST_THREE_BITS_OFFSET);
+            }
+            if (len != 0)
+            {
+                Dlen_inblocks = (len + RATE_INBYTES - 1) / RATE_INBYTES;
+                for (i = 0; i < Dlen_inblocks - 1; i++)
+                {
+                    PHOTON_Permutation();
+                    rhoohr(output, outOff + i * RATE_INBYTES, input, inOff + i * RATE_INBYTES, RATE_INBYTES);
+                }
+                PHOTON_Permutation();
+                LastDBlocklen = len - i * RATE_INBYTES;
+                rhoohr(output, outOff + i * RATE_INBYTES, input, inOff + i * RATE_INBYTES, LastDBlocklen);
+                if (LastDBlocklen < RATE_INBYTES)
+                {
+                    state[LastDBlocklen] ^= 0x01; // ozs
+                }
+                state[STATE_INBYTES - 1] ^= (byte)(c1 << LAST_THREE_BITS_OFFSET);
+            }
+            outOff += len;
+            if (input_empty)
+            {
+                state[STATE_INBYTES - 1] ^= (byte)(1 << LAST_THREE_BITS_OFFSET);
+            }
+            PHOTON_Permutation();
+            T = new byte[TAG_INBYTES];
+            Array.Copy(state, 0, T, 0, TAG_INBYTES);
+            if (forEncryption)
+            {
+                Array.Copy(T, 0, output, outOff, TAG_INBYTES);
+                len += TAG_INBYTES;
+            }
+            else
+            {
+                for (i = 0; i < TAG_INBYTES; ++i)
+                {
+                    if (T[i] != input[len + i])
+                    {
+                        throw new ArgumentException("Mac does not match");
+                    }
+                }
+            }
+            reset(false);
+            return len;
+        }
+
+        public int GetBlockSize()
+        {
+            return RATE_INBYTES;
+        }
+
+        public int GetKeyBytesSize()
+        {
+            return CRYPTO_KEYBYTES;
+        }
+
+        public int GetIVBytesSize()
+        {
+            return CRYPTO_NPUBBYTES;
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void ProcessAadBytes(ReadOnlySpan<byte> input)
+        {
+            aadData.Write(input);
+        }
+
+        public int ProcessByte(byte input, Span<byte> output)
+        {
+            byte[] rv = new byte[1];
+            int len = ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return len;
+        }
+
+        public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            byte[] rv = new byte[input.Length];
+            int len = ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return len;
+        }
+
+        public int DoFinal(Span<byte> output)
+        {
+            byte[] rv;
+            if (forEncryption)
+            {
+                rv = new byte[message.Length + 16];
+            }
+            else
+            {
+                rv = new byte[message.Length - 16];
+            }
+            int len = DoFinal(rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return rv.Length;
+        }
+#endif
+    }
+}
diff --git a/crypto/src/crypto/engines/RC2WrapEngine.cs b/crypto/src/crypto/engines/RC2WrapEngine.cs
index bc50f0db4..0dd20c176 100644
--- a/crypto/src/crypto/engines/RC2WrapEngine.cs
+++ b/crypto/src/crypto/engines/RC2WrapEngine.cs
@@ -56,14 +56,14 @@ namespace Org.BouncyCastle.Crypto.Engines
 			this.forWrapping = forWrapping;
 			this.engine = new CbcBlockCipher(new RC2Engine());
 
-			if (parameters is ParametersWithRandom pWithR)
+			if (parameters is ParametersWithRandom withRandom)
 			{
-				sr = pWithR.Random;
-				parameters = pWithR.Parameters;
+				sr = withRandom.Random;
+				parameters = withRandom.Parameters;
 			}
 			else
 			{
-				sr = CryptoServicesRegistrar.GetSecureRandom();
+                sr = forWrapping ? CryptoServicesRegistrar.GetSecureRandom() : null;
 			}
 
 			if (parameters is ParametersWithIV)
@@ -111,96 +111,66 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @param inLen
 		* @return
 		*/
-        public virtual byte[] Wrap(
-			byte[]	input,
-			int		inOff,
-			int		length)
+        public virtual byte[] Wrap(byte[] input, int inOff, int length)
 		{
 			if (!forWrapping)
-			{
 				throw new InvalidOperationException("Not initialized for wrapping");
-			}
 
-			int len = length + 1;
-			if ((len % 8) != 0)
-			{
-				len += 8 - (len % 8);
-			}
+			int len = (length + 8) & ~7;
+			int ivLen = iv.Length;
 
-			byte [] keyToBeWrapped = new byte[len];
+            // Let TEMP = IV || WKCKS.
+            byte[] TEMP = Arrays.CopyOf(iv, ivLen + len + 8);
+			TEMP[ivLen] = (byte)length;
+			Array.Copy(input, inOff, TEMP, ivLen + 1, length);
 
-			keyToBeWrapped[0] = (byte)length;
-			Array.Copy(input, inOff, keyToBeWrapped, 1, length);
-
-			byte[] pad = new byte[keyToBeWrapped.Length - length - 1];
-
-			if (pad.Length > 0)
+            int padLen = len - length - 1;
+			if (padLen > 0)
 			{
-				sr.NextBytes(pad);
-				Array.Copy(pad, 0, keyToBeWrapped, length + 1, pad.Length);
-			}
+                sr.NextBytes(TEMP, ivLen + len - padLen, padLen);
+            }
 
-			// Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
-			byte[] CKS = CalculateCmsKeyChecksum(keyToBeWrapped);
+            // Compute the CMS Key Checksum, (section 5.6.1), call this CKS.
+            CalculateCmsKeyChecksum(TEMP, ivLen, len, TEMP, ivLen + len);
 
-			// Let WKCKS = WK || CKS where || is concatenation.
-			byte[] WKCKS = new byte[keyToBeWrapped.Length + CKS.Length];
-
-			Array.Copy(keyToBeWrapped, 0, WKCKS, 0, keyToBeWrapped.Length);
-			Array.Copy(CKS, 0, WKCKS, keyToBeWrapped.Length, CKS.Length);
-
-			// Encrypt WKCKS in CBC mode using KEK as the key and IV as the
-			// initialization vector. Call the results TEMP1.
-			byte [] TEMP1 = new byte[WKCKS.Length];
-
-			Array.Copy(WKCKS, 0, TEMP1, 0, WKCKS.Length);
-
-			int noOfBlocks = WKCKS.Length / engine.GetBlockSize();
-			int extraBytes = WKCKS.Length % engine.GetBlockSize();
-
-			if (extraBytes != 0)
-			{
-				throw new InvalidOperationException("Not multiple of block length");
-			}
+            int blockSize = engine.GetBlockSize();
 
-			engine.Init(true, paramPlusIV);
+            // Encrypt WKCKS in CBC mode using KEK as the key and IV as the initialization vector.
+            {
+                engine.Init(true, paramPlusIV);
 
-			for (int i = 0; i < noOfBlocks; i++)
-			{
-				int currentBytePos = i * engine.GetBlockSize();
+				int pos = ivLen;
+				while (pos < TEMP.Length)
+				{
+					engine.ProcessBlock(TEMP, pos, TEMP, pos);
+					pos += blockSize;
+				}
 
-				engine.ProcessBlock(TEMP1, currentBytePos, TEMP1, currentBytePos);
+				if (pos != TEMP.Length)
+					throw new InvalidOperationException("Not multiple of block length");
 			}
 
-			// Left TEMP2 = IV || TEMP1.
-			byte[] TEMP2 = new byte[this.iv.Length + TEMP1.Length];
-
-			Array.Copy(this.iv, 0, TEMP2, 0, this.iv.Length);
-			Array.Copy(TEMP1, 0, TEMP2, this.iv.Length, TEMP1.Length);
-
-			// Reverse the order of the octets in TEMP2 and call the result TEMP3.
-			byte[] TEMP3 = new byte[TEMP2.Length];
-
-			for (int i = 0; i < TEMP2.Length; i++)
-			{
-				TEMP3[i] = TEMP2[TEMP2.Length - (i + 1)];
-			}
+			// Reverse the order of the octets in TEMP.
+			Array.Reverse(TEMP);
 
-			// Encrypt TEMP3 in CBC mode using the KEK and an initialization vector
+			// Encrypt TEMP in CBC mode using the KEK and an initialization vector
 			// of 0x 4a dd a2 2c 79 e8 21 05. The resulting cipher text is the desired
 			// result. It is 40 octets long if a 168 bit key is being wrapped.
-			ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
-
-			this.engine.Init(true, param2);
-
-			for (int i = 0; i < noOfBlocks + 1; i++)
 			{
-				int currentBytePos = i * engine.GetBlockSize();
+                engine.Init(true, new ParametersWithIV(this.parameters, IV2));
 
-				engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
-			}
+                int pos = 0;
+                while (pos < TEMP.Length)
+                {
+                    engine.ProcessBlock(TEMP, pos, TEMP, pos);
+                    pos += blockSize;
+                }
 
-			return TEMP3;
+                if (pos != TEMP.Length)
+                    throw new InvalidOperationException("Not multiple of block length");
+            }
+
+            return TEMP;
 		}
 
 		/**
@@ -212,28 +182,16 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @return
 		* @throws InvalidCipherTextException
 		*/
-        public virtual byte[] Unwrap(
-			byte[]	input,
-			int		inOff,
-			int		length)
+        public virtual byte[] Unwrap(byte[] input, int inOff, int length)
 		{
 			if (forWrapping)
-			{
 				throw new InvalidOperationException("Not set for unwrapping");
-			}
-
 			if (input == null)
-			{
 				throw new InvalidCipherTextException("Null pointer as ciphertext");
-			}
-
 			if (length % engine.GetBlockSize() != 0)
-			{
-				throw new InvalidCipherTextException("Ciphertext not multiple of "
-					+ engine.GetBlockSize());
-			}
+				throw new InvalidCipherTextException("Ciphertext not multiple of " + engine.GetBlockSize());
 
-			/*
+            /*
 			// Check if the length of the cipher text is reasonable given the key
 			// type. It must be 40 bytes for a 168 bit key and either 32, 40, or
 			// 48 bytes for a 128, 192, or 256 bit key. If the length is not supported
@@ -249,82 +207,64 @@ namespace Org.BouncyCastle.Crypto.Engines
 			}
 			*/
 
-			// Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
-			// and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP3.
-			ParametersWithIV param2 = new ParametersWithIV(this.parameters, IV2);
-
-			this.engine.Init(false, param2);
+            int blockSize = engine.GetBlockSize();
 
-			byte [] TEMP3 = new byte[length];
+			byte[] TEMP = new byte[length];
 
-			Array.Copy(input, inOff, TEMP3, 0, length);
+            // Decrypt the cipher text with TRIPLedeS in CBC mode using the KEK
+            // and an initialization vector (IV) of 0x4adda22c79e82105. Call the output TEMP.
+            {
+                engine.Init(false, new ParametersWithIV(this.parameters, IV2));
 
-			for (int i = 0; i < (TEMP3.Length / engine.GetBlockSize()); i++)
-			{
-				int currentBytePos = i * engine.GetBlockSize();
-
-				engine.ProcessBlock(TEMP3, currentBytePos, TEMP3, currentBytePos);
-			}
-
-			// Reverse the order of the octets in TEMP3 and call the result TEMP2.
-			byte[] TEMP2 = new byte[TEMP3.Length];
-
-			for (int i = 0; i < TEMP3.Length; i++)
-			{
-				TEMP2[i] = TEMP3[TEMP3.Length - (i + 1)];
-			}
-
-			// Decompose TEMP2 into IV, the first 8 octets, and TEMP1, the remaining octets.
-			this.iv = new byte[8];
-
-			byte[] TEMP1 = new byte[TEMP2.Length - 8];
-
-			Array.Copy(TEMP2, 0, this.iv, 0, 8);
-			Array.Copy(TEMP2, 8, TEMP1, 0, TEMP2.Length - 8);
+                int pos = 0;
+				while (pos < TEMP.Length)
+				{
+					engine.ProcessBlock(input, inOff + pos, TEMP, pos);
+					pos += blockSize;
+				}
 
-			// Decrypt TEMP1 using TRIPLedeS in CBC mode using the KEK and the IV
-			// found in the previous step. Call the result WKCKS.
-			this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
+                if (pos != TEMP.Length)
+                    throw new InvalidOperationException("Not multiple of block length");
+            }
 
-			this.engine.Init(false, this.paramPlusIV);
+            // Reverse the order of the octets in TEMP.
+            Array.Reverse(TEMP);
 
-			byte[] LCEKPADICV = new byte[TEMP1.Length];
+			// Decompose TEMP into IV, the first 8 octets, and LCEKPADICV, the remaining octets.
+			this.iv = Arrays.CopyOf(TEMP, 8);
 
-			Array.Copy(TEMP1, 0, LCEKPADICV, 0, TEMP1.Length);
+            // Decrypt LCEKPADICV using TRIPLedeS in CBC mode using the KEK and the IV
+            // found in the previous step. Call the result WKCKS.
+            this.paramPlusIV = new ParametersWithIV(this.parameters, this.iv);
 
-			for (int i = 0; i < (LCEKPADICV.Length / engine.GetBlockSize()); i++)
 			{
-				int currentBytePos = i * engine.GetBlockSize();
+				this.engine.Init(false, this.paramPlusIV);
 
-				engine.ProcessBlock(LCEKPADICV, currentBytePos, LCEKPADICV, currentBytePos);
-			}
+				int pos = 8;
+				while (pos < TEMP.Length)
+				{
+					engine.ProcessBlock(TEMP, pos, TEMP, pos);
+					pos += blockSize;
+				}
 
-			// Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are
-			// those octets before the CKS.
-			byte[] result = new byte[LCEKPADICV.Length - 8];
-			byte[] CKStoBeVerified = new byte[8];
+                if (pos != TEMP.Length)
+                    throw new InvalidOperationException("Not multiple of block length");
+            }
 
-			Array.Copy(LCEKPADICV, 0, result, 0, LCEKPADICV.Length - 8);
-			Array.Copy(LCEKPADICV, LCEKPADICV.Length - 8, CKStoBeVerified, 0, 8);
+            // Decompose LCEKPADICV. CKS is the last 8 octets and WK, the wrapped key, are
+            // those octets before the CKS.
 
-			// Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
-			// with the CKS extracted in the above step. If they are not equal, return error.
-			if (!CheckCmsKeyChecksum(result, CKStoBeVerified))
-			{
-				throw new InvalidCipherTextException(
-					"Checksum inside ciphertext is corrupted");
-			}
+            // Calculate a CMS Key Checksum, (section 5.6.1), over the WK and compare
+            // with the CKS extracted in the above step. If they are not equal, return error.
+            if (!CheckCmsKeyChecksum(TEMP, 8, TEMP.Length - 16, TEMP, TEMP.Length - 8))
+				throw new InvalidCipherTextException("Checksum inside ciphertext is corrupted");
 
-			if ((result.Length - ((result[0] & 0xff) + 1)) > 7)
-			{
-				throw new InvalidCipherTextException(
-					"too many pad bytes (" + (result.Length - ((result[0] & 0xff) + 1)) + ")");
-			}
+			int padLen = TEMP.Length - 16 - TEMP[8] - 1;
+            if ((padLen & 7) != padLen)
+				throw new InvalidCipherTextException("Invalid padding length (" + padLen + ")");
 
 			// CEK is the wrapped key, now extracted for use in data decryption.
-			byte[] CEK = new byte[result[0]];
-			Array.Copy(result, 1, CEK, 0, CEK.Length);
-			return CEK;
+			return Arrays.CopyOfRange(TEMP, 9, 9 + TEMP[8]);
 		}
 
 		/**
@@ -340,15 +280,12 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @throws Exception
 		* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
 		*/
-		private byte[] CalculateCmsKeyChecksum(
-			byte[] key)
+		private void CalculateCmsKeyChecksum(byte[] key, int keyOff, int keyLen, byte[] cks, int cksOff)
 		{
-			sha1.BlockUpdate(key, 0, key.Length);
+			sha1.BlockUpdate(key, keyOff, keyLen);
 			sha1.DoFinal(digest, 0);
 
-			byte[] result = new byte[8];
-			Array.Copy(digest, 0, result, 0, 8);
-			return result;
+			Array.Copy(digest, 0, cks, cksOff, 8);
 		}
 
 		/**
@@ -357,11 +294,12 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @return
 		* @see http://www.w3.org/TR/xmlenc-core/#sec-CMSKeyChecksum
 		*/
-		private bool CheckCmsKeyChecksum(
-			byte[]	key,
-			byte[]	checksum)
+		private bool CheckCmsKeyChecksum(byte[] key, int keyOff, int keyLen, byte[] cks, int cksOff)
 		{
-			return Arrays.FixedTimeEquals(CalculateCmsKeyChecksum(key), checksum);
+            sha1.BlockUpdate(key, keyOff, keyLen);
+            sha1.DoFinal(digest, 0);
+
+            return Arrays.FixedTimeEquals(8, digest, 0, cks, cksOff);
 		}
 	}
 }
diff --git a/crypto/src/crypto/engines/RFC3211WrapEngine.cs b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
index 42027cf25..86bd08f8f 100644
--- a/crypto/src/crypto/engines/RFC3211WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
@@ -30,17 +30,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 			if (param is ParametersWithRandom withRandom)
 			{
-                this.rand = withRandom.Random;
                 this.param = withRandom.Parameters as ParametersWithIV;
-			}
-			else
+                this.rand = withRandom.Random;
+            }
+            else
 			{
-				if (forWrapping)
-				{
-					rand = CryptoServicesRegistrar.GetSecureRandom();
-				}
-
                 this.param = param as ParametersWithIV;
+				this.rand = forWrapping ? CryptoServicesRegistrar.GetSecureRandom() : null;
             }
 
             if (null == this.param)
diff --git a/crypto/src/crypto/engines/RFC3394WrapEngine.cs b/crypto/src/crypto/engines/RFC3394WrapEngine.cs
index 9744130d2..e1368f25b 100644
--- a/crypto/src/crypto/engines/RFC3394WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3394WrapEngine.cs
@@ -34,31 +34,28 @@ namespace Org.BouncyCastle.Crypto.Engines
             this.wrapCipherMode = !useReverseDirection;
         }
 
-        public virtual void Init(
-			bool				forWrapping,
-			ICipherParameters	parameters)
+        public virtual void Init(bool forWrapping, ICipherParameters parameters)
 		{
 			this.forWrapping = forWrapping;
 
-			if (parameters is ParametersWithRandom)
+			if (parameters is ParametersWithRandom withRandom)
 			{
-				parameters = ((ParametersWithRandom) parameters).Parameters;
+				parameters = withRandom.Parameters;
 			}
 
-			if (parameters is KeyParameter)
+			if (parameters is KeyParameter keyParameter)
 			{
-				this.param = (KeyParameter) parameters;
+				this.param = keyParameter;
 			}
-			else if (parameters is ParametersWithIV)
+			else if (parameters is ParametersWithIV withIV)
 			{
-				ParametersWithIV pIV = (ParametersWithIV) parameters;
-				byte[] iv = pIV.GetIV();
+				byte[] iv = withIV.GetIV();
 
 				if (iv.Length != 8)
 					throw new ArgumentException("IV length not equal to 8", "parameters");
 
 				this.iv = iv;
-				this.param = (KeyParameter) pIV.Parameters;
+				this.param = (KeyParameter)withIV.Parameters;
 			}
 			else
 			{
diff --git a/crypto/src/crypto/engines/RSABlindingEngine.cs b/crypto/src/crypto/engines/RSABlindingEngine.cs
index 11bb8d9d9..13b364582 100644
--- a/crypto/src/crypto/engines/RSABlindingEngine.cs
+++ b/crypto/src/crypto/engines/RSABlindingEngine.cs
@@ -49,10 +49,8 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			RsaBlindingParameters p;
 
-			if (param is ParametersWithRandom)
+			if (param is ParametersWithRandom rParam)
 			{
-				ParametersWithRandom rParam = (ParametersWithRandom)param;
-
 				p = (RsaBlindingParameters)rParam.Parameters;
 			}
 			else
diff --git a/crypto/src/crypto/engines/RSACoreEngine.cs b/crypto/src/crypto/engines/RSACoreEngine.cs
index bd3d62f7c..ffa448b3d 100644
--- a/crypto/src/crypto/engines/RSACoreEngine.cs
+++ b/crypto/src/crypto/engines/RSACoreEngine.cs
@@ -33,15 +33,15 @@ namespace Org.BouncyCastle.Crypto.Engines
 			bool				forEncryption,
 			ICipherParameters	parameters)
 		{
-			if (parameters is ParametersWithRandom)
+			if (parameters is ParametersWithRandom withRandom)
 			{
-				parameters = ((ParametersWithRandom) parameters).Parameters;
+				parameters = withRandom.Parameters;
 			}
 
-			if (!(parameters is RsaKeyParameters))
+			if (!(parameters is RsaKeyParameters rsaKeyParameters))
 				throw new InvalidKeyException("Not an RSA key");
 
-			this.key = (RsaKeyParameters) parameters;
+			this.key = rsaKeyParameters;
 			this.forEncryption = forEncryption;
 			this.bitSize = key.Modulus.BitLength;
 		}
@@ -118,39 +118,30 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
             CheckInitialised();
 
-            if (key is RsaPrivateCrtKeyParameters)
+            if (key is RsaPrivateCrtKeyParameters crt)
 			{
 				//
 				// we have the extra factors, use the Chinese Remainder Theorem - the author
 				// wishes to express his thanks to Dirk Bonekaemper at rtsffm.com for
 				// advice regarding the expression of this.
 				//
-				RsaPrivateCrtKeyParameters crtKey = (RsaPrivateCrtKeyParameters)key;
-
-				BigInteger p = crtKey.P;
-				BigInteger q = crtKey.Q;
-				BigInteger dP = crtKey.DP;
-				BigInteger dQ = crtKey.DQ;
-				BigInteger qInv = crtKey.QInv;
-
-				BigInteger mP, mQ, h, m;
+				BigInteger p = crt.P;
+				BigInteger q = crt.Q;
+				BigInteger dP = crt.DP;
+				BigInteger dQ = crt.DQ;
+				BigInteger qInv = crt.QInv;
 
 				// mP = ((input Mod p) ^ dP)) Mod p
-				mP = (input.Remainder(p)).ModPow(dP, p);
+				BigInteger mP = (input.Remainder(p)).ModPow(dP, p);
 
-				// mQ = ((input Mod q) ^ dQ)) Mod q
-				mQ = (input.Remainder(q)).ModPow(dQ, q);
+                // mQ = ((input Mod q) ^ dQ)) Mod q
+                BigInteger mQ = (input.Remainder(q)).ModPow(dQ, q);
 
 				// h = qInv * (mP - mQ) Mod p
-				h = mP.Subtract(mQ);
-				h = h.Multiply(qInv);
-				h = h.Mod(p);               // Mod (in Java) returns the positive residual
-
-				// m = h * q + mQ
-				m = h.Multiply(q);
-				m = m.Add(mQ);
+				BigInteger h = mP.Subtract(mQ).Multiply(qInv).Mod(p);
 
-				return m;
+                // m = h * q + mQ
+                return h.Multiply(q).Add(mQ);
 			}
 
 			return input.ModPow(key.Exponent, key.Modulus);
diff --git a/crypto/src/crypto/engines/SM2Engine.cs b/crypto/src/crypto/engines/SM2Engine.cs
index e0734d424..96bad4eb2 100644
--- a/crypto/src/crypto/engines/SM2Engine.cs
+++ b/crypto/src/crypto/engines/SM2Engine.cs
@@ -55,23 +55,27 @@ namespace Org.BouncyCastle.Crypto.Engines
         {
             this.mForEncryption = forEncryption;
 
-            if (forEncryption)
+            SecureRandom random = null;
+            if (param is ParametersWithRandom withRandom)
             {
-                ParametersWithRandom rParam = (ParametersWithRandom)param;
+                param = withRandom.Parameters;
+                random = withRandom.Random;
+            }
+
+            mECKey = (ECKeyParameters)param;
+            mECParams = mECKey.Parameters;
 
-                mECKey = (ECKeyParameters)rParam.Parameters;
-                mECParams = mECKey.Parameters;
+            if (forEncryption)
+            {
+                mRandom = CryptoServicesRegistrar.GetSecureRandom(random);
 
                 ECPoint s = ((ECPublicKeyParameters)mECKey).Q.Multiply(mECParams.H);
                 if (s.IsInfinity)
                     throw new ArgumentException("invalid key: [h]Q at infinity");
-
-                mRandom = rParam.Random;
             }
             else
             {
-                mECKey = (ECKeyParameters)param;
-                mECParams = mECKey.Parameters;
+                mRandom = null;
             }
 
             mCurveLength = (mECParams.Curve.FieldSize + 7) / 8;
diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs
index 7c2c1e1f9..2e8f8e50a 100644
--- a/crypto/src/crypto/engines/Salsa20Engine.cs
+++ b/crypto/src/crypto/engines/Salsa20Engine.cs
@@ -27,7 +27,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         private readonly static uint[] TAU_SIGMA = Pack.LE_To_UInt32(Strings.ToAsciiByteArray("expand 16-byte k" + "expand 32-byte k"), 0, 8);
 
-        internal void PackTauOrSigma(int keyLength, uint[] state, int stateOffset)
+        internal static void PackTauOrSigma(int keyLength, uint[] state, int stateOffset)
         {
             int tsOff = (keyLength - 16) / 4;
             state[stateOffset] = TAU_SIGMA[tsOff];
diff --git a/crypto/src/crypto/engines/XoodyakEngine.cs b/crypto/src/crypto/engines/XoodyakEngine.cs
new file mode 100644
index 000000000..fb4f074ee
--- /dev/null
+++ b/crypto/src/crypto/engines/XoodyakEngine.cs
@@ -0,0 +1,450 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Utilities;
+/**
+* Xoodyak v1, https://csrc.nist.gov/CSRC/media/Projects/lightweight-cryptography/documents/finalist-round/updated-spec-doc/xoodyak-spec-final.pdf
+* <p>
+* Xoodyak with reference to C Reference Impl from: https://github.com/XKCP/XKCP
+* </p>
+*/
+namespace Org.BouncyCastle.Crypto.Engines
+{
+    public sealed class XoodyakEngine : IAeadBlockCipher
+    {
+        private bool forEncryption;
+        private byte[] state;
+        private int phase;
+        private MODE mode;
+        private int Rabsorb;
+        private const int f_bPrime = 48;
+        private const int Rkout = 24;
+        private byte[] K;
+        private byte[] iv;
+        private const int PhaseDown = 1;
+        private const int PhaseUp = 2;
+        private const int NLANES = 12;
+        private const int NROWS = 3;
+        private const int NCOLUMS = 4;
+        private const int MAXROUNDS = 12;
+        private const int TAGLEN = 16;
+        const int Rkin = 44;
+        private byte[] tag;
+        private readonly uint[] RC = {0x00000058, 0x00000038, 0x000003C0, 0x000000D0, 0x00000120, 0x00000014, 0x00000060,
+        0x0000002C, 0x00000380, 0x000000F0, 0x000001A0, 0x00000012};
+        private bool aadFinished;
+        private bool encrypted;
+        private bool initialised = false;
+        public string AlgorithmName => "Xoodak AEAD";
+
+        public IBlockCipher UnderlyingCipher => throw new NotImplementedException();
+
+        private MemoryStream aadData = new MemoryStream();
+        private MemoryStream message = new MemoryStream();
+
+        enum MODE
+        {
+            ModeHash,
+            ModeKeyed
+        }
+
+        public void Init(bool forEncryption, ICipherParameters param)
+        {
+            this.forEncryption = forEncryption;
+            if (!(param is ParametersWithIV))
+            {
+                throw new ArgumentException("Xoodyak init parameters must include an IV");
+            }
+            ParametersWithIV ivParams = (ParametersWithIV)param;
+            iv = ivParams.GetIV();
+            if (iv == null || iv.Length != 16)
+            {
+                throw new ArgumentException("Xoodyak requires exactly 16 bytes of IV");
+            }
+            if (!(ivParams.Parameters is KeyParameter))
+            {
+                throw new ArgumentException("Xoodyak init parameters must include a key");
+            }
+            KeyParameter key = (KeyParameter)ivParams.Parameters;
+            K = key.GetKey();
+            if (K.Length != 16)
+            {
+                throw new ArgumentException("Xoodyak key must be 128 bits long");
+            }
+            state = new byte[48];
+            tag = new byte[TAGLEN];
+            initialised = true;
+            reset(false);
+        }
+
+        public void ProcessAadByte(byte input)
+        {
+            if (aadFinished)
+            {
+                throw new ArgumentException("AAD cannot be added after reading a full block(" + GetBlockSize() +
+                    " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+            }
+            aadData.Write(new byte[] { input }, 0, 1);
+        }
+
+
+        public void ProcessAadBytes(byte[] input, int inOff, int len)
+        {
+            if (aadFinished)
+            {
+                throw new ArgumentException("AAD cannot be added after reading a full block(" + GetBlockSize() +
+                    " bytes) of input for " + (forEncryption ? "encryption" : "decryption"));
+            }
+            if ((inOff + len) > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            aadData.Write(input, inOff, len);
+        }
+
+
+        public int ProcessByte(byte input, byte[] output, int outOff)
+        {
+            return ProcessBytes(new byte[] { input }, 0, 1, output, outOff);
+        }
+
+        private void processAAD()
+        {
+            if (!aadFinished)
+            {
+                byte[] ad = aadData.GetBuffer();
+                AbsorbAny(ad, 0, (int)aadData.Length, Rabsorb, 0x03);
+                aadFinished = true;
+            }
+        }
+
+        public int ProcessBytes(byte[] input, int inOff, int len, byte[] output, int outOff)
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            if (mode != MODE.ModeKeyed)
+            {
+                throw new ArgumentException("Xoodyak has not been initialised");
+            }
+            if (inOff + len > input.Length)
+            {
+                throw new DataLengthException("input buffer too short");
+            }
+            message.Write(input, inOff, len);
+            int blockLen = (int)message.Length - (forEncryption ? 0 : TAGLEN);
+            if (blockLen >= GetBlockSize())
+            {
+                byte[] blocks = message.GetBuffer();
+                len = blockLen / GetBlockSize() * GetBlockSize();
+                if (len + outOff > output.Length)
+                {
+                    throw new OutputLengthException("output buffer is too short");
+                }
+                processAAD();
+                encrypt(blocks, 0, len, output, outOff);
+                int messageLen = (int)message.Length;
+                message.SetLength(0);
+                message.Write(blocks, len, messageLen - len);
+                return len;
+            }
+            return 0;
+        }
+
+        private int encrypt(byte[] input, int inOff, int len, byte[] output, int outOff)
+        {
+            int IOLen = len;
+            int splitLen;
+            byte[] P = new byte[Rkout];
+            uint Cu = encrypted ? 0u : 0x80u;
+            while (IOLen != 0 || !encrypted)
+            {
+                splitLen = System.Math.Min(IOLen, Rkout); /* use Rkout instead of Rsqueeze, this function is only called in keyed mode */
+                if (forEncryption)
+                {
+                    Array.Copy(input, inOff, P, 0, splitLen);
+                }
+                Up(null, 0, Cu); /* Up without extract */
+                /* Extract from Up and Add */
+                for (int i = 0; i < splitLen; i++)
+                {
+                    output[outOff + i] = (byte)(input[inOff++] ^ state[i]);
+                }
+                if (forEncryption)
+                {
+                    Down(P, 0, splitLen, 0x00);
+                }
+                else
+                {
+                    Down(output, outOff, splitLen, 0x00);
+                }
+                Cu = 0x00;
+                outOff += splitLen;
+                IOLen -= splitLen;
+                encrypted = true;
+            }
+            return len;
+        }
+
+
+        public int DoFinal(byte[] output, int outOff)
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+
+            byte[] blocks = message.GetBuffer();
+            int len = (int)message.Length;
+            if ((forEncryption && len + TAGLEN + outOff > output.Length) ||
+                (!forEncryption && len - TAGLEN + outOff > output.Length))
+            {
+                throw new OutputLengthException("output buffer too short");
+            }
+            processAAD();
+            int rv = 0;
+            if (forEncryption)
+            {
+                encrypt(blocks, 0, len, output, outOff);
+                outOff += len;
+                tag = new byte[TAGLEN];
+                Up(tag, TAGLEN, 0x40);
+                Array.Copy(tag, 0, output, outOff, TAGLEN);
+                rv = len + TAGLEN;
+            }
+            else
+            {
+                int inOff = len - TAGLEN;
+                rv = inOff;
+                encrypt(blocks, 0, inOff, output, outOff);
+                tag = new byte[TAGLEN];
+                Up(tag, TAGLEN, 0x40);
+                for (int i = 0; i < TAGLEN; ++i)
+                {
+                    if (tag[i] != blocks[inOff++])
+                    {
+                        throw new ArgumentException("Mac does not match");
+                    }
+                }
+            }
+            reset(false);
+            return rv;
+        }
+
+
+        public byte[] GetMac()
+        {
+            return tag;
+        }
+
+
+        public int GetUpdateOutputSize(int len)
+        {
+            return len;
+        }
+
+
+        public int GetOutputSize(int len)
+        {
+            return len + TAGLEN;
+        }
+
+
+        public void Reset()
+        {
+            if (!initialised)
+            {
+                throw new ArgumentException("Need call init function before encryption/decryption");
+            }
+            reset(true);
+        }
+
+        private void reset(bool clearMac)
+        {
+            if (clearMac)
+            {
+                tag = null;
+            }
+            Arrays.Fill(state, (byte)0);
+            aadFinished = false;
+            encrypted = false;
+            phase = PhaseUp;
+            message.SetLength(0);
+            aadData.SetLength(0);
+            //Absorb key
+            int KLen = K.Length;
+            int IDLen = iv.Length;
+            byte[] KID = new byte[Rkin];
+            mode = MODE.ModeKeyed;
+            Rabsorb = Rkin;
+            Array.Copy(K, 0, KID, 0, KLen);
+            Array.Copy(iv, 0, KID, KLen, IDLen);
+            KID[KLen + IDLen] = (byte)IDLen;
+            AbsorbAny(KID, 0, KLen + IDLen + 1, Rabsorb, 0x02);
+        }
+
+        private void AbsorbAny(byte[] X, int Xoff, int XLen, int r, uint Cd)
+        {
+            int splitLen;
+            do
+            {
+                if (phase != PhaseUp)
+                {
+                    Up(null, 0, 0);
+                }
+                splitLen = System.Math.Min(XLen, r);
+                Down(X, Xoff, splitLen, Cd);
+                Cd = 0;
+                Xoff += splitLen;
+                XLen -= splitLen;
+            }
+            while (XLen != 0);
+        }
+
+        private void Up(byte[] Yi, int YiLen, uint Cu)
+        {
+            if (mode != MODE.ModeHash)
+            {
+                state[f_bPrime - 1] ^= (byte)Cu;
+            }
+            uint[] a = new uint[NLANES];
+            Pack.LE_To_UInt32(state, 0, a, 0, a.Length);
+            uint x, y;
+            uint[] b = new uint[NLANES];
+            uint[] p = new uint[NCOLUMS];
+            uint[] e = new uint[NCOLUMS];
+            for (int i = 0; i < MAXROUNDS; ++i)
+            {
+                /* Theta: Column Parity Mixer */
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    p[x] = a[index(x, 0)] ^ a[index(x, 1)] ^ a[index(x, 2)];
+                }
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    y = p[(x + 3) & 3];
+                    e[x] = ROTL32(y, 5) ^ ROTL32(y, 14);
+                }
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    for (y = 0; y < NROWS; ++y)
+                    {
+                        a[index(x, y)] ^= e[x];
+                    }
+                }
+                /* Rho-west: plane shift */
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    b[index(x, 0)] = a[index(x, 0)];
+                    b[index(x, 1)] = a[index(x + 3, 1)];
+                    b[index(x, 2)] = ROTL32(a[index(x, 2)], 11);
+                }
+                /* Iota: round ant */
+                b[0] ^= RC[i];
+                /* Chi: non linear layer */
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    for (y = 0; y < NROWS; ++y)
+                    {
+                        a[index(x, y)] = b[index(x, y)] ^ (~b[index(x, y + 1)] & b[index(x, y + 2)]);
+                    }
+                }
+                /* Rho-east: plane shift */
+                for (x = 0; x < NCOLUMS; ++x)
+                {
+                    b[index(x, 0)] = a[index(x, 0)];
+                    b[index(x, 1)] = ROTL32(a[index(x, 1)], 1);
+                    b[index(x, 2)] = ROTL32(a[index(x + 2, 2)], 8);
+                }
+                Array.Copy(b, 0, a, 0, NLANES);
+            }
+            Pack.UInt32_To_LE(a, 0, a.Length, state, 0);
+            phase = PhaseUp;
+            if (Yi != null)
+            {
+                Array.Copy(state, 0, Yi, 0, YiLen);
+            }
+        }
+
+        void Down(byte[] Xi, int XiOff, int XiLen, uint Cd)
+        {
+            for (int i = 0; i < XiLen; i++)
+            {
+                state[i] ^= Xi[XiOff++];
+            }
+            state[XiLen] ^= 0x01;
+            state[f_bPrime - 1] ^= (byte)((mode == MODE.ModeHash) ? (Cd & 0x01) : Cd);
+            phase = PhaseDown;
+        }
+
+        private uint index(uint x, uint y)
+        {
+            return (((y % NROWS) * NCOLUMS) + ((x) % NCOLUMS));
+        }
+
+        private uint ROTL32(uint a, int offset)
+        {
+            return (a << (offset & 31)) ^ (a >> ((32 - (offset)) & 31));
+        }
+
+        public int GetBlockSize()
+        {
+            return Rkout;
+        }
+
+        public int GetKeyBytesSize()
+        {
+            return 16;
+        }
+
+        public int GetIVBytesSize()
+        {
+            return 16;
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public void ProcessAadBytes(ReadOnlySpan<byte> input)
+        {
+            aadData.Write(input);
+        }
+
+        public int ProcessByte(byte input, Span<byte> output)
+        {
+            byte[] rv = new byte[1];
+            int len = ProcessBytes(new byte[] { input }, 0, 1, rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return len;
+        }
+
+        public int ProcessBytes(ReadOnlySpan<byte> input, Span<byte> output)
+        {
+            byte[] rv = new byte[input.Length];
+            int len = ProcessBytes(input.ToArray(), 0, rv.Length, rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return len;
+        }
+
+        public int DoFinal(Span<byte> output)
+        {
+            byte[] rv;
+            if (forEncryption)
+            {
+                rv = new byte[message.Length + 16];
+            }
+            else
+            {
+                rv = new byte[message.Length - 16];
+            }
+            int len = DoFinal(rv, 0);
+            rv.AsSpan(0, len).CopyTo(output);
+            return rv.Length;
+        }
+
+#endif
+
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/crypto/generators/ECKeyPairGenerator.cs b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
index 6aba6921e..9ef5cdefd 100644
--- a/crypto/src/crypto/generators/ECKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -50,26 +50,26 @@ namespace Org.BouncyCastle.Crypto.Generators
                 DerObjectIdentifier oid;
                 switch (parameters.Strength)
                 {
-                    case 192:
-                        oid = X9ObjectIdentifiers.Prime192v1;
-                        break;
-                    case 224:
-                        oid = SecObjectIdentifiers.SecP224r1;
-                        break;
-                    case 239:
-                        oid = X9ObjectIdentifiers.Prime239v1;
-                        break;
-                    case 256:
-                        oid = X9ObjectIdentifiers.Prime256v1;
-                        break;
-                    case 384:
-                        oid = SecObjectIdentifiers.SecP384r1;
-                        break;
-                    case 521:
-                        oid = SecObjectIdentifiers.SecP521r1;
-                        break;
-                    default:
-                        throw new InvalidParameterException("unknown key size.");
+                case 192:
+                    oid = X9ObjectIdentifiers.Prime192v1;
+                    break;
+                case 224:
+                    oid = SecObjectIdentifiers.SecP224r1;
+                    break;
+                case 239:
+                    oid = X9ObjectIdentifiers.Prime239v1;
+                    break;
+                case 256:
+                    oid = X9ObjectIdentifiers.Prime256v1;
+                    break;
+                case 384:
+                    oid = SecObjectIdentifiers.SecP384r1;
+                    break;
+                case 521:
+                    oid = SecObjectIdentifiers.SecP521r1;
+                    break;
+                default:
+                    throw new InvalidParameterException("unknown key size.");
                 }
 
                 X9ECParameters ecps = FindECCurveByOid(oid);
@@ -131,42 +131,22 @@ namespace Org.BouncyCastle.Crypto.Generators
 
         internal static X9ECParameters FindECCurveByName(string name)
         {
-            X9ECParameters ecP = CustomNamedCurves.GetByName(name);
-            if (ecP == null)
-            {
-                ecP = ECNamedCurveTable.GetByName(name);
-            }
-            return ecP;
+            return CustomNamedCurves.GetByName(name) ?? ECNamedCurveTable.GetByName(name);
         }
 
         internal static X9ECParametersHolder FindECCurveByNameLazy(string name)
         {
-            X9ECParametersHolder holder = CustomNamedCurves.GetByNameLazy(name);
-            if (holder == null)
-            {
-                holder = ECNamedCurveTable.GetByNameLazy(name);
-            }
-            return holder;
+            return CustomNamedCurves.GetByNameLazy(name) ?? ECNamedCurveTable.GetByNameLazy(name);
         }
 
         internal static X9ECParameters FindECCurveByOid(DerObjectIdentifier oid)
         {
-            X9ECParameters ecP = CustomNamedCurves.GetByOid(oid);
-            if (ecP == null)
-            {
-                ecP = ECNamedCurveTable.GetByOid(oid);
-            }
-            return ecP;
+            return CustomNamedCurves.GetByOid(oid) ?? ECNamedCurveTable.GetByOid(oid);
         }
 
         internal static X9ECParametersHolder FindECCurveByOidLazy(DerObjectIdentifier oid)
         {
-            X9ECParametersHolder holder = CustomNamedCurves.GetByOidLazy(oid);
-            if (holder == null)
-            {
-                holder = ECNamedCurveTable.GetByOidLazy(oid);
-            }
-            return holder;
+            return CustomNamedCurves.GetByOidLazy(oid) ?? ECNamedCurveTable.GetByOidLazy(oid);
         }
 
         internal static ECPublicKeyParameters GetCorrespondingPublicKey(
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
index d02216309..adf4975ba 100644
--- a/crypto/src/crypto/macs/Poly1305.cs
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -4,6 +4,7 @@ using System.Diagnostics;
 using System.Runtime.CompilerServices;
 #endif
 
+using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
 
@@ -22,7 +23,7 @@ namespace Org.BouncyCastle.Crypto.Macs
     /// href="https://github.com/floodyberry/poly1305-donna">poly1305-donna-unrolled</a> C implementation
     /// by Andrew M (@floodyberry).
     /// </remarks>
-    /// <seealso cref="Org.BouncyCastle.Crypto.Generators.Poly1305KeyGenerator"/>
+    /// <seealso cref="Poly1305KeyGenerator"/>
     public class Poly1305
         : IMac
     {
diff --git a/crypto/src/crypto/modes/CfbBlockCipher.cs b/crypto/src/crypto/modes/CfbBlockCipher.cs
index 7bce9843f..cdb17dd3c 100644
--- a/crypto/src/crypto/modes/CfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/CfbBlockCipher.cs
@@ -61,9 +61,8 @@ namespace Org.BouncyCastle.Crypto.Modes
             ICipherParameters parameters)
         {
             this.encrypting = forEncryption;
-            if (parameters is ParametersWithIV)
+            if (parameters is ParametersWithIV ivParam)
             {
-                ParametersWithIV ivParam = (ParametersWithIV) parameters;
                 byte[] iv = ivParam.GetIV();
                 int diff = IV.Length - iv.Length;
                 Array.Copy(iv, 0, IV, diff, iv.Length);
diff --git a/crypto/src/crypto/modes/EcbBlockCipher.cs b/crypto/src/crypto/modes/EcbBlockCipher.cs
index 96f9811dd..b41452622 100644
--- a/crypto/src/crypto/modes/EcbBlockCipher.cs
+++ b/crypto/src/crypto/modes/EcbBlockCipher.cs
@@ -17,10 +17,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public EcbBlockCipher(IBlockCipher cipher)
         {
-            if (cipher == null)
-                throw new ArgumentNullException(nameof(cipher));
-
-            m_cipher = cipher;
+            m_cipher = cipher ?? throw new ArgumentNullException(nameof(cipher));
         }
 
         public bool IsPartialBlockOkay => false;
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index f75235cf2..aed9ef311 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -108,30 +108,24 @@ namespace Org.BouncyCastle.Crypto.Modes
             KeyParameter keyParam;
             byte[] newNonce;
 
-            if (parameters is AeadParameters)
+            if (parameters is AeadParameters aeadParameters)
             {
-                AeadParameters param = (AeadParameters)parameters;
+                newNonce = aeadParameters.GetNonce();
+                initialAssociatedText = aeadParameters.GetAssociatedText();
 
-                newNonce = param.GetNonce();
-                initialAssociatedText = param.GetAssociatedText();
-
-                int macSizeBits = param.MacSize;
+                int macSizeBits = aeadParameters.MacSize;
                 if (macSizeBits < 32 || macSizeBits > 128 || macSizeBits % 8 != 0)
-                {
                     throw new ArgumentException("Invalid value for MAC size: " + macSizeBits);
-                }
 
                 macSize = macSizeBits / 8; 
-                keyParam = param.Key;
+                keyParam = aeadParameters.Key;
             }
-            else if (parameters is ParametersWithIV)
+            else if (parameters is ParametersWithIV withIV)
             {
-                ParametersWithIV param = (ParametersWithIV)parameters;
-
-                newNonce = param.GetIV();
+                newNonce = withIV.GetIV();
                 initialAssociatedText = null;
                 macSize = 16; 
-                keyParam = (KeyParameter)param.Parameters;
+                keyParam = (KeyParameter)withIV.Parameters;
             }
             else
             {
@@ -142,22 +136,17 @@ namespace Org.BouncyCastle.Crypto.Modes
             this.bufBlock = new byte[bufLength];
 
             if (newNonce == null || newNonce.Length < 1)
-            {
                 throw new ArgumentException("IV must be at least 1 byte");
-            }
 
             if (forEncryption)
             {
                 if (nonce != null && Arrays.AreEqual(nonce, newNonce))
                 {
                     if (keyParam == null)
-                    {
                         throw new ArgumentException("cannot reuse nonce for GCM encryption");
-                    }
+
                     if (lastKey != null && Arrays.AreEqual(lastKey, keyParam.GetKey()))
-                    {
                         throw new ArgumentException("cannot reuse nonce for GCM encryption");
-                    }
                 }
             }
 
@@ -223,9 +212,7 @@ namespace Org.BouncyCastle.Crypto.Modes
 
         public byte[] GetMac()
         {
-            return macBlock == null
-                ?   new byte[macSize]
-                :   Arrays.Clone(macBlock);
+            return macBlock == null ? new byte[macSize] : (byte[])macBlock.Clone();
         }
 
         public int GetOutputSize(int len)
@@ -233,9 +220,7 @@ namespace Org.BouncyCastle.Crypto.Modes
             int totalData = len + bufOff;
 
             if (forEncryption)
-            {
                 return totalData + macSize;
-            }
 
             return totalData < macSize ? 0 : totalData - macSize;
         }
@@ -246,9 +231,8 @@ namespace Org.BouncyCastle.Crypto.Modes
             if (!forEncryption)
             {
                 if (totalData < macSize)
-                {
                     return 0;
-                }
+
                 totalData -= macSize;
             }
             return totalData - totalData % BlockSize;
@@ -1490,9 +1474,8 @@ namespace Org.BouncyCastle.Crypto.Modes
             if (!initialised)
             {
                 if (forEncryption)
-                {
                     throw new InvalidOperationException("GCM cipher cannot be reused for encryption");
-                }
+
                 throw new InvalidOperationException("GCM cipher needs to be initialised");
             }
         }
diff --git a/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs b/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
index 4e6e0ffaa..dff5af1c6 100644
--- a/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
+++ b/crypto/src/crypto/modes/OpenPgpCfbBlockCipher.cs
@@ -161,7 +161,6 @@ namespace Org.BouncyCastle.Crypto.Modes
             return (byte)(FRE[blockOff] ^ data);
         }
 
-
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         private int EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
         {
diff --git a/crypto/src/crypto/modes/SicBlockCipher.cs b/crypto/src/crypto/modes/SicBlockCipher.cs
index fee8bb028..ee204c18c 100644
--- a/crypto/src/crypto/modes/SicBlockCipher.cs
+++ b/crypto/src/crypto/modes/SicBlockCipher.cs
@@ -1,7 +1,6 @@
 using System;
 
 using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Math;
 
 using Org.BouncyCastle.Utilities;
 
@@ -45,8 +44,7 @@ namespace Org.BouncyCastle.Crypto.Modes
             bool				forEncryption, //ignored by this CTR mode
             ICipherParameters	parameters)
         {
-            ParametersWithIV ivParam = parameters as ParametersWithIV;
-            if (ivParam == null)
+            if (!(parameters is ParametersWithIV ivParam))
                 throw new ArgumentException("CTR/SIC mode requires ParametersWithIV", "parameters");
 
             this.IV = Arrays.Clone(ivParam.GetIV());
@@ -58,13 +56,13 @@ namespace Org.BouncyCastle.Crypto.Modes
             if (blockSize - IV.Length > maxCounterSize)
                 throw new ArgumentException("CTR/SIC mode requires IV of at least: " + (blockSize - maxCounterSize) + " bytes.");
 
+            Reset();
+
             // if null it's an IV changed only.
             if (ivParam.Parameters != null)
             {
                 cipher.Init(true, ivParam.Parameters);
             }
-
-            Reset();
         }
 
         public virtual string AlgorithmName
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index 97b34fb61..a239e9ec0 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -14,7 +14,7 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Modes.Gcm
 {
-    internal abstract class GcmUtilities
+    internal static class GcmUtilities
     {
         internal struct FieldElement
         {
@@ -177,13 +177,13 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             ulong z1 = Interleave.Expand64To128Rev(x.n0, out ulong z0);
             ulong z3 = Interleave.Expand64To128Rev(x.n1, out ulong z2);
 
-            Debug.Assert(z3 << 63 == 0);
+            Debug.Assert(z3 << 63 == 0UL);
 
             z1 ^= z3 ^ (z3 >>  1) ^ (z3 >>  2) ^ (z3 >>  7);
 //          z2 ^=      (z3 << 63) ^ (z3 << 62) ^ (z3 << 57);
             z2 ^=                   (z3 << 62) ^ (z3 << 57);
 
-            Debug.Assert(z2 << 63 == 0);
+            Debug.Assert(z2 << 63 == 0UL);
 
             z0 ^= z2 ^ (z2 >>  1) ^ (z2 >>  2) ^ (z2 >>  7);
 //          z1 ^=      (z2 << 63) ^ (z2 << 62) ^ (z2 << 57);
diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs
index ea8d28771..acbeb12e8 100644
--- a/crypto/src/crypto/operators/Asn1Signature.cs
+++ b/crypto/src/crypto/operators/Asn1Signature.cs
@@ -3,6 +3,7 @@ using System.Collections.Generic;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.EdEC;
 using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
@@ -97,6 +98,9 @@ namespace Org.BouncyCastle.Crypto.Operators
             m_algorithms.Add("GOST3411-2012-256WITHECGOST3410-2012-256", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256);
             m_algorithms.Add("GOST3411-2012-512WITHECGOST3410", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512);
             m_algorithms.Add("GOST3411-2012-512WITHECGOST3410-2012-512", RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512);
+            m_algorithms.Add("Ed25519", EdECObjectIdentifiers.id_Ed25519);
+            m_algorithms.Add("Ed448", EdECObjectIdentifiers.id_Ed448);
+            // TODO Ed25519ctx, Ed25519ph, Ed448ph
 
             //
             // According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
diff --git a/crypto/src/crypto/parameters/DHKeyParameters.cs b/crypto/src/crypto/parameters/DHKeyParameters.cs
index 1a5c1386f..8aabddd8b 100644
--- a/crypto/src/crypto/parameters/DHKeyParameters.cs
+++ b/crypto/src/crypto/parameters/DHKeyParameters.cs
@@ -57,7 +57,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
 		protected bool Equals(
 			DHKeyParameters other)
 		{
-			return Platform.Equals(parameters, other.parameters)
+			return Objects.Equals(parameters, other.parameters)
 				&& base.Equals(other);
 		}
 
diff --git a/crypto/src/crypto/parameters/DHParameters.cs b/crypto/src/crypto/parameters/DHParameters.cs
index bdea12432..a71678a88 100644
--- a/crypto/src/crypto/parameters/DHParameters.cs
+++ b/crypto/src/crypto/parameters/DHParameters.cs
@@ -167,7 +167,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
 		{
 			return p.Equals(other.p)
 				&& g.Equals(other.g)
-				&& Platform.Equals(q, other.q);
+				&& Objects.Equals(q, other.q);
 		}
 
 		public override int GetHashCode()
diff --git a/crypto/src/crypto/parameters/DsaKeyParameters.cs b/crypto/src/crypto/parameters/DsaKeyParameters.cs
index 5fe6d7ab4..4097144a5 100644
--- a/crypto/src/crypto/parameters/DsaKeyParameters.cs
+++ b/crypto/src/crypto/parameters/DsaKeyParameters.cs
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
 		protected bool Equals(
 			DsaKeyParameters other)
 		{
-			return Platform.Equals(parameters, other.parameters)
+			return Objects.Equals(parameters, other.parameters)
 				&& base.Equals(other);
 		}
 
diff --git a/crypto/src/crypto/parameters/ElGamalKeyParameters.cs b/crypto/src/crypto/parameters/ElGamalKeyParameters.cs
index 8b6e27957..146049aca 100644
--- a/crypto/src/crypto/parameters/ElGamalKeyParameters.cs
+++ b/crypto/src/crypto/parameters/ElGamalKeyParameters.cs
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
 		protected bool Equals(
 			ElGamalKeyParameters other)
 		{
-			return Platform.Equals(parameters, other.parameters)
+			return Objects.Equals(parameters, other.parameters)
 				&& base.Equals(other);
 		}
 
diff --git a/crypto/src/crypto/prng/BasicEntropySourceProvider.cs b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
index 5de1e4e5e..7a3e2b2b4 100644
--- a/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
+++ b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
@@ -71,7 +71,7 @@ namespace Org.BouncyCastle.Crypto.Prng
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
             int IEntropySource.GetEntropy(Span<byte> output)
             {
-                int length = (mEntropySize + 7) / 8;
+                int length = System.Math.Min(output.Length, (mEntropySize + 7) / 8);
                 mSecureRandom.NextBytes(output[..length]);
                 return length;
             }
diff --git a/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs b/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
index 9a2f6de2c..d20b5b22b 100644
--- a/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
+++ b/crypto/src/crypto/prng/CryptoApiEntropySourceProvider.cs
@@ -59,7 +59,7 @@ namespace Org.BouncyCastle.Crypto.Prng
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
             int IEntropySource.GetEntropy(Span<byte> output)
             {
-                int length = (mEntropySize + 7) / 8;
+                int length = System.Math.Min(output.Length, (mEntropySize + 7) / 8);
                 mRng.GetBytes(output[..length]);
                 return length;
             }
diff --git a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
index dcd3baa1c..bafb4fd5e 100644
--- a/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
+++ b/crypto/src/crypto/prng/CryptoApiRandomGenerator.cs
@@ -52,8 +52,8 @@ namespace Org.BouncyCastle.Crypto.Prng
             m_randomNumberGenerator.GetBytes(bytes, start, len);
 #else
             if (start < 0)
-                throw new ArgumentException("Start offset cannot be negative", "start");
-            if (bytes.Length < (start + len))
+                throw new ArgumentException("Start offset cannot be negative", nameof(start));
+            if (start > bytes.Length - len)
                 throw new ArgumentException("Byte array too small for requested offset and length");
 
             if (bytes.Length == len && start == 0) 
@@ -62,9 +62,9 @@ namespace Org.BouncyCastle.Crypto.Prng
             }
             else 
             {
-                byte[] tmpBuf = new byte[len];
-                NextBytes(tmpBuf);
-                Array.Copy(tmpBuf, 0, bytes, start, len);
+                byte[] tmp = new byte[len];
+                NextBytes(tmp);
+                tmp.CopyTo(bytes, start);
             }
 #endif
         }
diff --git a/crypto/src/crypto/prng/EntropyUtilities.cs b/crypto/src/crypto/prng/EntropyUtilities.cs
index 58c8703f4..156b46622 100644
--- a/crypto/src/crypto/prng/EntropyUtilities.cs
+++ b/crypto/src/crypto/prng/EntropyUtilities.cs
@@ -16,6 +16,10 @@ namespace Org.BouncyCastle.Crypto.Prng
         public static byte[] GenerateSeed(IEntropySource entropySource, int numBytes)
         {
             byte[] bytes = new byte[numBytes];
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            GenerateSeed(entropySource, bytes);
+#else
             int count = 0;
             while (count < numBytes)
             {
@@ -24,7 +28,20 @@ namespace Org.BouncyCastle.Crypto.Prng
                 Array.Copy(entropy, 0, bytes, count, toCopy);
                 count += toCopy;
             }
+#endif
+
             return bytes;
         }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void GenerateSeed(IEntropySource entropySource, Span<byte> seed)
+        {
+            while (!seed.IsEmpty)
+            {
+                int len = entropySource.GetEntropy(seed);
+                seed = seed[len..];
+            }
+        }
+#endif
     }
 }
diff --git a/crypto/src/crypto/prng/SP800SecureRandom.cs b/crypto/src/crypto/prng/SP800SecureRandom.cs
index a18576d03..4fbbc927f 100644
--- a/crypto/src/crypto/prng/SP800SecureRandom.cs
+++ b/crypto/src/crypto/prng/SP800SecureRandom.cs
@@ -113,6 +113,13 @@ namespace Org.BouncyCastle.Crypto.Prng
             return EntropyUtilities.GenerateSeed(mEntropySource, numBytes);
         }
 
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public override void GenerateSeed(Span<byte> seed)
+        {
+            EntropyUtilities.GenerateSeed(mEntropySource, seed);
+        }
+#endif
+
         /// <summary>Force a reseed of the DRBG.</summary>
         /// <param name="additionalInput">optional additional input</param>
         public virtual void Reseed(byte[] additionalInput)
diff --git a/crypto/src/crypto/prng/X931SecureRandom.cs b/crypto/src/crypto/prng/X931SecureRandom.cs
index d40134851..6c0114cb2 100644
--- a/crypto/src/crypto/prng/X931SecureRandom.cs
+++ b/crypto/src/crypto/prng/X931SecureRandom.cs
@@ -96,5 +96,12 @@ namespace Org.BouncyCastle.Crypto.Prng
         {
             return EntropyUtilities.GenerateSeed(mDrbg.EntropySource, numBytes);
         }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public override void GenerateSeed(Span<byte> seed)
+        {
+            EntropyUtilities.GenerateSeed(mDrbg.EntropySource, seed);
+        }
+#endif
     }
 }
diff --git a/crypto/src/crypto/signers/DsaDigestSigner.cs b/crypto/src/crypto/signers/DsaDigestSigner.cs
index f546785bd..608e55304 100644
--- a/crypto/src/crypto/signers/DsaDigestSigner.cs
+++ b/crypto/src/crypto/signers/DsaDigestSigner.cs
@@ -78,7 +78,7 @@ namespace Org.BouncyCastle.Crypto.Signers
         public virtual byte[] GenerateSignature()
 		{
 			if (!forSigning)
-				throw new InvalidOperationException("DSADigestSigner not initialised for signature generation.");
+				throw new InvalidOperationException("DsaDigestSigner not initialized for signature generation.");
 
 			byte[] hash = new byte[digest.GetDigestSize()];
 			digest.DoFinal(hash, 0);
@@ -98,7 +98,7 @@ namespace Org.BouncyCastle.Crypto.Signers
         public virtual bool VerifySignature(byte[] signature)
 		{
 			if (forSigning)
-				throw new InvalidOperationException("DSADigestSigner not initialised for verification");
+				throw new InvalidOperationException("DsaDigestSigner not initialized for verification");
 
 			byte[] hash = new byte[digest.GetDigestSize()];
 			digest.DoFinal(hash, 0);
diff --git a/crypto/src/crypto/signers/DsaSigner.cs b/crypto/src/crypto/signers/DsaSigner.cs
index 318eeeb48..a45c05c33 100644
--- a/crypto/src/crypto/signers/DsaSigner.cs
+++ b/crypto/src/crypto/signers/DsaSigner.cs
@@ -48,25 +48,23 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             if (forSigning)
             {
-                if (parameters is ParametersWithRandom)
+                if (parameters is ParametersWithRandom rParam)
                 {
-                    ParametersWithRandom rParam = (ParametersWithRandom)parameters;
-
                     providedRandom = rParam.Random;
                     parameters = rParam.Parameters;
                 }
 
-                if (!(parameters is DsaPrivateKeyParameters))
+                if (!(parameters is DsaPrivateKeyParameters dsaPrivateKeyParameters))
                     throw new InvalidKeyException("DSA private key required for signing");
 
-                this.key = (DsaPrivateKeyParameters)parameters;
+                this.key = dsaPrivateKeyParameters;
             }
             else
             {
-                if (!(parameters is DsaPublicKeyParameters))
+                if (!(parameters is DsaPublicKeyParameters dsaPublicKeyParameters))
                     throw new InvalidKeyException("DSA public key required for verification");
 
-                this.key = (DsaPublicKeyParameters)parameters;
+                this.key = dsaPublicKeyParameters;
             }
 
             this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
diff --git a/crypto/src/crypto/signers/ECDsaSigner.cs b/crypto/src/crypto/signers/ECDsaSigner.cs
index d78e92516..32225ec82 100644
--- a/crypto/src/crypto/signers/ECDsaSigner.cs
+++ b/crypto/src/crypto/signers/ECDsaSigner.cs
@@ -51,25 +51,23 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             if (forSigning)
             {
-                if (parameters is ParametersWithRandom)
+                if (parameters is ParametersWithRandom rParam)
                 {
-                    ParametersWithRandom rParam = (ParametersWithRandom)parameters;
-
                     providedRandom = rParam.Random;
                     parameters = rParam.Parameters;
                 }
 
-                if (!(parameters is ECPrivateKeyParameters))
+                if (!(parameters is ECPrivateKeyParameters ecPrivateKeyParameters))
                     throw new InvalidKeyException("EC private key required for signing");
 
-                this.key = (ECPrivateKeyParameters)parameters;
+                this.key = ecPrivateKeyParameters;
             }
             else
             {
-                if (!(parameters is ECPublicKeyParameters))
+                if (!(parameters is ECPublicKeyParameters ecPublicKeyParameters))
                     throw new InvalidKeyException("EC public key required for verification");
 
-                this.key = (ECPublicKeyParameters)parameters;
+                this.key = ecPublicKeyParameters;
             }
 
             this.random = InitSecureRandom(forSigning && !kCalculator.IsDeterministic, providedRandom);
diff --git a/crypto/src/crypto/signers/Ed25519phSigner.cs b/crypto/src/crypto/signers/Ed25519phSigner.cs
index d4ff2aae9..60bf3376c 100644
--- a/crypto/src/crypto/signers/Ed25519phSigner.cs
+++ b/crypto/src/crypto/signers/Ed25519phSigner.cs
@@ -1,9 +1,7 @@
 using System;
-using System.IO;
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math.EC.Rfc8032;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Signers
 {
@@ -74,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             byte[] msg = new byte[Ed25519.PrehashSize];
             if (Ed25519.PrehashSize != prehash.DoFinal(msg, 0))
-                throw new InvalidOperationException("Prehash digest failed");
+                throw new InvalidOperationException("Prehash calculation failed");
 
             byte[] signature = new byte[Ed25519PrivateKeyParameters.SignatureSize];
             privateKey.Sign(Ed25519.Algorithm.Ed25519ph, context, msg, 0, Ed25519.PrehashSize, signature, 0);
@@ -93,7 +91,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             byte[] msg = new byte[Ed25519.PrehashSize];
             if (Ed25519.PrehashSize != prehash.DoFinal(msg, 0))
-                throw new InvalidOperationException("Prehash digest failed");
+                throw new InvalidOperationException("Prehash calculation failed");
 
             return publicKey.Verify(Ed25519.Algorithm.Ed25519ph, context, msg, 0, Ed25519.PrehashSize, signature, 0);
         }
diff --git a/crypto/src/crypto/signers/Ed448Signer.cs b/crypto/src/crypto/signers/Ed448Signer.cs
index 79c0fefce..5bacb0a46 100644
--- a/crypto/src/crypto/signers/Ed448Signer.cs
+++ b/crypto/src/crypto/signers/Ed448Signer.cs
@@ -3,7 +3,6 @@ using System.IO;
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math.EC.Rfc8032;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Signers
 {
diff --git a/crypto/src/crypto/signers/Ed448phSigner.cs b/crypto/src/crypto/signers/Ed448phSigner.cs
index 75f841923..02d65b6fb 100644
--- a/crypto/src/crypto/signers/Ed448phSigner.cs
+++ b/crypto/src/crypto/signers/Ed448phSigner.cs
@@ -1,9 +1,7 @@
 using System;
-using System.IO;
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math.EC.Rfc8032;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Signers
 {
@@ -74,7 +72,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             byte[] msg = new byte[Ed448.PrehashSize];
             if (Ed448.PrehashSize != prehash.OutputFinal(msg, 0, Ed448.PrehashSize))
-                throw new InvalidOperationException("Prehash digest failed");
+                throw new InvalidOperationException("Prehash calculation failed");
 
             byte[] signature = new byte[Ed448PrivateKeyParameters.SignatureSize];
             privateKey.Sign(Ed448.Algorithm.Ed448ph, context, msg, 0, Ed448.PrehashSize, signature, 0);
@@ -93,7 +91,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             byte[] msg = new byte[Ed448.PrehashSize];
             if (Ed448.PrehashSize != prehash.OutputFinal(msg, 0, Ed448.PrehashSize))
-                throw new InvalidOperationException("Prehash digest failed");
+                throw new InvalidOperationException("Prehash calculation failed");
 
             return publicKey.Verify(Ed448.Algorithm.Ed448ph, context, msg, 0, Ed448.PrehashSize, signature, 0);
         }
diff --git a/crypto/src/crypto/signers/GOST3410DigestSigner.cs b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
index 63e65986b..dcbf67723 100644
--- a/crypto/src/crypto/signers/GOST3410DigestSigner.cs
+++ b/crypto/src/crypto/signers/GOST3410DigestSigner.cs
@@ -35,9 +35,9 @@ namespace Org.BouncyCastle.Crypto.Signers
             this.forSigning = forSigning;
 
             AsymmetricKeyParameter k;
-            if (parameters is ParametersWithRandom)
+            if (parameters is ParametersWithRandom withRandom)
             {
-                k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+                k = (AsymmetricKeyParameter)withRandom.Parameters;
             }
             else
             {
@@ -45,15 +45,10 @@ namespace Org.BouncyCastle.Crypto.Signers
             }
 
             if (forSigning && !k.IsPrivate)
-            {
                 throw new InvalidKeyException("Signing Requires Private Key.");
-            }
 
             if (!forSigning && k.IsPrivate)
-            {
                 throw new InvalidKeyException("Verification Requires Public Key.");
-            }
-
 
             Reset();
 
diff --git a/crypto/src/crypto/signers/GenericSigner.cs b/crypto/src/crypto/signers/GenericSigner.cs
index 36a9cc9a5..5de4c162f 100644
--- a/crypto/src/crypto/signers/GenericSigner.cs
+++ b/crypto/src/crypto/signers/GenericSigner.cs
@@ -39,9 +39,9 @@ namespace Org.BouncyCastle.Crypto.Signers
             this.forSigning = forSigning;
 
             AsymmetricKeyParameter k;
-            if (parameters is ParametersWithRandom)
+            if (parameters is ParametersWithRandom withRandom)
             {
-                k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+                k = (AsymmetricKeyParameter)withRandom.Parameters;
             }
             else
             {
diff --git a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
index ce7130538..8657f6eaf 100644
--- a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
+++ b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -115,11 +115,7 @@ namespace Org.BouncyCastle.Crypto.Signers
             if (parameters is ParametersWithRandom withRandom)
             {
                 kParam = (RsaKeyParameters)withRandom.Parameters;
-
-                if (forSigning)
-                {
-                    random = withRandom.Random;
-                }
+                random = forSigning ? withRandom.Random : null;
             }
             else if (parameters is ParametersWithSalt withSalt)
             {
@@ -135,11 +131,7 @@ namespace Org.BouncyCastle.Crypto.Signers
             else
             {
                 kParam = (RsaKeyParameters)parameters;
-
-                if (forSigning)
-                {
-                    random = CryptoServicesRegistrar.GetSecureRandom();
-                }
+                random = forSigning ? CryptoServicesRegistrar.GetSecureRandom() : null;
             }
 
             cipher.Init(forSigning, kParam);
diff --git a/crypto/src/crypto/signers/IsoTrailers.cs b/crypto/src/crypto/signers/IsoTrailers.cs
index 61006b848..83b9c192d 100644
--- a/crypto/src/crypto/signers/IsoTrailers.cs
+++ b/crypto/src/crypto/signers/IsoTrailers.cs
@@ -42,7 +42,10 @@ namespace Org.BouncyCastle.Crypto.Signers
 
         public static int GetTrailer(IDigest digest)
         {
-            return TrailerMap[digest.AlgorithmName];
+            if (TrailerMap.TryGetValue(digest.AlgorithmName, out var trailer))
+                return trailer;
+
+            throw new InvalidOperationException("No trailer for digest");
         }
 
         public static bool NoTrailerAvailable(IDigest digest)
diff --git a/crypto/src/crypto/signers/PssSigner.cs b/crypto/src/crypto/signers/PssSigner.cs
index 69f9e96e4..2e4c37772 100644
--- a/crypto/src/crypto/signers/PssSigner.cs
+++ b/crypto/src/crypto/signers/PssSigner.cs
@@ -158,21 +158,18 @@ namespace Org.BouncyCastle.Crypto.Signers
 			{
 				parameters = withRandom.Parameters;
 				random = withRandom.Random;
-			}
-			else
+                cipher.Init(forSigning, withRandom);
+            }
+            else
 			{
-				if (forSigning)
-				{
-					random = CryptoServicesRegistrar.GetSecureRandom();
-				}
-			}
-
-			cipher.Init(forSigning, parameters);
+				random = forSigning ? CryptoServicesRegistrar.GetSecureRandom() : null;
+                cipher.Init(forSigning, parameters);
+            }
 
-			RsaKeyParameters kParam;
-			if (parameters is RsaBlindingParameters)
+            RsaKeyParameters kParam;
+			if (parameters is RsaBlindingParameters blinding)
 			{
-				kParam = ((RsaBlindingParameters)parameters).PublicKey;
+				kParam = blinding.PublicKey;
 			}
 			else
 			{
@@ -188,8 +185,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 		}
 
 		/// <summary> clear possible sensitive data</summary>
-		private void ClearBlock(
-			byte[] block)
+		private void ClearBlock(byte[] block)
 		{
 			Array.Clear(block, 0, block.Length);
 		}
@@ -346,24 +342,17 @@ namespace Org.BouncyCastle.Crypto.Signers
 			sp[3] = (byte)((uint) i >> 0);
 		}
 
-		private byte[] MaskGeneratorFunction(
-			byte[] Z,
-			int zOff,
-			int zLen,
-			int length)
-		{
-			if (mgfDigest is IXof)
+        private byte[] MaskGeneratorFunction(byte[] Z, int zOff, int zLen, int length)
+        {
+            if (mgfDigest is IXof xof)
 			{
 				byte[] mask = new byte[length];
-				mgfDigest.BlockUpdate(Z, zOff, zLen);
-				((IXof)mgfDigest).OutputFinal(mask, 0, mask.Length);
-
+				xof.BlockUpdate(Z, zOff, zLen);
+				xof.OutputFinal(mask, 0, mask.Length);
 				return mask;
 			}
-			else
-			{
-				return MaskGeneratorFunction1(Z, zOff, zLen, length);
-			}
+
+			return MaskGeneratorFunction1(Z, zOff, zLen, length);
 		}
 
 		/// <summary> mask generator function, as described in Pkcs1v2.</summary>
diff --git a/crypto/src/crypto/signers/RsaDigestSigner.cs b/crypto/src/crypto/signers/RsaDigestSigner.cs
index 77d9b9ac3..80b1a4356 100644
--- a/crypto/src/crypto/signers/RsaDigestSigner.cs
+++ b/crypto/src/crypto/signers/RsaDigestSigner.cs
@@ -100,11 +100,11 @@ namespace Org.BouncyCastle.Crypto.Signers
             ICipherParameters	parameters)
         {
             this.forSigning = forSigning;
-            AsymmetricKeyParameter k;
 
-            if (parameters is ParametersWithRandom)
+            AsymmetricKeyParameter k;
+            if (parameters is ParametersWithRandom withRandom)
             {
-                k = (AsymmetricKeyParameter)((ParametersWithRandom)parameters).Parameters;
+                k = (AsymmetricKeyParameter)withRandom.Parameters;
             }
             else
             {
diff --git a/crypto/src/crypto/signers/SM2Signer.cs b/crypto/src/crypto/signers/SM2Signer.cs
index 60fae3264..cd4b2d554 100644
--- a/crypto/src/crypto/signers/SM2Signer.cs
+++ b/crypto/src/crypto/signers/SM2Signer.cs
@@ -55,10 +55,10 @@ namespace Org.BouncyCastle.Crypto.Signers
             ICipherParameters baseParam;
             byte[] userID;
 
-            if (parameters is ParametersWithID)
+            if (parameters is ParametersWithID withID)
             {
-                baseParam = ((ParametersWithID)parameters).Parameters;
-                userID = ((ParametersWithID)parameters).GetID();
+                baseParam = withID.Parameters;
+                userID = withID.GetID();
 
                 if (userID.Length >= 8192)
                     throw new ArgumentException("SM2 user ID must be less than 2^16 bits long");
@@ -72,18 +72,23 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             if (forSigning)
             {
+                SecureRandom random = null;
                 if (baseParam is ParametersWithRandom rParam)
                 {
                     ecKey = (ECKeyParameters)rParam.Parameters;
                     ecParams = ecKey.Parameters;
-                    kCalculator.Init(ecParams.N, rParam.Random);
+                    random = rParam.Random;
                 }
                 else
                 {
                     ecKey = (ECKeyParameters)baseParam;
                     ecParams = ecKey.Parameters;
-                    kCalculator.Init(ecParams.N, CryptoServicesRegistrar.GetSecureRandom());
                 }
+                if (!kCalculator.IsDeterministic)
+                {
+                    random = CryptoServicesRegistrar.GetSecureRandom(random);
+                }
+                kCalculator.Init(ecParams.N, random);
                 pubPoint = CreateBasePointMultiplier().Multiply(ecParams.G, ((ECPrivateKeyParameters)ecKey).D).Normalize();
             }
             else
diff --git a/crypto/src/crypto/signers/StandardDsaEncoding.cs b/crypto/src/crypto/signers/StandardDsaEncoding.cs
index 77cd6124d..8fa195982 100644
--- a/crypto/src/crypto/signers/StandardDsaEncoding.cs
+++ b/crypto/src/crypto/signers/StandardDsaEncoding.cs
@@ -24,7 +24,7 @@ namespace Org.BouncyCastle.Crypto.Signers
                     return new BigInteger[]{ r, s };
             }
 
-            throw new ArgumentException("Malformed signature", "encoding");
+            throw new ArgumentException("Malformed signature", nameof(encoding));
         }
 
         public virtual byte[] Encode(BigInteger n, BigInteger r, BigInteger s)
@@ -55,7 +55,7 @@ namespace Org.BouncyCastle.Crypto.Signers
         protected virtual BigInteger CheckValue(BigInteger n, BigInteger x)
         {
             if (x.SignValue < 0 || (null != n && x.CompareTo(n) >= 0))
-                throw new ArgumentException("Value out of range", "x");
+                throw new ArgumentException("Value out of range", nameof(x));
 
             return x;
         }
diff --git a/crypto/src/crypto/signers/X931Signer.cs b/crypto/src/crypto/signers/X931Signer.cs
index 9db4e1642..c185eacfd 100644
--- a/crypto/src/crypto/signers/X931Signer.cs
+++ b/crypto/src/crypto/signers/X931Signer.cs
@@ -71,9 +71,16 @@ namespace Org.BouncyCastle.Crypto.Signers
 
         public virtual void Init(bool forSigning, ICipherParameters parameters)
         {
-            kParam = (RsaKeyParameters)parameters;
+            if (parameters is ParametersWithRandom withRandom)
+            {
+                kParam = (RsaKeyParameters)withRandom.Parameters;
+            }
+            else
+            {
+                kParam = (RsaKeyParameters)parameters;
+            }
 
-            cipher.Init(forSigning, kParam);
+            cipher.Init(forSigning, parameters);
 
             keyBits = kParam.Modulus.BitLength;
 
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index 3999ba4f0..624495051 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -675,9 +675,40 @@ namespace Org.BouncyCastle.Math.EC
     public abstract class AbstractFpCurve
         : ECCurve
     {
+        private static readonly HashSet<BigInteger> KnownQs = new HashSet<BigInteger>();
+
         protected AbstractFpCurve(BigInteger q)
+            : this(q, false)
+        {
+        }
+
+        internal AbstractFpCurve(BigInteger q, bool isInternal)
             : base(FiniteFields.GetPrimeField(q))
         {
+            if (!isInternal)
+            {
+                bool unknownQ;
+                lock (KnownQs) unknownQ = !KnownQs.Contains(q);
+
+                if (unknownQ)
+                {
+                    int maxBitLength = ImplGetInteger("Org.BouncyCastle.EC.Fp_MaxSize", 1042); // 2 * 521
+                    int certainty = ImplGetInteger("Org.BouncyCastle.EC.Fp_Certainty", 100);
+
+                    int qBitLength = q.BitLength;
+                    if (maxBitLength < qBitLength)
+                        throw new ArgumentException("Fp q value out of range");
+
+                    if (Primes.HasAnySmallFactors(q) ||
+                        !Primes.IsMRProbablePrime(q, SecureRandom.ArbitraryRandom,
+                            ImplGetNumberOfIterations(qBitLength, certainty)))
+                    {
+                        throw new ArgumentException("Fp q value not prime");
+                    }
+                }
+            }
+
+            lock (KnownQs) KnownQs.Add(q);
         }
 
         public override bool IsValidFieldElement(BigInteger x)
@@ -730,6 +761,47 @@ namespace Org.BouncyCastle.Math.EC
             return CreateRawPoint(x, y);
         }
 
+        private static int ImplGetInteger(string envVariable, int defaultValue)
+        {
+            string v = Platform.GetEnvironmentVariable(envVariable);
+            if (v == null)
+                return defaultValue;
+
+            return int.Parse(v);
+        }
+
+        private static int ImplGetNumberOfIterations(int bits, int certainty)
+        {
+            /*
+             * NOTE: We enforce a minimum 'certainty' of 100 for bits >= 1024 (else 80). Where the
+             * certainty is higher than the FIPS 186-4 tables (C.2/C.3) cater to, extra iterations
+             * are added at the "worst case rate" for the excess.
+             */
+            if (bits >= 1536)
+            {
+                return certainty <= 100 ? 3
+                    : certainty <= 128 ? 4
+                    : 4 + (certainty - 128 + 1) / 2;
+            }
+            else if (bits >= 1024)
+            {
+                return certainty <= 100 ? 4
+                    : certainty <= 112 ? 5
+                    : 5 + (certainty - 112 + 1) / 2;
+            }
+            else if (bits >= 512)
+            {
+                return certainty <= 80 ? 5
+                    : certainty <= 100 ? 7
+                    : 7 + (certainty - 100 + 1) / 2;
+            }
+            else
+            {
+                return certainty <= 80 ? 40
+                    : 40 + (certainty - 80 + 1) / 2;
+            }
+        }
+
         private static BigInteger ImplRandomFieldElement(SecureRandom r, BigInteger p)
         {
             BigInteger x;
@@ -761,8 +833,6 @@ namespace Org.BouncyCastle.Math.EC
     {
         private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
 
-        private static readonly HashSet<BigInteger> KnownQs = new HashSet<BigInteger>();
-
         protected readonly BigInteger m_q, m_r;
         protected readonly FpPoint m_infinity;
 
@@ -778,32 +848,8 @@ namespace Org.BouncyCastle.Math.EC
         }
 
         internal FpCurve(BigInteger q, BigInteger a, BigInteger b, BigInteger order, BigInteger cofactor, bool isInternal)
-            : base(q)
+            : base(q, isInternal)
         {
-            if (!isInternal)
-            {
-                bool unknownQ;
-                lock (KnownQs) unknownQ = !KnownQs.Contains(q);
-
-                if (unknownQ)
-                {
-                    int maxBitLength = AsInteger("Org.BouncyCastle.EC.Fp_MaxSize", 1042); // 2 * 521
-                    int certainty = AsInteger("Org.BouncyCastle.EC.Fp_Certainty", 100);
-
-                    int qBitLength = q.BitLength;
-                    if (maxBitLength < qBitLength)
-                        throw new ArgumentException("Fp q value out of range");
-
-                    if (Primes.HasAnySmallFactors(q) ||
-                        !Primes.IsMRProbablePrime(q, SecureRandom.ArbitraryRandom,
-                            GetNumberOfIterations(qBitLength, certainty)))
-                    {
-                        throw new ArgumentException("Fp q value not prime");
-                    }
-                }
-            }
-
-            lock (KnownQs) KnownQs.Add(q);
             this.m_q = q;
 
             this.m_r = FpFieldElement.CalculateResidue(q);
@@ -818,7 +864,7 @@ namespace Org.BouncyCastle.Math.EC
 
         internal FpCurve(BigInteger q, BigInteger r, ECFieldElement a, ECFieldElement b, BigInteger order,
             BigInteger cofactor)
-            : base(q)
+            : base(q, true)
         {
             this.m_q = q;
             this.m_r = r;
@@ -903,50 +949,6 @@ namespace Org.BouncyCastle.Math.EC
 
             return base.ImportPoint(p);
         }
-
-        private int GetNumberOfIterations(int bits, int certainty)
-        {
-            /*
-             * NOTE: We enforce a minimum 'certainty' of 100 for bits >= 1024 (else 80). Where the
-             * certainty is higher than the FIPS 186-4 tables (C.2/C.3) cater to, extra iterations
-             * are added at the "worst case rate" for the excess.
-             */
-            if (bits >= 1536)
-            {
-                return  certainty <= 100 ? 3
-                    :   certainty <= 128 ? 4
-                    :   4 + (certainty - 128 + 1) / 2;
-            }
-            else if (bits >= 1024)
-            {
-                return  certainty <= 100 ? 4
-                    :   certainty <= 112 ? 5
-                    :   5 + (certainty - 112 + 1) / 2;
-            }
-            else if (bits >= 512)
-            {
-                return  certainty <= 80  ? 5
-                    :   certainty <= 100 ? 7
-                    :   7 + (certainty - 100 + 1) / 2;
-            }
-            else
-            {
-                return  certainty <= 80  ? 40
-                    :   40 + (certainty - 80 + 1) / 2;
-            }
-        }
-
-        int AsInteger(string envVariable, int defaultValue)
-        {
-            string v = Platform.GetEnvironmentVariable(envVariable);
-
-            if (v == null)
-            {
-                return defaultValue;
-            }
-
-            return int.Parse(v);
-        }
     }
 
     public abstract class AbstractF2mCurve
diff --git a/crypto/src/math/ec/ECPoint.cs b/crypto/src/math/ec/ECPoint.cs
index ee7cf9a92..4607c8cfe 100644
--- a/crypto/src/math/ec/ECPoint.cs
+++ b/crypto/src/math/ec/ECPoint.cs
@@ -12,7 +12,7 @@ namespace Org.BouncyCastle.Math.EC
      */
     public abstract class ECPoint
     {
-        protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0];
+        protected static readonly ECFieldElement[] EMPTY_ZS = new ECFieldElement[0];
 
         protected static ECFieldElement[] GetInitialZCoords(ECCurve curve)
         {
@@ -487,11 +487,7 @@ namespace Org.BouncyCastle.Math.EC
 
             public PreCompInfo Precompute(PreCompInfo existing)
             {
-                ValidityPreCompInfo info = existing as ValidityPreCompInfo;
-                if (info == null)
-                {
-                    info = new ValidityPreCompInfo();
-                }
+                ValidityPreCompInfo info = existing as ValidityPreCompInfo ?? new ValidityPreCompInfo();
 
                 if (info.HasFailed())
                     return info;
diff --git a/crypto/src/math/ec/LongArray.cs b/crypto/src/math/ec/LongArray.cs
index aa36de215..3475e9ecc 100644
--- a/crypto/src/math/ec/LongArray.cs
+++ b/crypto/src/math/ec/LongArray.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Text;
+
 using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
diff --git a/crypto/src/math/ec/abc/Tnaf.cs b/crypto/src/math/ec/abc/Tnaf.cs
index fd073bb7b..88a4eeb96 100644
--- a/crypto/src/math/ec/abc/Tnaf.cs
+++ b/crypto/src/math/ec/abc/Tnaf.cs
@@ -13,7 +13,7 @@ namespace Org.BouncyCastle.Math.EC.Abc
     * by Jerome A. Solinas. The paper first appeared in the Proceedings of
     * Crypto 1997.
     */
-    internal class Tnaf
+    internal static class Tnaf
     {
         private static readonly BigInteger MinusOne = BigInteger.One.Negate();
         private static readonly BigInteger MinusTwo = BigInteger.Two.Negate();
@@ -552,7 +552,7 @@ namespace Org.BouncyCastle.Math.EC.Abc
             return new BigInteger[] { dividend0, dividend1 };
         }
 
-        protected static int GetShiftsForCofactor(BigInteger h)
+        private static int GetShiftsForCofactor(BigInteger h)
         {
             if (h != null && h.BitLength < 4)
             {
diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs b/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs
index ae6c6e1d9..3147ccf98 100644
--- a/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs
+++ b/crypto/src/math/ec/custom/gm/SM2P256V1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.GM
         protected readonly SM2P256V1Point m_infinity;
 
         public SM2P256V1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SM2P256V1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
index a5fc338da..5fa18d470 100644
--- a/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP128R1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP128R1Point m_infinity;
 
         public SecP128R1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP128R1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
index 99318a2d8..b757659d2 100644
--- a/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP160K1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP160K1Point m_infinity;
 
         public SecP160K1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP160K1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
index b3e90f82a..3b7e1aa06 100644
--- a/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP160R1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP160R1Point m_infinity;
 
         public SecP160R1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP160R1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs b/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
index 54a67d796..0f226ad19 100644
--- a/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP160R2Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP160R2Point m_infinity;
 
         public SecP160R2Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP160R2Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
index 9e73e5d51..b9ff71ac8 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP192K1Point m_infinity;
 
         public SecP192K1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP192K1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
index fb9e0f7ad..77524b362 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP192R1Point m_infinity;
 
         public SecP192R1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP192R1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
index 91af66685..04be47202 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP224K1Point m_infinity;
 
         public SecP224K1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP224K1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
index b82841446..8cd2b7272 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP224R1Point m_infinity;
 
         public SecP224R1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP224R1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs b/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
index d9c876818..804b65d60 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP256K1Point m_infinity;
 
         public SecP256K1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP256K1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
index 7a5cec8b3..dd2b964c6 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP256R1Point m_infinity;
 
         public SecP256R1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP256R1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
index 242b73fc6..f54dd44c2 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP384R1Point m_infinity;
 
         public SecP384R1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP384R1Point(this, null, null);
 
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs b/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
index 9cdcec036..a5f4cf957 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1Curve.cs
@@ -18,7 +18,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
         protected readonly SecP521R1Point m_infinity;
 
         public SecP521R1Curve()
-            : base(q)
+            : base(q, true)
         {
             this.m_infinity = new SecP521R1Point(this, null, null);
 
diff --git a/crypto/src/math/raw/Interleave.cs b/crypto/src/math/raw/Interleave.cs
index 196f7c9b5..17351d002 100644
--- a/crypto/src/math/raw/Interleave.cs
+++ b/crypto/src/math/raw/Interleave.cs
@@ -6,7 +6,7 @@ using System.Runtime.Intrinsics.X86;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Interleave
+    internal static class Interleave
     {
         private const ulong M32 = 0x55555555UL;
         private const ulong M64 = 0x5555555555555555UL;
diff --git a/crypto/src/math/raw/Nat.cs b/crypto/src/math/raw/Nat.cs
index fa76f305e..1d08b6d92 100644
--- a/crypto/src/math/raw/Nat.cs
+++ b/crypto/src/math/raw/Nat.cs
@@ -8,7 +8,7 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat
+    internal static class Nat
     {
         private const ulong M = 0xFFFFFFFFUL;
 
diff --git a/crypto/src/math/raw/Nat128.cs b/crypto/src/math/raw/Nat128.cs
index 0705844e7..d0cdc9985 100644
--- a/crypto/src/math/raw/Nat128.cs
+++ b/crypto/src/math/raw/Nat128.cs
@@ -5,7 +5,7 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat128
+    internal static class Nat128
     {
         private const ulong M = 0xFFFFFFFFUL;
 
diff --git a/crypto/src/math/raw/Nat160.cs b/crypto/src/math/raw/Nat160.cs
index f862700b1..85e4aba58 100644
--- a/crypto/src/math/raw/Nat160.cs
+++ b/crypto/src/math/raw/Nat160.cs
@@ -5,7 +5,7 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat160
+    internal static class Nat160
     {
         private const ulong M = 0xFFFFFFFFUL;
 
diff --git a/crypto/src/math/raw/Nat192.cs b/crypto/src/math/raw/Nat192.cs
index 7c36b21cf..1980a47c6 100644
--- a/crypto/src/math/raw/Nat192.cs
+++ b/crypto/src/math/raw/Nat192.cs
@@ -5,7 +5,7 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat192
+    internal static class Nat192
     {
         private const ulong M = 0xFFFFFFFFUL;
 
diff --git a/crypto/src/math/raw/Nat224.cs b/crypto/src/math/raw/Nat224.cs
index 8393dc763..2182261ae 100644
--- a/crypto/src/math/raw/Nat224.cs
+++ b/crypto/src/math/raw/Nat224.cs
@@ -5,7 +5,7 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat224
+    internal static class Nat224
     {
         private const ulong M = 0xFFFFFFFFUL;
 
diff --git a/crypto/src/math/raw/Nat256.cs b/crypto/src/math/raw/Nat256.cs
index edf793d3d..59039d3fa 100644
--- a/crypto/src/math/raw/Nat256.cs
+++ b/crypto/src/math/raw/Nat256.cs
@@ -11,7 +11,7 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat256
+    internal static class Nat256
     {
         private const ulong M = 0xFFFFFFFFUL;
 
diff --git a/crypto/src/math/raw/Nat320.cs b/crypto/src/math/raw/Nat320.cs
index 06f7b58cc..d52389cb1 100644
--- a/crypto/src/math/raw/Nat320.cs
+++ b/crypto/src/math/raw/Nat320.cs
@@ -5,7 +5,7 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat320
+    internal static class Nat320
     {
         public static void Copy64(ulong[] x, ulong[] z)
         {
diff --git a/crypto/src/math/raw/Nat384.cs b/crypto/src/math/raw/Nat384.cs
index ed1c47e8c..2373d4610 100644
--- a/crypto/src/math/raw/Nat384.cs
+++ b/crypto/src/math/raw/Nat384.cs
@@ -3,7 +3,7 @@ using System.Diagnostics;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat384
+    internal static class Nat384
     {
         public static void Mul(uint[] x, uint[] y, uint[] zz)
         {
diff --git a/crypto/src/math/raw/Nat448.cs b/crypto/src/math/raw/Nat448.cs
index 2da03bf0f..ac29ca9af 100644
--- a/crypto/src/math/raw/Nat448.cs
+++ b/crypto/src/math/raw/Nat448.cs
@@ -5,7 +5,7 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat448
+    internal static class Nat448
     {
         public static void Copy64(ulong[] x, ulong[] z)
         {
diff --git a/crypto/src/math/raw/Nat512.cs b/crypto/src/math/raw/Nat512.cs
index f8a34027f..56fa9a2c9 100644
--- a/crypto/src/math/raw/Nat512.cs
+++ b/crypto/src/math/raw/Nat512.cs
@@ -8,7 +8,7 @@ using System.Runtime.Intrinsics.X86;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat512
+    internal static class Nat512
     {
         public static void Mul(uint[] x, uint[] y, uint[] zz)
         {
diff --git a/crypto/src/math/raw/Nat576.cs b/crypto/src/math/raw/Nat576.cs
index 3525a0f05..73b959366 100644
--- a/crypto/src/math/raw/Nat576.cs
+++ b/crypto/src/math/raw/Nat576.cs
@@ -5,7 +5,7 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Math.Raw
 {
-    internal abstract class Nat576
+    internal static class Nat576
     {
         public static void Copy64(ulong[] x, ulong[] z)
         {
diff --git a/crypto/src/ocsp/BasicOCSPResp.cs b/crypto/src/ocsp/BasicOCSPResp.cs
index 6c8ad9eee..3e22931af 100644
--- a/crypto/src/ocsp/BasicOCSPResp.cs
+++ b/crypto/src/ocsp/BasicOCSPResp.cs
@@ -117,10 +117,11 @@ namespace Org.BouncyCastle.Ocsp
 			{
 				foreach (Asn1Encodable ae in certs)
 				{
-					if (ae != null && ae.ToAsn1Object() is Asn1Sequence s)
-					{
-						result.Add(new X509Certificate(X509CertificateStructure.GetInstance(s)));
-					}
+                    var c = X509CertificateStructure.GetInstance(ae);
+                    if (c != null)
+                    {
+                        result.Add(new X509Certificate(c));
+                    }
 				}
 			}
 
diff --git a/crypto/src/ocsp/OCSPReq.cs b/crypto/src/ocsp/OCSPReq.cs
index cb2748780..194b6c9c7 100644
--- a/crypto/src/ocsp/OCSPReq.cs
+++ b/crypto/src/ocsp/OCSPReq.cs
@@ -165,9 +165,10 @@ namespace Org.BouncyCastle.Ocsp
 			{
 				foreach (Asn1Encodable ae in certs)
 				{
-                    if (ae != null && ae.ToAsn1Object() is Asn1Sequence s)
+                    var c = X509CertificateStructure.GetInstance(ae);
+                    if (c != null)
                     {
-                        result.Add(new X509Certificate(X509CertificateStructure.GetInstance(s)));
+                        result.Add(new X509Certificate(c));
                     }
                 }
 			}
diff --git a/crypto/src/ocsp/OCSPReqGenerator.cs b/crypto/src/ocsp/OCSPReqGenerator.cs
index dda1625e5..9a5d72ae8 100644
--- a/crypto/src/ocsp/OCSPReqGenerator.cs
+++ b/crypto/src/ocsp/OCSPReqGenerator.cs
@@ -6,6 +6,7 @@ using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Ocsp;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.IO;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Security.Certificates;
@@ -93,13 +94,10 @@ namespace Org.BouncyCastle.Ocsp
 			this.requestExtensions = requestExtensions;
 		}
 
-		private OcspReq GenerateRequest(
-			DerObjectIdentifier		signingAlgorithm,
-			AsymmetricKeyParameter	privateKey,
-			X509Certificate[]		chain,
-			SecureRandom			random)
+		private OcspReq GenerateRequest(DerObjectIdentifier signingAlgorithm, AsymmetricKeyParameter privateKey,
+			X509Certificate[] chain, SecureRandom random)
 		{
-			Asn1EncodableVector requests = new Asn1EncodableVector();
+			Asn1EncodableVector requests = new Asn1EncodableVector(list.Count);
 
 			foreach (RequestObject reqObj in list)
 			{
@@ -114,42 +112,29 @@ namespace Org.BouncyCastle.Ocsp
 			}
 
 			TbsRequest tbsReq = new TbsRequest(requestorName, new DerSequence(requests), requestExtensions);
-
-			ISigner sig = null;
 			Signature signature = null;
 
 			if (signingAlgorithm != null)
 			{
 				if (requestorName == null)
-				{
 					throw new OcspException("requestorName must be specified if request is signed.");
-				}
 
-				try
-				{
-					sig = SignerUtilities.GetSigner(signingAlgorithm.Id);
-					if (random != null)
-					{
-						sig.Init(true, new ParametersWithRandom(privateKey, random));
-					}
-					else
-					{
-						sig.Init(true, privateKey);
-					}
+                ISigner signer;
+                try
+                {
+					signer = SignerUtilities.InitSigner(signingAlgorithm, true, privateKey, random);
 				}
 				catch (Exception e)
 				{
 					throw new OcspException("exception creating signature: " + e, e);
 				}
 
-				DerBitString bitSig = null;
-
+				DerBitString bitSig;
 				try
 				{
-					byte[] encoded = tbsReq.GetEncoded();
-					sig.BlockUpdate(encoded, 0, encoded.Length);
+					tbsReq.EncodeTo(new SignerSink(signer), Asn1Encodable.Der);
 
-					bitSig = new DerBitString(sig.GenerateSignature());
+					bitSig = new DerBitString(signer.GenerateSignature());
 				}
 				catch (Exception e)
 				{
@@ -158,9 +143,10 @@ namespace Org.BouncyCastle.Ocsp
 
 				AlgorithmIdentifier sigAlgId = new AlgorithmIdentifier(signingAlgorithm, DerNull.Instance);
 
-				if (chain != null && chain.Length > 0)
+				Asn1Sequence certs = null;
+				if (!Arrays.IsNullOrEmpty(chain))
 				{
-					Asn1EncodableVector v = new Asn1EncodableVector();
+					Asn1EncodableVector v = new Asn1EncodableVector(chain.Length);
 					try
 					{
 						for (int i = 0; i != chain.Length; i++)
@@ -177,15 +163,13 @@ namespace Org.BouncyCastle.Ocsp
 						throw new OcspException("error encoding certs", e);
 					}
 
-					signature = new Signature(sigAlgId, bitSig, new DerSequence(v));
+					certs = new DerSequence(v);
 				}
-				else
-				{
-					signature = new Signature(sigAlgId, bitSig);
-				}
-			}
 
-			return new OcspReq(new OcspRequest(tbsReq, signature));
+                signature = new Signature(sigAlgId, bitSig, certs);
+            }
+
+            return new OcspReq(new OcspRequest(tbsReq, signature));
 		}
 
 		/**
diff --git a/crypto/src/openpgp/PgpSignatureGenerator.cs b/crypto/src/openpgp/PgpSignatureGenerator.cs
index 12edf9f89..64d256653 100644
--- a/crypto/src/openpgp/PgpSignatureGenerator.cs
+++ b/crypto/src/openpgp/PgpSignatureGenerator.cs
@@ -40,36 +40,34 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         }
 
 		/// <summary>Initialise the generator for signing.</summary>
-        public void InitSign(
-            int				sigType,
-            PgpPrivateKey	privKey)
+        public void InitSign(int sigType, PgpPrivateKey privKey)
         {
 			InitSign(sigType, privKey, null);
         }
 
 		/// <summary>Initialise the generator for signing.</summary>
-		public void InitSign(
-			int				sigType,
-			PgpPrivateKey privKey,
-			SecureRandom	random)
+		public void InitSign(int sigType, PgpPrivateKey privKey, SecureRandom random)
 		{
 			this.privKey = privKey;
 			this.signatureType = sigType;
 
 			AsymmetricKeyParameter key = privKey.Key;
 
-			if (sig == null)
-			{
-                this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key);
-            }
+            this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key);
 
             try
 			{
 				ICipherParameters cp = key;
-				if (random != null)
+
+				// TODO Ask SignerUtilities whether random is permitted?
+				if (keyAlgorithm == PublicKeyAlgorithmTag.EdDsa)
 				{
-					cp = new ParametersWithRandom(cp, random);
+					// EdDSA signers don't expect a SecureRandom
 				}
+				else
+				{
+                    cp = ParameterUtilities.WithRandom(cp, random);
+                }
 
 				sig.Init(true, cp);
 			}
diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs
index f400d36cc..8b8f7d9c5 100644
--- a/crypto/src/openpgp/PgpUtilities.cs
+++ b/crypto/src/openpgp/PgpUtilities.cs
@@ -51,10 +51,6 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             return d;
         }
 
-        private PgpUtilities()
-        {
-        }
-
 		public static MPInteger[] DsaSigToMpi(
 			byte[] encoding)
 		{
@@ -89,24 +85,24 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         {
             switch (hashAlgorithm)
             {
-				case HashAlgorithmTag.Sha1:
-					return "SHA1";
-				case HashAlgorithmTag.MD2:
-					return "MD2";
-				case HashAlgorithmTag.MD5:
-					return "MD5";
-				case HashAlgorithmTag.RipeMD160:
-					return "RIPEMD160";
-				case HashAlgorithmTag.Sha224:
-					return "SHA224";
-				case HashAlgorithmTag.Sha256:
-					return "SHA256";
-				case HashAlgorithmTag.Sha384:
-					return "SHA384";
-				case HashAlgorithmTag.Sha512:
-					return "SHA512";
-				default:
-					throw new PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm);
+			case HashAlgorithmTag.Sha1:
+				return "SHA1";
+			case HashAlgorithmTag.MD2:
+				return "MD2";
+			case HashAlgorithmTag.MD5:
+				return "MD5";
+			case HashAlgorithmTag.RipeMD160:
+				return "RIPEMD160";
+			case HashAlgorithmTag.Sha224:
+				return "SHA224";
+			case HashAlgorithmTag.Sha256:
+				return "SHA256";
+			case HashAlgorithmTag.Sha384:
+				return "SHA384";
+			case HashAlgorithmTag.Sha512:
+				return "SHA512";
+			default:
+				throw new PgpException("unknown hash algorithm tag in GetDigestName: " + hashAlgorithm);
 			}
         }
 
@@ -140,28 +136,28 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             string encAlg;
 			switch (keyAlgorithm)
             {
-				case PublicKeyAlgorithmTag.RsaGeneral:
-				case PublicKeyAlgorithmTag.RsaSign:
-					encAlg = "RSA";
-					break;
-				case PublicKeyAlgorithmTag.Dsa:
-					encAlg = "DSA";
-					break;
-                case PublicKeyAlgorithmTag.ECDH:
-                    encAlg = "ECDH";
-                    break;
-                case PublicKeyAlgorithmTag.ECDsa:
-                    encAlg = "ECDSA";
-                    break;
-                case PublicKeyAlgorithmTag.EdDsa:
-                    encAlg = "EdDSA";
-                    break;
-                case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
-				case PublicKeyAlgorithmTag.ElGamalGeneral:
-					encAlg = "ElGamal";
-					break;
-				default:
-					throw new PgpException("unknown algorithm tag in signature:" + keyAlgorithm);
+			case PublicKeyAlgorithmTag.RsaGeneral:
+			case PublicKeyAlgorithmTag.RsaSign:
+				encAlg = "RSA";
+				break;
+			case PublicKeyAlgorithmTag.Dsa:
+				encAlg = "DSA";
+				break;
+            case PublicKeyAlgorithmTag.ECDH:
+                encAlg = "ECDH";
+                break;
+            case PublicKeyAlgorithmTag.ECDsa:
+                encAlg = "ECDSA";
+                break;
+            case PublicKeyAlgorithmTag.EdDsa:
+                encAlg = "EdDSA";
+                break;
+            case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
+			case PublicKeyAlgorithmTag.ElGamalGeneral:
+				encAlg = "ElGamal";
+				break;
+			default:
+				throw new PgpException("unknown algorithm tag in signature:" + keyAlgorithm);
             }
 
 			return GetDigestName(hashAlgorithm) + "with" + encAlg;
@@ -172,36 +168,36 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         {
             switch (algorithm)
             {
-				case SymmetricKeyAlgorithmTag.Null:
-					return null;
-				case SymmetricKeyAlgorithmTag.TripleDes:
-					return "DESEDE";
-				case SymmetricKeyAlgorithmTag.Idea:
-					return "IDEA";
-				case SymmetricKeyAlgorithmTag.Cast5:
-					return "CAST5";
-				case SymmetricKeyAlgorithmTag.Blowfish:
-					return "Blowfish";
-				case SymmetricKeyAlgorithmTag.Safer:
-					return "SAFER";
-				case SymmetricKeyAlgorithmTag.Des:
-					return "DES";
-				case SymmetricKeyAlgorithmTag.Aes128:
-					return "AES";
-				case SymmetricKeyAlgorithmTag.Aes192:
-					return "AES";
-				case SymmetricKeyAlgorithmTag.Aes256:
-					return "AES";
-				case SymmetricKeyAlgorithmTag.Twofish:
-					return "Twofish";
-				case SymmetricKeyAlgorithmTag.Camellia128:
-					return "Camellia";
-				case SymmetricKeyAlgorithmTag.Camellia192:
-					return "Camellia";
-				case SymmetricKeyAlgorithmTag.Camellia256:
-					return "Camellia";
-				default:
-					throw new PgpException("unknown symmetric algorithm: " + algorithm);
+			case SymmetricKeyAlgorithmTag.Null:
+				return null;
+			case SymmetricKeyAlgorithmTag.TripleDes:
+				return "DESEDE";
+			case SymmetricKeyAlgorithmTag.Idea:
+				return "IDEA";
+			case SymmetricKeyAlgorithmTag.Cast5:
+				return "CAST5";
+			case SymmetricKeyAlgorithmTag.Blowfish:
+				return "Blowfish";
+			case SymmetricKeyAlgorithmTag.Safer:
+				return "SAFER";
+			case SymmetricKeyAlgorithmTag.Des:
+				return "DES";
+			case SymmetricKeyAlgorithmTag.Aes128:
+				return "AES";
+			case SymmetricKeyAlgorithmTag.Aes192:
+				return "AES";
+			case SymmetricKeyAlgorithmTag.Aes256:
+				return "AES";
+			case SymmetricKeyAlgorithmTag.Twofish:
+				return "Twofish";
+			case SymmetricKeyAlgorithmTag.Camellia128:
+				return "Camellia";
+			case SymmetricKeyAlgorithmTag.Camellia192:
+				return "Camellia";
+			case SymmetricKeyAlgorithmTag.Camellia256:
+				return "Camellia";
+			default:
+				throw new PgpException("unknown symmetric algorithm: " + algorithm);
             }
         }
 
@@ -210,29 +206,29 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             int keySize;
             switch (algorithm)
             {
-                case SymmetricKeyAlgorithmTag.Des:
-                    keySize = 64;
-                    break;
-                case SymmetricKeyAlgorithmTag.Idea:
-                case SymmetricKeyAlgorithmTag.Cast5:
-                case SymmetricKeyAlgorithmTag.Blowfish:
-                case SymmetricKeyAlgorithmTag.Safer:
-                case SymmetricKeyAlgorithmTag.Aes128:
-                case SymmetricKeyAlgorithmTag.Camellia128:
-                    keySize = 128;
-                    break;
-                case SymmetricKeyAlgorithmTag.TripleDes:
-                case SymmetricKeyAlgorithmTag.Aes192:
-                case SymmetricKeyAlgorithmTag.Camellia192:
-                    keySize = 192;
-                    break;
-                case SymmetricKeyAlgorithmTag.Aes256:
-                case SymmetricKeyAlgorithmTag.Twofish:
-                case SymmetricKeyAlgorithmTag.Camellia256:
-                    keySize = 256;
-                    break;
-                default:
-                    throw new PgpException("unknown symmetric algorithm: " + algorithm);
+            case SymmetricKeyAlgorithmTag.Des:
+                keySize = 64;
+                break;
+            case SymmetricKeyAlgorithmTag.Idea:
+            case SymmetricKeyAlgorithmTag.Cast5:
+            case SymmetricKeyAlgorithmTag.Blowfish:
+            case SymmetricKeyAlgorithmTag.Safer:
+            case SymmetricKeyAlgorithmTag.Aes128:
+            case SymmetricKeyAlgorithmTag.Camellia128:
+                keySize = 128;
+                break;
+            case SymmetricKeyAlgorithmTag.TripleDes:
+            case SymmetricKeyAlgorithmTag.Aes192:
+            case SymmetricKeyAlgorithmTag.Camellia192:
+                keySize = 192;
+                break;
+            case SymmetricKeyAlgorithmTag.Aes256:
+            case SymmetricKeyAlgorithmTag.Twofish:
+            case SymmetricKeyAlgorithmTag.Camellia256:
+                keySize = 256;
+                break;
+            default:
+                throw new PgpException("unknown symmetric algorithm: " + algorithm);
             }
 
 			return keySize;
@@ -323,47 +319,47 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
 					switch (s2k.Type)
                     {
-						case S2k.Simple:
-							digest.BlockUpdate(pBytes, 0, pBytes.Length);
-							break;
-						case S2k.Salted:
-							digest.BlockUpdate(iv, 0, iv.Length);
-							digest.BlockUpdate(pBytes, 0, pBytes.Length);
-							break;
-						case S2k.SaltedAndIterated:
-							long count = s2k.IterationCount;
-							digest.BlockUpdate(iv, 0, iv.Length);
-							digest.BlockUpdate(pBytes, 0, pBytes.Length);
-
-							count -= iv.Length + pBytes.Length;
-
-							while (count > 0)
+					case S2k.Simple:
+						digest.BlockUpdate(pBytes, 0, pBytes.Length);
+						break;
+					case S2k.Salted:
+						digest.BlockUpdate(iv, 0, iv.Length);
+						digest.BlockUpdate(pBytes, 0, pBytes.Length);
+						break;
+					case S2k.SaltedAndIterated:
+						long count = s2k.IterationCount;
+						digest.BlockUpdate(iv, 0, iv.Length);
+						digest.BlockUpdate(pBytes, 0, pBytes.Length);
+
+						count -= iv.Length + pBytes.Length;
+
+						while (count > 0)
+						{
+							if (count < iv.Length)
+							{
+								digest.BlockUpdate(iv, 0, (int)count);
+								break;
+							}
+							else
+							{
+								digest.BlockUpdate(iv, 0, iv.Length);
+								count -= iv.Length;
+							}
+
+							if (count < pBytes.Length)
+							{
+								digest.BlockUpdate(pBytes, 0, (int)count);
+								count = 0;
+							}
+							else
 							{
-								if (count < iv.Length)
-								{
-									digest.BlockUpdate(iv, 0, (int)count);
-									break;
-								}
-								else
-								{
-									digest.BlockUpdate(iv, 0, iv.Length);
-									count -= iv.Length;
-								}
-
-								if (count < pBytes.Length)
-								{
-									digest.BlockUpdate(pBytes, 0, (int)count);
-									count = 0;
-								}
-								else
-								{
-									digest.BlockUpdate(pBytes, 0, pBytes.Length);
-									count -= pBytes.Length;
-								}
+								digest.BlockUpdate(pBytes, 0, pBytes.Length);
+								count -= pBytes.Length;
 							}
-							break;
-						default:
-							throw new PgpException("unknown S2k type: " + s2k.Type);
+						}
+						break;
+					default:
+						throw new PgpException("unknown S2k type: " + s2k.Type);
                     }
                 }
                 else
diff --git a/crypto/src/openpgp/PgpV3SignatureGenerator.cs b/crypto/src/openpgp/PgpV3SignatureGenerator.cs
index 324dbd768..03dd8795d 100644
--- a/crypto/src/openpgp/PgpV3SignatureGenerator.cs
+++ b/crypto/src/openpgp/PgpV3SignatureGenerator.cs
@@ -47,20 +47,23 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
             AsymmetricKeyParameter key = privKey.Key;
 
-            if (sig == null)
-            {
-                this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key);
-            }
+            this.sig = PgpUtilities.CreateSigner(keyAlgorithm, hashAlgorithm, key);
 
             try
             {
-				ICipherParameters cp = key;
-				if (random != null)
-				{
-					cp = new ParametersWithRandom(cp, random);
-				}
+                ICipherParameters cp = key;
+
+                // TODO Ask SignerUtilities whether random is permitted?
+                if (keyAlgorithm == PublicKeyAlgorithmTag.EdDsa)
+                {
+                    // EdDSA signers don't expect a SecureRandom
+                }
+                else
+                {
+                    cp = ParameterUtilities.WithRandom(cp, random);
+                }
 
-				sig.Init(true, cp);
+                sig.Init(true, cp);
             }
             catch (InvalidKeyException e)
             {
diff --git a/crypto/src/openssl/MiscPemGenerator.cs b/crypto/src/openssl/MiscPemGenerator.cs
index 0e918f793..fe2583063 100644
--- a/crypto/src/openssl/MiscPemGenerator.cs
+++ b/crypto/src/openssl/MiscPemGenerator.cs
@@ -32,15 +32,11 @@ namespace Org.BouncyCastle.OpenSsl
         private readonly SecureRandom random;
 
         public MiscPemGenerator(object obj)
+            : this(obj, null, null, null)
         {
-            this.obj = obj;
         }
 
-        public MiscPemGenerator(
-            object			obj,
-            string			algorithm,
-            char[]			password,
-            SecureRandom	random)
+        public MiscPemGenerator(object obj, string algorithm, char[] password, SecureRandom random)
         {
             this.obj = obj;
             this.algorithm = algorithm;
@@ -54,9 +50,7 @@ namespace Org.BouncyCastle.OpenSsl
                 throw new ArgumentNullException("obj");
 
             if (obj is AsymmetricCipherKeyPair keyPair)
-            {
                 return CreatePemObject(keyPair.Private);
-            }
 
             string type;
             byte[] encoding;
diff --git a/crypto/src/openssl/PEMReader.cs b/crypto/src/openssl/PEMReader.cs
index d2354dbe3..a2c4fd1d6 100644
--- a/crypto/src/openssl/PEMReader.cs
+++ b/crypto/src/openssl/PEMReader.cs
@@ -367,23 +367,17 @@ namespace Org.BouncyCastle.OpenSsl
             }
         }
 
-        // TODO Add an equivalent class for ECNamedCurveParameterSpec?
-        //private ECNamedCurveParameterSpec ReadECParameters(
-//		private X9ECParameters ReadECParameters(PemObject pemObject)
-//		{
-//			DerObjectIdentifier oid = (DerObjectIdentifier)Asn1Object.FromByteArray(pemObject.Content);
-//
-//			//return ECNamedCurveTable.getParameterSpec(oid.Id);
-//			return GetCurveParameters(oid.Id);
-//		}
-
-        private static X9ECParameters GetCurveParameters(string name)
-        {
-            X9ECParameters ecP = ECKeyPairGenerator.FindECCurveByName(name);
-            if (ecP == null)
-                throw new Exception("unknown curve name: " + name);
-
-            return ecP;
-        }
+        //private X9ECParameters ReadECParameters(PemObject pemObject)
+        //{
+        //    DerObjectIdentifier oid = (DerObjectIdentifier)Asn1Object.FromByteArray(pemObject.Content);
+
+        //    //return ECNamedCurveTable.getParameterSpec(oid.Id);
+        //    return GetCurveParameters(oid.Id);
+        //}
+
+        //private static X9ECParameters GetCurveParameters(string name)
+        //{
+        //    return ECKeyPairGenerator.FindECCurveByName(name) ?? throw new Exception("unknown curve name: " + name);
+        //}
     }
 }
diff --git a/crypto/src/openssl/PEMWriter.cs b/crypto/src/openssl/PEMWriter.cs
index 043869cc3..58b6156d5 100644
--- a/crypto/src/openssl/PEMWriter.cs
+++ b/crypto/src/openssl/PEMWriter.cs
@@ -17,26 +17,22 @@ namespace Org.BouncyCastle.OpenSsl
 
 		public void WriteObject(object obj) 
 		{
-			try
-			{
-				base.WriteObject(new MiscPemGenerator(obj));
-			}
-			catch (PemGenerationException e)
-			{
-				if (e.InnerException is IOException inner)
-					throw inner;
-
-				throw e;
-			}
+			WriteObject(obj, null, null, null);
 		}
 
-		public void WriteObject(
-			object			obj,
-			string			algorithm,
-			char[]			password,
-			SecureRandom	random)
+		public void WriteObject(object obj, string algorithm, char[] password, SecureRandom random)
 		{
-			base.WriteObject(new MiscPemGenerator(obj, algorithm, password, random));
+            try
+            {
+                base.WriteObject(new MiscPemGenerator(obj, algorithm, password, random));
+            }
+            catch (PemGenerationException e)
+            {
+                if (e.InnerException is IOException inner)
+                    throw inner;
+
+                throw e;
+            }
 		}
 	}
 }
diff --git a/crypto/src/pkix/CertStatus.cs b/crypto/src/pkix/CertStatus.cs
index aff1b1857..4fe98998c 100644
--- a/crypto/src/pkix/CertStatus.cs
+++ b/crypto/src/pkix/CertStatus.cs
@@ -15,7 +15,7 @@ namespace Org.BouncyCastle.Pkix
         /// <summary>
         /// Returns the revocationDate.
         /// </summary>
-         public DateTime? RevocationDate
+        public DateTime? RevocationDate
         {
             get { return revocationDate; }
             set { this.revocationDate = value; }
diff --git a/crypto/src/pkix/PkixCertPath.cs b/crypto/src/pkix/PkixCertPath.cs
index 7f04b1b63..a2ea3074d 100644
--- a/crypto/src/pkix/PkixCertPath.cs
+++ b/crypto/src/pkix/PkixCertPath.cs
@@ -3,13 +3,13 @@ using System.Collections.Generic;
 using System.IO;
 
 using Org.BouncyCastle.Asn1;
-using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.Pkcs;
-using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.OpenSsl;
 using Org.BouncyCastle.Security.Certificates;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.X509;
 
 namespace Org.BouncyCastle.Pkix
 {
@@ -78,7 +78,7 @@ namespace Org.BouncyCastle.Pkix
 	public class PkixCertPath
 //		: CertPath
 	{
-		internal static readonly List<string> m_encodings = new List<string>{ "PkiPath", "PEM", "PKCS7" };
+		private static readonly List<string> EncodingNames = new List<string>{ "PkiPath", "PEM", "PKCS7" };
 
         private readonly IList<X509Certificate> m_certificates;
 
@@ -186,31 +186,24 @@ namespace Org.BouncyCastle.Pkix
 		 **/
 		public PkixCertPath(Stream inStream, string encoding)
 		{
-            //string upper = Platform.ToUpperInvariant(encoding);
-
             IList<X509Certificate> certs;
 			try
 			{
 				if (Platform.EqualsIgnoreCase("PkiPath", encoding))
 				{
 					Asn1InputStream derInStream = new Asn1InputStream(inStream);
-					Asn1Object derObject = derInStream.ReadObject();
-					if (!(derObject is Asn1Sequence))
-					{
-						throw new CertificateException(
+                    if (!(derInStream.ReadObject() is Asn1Sequence asn1Sequence))
+                    {
+                        throw new CertificateException(
 							"input stream does not contain a ASN1 SEQUENCE while reading PkiPath encoded data to load CertPath");
 					}
 
-					certs = new List<X509Certificate>();
+					var certArray = asn1Sequence.MapElements(
+						element => new X509Certificate(X509CertificateStructure.GetInstance(element.ToAsn1Object())));
 
-                    foreach (Asn1Encodable ae in (Asn1Sequence)derObject)
-                    {
-                        byte[] derBytes = ae.GetEncoded(Asn1Encodable.Der);
-                        Stream certInStream = new MemoryStream(derBytes, false);
+					Array.Reverse(certArray);
 
-                        // TODO Is inserting at the front important (list will be sorted later anyway)?
-                        certs.Insert(0, new X509CertificateParser().ReadCertificate(certInStream));
-					}
+					certs = new List<X509Certificate>(certArray);
 				}
 				else if (Platform.EqualsIgnoreCase("PEM", encoding) ||
 					     Platform.EqualsIgnoreCase("PKCS7", encoding))
@@ -242,7 +235,7 @@ namespace Org.BouncyCastle.Pkix
 		 **/
 		public virtual IEnumerable<string> Encodings
 		{
-            get { return CollectionUtilities.Proxy(m_encodings); }
+            get { return CollectionUtilities.Proxy(EncodingNames); }
 		}
 
 		/**
@@ -304,7 +297,7 @@ namespace Org.BouncyCastle.Pkix
 		 **/
 		public virtual byte[] GetEncoded()
 		{
-			return GetEncoded(m_encodings[0]);
+			return GetEncoded(EncodingNames[0]);
 		}
 
 		/**
diff --git a/crypto/src/pkix/PkixCertPathBuilderResult.cs b/crypto/src/pkix/PkixCertPathBuilderResult.cs
index a9dfc6722..6494f9b7b 100644
--- a/crypto/src/pkix/PkixCertPathBuilderResult.cs
+++ b/crypto/src/pkix/PkixCertPathBuilderResult.cs
@@ -2,32 +2,22 @@ using System;
 using System.Text;
 
 using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Pkix;
 
 namespace Org.BouncyCastle.Pkix
 {
-	/// <summary>
-	/// Summary description for PkixCertPathBuilderResult.
-	/// </summary>
 	public class PkixCertPathBuilderResult
 		: PkixCertPathValidatorResult//, ICertPathBuilderResult
 	{
 		private PkixCertPath certPath;
-		
-		public PkixCertPathBuilderResult(
-			PkixCertPath			certPath,
-			TrustAnchor				trustAnchor,
-			PkixPolicyNode			policyTree,
-			AsymmetricKeyParameter	subjectPublicKey)
-			: base(trustAnchor, policyTree, subjectPublicKey)
-		{			
-			if (certPath == null)
-				throw new ArgumentNullException("certPath");
 
-			this.certPath = certPath;
-		}
+        public PkixCertPathBuilderResult(PkixCertPath certPath, TrustAnchor trustAnchor, PkixPolicyNode policyTree,
+            AsymmetricKeyParameter subjectPublicKey)
+            : base(trustAnchor, policyTree, subjectPublicKey)
+		{			
+			this.certPath = certPath ?? throw new ArgumentNullException(nameof(certPath));
+        }
 
-		public PkixCertPath CertPath
+        public PkixCertPath CertPath
 		{
             get { return certPath; }
 		}
diff --git a/crypto/src/pkix/PkixCertPathChecker.cs b/crypto/src/pkix/PkixCertPathChecker.cs
index 08b7e3d41..856053d11 100644
--- a/crypto/src/pkix/PkixCertPathChecker.cs
+++ b/crypto/src/pkix/PkixCertPathChecker.cs
@@ -32,7 +32,6 @@ namespace Org.BouncyCastle.Pkix
          *                checking must be supported
          */
         public abstract void Init(bool forward);
-        //throws CertPathValidatorException;
 
         /**
          * Indicates if forward checking is supported. Forward checking refers to
@@ -82,7 +81,6 @@ namespace Org.BouncyCastle.Pkix
          *                if the specified certificate does not pass the check
          */
         public abstract void Check(X509Certificate cert, ISet<string> unresolvedCritExts);
-        //throws CertPathValidatorException;
 
         /**
          * Returns a clone of this object. Calls the <code>Object.clone()</code>
diff --git a/crypto/src/pkix/PkixCertPathValidator.cs b/crypto/src/pkix/PkixCertPathValidator.cs
index 6fe3fd903..0c585f520 100644
--- a/crypto/src/pkix/PkixCertPathValidator.cs
+++ b/crypto/src/pkix/PkixCertPathValidator.cs
@@ -212,7 +212,7 @@ namespace Org.BouncyCastle.Pkix
             //
 
 			var targetConstraints = paramsPkix.GetTargetConstraintsCert();
-            if (targetConstraints != null && !targetConstraints.Match((X509Certificate)certs[0]))
+            if (targetConstraints != null && !targetConstraints.Match(certs[0]))
             {
                 throw new PkixCertPathValidatorException(
 					"Target certificate in certification path does not match targetConstraints.", null, 0);
@@ -222,7 +222,7 @@ namespace Org.BouncyCastle.Pkix
             // initialize CertPathChecker's
             //
             var certPathCheckers = paramsPkix.GetCertPathCheckers();
-            foreach (PkixCertPathChecker certPathChecker in certPathCheckers)
+            foreach (var certPathChecker in certPathCheckers)
             {
                 certPathChecker.Init(false);
             }
diff --git a/crypto/src/pkix/PkixCertPathValidatorException.cs b/crypto/src/pkix/PkixCertPathValidatorException.cs
index 3c9dbe349..6f9812a49 100644
--- a/crypto/src/pkix/PkixCertPathValidatorException.cs
+++ b/crypto/src/pkix/PkixCertPathValidatorException.cs
@@ -13,11 +13,10 @@ namespace Org.BouncyCastle.Pkix
 	 * exceptions. The {@link #getCause getCause} method returns the throwable, 
 	 * if any, that caused this exception to be thrown. <br />
 	 * <br />
-	 * A <code>CertPathValidatorException</code> may also include the 
-	 * certification path that was being validated when the exception was thrown 
-	 * and the index of the certificate in the certification path that caused the 
-	 * exception to be thrown. Use the {@link #getCertPath getCertPath} and
-	 * {@link #getIndex getIndex} methods to retrieve this information.<br />
+	 * A <code>CertPathValidatorException</code> may also include the index of
+	 * the certificate in the certification path that caused the 
+	 * exception to be thrown. Use the {@link #Index Index} property to retrieve
+	 * this information.<br />
 	 * <br />
 	 * <b>Concurrent Access</b><br />
 	 * <br />
diff --git a/crypto/src/pkix/PkixCertPathValidatorResult.cs b/crypto/src/pkix/PkixCertPathValidatorResult.cs
index 07cb350c1..b89ec9d53 100644
--- a/crypto/src/pkix/PkixCertPathValidatorResult.cs
+++ b/crypto/src/pkix/PkixCertPathValidatorResult.cs
@@ -2,13 +2,9 @@ using System;
 using System.Text;
 
 using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pkix
 {
-	/// <summary>
-	/// Summary description for PkixCertPathValidatorResult.
-	/// </summary>
 	public class PkixCertPathValidatorResult
 		//: ICertPathValidatorResult
 	{
@@ -34,15 +30,10 @@ namespace Org.BouncyCastle.Pkix
 		public PkixCertPathValidatorResult(TrustAnchor trustAnchor, PkixPolicyNode policyTree,
 			AsymmetricKeyParameter subjectPublicKey)
 		{
-            if (trustAnchor == null)
-                throw new ArgumentNullException(nameof(trustAnchor));
-            if (subjectPublicKey == null)
-				throw new ArgumentNullException(nameof(subjectPublicKey));
-
-			this.trustAnchor = trustAnchor;
-			this.policyTree = policyTree;
-			this.subjectPublicKey = subjectPublicKey;
-		}
+			this.trustAnchor = trustAnchor ?? throw new ArgumentNullException(nameof(trustAnchor));
+            this.policyTree = policyTree;
+			this.subjectPublicKey = subjectPublicKey ?? throw new ArgumentNullException(nameof(subjectPublicKey));
+        }
 
 		public object Clone()
 		{
diff --git a/crypto/src/pkix/PkixCertPathValidatorUtilities.cs b/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
index 88affe53d..efbf855ff 100644
--- a/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
+++ b/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
@@ -609,37 +609,33 @@ namespace Org.BouncyCastle.Pkix
 			throw new PkixCertPathValidatorException("DSA parameters cannot be inherited from previous certificate.");
 		}
 
-		internal static DateTime GetValidCertDateFromValidityModel(
-			PkixParameters	paramsPkix,
-			PkixCertPath	certPath,
-			int				index)
+		internal static DateTime GetValidCertDateFromValidityModel(PkixParameters paramsPkix, PkixCertPath certPath,
+			int index)
 		{
-			if (paramsPkix.ValidityModel != PkixParameters.ChainValidityModel)
+			if (PkixParameters.ChainValidityModel != paramsPkix.ValidityModel || index <= 0)
 			{
+				// use given signing/encryption/... time (or current date)
 				return GetValidDate(paramsPkix);
 			}
 
-			// if end cert use given signing/encryption/... time
-			if (index <= 0)
-			{
-				return GetValidDate(paramsPkix);
-				// else use time when previous cert was created
-			}
-
-			var cert = certPath.Certificates[index - 1];
+			var issuedCert = certPath.Certificates[index - 1];
 
 			if (index - 1 == 0)
 			{
-                Asn1GeneralizedTime dateOfCertgen;
+				// use time when cert was issued, if available
+                Asn1GeneralizedTime dateOfCertgen = null;
 				try
 				{
-					Asn1OctetString extVal = cert.GetExtensionValue(IsisMttObjectIdentifiers.IdIsisMttATDateOfCertGen);
-					dateOfCertgen = Asn1GeneralizedTime.GetInstance(extVal);
-				}
-				catch (ArgumentException)
+					byte[] extBytes = issuedCert.GetExtensionValue(IsisMttObjectIdentifiers.IdIsisMttATDateOfCertGen)
+						?.GetOctets();
+					if (extBytes != null)
+					{
+                        dateOfCertgen = Asn1GeneralizedTime.GetInstance(extBytes);
+                    }
+                }
+				catch (ArgumentException e)
 				{
-					throw new Exception(
-						"Date of cert gen extension could not be read.");
+					throw new Exception("Date of cert gen extension could not be read.", e);
 				}
 				if (dateOfCertgen != null)
 				{
@@ -649,14 +645,12 @@ namespace Org.BouncyCastle.Pkix
 					}
 					catch (ArgumentException e)
 					{
-						throw new Exception(
-							"Date from date of cert gen extension could not be parsed.",
-							e);
+						throw new Exception("Date from date of cert gen extension could not be parsed.", e);
 					}
 				}
 			}
 
-			return cert.NotBefore;
+			return issuedCert.NotBefore;
 		}
 
 		/**
@@ -683,7 +677,7 @@ namespace Org.BouncyCastle.Pkix
 			DistributionPoint		dp,
 			ICollection<X509Name>	issuerPrincipals,
 			X509CrlStoreSelector	selector,
-			PkixParameters			pkixParams)
+			PkixParameters			pkixParameters)
 		{
             var issuers = new List<X509Name>();
 			// indirect CRL
@@ -784,7 +778,7 @@ namespace Org.BouncyCastle.Pkix
 		 *             or no CRLs are found.
 		 */
 		internal static ISet<X509Crl> GetCompleteCrls(DistributionPoint dp, object certObj, DateTime currentDate,
-			PkixParameters paramsPKIX)
+			PkixParameters pkixParameters)
 		{
 			var certObjIssuer = GetIssuerPrincipal(certObj);
 
@@ -794,7 +788,7 @@ namespace Org.BouncyCastle.Pkix
 				var issuers = new HashSet<X509Name>();
 				issuers.Add(certObjIssuer);
 
-				GetCrlIssuersFromDistributionPoint(dp, issuers, crlselect, paramsPKIX);
+				GetCrlIssuersFromDistributionPoint(dp, issuers, crlselect, pkixParameters);
 			}
 			catch (Exception e)
 			{
@@ -814,7 +808,7 @@ namespace Org.BouncyCastle.Pkix
 
 			crlselect.CompleteCrlEnabled = true;
 
-			ISet<X509Crl> crls = CrlUtilities.FindCrls(crlselect, paramsPKIX, currentDate);
+			ISet<X509Crl> crls = CrlUtilities.FindCrls(crlselect, pkixParameters, currentDate);
 			if (crls.Count < 1)
 				throw new Exception("No CRLs found for issuer \"" + certObjIssuer + "\"");
 
@@ -831,10 +825,8 @@ namespace Org.BouncyCastle.Pkix
 		 * @throws Exception if an exception occurs while picking the delta
 		 *             CRLs.
 		 */
-		internal static ISet<X509Crl> GetDeltaCrls(
-			DateTime		currentDate,
-			PkixParameters	paramsPKIX,
-			X509Crl			completeCRL)
+		internal static ISet<X509Crl> GetDeltaCrls(DateTime currentDate, PkixParameters pkixParameters,
+			X509Crl completeCRL)
 		{
 			X509CrlStoreSelector deltaSelect = new X509CrlStoreSelector();
 
@@ -896,7 +888,7 @@ namespace Org.BouncyCastle.Pkix
 			deltaSelect.MaxBaseCrlNumber = completeCRLNumber;
 
 			// find delta CRLs
-			ISet<X509Crl> temp = CrlUtilities.FindCrls(deltaSelect, paramsPKIX, currentDate);
+			ISet<X509Crl> temp = CrlUtilities.FindCrls(deltaSelect, pkixParameters, currentDate);
 
 			var result = new HashSet<X509Crl>();
 
@@ -981,8 +973,8 @@ namespace Org.BouncyCastle.Pkix
 			return false;
 		}
 
-		internal static void ProcessCertD1ii(int index, IList<PkixPolicyNode>[] policyNodes,
-			DerObjectIdentifier _poid, ISet<PolicyQualifierInfo> _pq)
+		internal static void ProcessCertD1ii(int index, IList<PkixPolicyNode>[] policyNodes, DerObjectIdentifier _poid,
+			ISet<PolicyQualifierInfo> _pq)
 		{
 			foreach (var _node in policyNodes[index - 1])
 			{
@@ -1013,9 +1005,8 @@ namespace Org.BouncyCastle.Pkix
 		* @exception Exception
 		*                if an error occurs.
 		*/
-		internal static HashSet<X509Certificate> FindIssuerCerts(
-			X509Certificate			cert,
-			PkixBuilderParameters	pkixParams)
+		internal static HashSet<X509Certificate> FindIssuerCerts(X509Certificate cert,
+			PkixBuilderParameters pkixBuilderParameters)
 		{
 			X509CertStoreSelector certSelector = new X509CertStoreSelector();
 			try
@@ -1031,7 +1022,7 @@ namespace Org.BouncyCastle.Pkix
 			var certs = new HashSet<X509Certificate>();
 			try
 			{
-				CollectionUtilities.CollectMatches(certs, certSelector, pkixParams.GetStoresCert());
+				CollectionUtilities.CollectMatches(certs, certSelector, pkixBuilderParameters.GetStoresCert());
 			}
 			catch (Exception e)
 			{
diff --git a/crypto/src/pkix/PkixCrlUtilities.cs b/crypto/src/pkix/PkixCrlUtilities.cs
index facbf56c2..3451b8ac0 100644
--- a/crypto/src/pkix/PkixCrlUtilities.cs
+++ b/crypto/src/pkix/PkixCrlUtilities.cs
@@ -9,22 +9,27 @@ namespace Org.BouncyCastle.Pkix
 {
 	public class PkixCrlUtilities
 	{
-		public virtual ISet<X509Crl> FindCrls(X509CrlStoreSelector crlSelector, PkixParameters paramsPkix,
+        // TODO bc-fips-csharp implements this for ISelector<X509Crl>, using optional ICheckingCertificate
+        public virtual ISet<X509Crl> FindCrls(X509CrlStoreSelector crlSelector, PkixParameters paramsPkix)
+        {
+            // get complete CRL(s)
+            try
+            {
+                return FindCrls(crlSelector, paramsPkix.GetStoresCrl());
+            }
+            catch (Exception e)
+            {
+                throw new Exception("Exception obtaining complete CRLs.", e);
+            }
+        }
+
+        // TODO bc-fips-csharp implements this for ISelector<X509Crl>, using optional ICheckingCertificate
+        public virtual ISet<X509Crl> FindCrls(X509CrlStoreSelector crlSelector, PkixParameters paramsPkix,
 			DateTime currentDate)
 		{
-			HashSet<X509Crl> initialSet;
-
-			// get complete CRL(s)
-			try
-			{
-				initialSet = FindCrls(crlSelector, paramsPkix.GetStoresCrl());
-			}
-			catch (Exception e)
-			{
-				throw new Exception("Exception obtaining complete CRLs.", e);
-			}
+            var initialSet = FindCrls(crlSelector, paramsPkix);
 
-			var finalSet = new HashSet<X509Crl>();
+            var finalSet = new HashSet<X509Crl>();
 			DateTime validityDate = currentDate;
 
 			if (paramsPkix.Date != null)
@@ -32,15 +37,15 @@ namespace Org.BouncyCastle.Pkix
 				validityDate = paramsPkix.Date.Value;
 			}
 
-			// based on RFC 5280 6.3.3
-			foreach (X509Crl crl in initialSet)
+            X509Certificate cert = crlSelector.CertificateChecking;
+
+            // based on RFC 5280 6.3.3
+            foreach (X509Crl crl in initialSet)
 			{
                 DateTime? nextUpdate = crl.NextUpdate;
 
                 if (null == nextUpdate || nextUpdate.Value.CompareTo(validityDate) > 0)
 				{
-					X509Certificate cert = crlSelector.CertificateChecking;
-
                     if (null == cert || crl.ThisUpdate.CompareTo(cert.NotAfter) < 0)
                     {
                         finalSet.Add(crl);
@@ -51,19 +56,6 @@ namespace Org.BouncyCastle.Pkix
 			return finalSet;
 		}
 
-		public virtual ISet<X509Crl> FindCrls(X509CrlStoreSelector crlSelector, PkixParameters paramsPkix)
-		{
-			// get complete CRL(s)
-			try
-			{
-				return FindCrls(crlSelector, paramsPkix.GetStoresCrl());
-			}
-			catch (Exception e)
-			{
-				throw new Exception("Exception obtaining complete CRLs.", e);
-			}
-		}
-
 		/// <summary>
 		/// crl checking
 		/// Return a Collection of all CRLs found in the X509Store's that are
@@ -76,7 +68,7 @@ namespace Org.BouncyCastle.Pkix
 		/// <returns>a Collection of all found {@link X509CRL X509CRL} objects. May be
 		/// empty but never <code>null</code>.
 		/// </returns>
-		private HashSet<X509Crl> FindCrls(ISelector<X509Crl> crlSelector, IList<IStore<X509Crl>> crlStores)
+		private HashSet<X509Crl> FindCrls(ISelector<X509Crl> crlSelector, IEnumerable<IStore<X509Crl>> crlStores)
 		{
             var crls = new HashSet<X509Crl>();
 
diff --git a/crypto/src/pkix/PkixNameConstraintValidator.cs b/crypto/src/pkix/PkixNameConstraintValidator.cs
index ad59702c5..7a9e3f45e 100644
--- a/crypto/src/pkix/PkixNameConstraintValidator.cs
+++ b/crypto/src/pkix/PkixNameConstraintValidator.cs
@@ -1365,6 +1365,13 @@ namespace Org.BouncyCastle.Pkix
             return sub;
         }
 
+        /// <exception cref="PkixNameConstraintValidatorException"/>
+        [Obsolete("Use 'CheckPermittedName' instead")]
+        public void checkPermitted(GeneralName name)
+        {
+            CheckPermittedName(name);
+        }
+
         /**
          * Checks if the given GeneralName is in the permitted ISet.
          *
@@ -1372,8 +1379,8 @@ namespace Org.BouncyCastle.Pkix
          * @throws PkixNameConstraintValidatorException
          *          If the <code>name</code>
          */
-        public void checkPermitted(GeneralName name)
-        //throws PkixNameConstraintValidatorException
+        /// <exception cref="PkixNameConstraintValidatorException"/>
+        public void CheckPermittedName(GeneralName name)
         {
             switch (name.TagNo)
             {
@@ -1398,6 +1405,13 @@ namespace Org.BouncyCastle.Pkix
             }
         }
 
+        /// <exception cref="PkixNameConstraintValidatorException"/>
+        [Obsolete("Use 'CheckExcludedName' instead")]
+        public void checkExcluded(GeneralName name)
+        {
+            CheckExcludedName(name);
+        }
+
         /**
          * Check if the given GeneralName is contained in the excluded ISet.
          *
@@ -1406,8 +1420,8 @@ namespace Org.BouncyCastle.Pkix
          *          If the <code>name</code> is
          *          excluded.
          */
-        public void checkExcluded(GeneralName name)
-        //throws PkixNameConstraintValidatorException
+        /// <exception cref="PkixNameConstraintValidatorException"/>
+        public void CheckExcludedName(GeneralName name)
         {
             switch (name.TagNo)
             {
@@ -1792,7 +1806,8 @@ namespace Org.BouncyCastle.Pkix
 
         public override string ToString()
         {
-            StringBuilder sb = new StringBuilder("permitted:\n");
+            StringBuilder sb = new StringBuilder("permitted:");
+            sb.AppendLine();
             if (permittedSubtreesDN != null)
             {
                 Append(sb, "DN", permittedSubtreesDN);
@@ -1817,7 +1832,7 @@ namespace Org.BouncyCastle.Pkix
             {
                 Append(sb, "OtherName", StringifyOtherNameCollection(permittedSubtreesOtherName));
             }
-            sb.Append("excluded:\n");
+            sb.AppendLine("excluded:");
             if (excludedSubtreesDN.Count > 0)
             {
                 Append(sb, "DN", excludedSubtreesDN);
diff --git a/crypto/src/pkix/PkixParameters.cs b/crypto/src/pkix/PkixParameters.cs
index 89124f2e9..192a78780 100644
--- a/crypto/src/pkix/PkixParameters.cs
+++ b/crypto/src/pkix/PkixParameters.cs
@@ -249,9 +249,11 @@ namespace Org.BouncyCastle.Pkix
 		* @see X509CertStoreSelector
 		* @see X509AttributeCertStoreSelector
 		*/
-		public virtual void SetTargetConstraintsAttrCert(ISelector<X509V2AttributeCertificate> targetConstraintsAttrCert)
+		public virtual void SetTargetConstraintsAttrCert(
+			ISelector<X509V2AttributeCertificate> targetConstraintsAttrCert)
 		{
-			this.m_targetConstraintsAttrCert = (ISelector<X509V2AttributeCertificate>)targetConstraintsAttrCert?.Clone();
+			this.m_targetConstraintsAttrCert = (ISelector<X509V2AttributeCertificate>)
+				targetConstraintsAttrCert?.Clone();
 		}
 
 		/**
@@ -542,19 +544,25 @@ namespace Org.BouncyCastle.Pkix
 			return new List<IStore<X509Crl>>(m_storesCrl);
 		}
 
+		[Obsolete("Use 'SetStoresAttrCert' instead")]
 		public virtual void SetAttrStoresCert(IList<IStore<X509V2AttributeCertificate>> storesAttrCert)
 		{
-			if (storesAttrCert == null)
-			{
-				m_storesAttrCert = new List<IStore<X509V2AttributeCertificate>>();
-			}
-			else
-			{
-				m_storesAttrCert = new List<IStore<X509V2AttributeCertificate>>(storesAttrCert);
-			}
+			SetStoresAttrCert(storesAttrCert);
 		}
 
-		public virtual void SetStoresCert(IList<IStore<X509Certificate>> storesCert)
+        public virtual void SetStoresAttrCert(IList<IStore<X509V2AttributeCertificate>> storesAttrCert)
+        {
+            if (storesAttrCert == null)
+            {
+                m_storesAttrCert = new List<IStore<X509V2AttributeCertificate>>();
+            }
+            else
+            {
+                m_storesAttrCert = new List<IStore<X509V2AttributeCertificate>>(storesAttrCert);
+            }
+        }
+
+        public virtual void SetStoresCert(IList<IStore<X509Certificate>> storesCert)
 		{
 			if (storesCert == null)
 			{
@@ -619,8 +627,7 @@ namespace Org.BouncyCastle.Pkix
 		*
 		* @param enabled <code>true</code> if additional stores are used.
 		*/
-		public virtual void SetAdditionalLocationsEnabled(
-			bool enabled)
+		public virtual void SetAdditionalLocationsEnabled(bool enabled)
 		{
 			additionalLocationsEnabled = enabled;
 		}
diff --git a/crypto/src/pkix/Rfc3280CertPathUtilities.cs b/crypto/src/pkix/Rfc3280CertPathUtilities.cs
index a61d83679..f1a85eb09 100644
--- a/crypto/src/pkix/Rfc3280CertPathUtilities.cs
+++ b/crypto/src/pkix/Rfc3280CertPathUtilities.cs
@@ -186,7 +186,7 @@ namespace Org.BouncyCastle.Pkix
 						}
 					}
 				}
-				BasicConstraints bc = null;
+				BasicConstraints bc;
 				try
 				{
 					bc = BasicConstraints.GetInstance(PkixCertPathValidatorUtilities.GetExtensionValue(
@@ -237,8 +237,8 @@ namespace Org.BouncyCastle.Pkix
 			if (!(PkixCertPathValidatorUtilities.IsSelfIssued(cert) && (i < n)))
 			{
 				X509Name principal = cert.SubjectDN;
-				Asn1Sequence dns;
 
+				Asn1Sequence dns;
 				try
 				{
 					dns = Asn1Sequence.GetInstance(principal.GetEncoded());
@@ -260,7 +260,7 @@ namespace Org.BouncyCastle.Pkix
 						"Subtree check for certificate subject failed.", e, index);
 				}
 
-				GeneralNames altName = null;
+				GeneralNames altName;
 				try
 				{
 					altName = GeneralNames.GetInstance(
@@ -278,8 +278,8 @@ namespace Org.BouncyCastle.Pkix
 					GeneralName emailAsGeneralName = new GeneralName(GeneralName.Rfc822Name, email);
 					try
 					{
-						nameConstraintValidator.checkPermitted(emailAsGeneralName);
-						nameConstraintValidator.checkExcluded(emailAsGeneralName);
+						nameConstraintValidator.CheckPermittedName(emailAsGeneralName);
+						nameConstraintValidator.CheckExcludedName(emailAsGeneralName);
 					}
 					catch (PkixNameConstraintValidatorException ex)
 					{
@@ -289,7 +289,7 @@ namespace Org.BouncyCastle.Pkix
 				}
 				if (altName != null)
 				{
-					GeneralName[] genNames = null;
+					GeneralName[] genNames;
 					try
 					{
 						genNames = altName.GetNames();
@@ -303,8 +303,8 @@ namespace Org.BouncyCastle.Pkix
 					{
 						try
 						{
-							nameConstraintValidator.checkPermitted(genName);
-							nameConstraintValidator.checkExcluded(genName);
+							nameConstraintValidator.CheckPermittedName(genName);
+							nameConstraintValidator.CheckExcludedName(genName);
 						}
 						catch (PkixNameConstraintValidatorException e)
 						{
@@ -772,7 +772,7 @@ namespace Org.BouncyCastle.Pkix
 			Exception lastException = null;
 			for (int i = 0; i < validCerts.Count; i++)
 			{
-				X509Certificate signCert = (X509Certificate)validCerts[i];
+				X509Certificate signCert = validCerts[i];
 				bool[] keyusage = signCert.GetKeyUsage();
 
 				if (keyusage != null && (keyusage.Length < 7 || !keyusage[CRL_SIGN]))
@@ -1228,11 +1228,11 @@ namespace Org.BouncyCastle.Pkix
 							{
 								if (ANY_POLICY.Equals(node.ValidPolicy))
 								{
-									Asn1Sequence policies = null;
+									Asn1Sequence policies;
 									try
 									{
-										policies = (Asn1Sequence)PkixCertPathValidatorUtilities.GetExtensionValue(cert,
-											X509Extensions.CertificatePolicies);
+                                        policies = Asn1Sequence.GetInstance(
+                                            PkixCertPathValidatorUtilities.GetExtensionValue(cert, X509Extensions.CertificatePolicies));
 									}
 									catch (Exception e)
 									{
@@ -1360,7 +1360,7 @@ namespace Org.BouncyCastle.Pkix
 				}
 			}
 
-			return new []{ completeSet, deltaSet };
+			return new ISet<X509Crl>[]{ completeSet, deltaSet };
 		}
 
 		internal static ISet<X509Crl> ProcessCrlA1i(
@@ -1570,7 +1570,7 @@ namespace Org.BouncyCastle.Pkix
 			//
 			// (i)
 			//
-			Asn1Sequence pc = null;
+			Asn1Sequence pc;
 			try
 			{
                 pc = Asn1Sequence.GetInstance(
@@ -1688,7 +1688,7 @@ namespace Org.BouncyCastle.Pkix
 			//
 			// (j)
 			//
-			DerInteger iap = null;
+			DerInteger iap;
 			try
 			{
 				iap = DerInteger.GetInstance(
@@ -1822,7 +1822,7 @@ namespace Org.BouncyCastle.Pkix
 
 		/// <exception cref="PkixCertPathValidatorException"/>
 		internal static void PrepareNextCertO(PkixCertPath certPath, int index, ISet<string> criticalExtensions,
-			IList<PkixCertPathChecker> checkers)
+			IEnumerable<PkixCertPathChecker> checkers)
 		{
 			var certs = certPath.Certificates;
 			X509Certificate cert = certs[index];
@@ -1891,7 +1891,6 @@ namespace Org.BouncyCastle.Pkix
 			return policyMapping;
 		}
 
-
 		internal static int PrepareNextCertH3(
 			PkixCertPath	certPath,
 			int				index,
@@ -1979,7 +1978,7 @@ namespace Org.BouncyCastle.Pkix
 		}
 
 		/// <exception cref="PkixCertPathValidatorException"/>
-		internal static void WrapupCertF(PkixCertPath certPath, int index, IList<PkixCertPathChecker> checkers,
+		internal static void WrapupCertF(PkixCertPath certPath, int index, IEnumerable<PkixCertPathChecker> checkers,
 			ISet<string> criticalExtensions)
 		{
 			var certs = certPath.Certificates;
@@ -2074,8 +2073,8 @@ namespace Org.BouncyCastle.Pkix
 								var node = nodes[k];
 								if (!node.HasChildren)
 								{
-									validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(
-										validPolicyTree, policyNodes, node);
+									validPolicyTree = PkixCertPathValidatorUtilities.RemovePolicyNode(validPolicyTree,
+										policyNodes, node);
 								}
 							}
 						}
@@ -2172,7 +2171,7 @@ namespace Org.BouncyCastle.Pkix
 			if (deltaCRL == null)
 				return;
 
-			IssuingDistributionPoint completeidp = null;
+			IssuingDistributionPoint completeidp;
 			try
 			{
 				completeidp = IssuingDistributionPoint.GetInstance(
@@ -2190,7 +2189,7 @@ namespace Org.BouncyCastle.Pkix
 					throw new Exception("Complete CRL issuer does not match delta CRL issuer.");
 
 				// (c) (2)
-				IssuingDistributionPoint deltaidp = null;
+				IssuingDistributionPoint deltaidp;
 				try
 				{
 					deltaidp = IssuingDistributionPoint.GetInstance(
@@ -2202,14 +2201,14 @@ namespace Org.BouncyCastle.Pkix
 						"Issuing distribution point extension from delta CRL could not be decoded.", e);
 				}
 
-				if (!Platform.Equals(completeidp, deltaidp))
+				if (!Objects.Equals(completeidp, deltaidp))
 				{
 					throw new Exception(
 						"Issuing distribution point extension from delta CRL and complete CRL does not match.");
 				}
 
 				// (c) (3)
-				Asn1Object completeKeyIdentifier = null;
+				Asn1Object completeKeyIdentifier;
 				try
 				{
 					completeKeyIdentifier = PkixCertPathValidatorUtilities.GetExtensionValue(
@@ -2221,7 +2220,7 @@ namespace Org.BouncyCastle.Pkix
 						"Authority key identifier extension could not be extracted from complete CRL.", e);
 				}
 
-				Asn1Object deltaKeyIdentifier = null;
+				Asn1Object deltaKeyIdentifier;
 				try
 				{
 					deltaKeyIdentifier = PkixCertPathValidatorUtilities.GetExtensionValue(
@@ -2283,7 +2282,7 @@ namespace Org.BouncyCastle.Pkix
 			//
 			// (e)
 			//
-			Asn1Sequence certPolicies = null;
+			Asn1Sequence certPolicies;
 			try
 			{
                 certPolicies = Asn1Sequence.GetInstance(
diff --git a/crypto/src/pkix/Rfc3281CertPathUtilities.cs b/crypto/src/pkix/Rfc3281CertPathUtilities.cs
index 4d12ad0c0..b0746bc83 100644
--- a/crypto/src/pkix/Rfc3281CertPathUtilities.cs
+++ b/crypto/src/pkix/Rfc3281CertPathUtilities.cs
@@ -253,26 +253,21 @@ namespace Org.BouncyCastle.Pkix
 			}
 		}
 
-		internal static void ProcessAttrCert4(
-			X509Certificate	acIssuerCert,
-			PkixParameters	pkixParams)
+		internal static void ProcessAttrCert4(X509Certificate acIssuerCert, PkixParameters pkixParams)
 		{
-			var set = pkixParams.GetTrustedACIssuers();
-			bool trusted = false;
-			foreach (TrustAnchor anchor in set)
+			foreach (var anchor in pkixParams.GetTrustedACIssuers())
 			{
                 var symbols = X509Name.RFC2253Symbols;
+
                 if (acIssuerCert.SubjectDN.ToString(false, symbols).Equals(anchor.CAName)
 					|| acIssuerCert.Equals(anchor.TrustedCert))
 				{
-					trusted = true;
+					// Trusted
+					return;
 				}
 			}
-			if (!trusted)
-			{
-				throw new PkixCertPathValidatorException(
-					"Attribute certificate issuer is not directly trusted.");
-			}
+
+			throw new PkixCertPathValidatorException("Attribute certificate issuer is not directly trusted.");
 		}
 
 		internal static void ProcessAttrCert3(
diff --git a/crypto/src/pqc/crypto/bike/BikeEngine.cs b/crypto/src/pqc/crypto/bike/BikeEngine.cs
index 896503c6d..a6371b726 100644
--- a/crypto/src/pqc/crypto/bike/BikeEngine.cs
+++ b/crypto/src/pqc/crypto/bike/BikeEngine.cs
@@ -252,8 +252,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
 
             // 3. Compute K
             byte[] wlist = FunctionH(mPrime);
-            if (Arrays.AreEqual(ePrimeBytes, 0, ePrimeBytes.Length,
-                    wlist, 0, ePrimeBytes.Length))
+            if (Arrays.AreEqual(ePrimeBytes, 0, ePrimeBytes.Length, wlist, 0, ePrimeBytes.Length))
             {
                 FunctionK(mPrime, c0, c1, k);
             }
diff --git a/crypto/src/pqc/crypto/bike/BikeUtilities.cs b/crypto/src/pqc/crypto/bike/BikeUtilities.cs
index 0e60bc7b0..40bd6d148 100644
--- a/crypto/src/pqc/crypto/bike/BikeUtilities.cs
+++ b/crypto/src/pqc/crypto/bike/BikeUtilities.cs
@@ -1,4 +1,6 @@
-using Org.BouncyCastle.Crypto.Utilities;
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Utilities;
 
@@ -70,36 +72,45 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
 
         internal static void GenerateRandomByteArray(byte[] res, uint size, uint weight, IXof digest)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Span<byte> buf = stackalloc byte[4];
+#else
             byte[] buf = new byte[4];
-            uint rand_pos;
+#endif
 
             for (int i = (int)weight - 1; i >= 0; i--)
             {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                digest.Output(buf);
+                ulong temp = Pack.LE_To_UInt32(buf);
+#else
                 digest.Output(buf, 0, 4);
-                ulong temp = (Pack.LE_To_UInt32(buf, 0)) & 0xFFFFFFFFUL;
-                temp = temp * (size - (uint)i) >> 32;
-                rand_pos = (uint) temp;
+                ulong temp = Pack.LE_To_UInt32(buf, 0);
+#endif
 
-                rand_pos += (uint)i;
+                temp = temp * (size - (uint)i) >> 32;
+                uint rand_pos = (uint)i + (uint)temp;
 
-                if(CHECK_BIT(res, rand_pos) != 0)
+                if (CheckBit(res, rand_pos) != 0)
                 {
                     rand_pos = (uint)i;
                 }
-                SET_BIT(res, rand_pos);
+                SetBit(res, rand_pos);
             }
         }
-        protected static uint CHECK_BIT(byte[] tmp, uint position)
+
+        private static uint CheckBit(byte[] tmp, uint position)
         {
             uint index = position / 8;
             uint pos = position % 8;
-            return (((uint)tmp[index] >> (int)(pos))  & 0x01);
+            return ((uint)tmp[index] >> (int)pos) & 1U;
         }
-        protected static void SET_BIT(byte[] tmp, uint position)
+
+        private static void SetBit(byte[] tmp, uint position)
         {
-            uint index = position/8;
-            uint pos = position%8;
-            tmp[index] |= (byte)(1UL << (int)pos);
+            uint index = position / 8;
+            uint pos = position % 8;
+            tmp[index] |= (byte)(1 << (int)pos);
         }
     }
 }
diff --git a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs
index 89519f134..d60c24222 100644
--- a/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs
+++ b/crypto/src/pqc/crypto/crystals/dilithium/DilithiumSigner.cs
@@ -20,10 +20,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium
         {
             if (forSigning)
             {
-                if (param is ParametersWithRandom)
+                if (param is ParametersWithRandom withRandom)
                 {
-                    privKey = (DilithiumPrivateKeyParameters)((ParametersWithRandom)param).Parameters;
-                    random = ((ParametersWithRandom)param).Random;
+                    privKey = (DilithiumPrivateKeyParameters)withRandom.Parameters;
+                    random = withRandom.Random;
                 }
                 else
                 {
@@ -33,9 +33,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium
             }
             else
             {
-                pubKey = (DilithiumPublicKeyParameters) param;
+                pubKey = (DilithiumPublicKeyParameters)param;
+                random = null;
             }
-
         }
 
         public byte[] GenerateSignature(byte[] message)
diff --git a/crypto/src/pqc/crypto/falcon/FalconNIST.cs b/crypto/src/pqc/crypto/falcon/FalconNIST.cs
index 0bc2adcad..8371fc3d3 100644
--- a/crypto/src/pqc/crypto/falcon/FalconNIST.cs
+++ b/crypto/src/pqc/crypto/falcon/FalconNIST.cs
@@ -17,17 +17,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon
         private int CRYPTO_PUBLICKEYBYTES;
         private int CRYPTO_SECRETKEYBYTES;
 
-        internal uint GetNonceLength() {
-            return this.noncelen;
-        }
-        internal uint GetLogn() {
-            return this.logn;
-        }
-        internal int GetCryptoBytes() {
-            return this.CRYPTO_BYTES;
-        }
+        internal uint NonceLength => this.noncelen;
+        internal uint LogN => this.logn;
+        internal int CryptoBytes => this.CRYPTO_BYTES;
 
-        internal FalconNist(SecureRandom random, uint logn, uint noncelen) {
+        internal FalconNist(SecureRandom random, uint logn, uint noncelen)
+        {
             this.logn = logn;
             this.codec = new FalconCodec();
             this.common = new FalconCommon();
diff --git a/crypto/src/pqc/crypto/falcon/FalconSigner.cs b/crypto/src/pqc/crypto/falcon/FalconSigner.cs
index abfbe3c17..7ad1385c7 100644
--- a/crypto/src/pqc/crypto/falcon/FalconSigner.cs
+++ b/crypto/src/pqc/crypto/falcon/FalconSigner.cs
@@ -2,6 +2,7 @@ using System;
 
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Falcon
 {
@@ -13,57 +14,53 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon
 
         public void Init(bool forSigning, ICipherParameters param)
         {
+            FalconParameters parameters;
+            SecureRandom random;
+
             if (forSigning)
             {
+                FalconPrivateKeyParameters skparam;
                 if (param is ParametersWithRandom withRandom)
                 {
-                    FalconPrivateKeyParameters skparam = (FalconPrivateKeyParameters)withRandom.Parameters;
-                    encodedkey = skparam.GetEncoded();
-                    nist = new FalconNist(
-                        withRandom.Random,
-                        (uint)skparam.Parameters.LogN,
-                        (uint)skparam.Parameters.NonceLength);
+                    skparam = (FalconPrivateKeyParameters)withRandom.Parameters;
+                    random = withRandom.Random;
                 }
                 else
                 {
-                    FalconPrivateKeyParameters skparam = (FalconPrivateKeyParameters)param;
-                    encodedkey = ((FalconPrivateKeyParameters)param).GetEncoded();
-                    nist = new FalconNist(
-                        CryptoServicesRegistrar.GetSecureRandom(),
-                        (uint)skparam.Parameters.LogN,
-                        (uint)skparam.Parameters.NonceLength);
+                    skparam = (FalconPrivateKeyParameters)param;
+                    random = CryptoServicesRegistrar.GetSecureRandom();
                 }
+                encodedkey = skparam.GetEncoded();
+                parameters = skparam.Parameters;
             }
             else
             {
                 FalconPublicKeyParameters pkparam = (FalconPublicKeyParameters)param;
+                random = null;
                 encodedkey = pkparam.GetEncoded();
-                nist = new FalconNist(
-                    CryptoServicesRegistrar.GetSecureRandom(),
-                    (uint)pkparam.Parameters.LogN,
-                    (uint)pkparam.Parameters.NonceLength);
+                parameters = pkparam.Parameters;
             }
+
+            nist = new FalconNist(random, (uint)parameters.LogN, (uint)parameters.NonceLength);
         }
 
         public byte[] GenerateSignature(byte[] message)
         {
-            byte[] sm = new byte[nist.GetCryptoBytes()];
+            byte[] sm = new byte[nist.CryptoBytes];
 
             return nist.crypto_sign(false, sm, message, 0, (uint)message.Length, encodedkey, 0);
         }
 
         public bool VerifySignature(byte[] message, byte[] signature)
         {
-            if (signature[0] != (byte)(0x30 + nist.GetLogn()))
-            {
+            if (signature[0] != (byte)(0x30 + nist.LogN))
                 return false;
-            }
-            byte[] nonce = new byte[nist.GetNonceLength()];
-            byte[] sig = new byte[signature.Length - nist.GetNonceLength() - 1];
-            Array.Copy(signature, 1, nonce, 0, nist.GetNonceLength());
-            Array.Copy(signature, nist.GetNonceLength() + 1, sig, 0, signature.Length - nist.GetNonceLength() - 1);
-            bool res = nist.crypto_sign_open(false, sig,nonce,message,encodedkey,0) == 0;
-            return res;
+
+            byte[] nonce = new byte[nist.NonceLength];
+            byte[] sig = new byte[signature.Length - nist.NonceLength - 1];
+            Array.Copy(signature, 1, nonce, 0, nist.NonceLength);
+            Array.Copy(signature, nist.NonceLength + 1, sig, 0, signature.Length - nist.NonceLength - 1);
+            return nist.crypto_sign_open(false, sig, nonce, message, encodedkey, 0) == 0;
         }
     }
 }
diff --git a/crypto/src/pqc/crypto/hqc/HqcEngine.cs b/crypto/src/pqc/crypto/hqc/HqcEngine.cs
index ee628e843..4e163fc6e 100644
--- a/crypto/src/pqc/crypto/hqc/HqcEngine.cs
+++ b/crypto/src/pqc/crypto/hqc/HqcEngine.cs
@@ -34,10 +34,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Hqc
         private int N1N2_BYTE;
         private int N1_BYTE;
         
-        private int GF_POLY_WT  = 5;
-        private int GF_POLY_M2 = 4;
+        //private int GF_POLY_WT  = 5;
+        //private int GF_POLY_M2 = 4;
         private int SALT_SIZE_BYTES = 16;
-        private int SALT_SIZE_64 = 2;
+        //private int SALT_SIZE_64 = 2;
 
         private int[] generatorPoly;
         private int SHA512_BYTES = 512 / 8;
diff --git a/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusSigner.cs b/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusSigner.cs
index 5c576eb15..275148209 100644
--- a/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusSigner.cs
+++ b/crypto/src/pqc/crypto/sphincsplus/SPHINCSPlusSigner.cs
@@ -36,19 +36,23 @@ namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus
         {
             if (forSigning)
             {
-                if (param is ParametersWithRandom parametersWithRandom)
+                m_pubKey = null;
+                if (param is ParametersWithRandom withRandom)
                 {
-                    m_privKey = (SphincsPlusPrivateKeyParameters)parametersWithRandom.Parameters;
-                    m_random = parametersWithRandom.Random;
+                    m_privKey = (SphincsPlusPrivateKeyParameters)withRandom.Parameters;
+                    m_random = withRandom.Random;
                 }
                 else
                 {
                     m_privKey = (SphincsPlusPrivateKeyParameters)param;
+                    m_random = null;
                 }
             }
             else
             {
                 m_pubKey = (SphincsPlusPublicKeyParameters)param;
+                m_privKey = null;
+                m_random = null;
             }
         }
 
diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs
index 521e7db0e..a9c062b4e 100644
--- a/crypto/src/security/SecureRandom.cs
+++ b/crypto/src/security/SecureRandom.cs
@@ -254,7 +254,7 @@ namespace Org.BouncyCastle.Security
                 ? stackalloc byte[seedLength]
                 : new byte[seedLength];
 #else
-                byte[] seed = new byte[seedLength];
+            byte[] seed = new byte[seedLength];
 #endif
             MasterRandom.NextBytes(seed);
             generator.AddSeedMaterial(seed);
diff --git a/crypto/src/security/SignerUtilities.cs b/crypto/src/security/SignerUtilities.cs
index 6500cdf13..917759a8e 100644
--- a/crypto/src/security/SignerUtilities.cs
+++ b/crypto/src/security/SignerUtilities.cs
@@ -10,16 +10,16 @@ using Org.BouncyCastle.Asn1.GM;
 using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Asn1.Oiw;
 using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.Rosstandart;
 using Org.BouncyCastle.Asn1.TeleTrust;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
-using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Signers;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
-using Org.BouncyCastle.Asn1.Rosstandart;
 
 namespace Org.BouncyCastle.Security
 {
@@ -28,9 +28,10 @@ namespace Org.BouncyCastle.Security
     /// </summary>
     public static class SignerUtilities
     {
-        internal static readonly IDictionary<string, string> AlgorithmMap =
+        private static readonly IDictionary<string, string> AlgorithmMap =
             new Dictionary<string, string>(StringComparer.OrdinalIgnoreCase);
-        internal static readonly IDictionary<string, DerObjectIdentifier> Oids =
+        private static readonly HashSet<string> NoRandom = new HashSet<string>(StringComparer.OrdinalIgnoreCase);
+        private static readonly IDictionary<string, DerObjectIdentifier> Oids =
             new Dictionary<string, DerObjectIdentifier>(StringComparer.OrdinalIgnoreCase);
 
         static SignerUtilities()
@@ -408,6 +409,14 @@ namespace Org.BouncyCastle.Security
             AlgorithmMap["SM3WITHSM2"] = "SM3withSM2";
             AlgorithmMap[GMObjectIdentifiers.sm2sign_with_sm3.Id] = "SM3withSM2";
 
+            NoRandom.Add("Ed25519");
+            NoRandom.Add(EdECObjectIdentifiers.id_Ed25519.Id);
+            NoRandom.Add("Ed25519ctx");
+            NoRandom.Add("Ed25519ph");
+            NoRandom.Add("Ed448");
+            NoRandom.Add(EdECObjectIdentifiers.id_Ed448.Id);
+            NoRandom.Add("Ed448ph");
+
             Oids["MD2withRSA"] = PkcsObjectIdentifiers.MD2WithRsaEncryption;
             Oids["MD4withRSA"] = PkcsObjectIdentifiers.MD4WithRsaEncryption;
             Oids["MD5withRSA"] = PkcsObjectIdentifiers.MD5WithRsaEncryption;
@@ -519,6 +528,11 @@ namespace Org.BouncyCastle.Security
             return DerNull.Instance;
         }
 
+        private static string GetMechanism(string algorithm)
+        {
+            return AlgorithmMap.TryGetValue(algorithm, out var v) ? v : algorithm.ToUpperInvariant();
+        }
+
         private static Asn1Encodable GetPssX509Parameters(
             string	digestName)
         {
@@ -536,6 +550,9 @@ namespace Org.BouncyCastle.Security
 
         public static ISigner GetSigner(DerObjectIdentifier id)
         {
+            if (id == null)
+                throw new ArgumentNullException(nameof(id));
+
             return GetSigner(id.Id);
         }
 
@@ -544,8 +561,17 @@ namespace Org.BouncyCastle.Security
             if (algorithm == null)
                 throw new ArgumentNullException(nameof(algorithm));
 
-            string mechanism = CollectionUtilities.GetValueOrKey(AlgorithmMap, algorithm.ToUpperInvariant());
+            string mechanism = GetMechanism(algorithm);
+
+            var signer = GetSignerForMechanism(mechanism);
+            if (signer == null)
+                throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
+
+            return signer;
+        }
 
+        private static ISigner GetSignerForMechanism(string mechanism)
+        {
             if (Platform.StartsWith(mechanism, "Ed"))
             {
                 if (mechanism.Equals("Ed25519"))
@@ -638,30 +664,37 @@ namespace Org.BouncyCastle.Security
             {
                 return new Gost3410DigestSigner(new Gost3410Signer(), new Gost3411Digest());
             }
-            if (mechanism.Equals("ECGOST3410"))
-            {
-                return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest());
-            }
-            if (mechanism.Equals("ECGOST3410-2012-256"))
-            {
-                return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411_2012_256Digest());
-            }
-            if (mechanism.Equals("ECGOST3410-2012-512"))
-            {
-                return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411_2012_512Digest());
-            }
 
-            if (mechanism.Equals("SHA1WITHRSA/ISO9796-2"))
-            {
-                return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true);
-            }
-            if (mechanism.Equals("MD5WITHRSA/ISO9796-2"))
+            if (Platform.StartsWith(mechanism, "ECGOST3410"))
             {
-                return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true);
+                if (mechanism.Equals("ECGOST3410"))
+                {
+                    return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411Digest());
+                }
+                if (mechanism.Equals("ECGOST3410-2012-256"))
+                {
+                    return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411_2012_256Digest());
+                }
+                if (mechanism.Equals("ECGOST3410-2012-512"))
+                {
+                    return new Gost3410DigestSigner(new ECGost3410Signer(), new Gost3411_2012_512Digest());
+                }
             }
-            if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2"))
+
+            if (Platform.EndsWith(mechanism, "/ISO9796-2"))
             {
-                return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true);
+                if (mechanism.Equals("SHA1WITHRSA/ISO9796-2"))
+                {
+                    return new Iso9796d2Signer(new RsaBlindedEngine(), new Sha1Digest(), true);
+                }
+                if (mechanism.Equals("MD5WITHRSA/ISO9796-2"))
+                {
+                    return new Iso9796d2Signer(new RsaBlindedEngine(), new MD5Digest(), true);
+                }
+                if (mechanism.Equals("RIPEMD160WITHRSA/ISO9796-2"))
+                {
+                    return new Iso9796d2Signer(new RsaBlindedEngine(), new RipeMD160Digest(), true);
+                }
             }
 
             if (Platform.EndsWith(mechanism, "/X9.31"))
@@ -672,19 +705,20 @@ namespace Org.BouncyCastle.Security
                 {
                     int endPos = withPos + "WITH".Length;
 
-                    string digestName = x931.Substring(0, withPos);
-                    IDigest digest = DigestUtilities.GetDigest(digestName);
-
                     string cipherName = x931.Substring(endPos, x931.Length - endPos);
                     if (cipherName.Equals("RSA"))
                     {
                         IAsymmetricBlockCipher cipher = new RsaBlindedEngine();
+
+                        string digestName = x931.Substring(0, withPos);
+                        IDigest digest = DigestUtilities.GetDigest(digestName);
+
                         return new X931Signer(cipher, digest);
                     }
                 }
             }
 
-            throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
+            return null;
         }
 
         public static string GetEncodingName(DerObjectIdentifier oid)
@@ -692,15 +726,36 @@ namespace Org.BouncyCastle.Security
             return CollectionUtilities.GetValueOrNull(AlgorithmMap, oid.Id);
         }
 
-        public static ISigner InitSigner(DerObjectIdentifier algorithmOid, bool forSigning, AsymmetricKeyParameter privateKey, SecureRandom random)
+        // TODO Rename 'privateKey' to 'key'
+        public static ISigner InitSigner(DerObjectIdentifier algorithmOid, bool forSigning,
+            AsymmetricKeyParameter privateKey, SecureRandom random)
         {
+            if (algorithmOid == null)
+                throw new ArgumentNullException(nameof(algorithmOid));
+
             return InitSigner(algorithmOid.Id, forSigning, privateKey, random);
         }
 
-        public static ISigner InitSigner(string algorithm, bool forSigning, AsymmetricKeyParameter privateKey, SecureRandom random)
+        // TODO Rename 'privateKey' to 'key'
+        public static ISigner InitSigner(string algorithm, bool forSigning, AsymmetricKeyParameter privateKey,
+            SecureRandom random)
         {
-            ISigner signer = GetSigner(algorithm);
-            signer.Init(forSigning, ParameterUtilities.WithRandom(privateKey, random));
+            if (algorithm == null)
+                throw new ArgumentNullException(nameof(algorithm));
+
+            string mechanism = GetMechanism(algorithm);
+
+            var signer = GetSignerForMechanism(mechanism);
+            if (signer == null)
+                throw new SecurityUtilityException("Signer " + algorithm + " not recognised.");
+
+            ICipherParameters cipherParameters = privateKey;
+            if (forSigning && !NoRandom.Contains(mechanism))
+            {
+                cipherParameters = ParameterUtilities.WithRandom(cipherParameters, random);
+            }
+
+            signer.Init(forSigning, cipherParameters);
             return signer;
         }
     }
diff --git a/crypto/src/tls/TlsClientProtocol.cs b/crypto/src/tls/TlsClientProtocol.cs
index ec1cd28d5..6aa1acf2f 100644
--- a/crypto/src/tls/TlsClientProtocol.cs
+++ b/crypto/src/tls/TlsClientProtocol.cs
@@ -1001,8 +1001,7 @@ namespace Org.BouncyCastle.Tls
                         throw new TlsFatalAlert(AlertDescription.illegal_parameter);
                     }
 
-                    TlsAgreement agreement = (TlsAgreement)m_clientAgreements[keyShareEntry.NamedGroup];
-                    if (null == agreement)
+                    if (!m_clientAgreements.TryGetValue(keyShareEntry.NamedGroup, out var agreement))
                         throw new TlsFatalAlert(AlertDescription.illegal_parameter);
 
                     agreement.ReceivePeerValue(keyShareEntry.KeyExchange);
diff --git a/crypto/src/tls/TlsExtensionsUtilities.cs b/crypto/src/tls/TlsExtensionsUtilities.cs
index 46d42417c..836c1b506 100644
--- a/crypto/src/tls/TlsExtensionsUtilities.cs
+++ b/crypto/src/tls/TlsExtensionsUtilities.cs
@@ -592,7 +592,7 @@ namespace Org.BouncyCastle.Tls
             // Placeholder for length
             TlsUtilities.WriteUint16(0, buf);
 
-            foreach (X509Name authority in authorities)
+            foreach (var authority in authorities)
             {
                 byte[] derEncoding = authority.GetEncoded(Asn1Encodable.Der);
                 TlsUtilities.WriteOpaque16(derEncoding, buf);
@@ -736,7 +736,6 @@ namespace Org.BouncyCastle.Tls
 
             if (null != filters)
             {
-                //foreach (DerObjectIdentifier certificateExtensionOid in filters.Keys)
                 foreach (var filter in filters)
                 {
                     var certificateExtensionOid = filter.Key;
@@ -1020,7 +1019,7 @@ namespace Org.BouncyCastle.Tls
             {
                 byte[] derEncoding = TlsUtilities.ReadOpaque16(buf, 1);
                 Asn1Object asn1 = TlsUtilities.ReadAsn1Object(derEncoding);
-                X509Name ca = X509Name.GetInstance(asn1);
+                var ca = X509Name.GetInstance(asn1);
                 TlsUtilities.RequireDerEncoding(ca, derEncoding);
                 authorities.Add(ca);
             }
diff --git a/crypto/src/tls/TlsUtilities.cs b/crypto/src/tls/TlsUtilities.cs
index 424fca133..e2c3e3094 100644
--- a/crypto/src/tls/TlsUtilities.cs
+++ b/crypto/src/tls/TlsUtilities.cs
@@ -2157,8 +2157,6 @@ namespace Org.BouncyCastle.Tls
             }
 
             buf.CopyInputTo(output);
-
-            output.Dispose();
         }
 
         internal static DigitallySigned GenerateCertificateVerifyClient(TlsClientContext clientContext,
@@ -2399,7 +2397,10 @@ namespace Org.BouncyCastle.Tls
             byte[] signature;
             if (streamSigner != null)
             {
-                SendSignatureInput(context, extraSignatureInput, digestBuffer, streamSigner.Stream);
+                using (var output = streamSigner.Stream)
+                {
+                    SendSignatureInput(context, extraSignatureInput, digestBuffer, output);
+                }
                 signature = streamSigner.GetSignature();
             }
             else
@@ -2445,7 +2446,10 @@ namespace Org.BouncyCastle.Tls
             bool verified;
             if (streamVerifier != null)
             {
-                SendSignatureInput(context, null, digestBuffer, streamVerifier.Stream);
+                using (var output = streamVerifier.Stream)
+                {
+                    SendSignatureInput(context, null, digestBuffer, output);
+                }
                 verified = streamVerifier.IsVerified();
             }
             else
@@ -5006,7 +5010,7 @@ namespace Org.BouncyCastle.Tls
         {
             if (null != clientShares && 1 == clientShares.Count)
             {
-                KeyShareEntry clientShare = (KeyShareEntry)clientShares[0];
+                KeyShareEntry clientShare = clientShares[0];
                 if (null != clientShare && clientShare.NamedGroup == keyShareGroup)
                 {
                     return clientShare;
@@ -5598,7 +5602,7 @@ namespace Org.BouncyCastle.Tls
                         int index = offeredPsks.GetIndexOfIdentity(new PskIdentity(psk.Identity, 0L));
                         if (index >= 0)
                         {
-                            byte[] binder = (byte[])offeredPsks.Binders[index];
+                            byte[] binder = offeredPsks.Binders[index];
 
                             TlsCrypto crypto = serverContext.Crypto;
                             TlsSecret earlySecret = GetPskEarlySecret(crypto, psk);
diff --git a/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs b/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs
index a8fb26697..e29993c92 100644
--- a/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs
+++ b/crypto/src/tls/crypto/impl/AbstractTlsCrypto.cs
@@ -64,14 +64,10 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl
         public virtual TlsSecret AdoptSecret(TlsSecret secret)
         {
             // TODO[tls] Need an alternative that doesn't require AbstractTlsSecret (which holds literal data)
-            if (secret is AbstractTlsSecret)
-            {
-                AbstractTlsSecret sec = (AbstractTlsSecret)secret;
+            if (secret is AbstractTlsSecret abstractTlsSecret)
+                return CreateSecret(abstractTlsSecret.CopyData());
 
-                return CreateSecret(sec.CopyData());
-            }
-
-            throw new ArgumentException("unrecognized TlsSecret - cannot copy data: " + Platform.GetTypeName(secret));
+            throw new ArgumentException("unrecognized TlsSecret - cannot copy data: " + secret.GetType().FullName);
         }
 
         public abstract TlsHash CreateHash(int cryptoHashAlgorithm);
diff --git a/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.cs b/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.cs
index 863b96634..bca415dcf 100644
--- a/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedAgreement.cs
@@ -39,7 +39,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             }
             else
             {
-                throw new ArgumentException("'privateKey' type not supported: " + Platform.GetTypeName(privateKey));
+                throw new ArgumentException("'privateKey' type not supported: " + privateKey.GetType().FullName);
             }
         }
 
diff --git a/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.cs b/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.cs
index b0e9f125e..bbe9af4e6 100644
--- a/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedDecryptor.cs
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             }
             else
             {
-                throw new ArgumentException("'privateKey' type not supported: " + Platform.GetTypeName(privateKey));
+                throw new ArgumentException("'privateKey' type not supported: " + privateKey.GetType().FullName);
             }
 
             this.m_crypto = crypto;
diff --git a/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.cs b/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.cs
index 6db84cdd8..82bc58f96 100644
--- a/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcDefaultTlsCredentialedSigner.cs
@@ -68,7 +68,7 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
             }
             else
             {
-                throw new ArgumentException("'privateKey' type not supported: " + Platform.GetTypeName(privateKey));
+                throw new ArgumentException("'privateKey' type not supported: " + privateKey.GetType().FullName);
             }
 
             return signer;
diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs b/crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs
index 683806347..fdd67fc71 100644
--- a/crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcTlsSecret.cs
@@ -14,17 +14,13 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
     {
         public static BcTlsSecret Convert(BcTlsCrypto crypto, TlsSecret secret)
         {
-            if (secret is BcTlsSecret)
-                return (BcTlsSecret)secret;
-
-            if (secret is AbstractTlsSecret)
-            {
-                AbstractTlsSecret abstractTlsSecret = (AbstractTlsSecret)secret;
+            if (secret is BcTlsSecret bcTlsSecret)
+                return bcTlsSecret;
 
+            if (secret is AbstractTlsSecret abstractTlsSecret)
                 return crypto.AdoptLocalSecret(CopyData(abstractTlsSecret));
-            }
 
-            throw new ArgumentException("unrecognized TlsSecret - cannot copy data: " + Platform.GetTypeName(secret));
+            throw new ArgumentException("unrecognized TlsSecret - cannot copy data: " + secret.GetType().FullName);
         }
 
         // SSL3 magic mix constants ("A", "BB", "CCC", ...)
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index 41e3c3195..a9ae6724a 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -606,9 +606,7 @@ namespace Org.BouncyCastle.Utilities
             return false;
         }
 
-        public static void Fill(
-            byte[]	buf,
-            byte	b)
+        public static void Fill(byte[] buf, byte b)
         {
             int i = buf.Length;
             while (i > 0)
@@ -618,9 +616,7 @@ namespace Org.BouncyCastle.Utilities
         }
 
         [CLSCompliant(false)]
-        public static void Fill(
-            ulong[]	buf,
-            ulong	b)
+        public static void Fill(ulong[] buf, ulong b)
         {
             int i = buf.Length;
             while (i > 0)
diff --git a/crypto/src/util/BigIntegers.cs b/crypto/src/util/BigIntegers.cs
index 668d92246..9c5477e6a 100644
--- a/crypto/src/util/BigIntegers.cs
+++ b/crypto/src/util/BigIntegers.cs
@@ -139,11 +139,7 @@ namespace Org.BouncyCastle.Utilities
         * @param random the source of randomness
         * @return a random BigInteger value in the range [min,max]
         */
-        public static BigInteger CreateRandomInRange(
-            BigInteger		min,
-            BigInteger		max,
-            // TODO Should have been just Random class
-            SecureRandom	random)
+        public static BigInteger CreateRandomInRange(BigInteger min, BigInteger max, SecureRandom random)
         {
             int cmp = min.CompareTo(max);
             if (cmp >= 0)
@@ -155,23 +151,39 @@ namespace Org.BouncyCastle.Utilities
             }
 
             if (min.BitLength > max.BitLength / 2)
-            {
                 return CreateRandomInRange(BigInteger.Zero, max.Subtract(min), random).Add(min);
-            }
 
             for (int i = 0; i < MaxIterations; ++i)
             {
                 BigInteger x = new BigInteger(max.BitLength, random);
                 if (x.CompareTo(min) >= 0 && x.CompareTo(max) <= 0)
-                {
                     return x;
-                }
             }
 
             // fall back to a faster (restricted) method
             return new BigInteger(max.Subtract(min).BitLength - 1, random).Add(min);
         }
 
+        public static BigInteger FromUnsignedByteArray(byte[] buf)
+        {
+            return new BigInteger(1, buf);
+        }
+
+        public static BigInteger FromUnsignedByteArray(byte[] buf, int off, int length)
+        {
+            return new BigInteger(1, buf, off, length);
+        }
+
+        public static int GetByteLength(BigInteger n)
+        {
+            return n.GetLengthofByteArray();
+        }
+
+        public static int GetUnsignedByteLength(BigInteger n)
+        {
+            return n.GetLengthofByteArrayUnsigned();
+        }
+
         public static BigInteger ModOddInverse(BigInteger M, BigInteger X)
         {
             if (!M.TestBit(0))
@@ -253,15 +265,5 @@ namespace Org.BouncyCastle.Utilities
                 return Nat.ToBigInteger(len, z);
             }
         }
-
-        public static int GetByteLength(BigInteger n)
-        {
-            return n.GetLengthofByteArray();
-        }
-
-        public static int GetUnsignedByteLength(BigInteger n)
-        {
-            return n.GetLengthofByteArrayUnsigned();
-        }
     }
 }
diff --git a/crypto/src/util/Platform.cs b/crypto/src/util/Platform.cs
index a78153b8c..e43714181 100644
--- a/crypto/src/util/Platform.cs
+++ b/crypto/src/util/Platform.cs
@@ -63,7 +63,12 @@ namespace Org.BouncyCastle.Utilities
 
         internal static string GetTypeName(object obj)
         {
-            return obj.GetType().FullName;
+            return GetTypeName(obj.GetType());
+        }
+
+        internal static string GetTypeName(Type t)
+        {
+            return t.FullName;
         }
     }
 }
diff --git a/crypto/src/util/collections/CollectionUtilities.cs b/crypto/src/util/collections/CollectionUtilities.cs
index 26b3f2a1d..a1fb0e949 100644
--- a/crypto/src/util/collections/CollectionUtilities.cs
+++ b/crypto/src/util/collections/CollectionUtilities.cs
@@ -31,6 +31,19 @@ namespace Org.BouncyCastle.Utilities.Collections
             return new StoreImpl<T>(contents);
         }
 
+        public static T GetFirstOrNull<T>(IEnumerable<T> e)
+            where T : class
+        {
+            if (e != null)
+            {
+                foreach (var t in e)
+                {
+                    return t;
+                }
+            }
+            return null;
+        }
+
         public static T GetValueOrKey<T>(IDictionary<T, T> d, T k)
         {
             return d.TryGetValue(k, out var v) ? v : k;
diff --git a/crypto/src/util/io/LimitedInputStream.cs b/crypto/src/util/io/LimitedInputStream.cs
index d6616eff5..4c6aac631 100644
--- a/crypto/src/util/io/LimitedInputStream.cs
+++ b/crypto/src/util/io/LimitedInputStream.cs
@@ -1,5 +1,4 @@
-using Org.BouncyCastle.Utilities.Zlib;
-using System;
+using System;
 using System.IO;
 
 namespace Org.BouncyCastle.Utilities.IO
diff --git a/crypto/src/util/io/pem/PemHeader.cs b/crypto/src/util/io/pem/PemHeader.cs
index c6236f534..b9bf10e34 100644
--- a/crypto/src/util/io/pem/PemHeader.cs
+++ b/crypto/src/util/io/pem/PemHeader.cs
@@ -38,8 +38,8 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 
 			PemHeader other = (PemHeader)obj;
 
-			return Platform.Equals(this.name, other.name)
-				&& Platform.Equals(this.val, other.val);
+			return Objects.Equals(this.name, other.name)
+				&& Objects.Equals(this.val, other.val);
 		}
 
 		private int GetHashCode(string s)
diff --git a/crypto/src/util/io/pem/PemObject.cs b/crypto/src/util/io/pem/PemObject.cs
index 2a152f81d..ccba962af 100644
--- a/crypto/src/util/io/pem/PemObject.cs
+++ b/crypto/src/util/io/pem/PemObject.cs
@@ -6,9 +6,9 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 	public class PemObject
 		: PemObjectGenerator
 	{
-		private string type;
-		private IList<PemHeader> headers;
-		private byte[] content;
+		private readonly string m_type;
+		private readonly IList<PemHeader> m_headers;
+		private readonly byte[] m_content;
 
 		public PemObject(string type, byte[] content)
 			: this(type, new List<PemHeader>(), content)
@@ -17,24 +17,24 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 
 		public PemObject(string type, IList<PemHeader> headers, byte[] content)
 		{
-			this.type = type;
-            this.headers = new List<PemHeader>(headers);
-			this.content = content;
+			m_type = type;
+            m_headers = new List<PemHeader>(headers);
+			m_content = content;
 		}
 
 		public string Type
 		{
-			get { return type; }
+			get { return m_type; }
 		}
 
 		public IList<PemHeader> Headers
 		{
-			get { return headers; }
+			get { return m_headers; }
 		}
 
 		public byte[] Content
 		{
-			get { return content; }
+			get { return m_content; }
 		}
 
 		public PemObject Generate()
diff --git a/crypto/src/util/io/pem/PemReader.cs b/crypto/src/util/io/pem/PemReader.cs
index 77b457338..6e27a3749 100644
--- a/crypto/src/util/io/pem/PemReader.cs
+++ b/crypto/src/util/io/pem/PemReader.cs
@@ -1,6 +1,7 @@
 using System;
 using System.Collections.Generic;
 using System.IO;
+using System.Text;
 
 using Org.BouncyCastle.Utilities.Encoders;
 
@@ -8,18 +9,19 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 {
 	public class PemReader
 		: IDisposable
-	{		
-		private readonly TextReader reader;
-		private readonly MemoryStream buffer;
-		private readonly StreamWriter textBuffer;
-		private readonly List<int> pushback = new List<int>();
-		int c = 0;
+	{
+        private const int LineLength = 64;
+
+        private readonly TextReader m_reader;
+		private readonly MemoryStream m_buffer;
+		private readonly StreamWriter m_textBuffer;
+		private readonly Stack<int> m_pushback = new Stack<int>();
 
 		public PemReader(TextReader reader)
 		{
-			this.reader = reader ?? throw new ArgumentNullException(nameof(reader));
-            this.buffer = new MemoryStream();
-            this.textBuffer = new StreamWriter(buffer);
+			m_reader = reader ?? throw new ArgumentNullException(nameof(reader));
+            m_buffer = new MemoryStream();
+            m_textBuffer = new StreamWriter(m_buffer);
 		}
 
         #region IDisposable
@@ -34,15 +36,15 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
         {
             if (disposing)
             {
-                reader.Dispose();
+                m_reader.Dispose();
             }
         }
 
         #endregion
 
-        public TextReader Reader
+        public TextReader Reader 
 		{
-			get { return reader; }
+			get { return m_reader; }
 		}
 
 
@@ -52,65 +54,43 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 		/// <exception cref="IOException"></exception>	
 		public PemObject ReadPemObject()
         {
-
 			//
 			// Look for BEGIN
 			//
 
 			for (;;)
 			{
-
 				// Seek a leading dash, ignore anything up to that point.
-				if (!seekDash())
-				{
-					// There are no pem objects here.
+				if (!SeekDash())
 					return null; 
-				}
-
 
 				// consume dash [-----]BEGIN ...
-				if (!consumeDash())
-				{
+				if (!ConsumeDash())
 					throw new IOException("no data after consuming leading dashes");
-				}
-
-
-				skipWhiteSpace();
-
-
-				if (!expect("BEGIN"))
-				{
-					continue;
-				}
 
-				break;
+				SkipWhiteSpace();
 
+				if (Expect("BEGIN"))
+					break;
 			}
 
-
-			skipWhiteSpace();
+			SkipWhiteSpace();
 
 			//
 			// Consume type, accepting whitespace
 			//
 
-			if (!bufferUntilStopChar('-',false) )
-            {
+			if (!BufferUntilStopChar('-', false))
 				throw new IOException("ran out of data before consuming type");
-			}
-
-			string type = bufferedString().Trim();
 
+			string type = BufferedString().Trim();
 
 			// Consume dashes after type.
 
-			if (!consumeDash())
-            {
+			if (!ConsumeDash())
 				throw new IOException("ran out of data consuming header");
-			}
-
-			skipWhiteSpace();
 
+			SkipWhiteSpace();
 
 			//
 			// Read ahead looking for headers.
@@ -119,127 +99,106 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 
 			var headers = new List<PemHeader>();
 
-			while (seekColon(64))
+			while (SeekColon(LineLength))
             {
-
-				if (!bufferUntilStopChar(':',false))
-                {
+				if (!BufferUntilStopChar(':', false))
 					throw new IOException("ran out of data reading header key value");
-				}
-
-				string key = bufferedString().Trim();
 
+				string key = BufferedString().Trim();
 
-				c = Read();
+				int c = Read();
 				if (c != ':')
-                {
 					throw new IOException("expected colon");
-                }
-				
 
 				//
 				// We are going to look for well formed headers, if they do not end with a "LF" we cannot
 				// discern where they end.
 				//
-			
-				if (!bufferUntilStopChar('\n', false)) // Now read to the end of the line.
-                {
+
+				if (!BufferUntilStopChar('\n', false)) // Now read to the end of the line.
 					throw new IOException("ran out of data before consuming header value");
-				}
 
-				skipWhiteSpace();
+				SkipWhiteSpace();
 
-				string value = bufferedString().Trim();
-				headers.Add(new PemHeader(key,value));
+				string value = BufferedString().Trim();
+				headers.Add(new PemHeader(key, value));
 			}
 
-
 			//
 			// Consume payload, ignoring all white space until we encounter a '-'
 			//
 
-			skipWhiteSpace();
+			SkipWhiteSpace();
 
-			if (!bufferUntilStopChar('-',true))
-			{
+			if (!BufferUntilStopChar('-', true))
 				throw new IOException("ran out of data before consuming payload");
-			}
 
-			string payload = bufferedString();
-		
+			string payload = BufferedString();
+
 			// Seek the start of the end.
-			if (!seekDash())
-			{
+			if (!SeekDash())
 				throw new IOException("did not find leading '-'");
-			}
 
-			if (!consumeDash())
-			{
+			if (!ConsumeDash())
 				throw new IOException("no data after consuming trailing dashes");
-			}
-
-			if (!expect("END "+type))
-			{
-				throw new IOException("END "+type+" was not found.");
-			}
-
 
+			if (!Expect("END " + type))
+				throw new IOException("END " + type + " was not found.");
 
-			if (!seekDash())
-			{
+			if (!SeekDash())
 				throw new IOException("did not find ending '-'");
-			}
-
 
 			// consume trailing dashes.
-			consumeDash();
-			
+			ConsumeDash();
 
 			return new PemObject(type, headers, Base64.Decode(payload));
-
 		}
 
-
-	
-		private string bufferedString()
+		private string BufferedString()
         {
-			textBuffer.Flush();
-			string value = Strings.FromUtf8ByteArray(buffer.ToArray());
-			buffer.Position = 0;
-			buffer.SetLength(0);
+			m_textBuffer.Flush();
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            if (!m_buffer.TryGetBuffer(out var data))
+                throw new InvalidOperationException();
+
+            string value = Encoding.UTF8.GetString(data);
+#else
+            string value = Strings.FromUtf8ByteArray(m_buffer.ToArray());
+#endif
+
+            m_buffer.Position = 0;
+			m_buffer.SetLength(0);
+
 			return value;
         }
 
-
-		private bool seekDash()
+		private bool SeekDash()
         {
-			c = 0;
-			while((c = Read()) >=0)
+			int c;
+			while ((c = Read()) >= 0)
             {
 				if (c == '-')
-                {
 					break;
-                }
             }
 
 			PushBack(c);
 
-			return c == '-';
+			return c >= 0;
         }
 
-
 		/// <summary>
 		/// Seek ':" up to the limit.
 		/// </summary>
 		/// <param name="upTo"></param>
 		/// <returns></returns>
-		private bool seekColon(int upTo)
+		private bool SeekColon(int upTo)
 		{
-			c = 0;
+			int c = 0;
 			bool colonFound = false;
 			var read = new List<int>();
 
-			for (; upTo>=0 && c >=0; upTo--)
+			for (; upTo >= 0 && c >= 0; upTo--)
             {
 				c = Read();
 				read.Add(c);
@@ -250,49 +209,45 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
                 }
             }
 
-			while(read.Count>0)
-            {
-				PushBack((int)read[read.Count-1]);
-				read.RemoveAt(read.Count-1);
-            }
+			int readPos = read.Count;
+			while (--readPos >= 0)
+			{
+				PushBack(read[readPos]);
+			}
 
 			return colonFound;
 		}
 
-
-
 		/// <summary>
 		/// Consume the dashes
 		/// </summary>
 		/// <returns></returns>
-		private bool consumeDash()
+		private bool ConsumeDash()
         {
-			c = 0;
+			int c;
 			while ((c = Read()) >= 0)
 			{
 				if (c != '-')
-				{
 					break;
-				}
 			}
 
 			PushBack(c);
 
-			return c != -1;
+			return c >= 0;
 		}
 
 		/// <summary>
 		/// Skip white space leave char in stream.
 		/// </summary>
-		private void skipWhiteSpace()
+		private void SkipWhiteSpace()
         {
+			int c;
 			while ((c = Read()) >= 0)
 			{
 				if (c > ' ')
-				{
 					break;
-				}
 			}
+
 			PushBack(c);
 		}
 
@@ -301,19 +256,12 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 		/// </summary>
 		/// <param name="value">expected string</param>
 		/// <returns>false if not consumed</returns>
-
-		private bool expect(string value)
+		private bool Expect(string value)
         {
-			for (int t=0; t<value.Length; t++)
+			for (int t = 0; t < value.Length; t++)
             {
-				c = Read();
-				if (c == value[t])
-                {
-					continue;
-                } else
-                {
+				if (Read() != value[t])
 					return false;
-                }
             }
 
 			return true;
@@ -323,51 +271,38 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 		/// Consume until dash.
 		/// </summary>
 		/// <returns>true if stream end not met</returns>
-		private bool bufferUntilStopChar(char stopChar,   bool skipWhiteSpace)
+		private bool BufferUntilStopChar(char stopChar, bool skipWhiteSpace)
         {
+			int c;
 			while ((c = Read()) >= 0)
 			{	
-				if (skipWhiteSpace && c <=' ')
-                {
+				if (skipWhiteSpace && c <= ' ')
 					continue;
-                }
 
-				if (c != stopChar)
+				if (c == stopChar)
 				{
-					textBuffer.Write((char)c);
-					textBuffer.Flush();
-					
-				} else
-                {
-					  PushBack(c);
-					break;
+                    PushBack(c);
+                    break;
                 }
+
+				m_textBuffer.Write((char)c);
+				m_textBuffer.Flush();
 			}
-			
-			return c > -1;
+
+			return c >= 0;
 		}
 
 		private void PushBack(int value)
         {
-			if (pushback.Count == 0)
-            {
-				pushback.Add(value);
-            } else
-            {
-				pushback.Insert(0, value);
-            }
+			m_pushback.Push(value);
         }
 
 		private int Read()
         {
-			if (pushback.Count > 0)
-            {
-				int i = pushback[0];
-				pushback.RemoveAt(0);
-				return i;
-            }
+			if (m_pushback.Count > 0)
+				return m_pushback.Pop();
 
-			return reader.Read();
+			return m_reader.Read();
         }
 	}
 }
diff --git a/crypto/src/util/io/pem/PemWriter.cs b/crypto/src/util/io/pem/PemWriter.cs
index ee92556c7..ce7b38821 100644
--- a/crypto/src/util/io/pem/PemWriter.cs
+++ b/crypto/src/util/io/pem/PemWriter.cs
@@ -13,9 +13,9 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 	{
 		private const int LineLength = 64;
 
-		private readonly TextWriter	writer;
-		private readonly int		nlLength;
-		private char[]				buf = new char[LineLength];
+		private readonly TextWriter m_writer;
+		private readonly int m_nlLength;
+		private readonly char[] m_buf = new char[LineLength];
 
 		/**
 		 * Base constructor.
@@ -24,8 +24,8 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 		 */
 		public PemWriter(TextWriter writer)
 		{
-			this.writer = writer ?? throw new ArgumentNullException(nameof(writer));
-            this.nlLength = Environment.NewLine.Length;
+			m_writer = writer ?? throw new ArgumentNullException(nameof(writer));
+            m_nlLength = Environment.NewLine.Length;
 		}
 
         #region IDisposable
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
         {
             if (disposing)
             {
-                writer.Dispose();
+                m_writer.Dispose();
             }
         }
 
@@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 
         public TextWriter Writer
 		{
-			get { return writer; }
+			get { return m_writer; }
 		}
 
 		/**
@@ -61,22 +61,22 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 		public int GetOutputSize(PemObject obj)
 		{
 			// BEGIN and END boundaries.
-			int size = (2 * (obj.Type.Length + 10 + nlLength)) + 6 + 4;
+			int size = (2 * (obj.Type.Length + 10 + m_nlLength)) + 6 + 4;
 
 			if (obj.Headers.Count > 0)
 			{
 				foreach (PemHeader header in obj.Headers)
 				{
-					size += header.Name.Length + ": ".Length + header.Value.Length + nlLength;
+					size += header.Name.Length + ": ".Length + header.Value.Length + m_nlLength;
 				}
 
-				size += nlLength;
+				size += m_nlLength;
 			}
 
 			// base64 encoding
 			int dataLen = ((obj.Content.Length + 2) / 3) * 4;
 
-			size += dataLen + (((dataLen + LineLength - 1) / LineLength) * nlLength);
+			size += dataLen + (((dataLen + LineLength - 1) / LineLength) * m_nlLength);
 
 			return size;
 		}
@@ -91,12 +91,12 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 			{
 				foreach (PemHeader header in obj.Headers)
 				{
-					writer.Write(header.Name);
-					writer.Write(": ");
-					writer.WriteLine(header.Value);
+					m_writer.Write(header.Name);
+					m_writer.Write(": ");
+					m_writer.WriteLine(header.Value);
 				}
 
-				writer.WriteLine();
+				m_writer.WriteLine();
 			}
 
 			WriteEncoded(obj.Content);
@@ -107,29 +107,29 @@ namespace Org.BouncyCastle.Utilities.IO.Pem
 		{
 			bytes = Base64.Encode(bytes);
 
-			for (int i = 0; i < bytes.Length; i += buf.Length)
+			for (int i = 0; i < bytes.Length; i += m_buf.Length)
 			{
 				int index = 0;
-				while (index != buf.Length)
+				while (index != m_buf.Length)
 				{
 					if ((i + index) >= bytes.Length)
 						break;
 
-					buf[index] = (char)bytes[i + index];
+					m_buf[index] = (char)bytes[i + index];
 					index++;
 				}
-				writer.WriteLine(buf, 0, index);
+				m_writer.WriteLine(m_buf, 0, index);
 			}
 		}
 
 		private void WritePreEncapsulationBoundary(string type)
 		{
-			writer.WriteLine("-----BEGIN " + type + "-----");
+			m_writer.WriteLine("-----BEGIN " + type + "-----");
 		}
 
 		private void WritePostEncapsulationBoundary(string type)
 		{
-			writer.WriteLine("-----END " + type + "-----");
+			m_writer.WriteLine("-----END " + type + "-----");
 		}
     }
 }
diff --git a/crypto/src/x509/AttributeCertificateHolder.cs b/crypto/src/x509/AttributeCertificateHolder.cs
index b3cea1cfe..903886085 100644
--- a/crypto/src/x509/AttributeCertificateHolder.cs
+++ b/crypto/src/x509/AttributeCertificateHolder.cs
@@ -360,26 +360,26 @@ namespace Org.BouncyCastle.X509
 
 					switch (DigestedObjectType)
 					{
-						case ObjectDigestInfo.PublicKey:
-						{
-							// TODO: DSA Dss-parms
-
-							//byte[] b = x509Cert.GetPublicKey().getEncoded();
-							// TODO Is this the right way to encode?
-							byte[] b = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
-								x509Cert.GetPublicKey()).GetEncoded();
-							md.BlockUpdate(b, 0, b.Length);
-							break;
-						}
+					case ObjectDigestInfo.PublicKey:
+					{
+						// TODO: DSA Dss-parms
+
+						//byte[] b = x509Cert.GetPublicKey().getEncoded();
+						// TODO Is this the right way to encode?
+						byte[] b = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(
+							x509Cert.GetPublicKey()).GetEncoded();
+						md.BlockUpdate(b, 0, b.Length);
+						break;
+					}
 
-						case ObjectDigestInfo.PublicKeyCert:
-						{
-							byte[] b = x509Cert.GetEncoded();
-							md.BlockUpdate(b, 0, b.Length);
-							break;
-						}
+					case ObjectDigestInfo.PublicKeyCert:
+					{
+						byte[] b = x509Cert.GetEncoded();
+						md.BlockUpdate(b, 0, b.Length);
+						break;
+					}
 
-						// TODO Default handler?
+					// TODO Default handler?
 					}
 
 					// TODO Shouldn't this be the other way around?
diff --git a/crypto/src/x509/AttributeCertificateIssuer.cs b/crypto/src/x509/AttributeCertificateIssuer.cs
index 799a48877..b0eb65cc8 100644
--- a/crypto/src/x509/AttributeCertificateIssuer.cs
+++ b/crypto/src/x509/AttributeCertificateIssuer.cs
@@ -149,25 +149,18 @@ namespace Org.BouncyCastle.X509
 				return MatchesDN(x509Cert.SubjectDN, issuer.IssuerName);
 			}
 
-			return MatchesDN(x509Cert.SubjectDN, (GeneralNames) form);
+			return MatchesDN(x509Cert.SubjectDN, (GeneralNames)form);
 		}
 
-		public override bool Equals(
-			object obj)
+		public override bool Equals(object obj)
 		{
 			if (obj == this)
-			{
 				return true;
-			}
 
-			if (!(obj is AttributeCertificateIssuer))
-			{
+			if (!(obj is AttributeCertificateIssuer that))
 				return false;
-			}
-
-			AttributeCertificateIssuer other = (AttributeCertificateIssuer)obj;
 
-			return this.form.Equals(other.form);
+			return this.form.Equals(that.form);
 		}
 
 		public override int GetHashCode()
diff --git a/crypto/src/x509/X509AttrCertParser.cs b/crypto/src/x509/X509AttrCertParser.cs
index f1dc09543..0019a48eb 100644
--- a/crypto/src/x509/X509AttrCertParser.cs
+++ b/crypto/src/x509/X509AttrCertParser.cs
@@ -114,9 +114,7 @@ namespace Org.BouncyCastle.X509
 				if (sData != null)
 				{
 					if (sDataObjectCount != sData.Count)
-					{
 						return GetCertificate();
-					}
 
 					sData = null;
 					sDataObjectCount = 0;
@@ -139,9 +137,7 @@ namespace Org.BouncyCastle.X509
                 }
 
                 if (tag != 0x30)  // assume ascii PEM encoded.
-				{
 					return ReadPemCertificate(inStream);
-				}
 
 				return ReadDerCertificate(new Asn1InputStream(inStream));
 			}
diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs
index 5b800efe5..e69aca1ce 100644
--- a/crypto/src/x509/X509Certificate.cs
+++ b/crypto/src/x509/X509Certificate.cs
@@ -339,7 +339,6 @@ namespace Org.BouncyCastle.X509
             return Arrays.Clone(keyUsage);
         }
 
-        // TODO Replace with something that returns a list of DerObjectIdentifier
         public virtual IList<DerObjectIdentifier> GetExtendedKeyUsage()
         {
             Asn1OctetString str = GetExtensionValue(X509Extensions.ExtendedKeyUsage);
@@ -576,12 +575,12 @@ namespace Org.BouncyCastle.X509
             buf.Append("  Signature Algorithm: ").Append(this.SigAlgName).AppendLine();
 
             byte[] sig = this.GetSignature();
-            buf.Append("            Signature: ").Append(Hex.ToHexString(sig, 0, 20)).AppendLine();
+            buf.Append("            Signature: ").AppendLine(Hex.ToHexString(sig, 0, 20));
 
             for (int i = 20; i < sig.Length; i += 20)
             {
                 int len = System.Math.Min(20, sig.Length - i);
-                buf.Append("                       ").Append(Hex.ToHexString(sig, i, len)).AppendLine();
+                buf.Append("                       ").AppendLine(Hex.ToHexString(sig, i, len));
             }
 
             X509Extensions extensions = c.TbsCertificate.Extensions;
@@ -592,7 +591,7 @@ namespace Org.BouncyCastle.X509
 
                 if (e.MoveNext())
                 {
-                    buf.Append("       Extensions: \n");
+                    buf.AppendLine("       Extensions:");
                 }
 
                 do
@@ -680,15 +679,13 @@ namespace Org.BouncyCastle.X509
             if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature))
                 throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
 
-            byte[] b = GetTbsCertificate();
-
             IStreamCalculator<IVerifier> streamCalculator = verifier.CreateCalculator();
             using (var stream = streamCalculator.Stream)
             {
-                stream.Write(b, 0, b.Length);
+                c.TbsCertificate.EncodeTo(stream, Asn1Encodable.Der);
             }
 
-            if (!streamCalculator.GetResult().IsVerified(this.GetSignature()))
+            if (!streamCalculator.GetResult().IsVerified(GetSignature()))
                 throw new InvalidKeyException("Public key presented not for certificate signature");
         }
 
@@ -733,7 +730,7 @@ namespace Org.BouncyCastle.X509
             Asn1Encodable p2 = id2.Parameters;
 
             if ((p1 == null) == (p2 == null))
-                return Platform.Equals(p1, p2);
+                return Objects.Equals(p1, p2);
 
             // Exactly one of p1, p2 is null at this point
             return p1 == null
diff --git a/crypto/src/x509/X509CertificatePair.cs b/crypto/src/x509/X509CertificatePair.cs
index fbeba4dc6..cc4434f37 100644
--- a/crypto/src/x509/X509CertificatePair.cs
+++ b/crypto/src/x509/X509CertificatePair.cs
@@ -15,65 +15,45 @@ namespace Org.BouncyCastle.X509
 	/// </remarks>
 	public class X509CertificatePair
 	{
-		private readonly X509Certificate forward;
-		private readonly X509Certificate reverse;
+		private readonly X509Certificate m_forward;
+		private readonly X509Certificate m_reverse;
 
 		/// <summary>Constructor</summary>
 		/// <param name="forward">Certificate from the other CA to this CA.</param>
 		/// <param name="reverse">Certificate from this CA to the other CA.</param>
-		public X509CertificatePair(
-			X509Certificate	forward,
-			X509Certificate	reverse)
+		public X509CertificatePair(X509Certificate forward, X509Certificate	reverse)
 		{
-			this.forward = forward;
-			this.reverse = reverse;
+			if (forward == null && reverse == null)
+				throw new ArgumentException("At least one of the pair shall be present");
+
+			m_forward = forward;
+			m_reverse = reverse;
 		}
 
 		/// <summary>Constructor from a ASN.1 CertificatePair structure.</summary>
 		/// <param name="pair">The <c>CertificatePair</c> ASN.1 object.</param>
-		public X509CertificatePair(
-			CertificatePair pair)
+		public X509CertificatePair(CertificatePair pair)
 		{
-			if (pair.Forward != null)
-			{
-				this.forward = new X509Certificate(pair.Forward);
-			}
-			if (pair.Reverse != null)
-			{
-				this.reverse = new X509Certificate(pair.Reverse);
-			}
+			var forward = pair.Forward;
+			var reverse = pair.Reverse;
+
+            m_forward = forward == null ? null : new X509Certificate(forward);
+            m_reverse = reverse == null ? null : new X509Certificate(reverse);
 		}
 
-		public byte[] GetEncoded()
+		public CertificatePair GetCertificatePair()
+		{
+			return new CertificatePair(m_forward?.CertificateStructure, m_reverse?.CertificateStructure);
+        }
+
+        public byte[] GetEncoded()
 		{
 			try
 			{
-				X509CertificateStructure f = null, r = null;
-
-				if (forward != null)
-				{
-					f = X509CertificateStructure.GetInstance(
-						Asn1Object.FromByteArray(forward.GetEncoded()));
-
-					if (f == null)
-						throw new CertificateEncodingException("unable to get encoding for forward");
-				}
-
-				if (reverse != null)
-				{
-					r = X509CertificateStructure.GetInstance(
-						Asn1Object.FromByteArray(reverse.GetEncoded()));
-
-					if (r == null)
-						throw new CertificateEncodingException("unable to get encoding for reverse");
-				}
-
-				return new CertificatePair(f, r).GetDerEncoded();
+				return GetCertificatePair().GetEncoded(Asn1Encodable.Der);
 			}
 			catch (Exception e)
 			{
-				// TODO
-//				throw new ExtCertificateEncodingException(e.toString(), e);
 				throw new CertificateEncodingException(e.Message, e);
 			}
 		}
@@ -81,41 +61,38 @@ namespace Org.BouncyCastle.X509
 		/// <summary>Returns the certificate from the other CA to this CA.</summary>
 		public X509Certificate Forward
 		{
-			get { return forward; }
+			get { return m_forward; }
 		}
 
 		/// <summary>Returns the certificate from this CA to the other CA.</summary>
 		public X509Certificate Reverse
 		{
-			get { return reverse; }
+			get { return m_reverse; }
 		}
 
-		public override bool Equals(
-			object obj)
+		public override bool Equals(object obj)
 		{
 			if (obj == this)
 				return true;
 
-			X509CertificatePair other = obj as X509CertificatePair;
-
-			if (other == null)
+			if (!(obj is X509CertificatePair that))
 				return false;
 
-			return Platform.Equals(this.forward, other.forward)
-				&& Platform.Equals(this.reverse, other.reverse);
+			return Objects.Equals(this.m_forward, that.m_forward)
+				&& Objects.Equals(this.m_reverse, that.m_reverse);
 		}
 
 		public override int GetHashCode()
 		{
 			int hash = -1;
-			if (forward != null)
+			if (m_forward != null)
 			{
-				hash ^= forward.GetHashCode();
+				hash ^= m_forward.GetHashCode();
 			}
-			if (reverse != null)
+			if (m_reverse != null)
 			{
 				hash *= 17;
-				hash ^= reverse.GetHashCode();
+				hash ^= m_reverse.GetHashCode();
 			}
 			return hash;
 		}
diff --git a/crypto/src/x509/X509Crl.cs b/crypto/src/x509/X509Crl.cs
index db13f4f2f..a3f08a0ed 100644
--- a/crypto/src/x509/X509Crl.cs
+++ b/crypto/src/x509/X509Crl.cs
@@ -130,12 +130,10 @@ namespace Org.BouncyCastle.X509
             if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
                 throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
 
-            byte[] b = GetTbsCertList();
-
             IStreamCalculator<IVerifier> streamCalculator = verifier.CreateCalculator();
 			using (var stream = streamCalculator.Stream)
 			{
-				stream.Write(b, 0, b.Length);
+				c.TbsCertList.EncodeTo(stream, Asn1Encodable.Der);
             }
 
             if (!streamCalculator.GetResult().IsVerified(GetSignature()))
@@ -308,13 +306,13 @@ namespace Org.BouncyCastle.X509
 			byte[] sig = this.GetSignature();
 
 			buf.Append("            Signature: ");
-			buf.Append(Hex.ToHexString(sig, 0, 20)).AppendLine();
+			buf.AppendLine(Hex.ToHexString(sig, 0, 20));
 
 			for (int i = 20; i < sig.Length; i += 20)
 			{
 				int count = System.Math.Min(20, sig.Length - i);
 				buf.Append("                       ");
-				buf.Append(Hex.ToHexString(sig, i, count)).AppendLine();
+				buf.AppendLine(Hex.ToHexString(sig, i, count));
 			}
 
 			X509Extensions extensions = c.TbsCertList.Extensions;
@@ -325,7 +323,7 @@ namespace Org.BouncyCastle.X509
 
 				if (e.MoveNext())
 				{
-					buf.Append("           Extensions: ").AppendLine();
+					buf.AppendLine("           Extensions:");
 				}
 
 				do
diff --git a/crypto/src/x509/X509CrlEntry.cs b/crypto/src/x509/X509CrlEntry.cs
index 87fc2e37a..0c45c857d 100644
--- a/crypto/src/x509/X509CrlEntry.cs
+++ b/crypto/src/x509/X509CrlEntry.cs
@@ -177,7 +177,7 @@ namespace Org.BouncyCastle.X509
 				var e = extensions.ExtensionOids.GetEnumerator();
 				if (e.MoveNext())
 				{
-					buf.Append("   crlEntryExtensions:").AppendLine();
+					buf.AppendLine("   crlEntryExtensions:");
 
 					do
 					{
diff --git a/crypto/src/x509/X509V1CertificateGenerator.cs b/crypto/src/x509/X509V1CertificateGenerator.cs
index d95f522e8..93ec03ea3 100644
--- a/crypto/src/x509/X509V1CertificateGenerator.cs
+++ b/crypto/src/x509/X509V1CertificateGenerator.cs
@@ -125,7 +125,7 @@ namespace Org.BouncyCastle.X509
 			TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
 
 			IStreamCalculator<IBlockResult> streamCalculator = signatureFactory.CreateCalculator();
-			using (Stream sigStream = streamCalculator.Stream)
+			using (var sigStream = streamCalculator.Stream)
 			{
 				tbsCert.EncodeTo(sigStream, Asn1Encodable.Der);
 			}
diff --git a/crypto/src/x509/X509V2AttributeCertificate.cs b/crypto/src/x509/X509V2AttributeCertificate.cs
index 61702aebd..b5a316d76 100644
--- a/crypto/src/x509/X509V2AttributeCertificate.cs
+++ b/crypto/src/x509/X509V2AttributeCertificate.cs
@@ -190,11 +190,9 @@ namespace Org.BouncyCastle.X509
 
 			try
 			{
-                byte[] b = this.cert.ACInfo.GetEncoded();
-
 				using (var stream = streamCalculator.Stream)
 				{
-                    stream.Write(b, 0, b.Length);
+					cert.ACInfo.EncodeTo(stream);
                 }
             }
 			catch (IOException e)
@@ -202,7 +200,7 @@ namespace Org.BouncyCastle.X509
 				throw new SignatureException("Exception encoding certificate info object", e);
 			}
 
-			if (!streamCalculator.GetResult().IsVerified(this.GetSignature()))
+			if (!streamCalculator.GetResult().IsVerified(GetSignature()))
 				throw new InvalidKeyException("Public key presented not for certificate signature");
 		}
 
diff --git a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
index 3a0a02ea9..f1f4c0473 100644
--- a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
+++ b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
@@ -120,7 +120,7 @@ namespace Org.BouncyCastle.X509
             AttributeCertificateInfo acInfo = acInfoGen.GenerateAttributeCertificateInfo();
 
 			IStreamCalculator<IBlockResult> streamCalculator = signatureFactory.CreateCalculator();
-			using (Stream sigStream = streamCalculator.Stream)
+			using (var sigStream = streamCalculator.Stream)
 			{
 				acInfo.EncodeTo(sigStream, Asn1Encodable.Der);
 			}
diff --git a/crypto/src/x509/X509V2CRLGenerator.cs b/crypto/src/x509/X509V2CRLGenerator.cs
index a57383613..01d7aee4a 100644
--- a/crypto/src/x509/X509V2CRLGenerator.cs
+++ b/crypto/src/x509/X509V2CRLGenerator.cs
@@ -7,7 +7,6 @@ using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security.Certificates;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.X509
 {
@@ -188,7 +187,7 @@ namespace Org.BouncyCastle.X509
 			TbsCertificateList tbsCertList = tbsGen.GenerateTbsCertList();
 
             IStreamCalculator<IBlockResult> streamCalculator = signatureFactory.CreateCalculator();
-			using (Stream sigStream = streamCalculator.Stream)
+			using (var sigStream = streamCalculator.Stream)
 			{
 				tbsCertList.EncodeTo(sigStream, Asn1Encodable.Der);
 			}
diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs
index 1854ac3b4..ee35b9479 100644
--- a/crypto/src/x509/X509V3CertificateGenerator.cs
+++ b/crypto/src/x509/X509V3CertificateGenerator.cs
@@ -260,7 +260,7 @@ namespace Org.BouncyCastle.X509
             TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
 
 			IStreamCalculator<IBlockResult> streamCalculator = signatureFactory.CreateCalculator();
-			using (Stream sigStream = streamCalculator.Stream)
+			using (var sigStream = streamCalculator.Stream)
             {
 				tbsCert.EncodeTo(sigStream, Asn1Encodable.Der);
 			}
diff --git a/crypto/src/x509/store/X509AttrCertStoreSelector.cs b/crypto/src/x509/store/X509AttrCertStoreSelector.cs
index e68208c74..6b3c854f1 100644
--- a/crypto/src/x509/store/X509AttrCertStoreSelector.cs
+++ b/crypto/src/x509/store/X509AttrCertStoreSelector.cs
@@ -72,8 +72,7 @@ namespace Org.BouncyCastle.X509.Store
 
 			if (targetNames.Count > 0 || targetGroups.Count > 0)
 			{
-				Asn1OctetString targetInfoExt = attrCert.GetExtensionValue(
-					X509Extensions.TargetInformation);
+				Asn1OctetString targetInfoExt = attrCert.GetExtensionValue(X509Extensions.TargetInformation);
 
 				if (targetInfoExt != null)
 				{
@@ -109,10 +108,9 @@ namespace Org.BouncyCastle.X509.Store
 								}
 							}
 						}
+
 						if (!found)
-						{
 							return false;
-						}
 					}
 
 					if (targetGroups.Count > 0)
@@ -136,9 +134,7 @@ namespace Org.BouncyCastle.X509.Store
 						}
 
 						if (!found)
-						{
 							return false;
-						}
 					}
 				}
 			}
@@ -204,8 +200,7 @@ namespace Org.BouncyCastle.X509.Store
 		*
 		* @param name The name as a GeneralName (not <code>null</code>)
 		*/
-		public void AddTargetName(
-			GeneralName name)
+		public void AddTargetName(GeneralName name)
 		{
 			targetNames.Add(name);
 		}
@@ -338,18 +333,7 @@ namespace Org.BouncyCastle.X509.Store
 			{
 				foreach (object o in names)
 				{
-					if (o is GeneralName gn)
-					{
-						result.Add(gn);
-					}
-					else if (o is byte[] bs)
-					{
-						result.Add(GeneralName.GetInstance(Asn1Object.FromByteArray(bs)));
-					}
-					else
-                    {
-						throw new InvalidOperationException();
-                    }
+                    result.Add(GeneralName.GetInstance(o));
 				}
 			}