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/AssemblyInfo.cs26
-rw-r--r--crypto/src/BouncyCastle.Crypto.csproj36
-rw-r--r--crypto/src/asn1/Asn1GeneralizedTime.cs439
-rw-r--r--crypto/src/asn1/Asn1InputStream.cs4
-rw-r--r--crypto/src/asn1/Asn1UniversalTypes.cs4
-rw-r--r--crypto/src/asn1/Asn1UtcTime.cs264
-rw-r--r--crypto/src/asn1/DerGeneralizedTime.cs350
-rw-r--r--crypto/src/asn1/DerUTCTime.cs259
-rw-r--r--crypto/src/asn1/bc/BCObjectIdentifiers.cs11
-rw-r--r--crypto/src/asn1/cmp/PKIHeader.cs6
-rw-r--r--crypto/src/asn1/cmp/PKIHeaderBuilder.cs4
-rw-r--r--crypto/src/asn1/cmp/RevAnnContent.cs20
-rw-r--r--crypto/src/asn1/cms/CMSObjectIdentifiers.cs3
-rw-r--r--crypto/src/asn1/cms/KEKIdentifier.cs12
-rw-r--r--crypto/src/asn1/cms/RecipientKeyIdentifier.cs14
-rw-r--r--crypto/src/asn1/cms/Time.cs42
-rw-r--r--crypto/src/asn1/esf/CrlIdentifier.cs47
-rw-r--r--crypto/src/asn1/esf/OcspIdentifier.cs25
-rw-r--r--crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs6
-rw-r--r--crypto/src/asn1/ocsp/CrlID.cs6
-rw-r--r--crypto/src/asn1/ocsp/ResponseData.cs10
-rw-r--r--crypto/src/asn1/ocsp/RevokedInfo.cs10
-rw-r--r--crypto/src/asn1/ocsp/SingleResponse.cs18
-rw-r--r--crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs11
-rw-r--r--crypto/src/asn1/tsp/TSTInfo.cs8
-rw-r--r--crypto/src/asn1/util/Asn1Dump.cs4
-rw-r--r--crypto/src/asn1/x509/AttCertValidityPeriod.cs16
-rw-r--r--crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs10
-rw-r--r--crypto/src/asn1/x509/TBSCertList.cs4
-rw-r--r--crypto/src/asn1/x509/Time.cs39
-rw-r--r--crypto/src/asn1/x509/V1TBSCertificateGenerator.cs4
-rw-r--r--crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs10
-rw-r--r--crypto/src/asn1/x509/V2TBSCertListGenerator.cs8
-rw-r--r--crypto/src/asn1/x509/V3TBSCertificateGenerator.cs4
-rw-r--r--crypto/src/asn1/x509/X509DefaultEntryConverter.cs2
-rw-r--r--crypto/src/asn1/x509/sigi/PersonalData.cs8
-rw-r--r--crypto/src/bcpg/SignaturePacket.cs10
-rw-r--r--crypto/src/bcpg/sig/Exportable.cs12
-rw-r--r--crypto/src/bcpg/sig/Features.cs18
-rw-r--r--crypto/src/bcpg/sig/IssuerKeyId.cs37
-rw-r--r--crypto/src/bcpg/sig/KeyExpirationTime.cs25
-rw-r--r--crypto/src/bcpg/sig/NotationData.cs2
-rw-r--r--crypto/src/bcpg/sig/PrimaryUserId.cs15
-rw-r--r--crypto/src/bcpg/sig/Revocable.cs15
-rw-r--r--crypto/src/bcpg/sig/RevocationReason.cs2
-rw-r--r--crypto/src/bcpg/sig/SignatureCreationTime.cs27
-rw-r--r--crypto/src/bcpg/sig/SignatureExpirationTime.cs32
-rw-r--r--crypto/src/bcpg/sig/SignerUserId.cs4
-rw-r--r--crypto/src/cmp/ProtectedPkiMessageBuilder.cs9
-rw-r--r--crypto/src/cms/CMSAuthenticatedDataGenerator.cs18
-rw-r--r--crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs20
-rw-r--r--crypto/src/cms/CMSAuthenticatedGenerator.cs15
-rw-r--r--crypto/src/cms/CMSCompressedData.cs8
-rw-r--r--crypto/src/cms/CMSCompressedDataGenerator.cs17
-rw-r--r--crypto/src/cms/CMSCompressedDataParser.cs5
-rw-r--r--crypto/src/cms/CMSCompressedDataStreamGenerator.cs40
-rw-r--r--crypto/src/cms/CMSEnvelopedDataGenerator.cs17
-rw-r--r--crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs15
-rw-r--r--crypto/src/cms/CMSEnvelopedGenerator.cs22
-rw-r--r--crypto/src/cms/CMSSignedDataGenerator.cs19
-rw-r--r--crypto/src/cms/CMSSignedDataStreamGenerator.cs9
-rw-r--r--crypto/src/cms/CMSSignedGenerator.cs17
-rw-r--r--crypto/src/cms/CMSSignedHelper.cs17
-rw-r--r--crypto/src/crmf/PKMacBuilder.cs5
-rw-r--r--crypto/src/crypto/CipherKeyGenerator.cs2
-rw-r--r--crypto/src/crypto/Security.cs74
-rw-r--r--crypto/src/crypto/agreement/DHAgreement.cs17
-rwxr-xr-xcrypto/src/crypto/agreement/jpake/JPakeParticipant.cs7
-rw-r--r--crypto/src/crypto/digests/Haraka256_X86.cs24
-rw-r--r--crypto/src/crypto/digests/Haraka512_X86.cs32
-rw-r--r--crypto/src/crypto/digests/HarakaBase.cs11
-rw-r--r--crypto/src/crypto/digests/KeccakDigest.cs58
-rw-r--r--crypto/src/crypto/encodings/OaepEncoding.cs2
-rw-r--r--crypto/src/crypto/encodings/Pkcs1Encoding.cs2
-rw-r--r--crypto/src/crypto/engines/AesEngine_X86.cs57
-rw-r--r--crypto/src/crypto/engines/ChaCha7539Engine.cs61
-rw-r--r--crypto/src/crypto/engines/ChaChaEngine.cs14
-rw-r--r--crypto/src/crypto/engines/DesEdeWrapEngine.cs5
-rw-r--r--crypto/src/crypto/engines/ElGamalEngine.cs22
-rw-r--r--crypto/src/crypto/engines/RC2WrapEngine.cs13
-rw-r--r--crypto/src/crypto/engines/RFC3211WrapEngine.cs14
-rw-r--r--crypto/src/crypto/engines/RSABlindedEngine.cs10
-rw-r--r--crypto/src/crypto/engines/Salsa20Engine.cs153
-rw-r--r--crypto/src/crypto/engines/VMPCEngine.cs28
-rw-r--r--crypto/src/crypto/fpe/SP80038G.cs99
-rw-r--r--crypto/src/crypto/generators/ECKeyPairGenerator.cs2
-rw-r--r--crypto/src/crypto/generators/RSABlindingFactorGenerator.cs9
-rw-r--r--crypto/src/crypto/generators/SCrypt.cs15
-rw-r--r--crypto/src/crypto/macs/Poly1305.cs77
-rw-r--r--crypto/src/crypto/modes/GCMBlockCipher.cs65
-rw-r--r--crypto/src/crypto/modes/gcm/GcmUtilities.cs28
-rw-r--r--crypto/src/crypto/operators/Asn1CipherBuilder.cs5
-rw-r--r--crypto/src/crypto/paddings/ISO10126d2Padding.cs2
-rw-r--r--crypto/src/crypto/parameters/ParametersWithRandom.cs2
-rw-r--r--crypto/src/crypto/prng/BasicEntropySourceProvider.cs6
-rw-r--r--crypto/src/crypto/prng/SP800SecureRandomBuilder.cs5
-rw-r--r--crypto/src/crypto/prng/VMPCRandomGenerator.cs122
-rw-r--r--crypto/src/crypto/prng/X931SecureRandomBuilder.cs5
-rw-r--r--crypto/src/crypto/signers/DsaSigner.cs2
-rw-r--r--crypto/src/crypto/signers/ECDsaSigner.cs2
-rw-r--r--crypto/src/crypto/signers/ECGOST3410Signer.cs2
-rw-r--r--crypto/src/crypto/signers/ECNRSigner.cs10
-rw-r--r--crypto/src/crypto/signers/GOST3410Signer.cs10
-rw-r--r--crypto/src/crypto/signers/Iso9796d2PssSigner.cs26
-rw-r--r--crypto/src/crypto/signers/PssSigner.cs18
-rw-r--r--crypto/src/crypto/signers/SM2Signer.cs6
-rw-r--r--crypto/src/crypto/util/Pack.cs6
-rw-r--r--crypto/src/math/BigInteger.cs10
-rw-r--r--crypto/src/math/ec/ECCurve.cs4
-rw-r--r--crypto/src/math/ec/ECPoint.cs7
-rw-r--r--crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs4
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs1
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571Field.cs20
-rw-r--r--crypto/src/math/raw/Mod.cs29
-rw-r--r--crypto/src/math/raw/Nat.cs593
-rw-r--r--crypto/src/math/raw/Nat256.cs71
-rw-r--r--crypto/src/math/raw/Nat512.cs315
-rw-r--r--crypto/src/ocsp/BasicOCSPRespGenerator.cs9
-rw-r--r--crypto/src/ocsp/RevokedStatus.cs2
-rw-r--r--crypto/src/openpgp/PgpCompressedData.cs23
-rw-r--r--crypto/src/openpgp/PgpCompressedDataGenerator.cs58
-rw-r--r--crypto/src/openpgp/PgpEncryptedDataGenerator.cs41
-rw-r--r--crypto/src/openssl/Pkcs8Generator.cs5
-rw-r--r--crypto/src/pkix/PkixCertPathValidatorUtilities.cs4
-rw-r--r--crypto/src/pqc/crypto/bike/BikeEngine.cs5
-rw-r--r--crypto/src/pqc/crypto/bike/BikeKeyPairGenerator.cs20
-rw-r--r--crypto/src/pqc/crypto/bike/BikeRing.cs45
-rw-r--r--crypto/src/pqc/crypto/cmce/CmceEngine.cs69
-rw-r--r--crypto/src/pqc/crypto/falcon/FalconFPR.cs5
-rw-r--r--crypto/src/pqc/crypto/falcon/FalconSigner.cs21
-rw-r--r--crypto/src/pqc/crypto/hqc/FastFourierTransform.cs279
-rw-r--r--crypto/src/pqc/crypto/hqc/GF2PolynomialCalculator.cs134
-rw-r--r--crypto/src/pqc/crypto/hqc/GFCalculator.cs29
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcEngine.cs436
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcKeccakRandomGenerator.cs321
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcKemExtractor.cs37
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcKemGenerator.cs89
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcKeyGenerationParameters.cs19
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcKeyPairGenerator.cs69
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcKeyParameters.cs19
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcParameters.cs71
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcPrivateKeyParameters.cs20
-rw-r--r--crypto/src/pqc/crypto/hqc/HqcPublicKeyParameters.cs21
-rw-r--r--crypto/src/pqc/crypto/hqc/ReedMuller.cs196
-rw-r--r--crypto/src/pqc/crypto/hqc/ReedSolomon.cs264
-rw-r--r--crypto/src/pqc/crypto/hqc/Utils.cs155
-rw-r--r--crypto/src/pqc/crypto/lms/HSS.cs54
-rw-r--r--crypto/src/pqc/crypto/lms/HSSKeyGenerationParameters.cs12
-rw-r--r--crypto/src/pqc/crypto/lms/HSSKeyPairGenerator.cs8
-rw-r--r--crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs161
-rw-r--r--crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs45
-rw-r--r--crypto/src/pqc/crypto/lms/HSSSignature.cs45
-rw-r--r--crypto/src/pqc/crypto/lms/HSSSigner.cs14
-rw-r--r--crypto/src/pqc/crypto/lms/ILMSContextBasedSigner.cs6
-rw-r--r--crypto/src/pqc/crypto/lms/ILMSContextBasedVerifier.cs6
-rw-r--r--crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs16
-rw-r--r--crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs42
-rw-r--r--crypto/src/pqc/crypto/lms/LMOtsSignature.cs22
-rw-r--r--crypto/src/pqc/crypto/lms/LMS.cs46
-rw-r--r--crypto/src/pqc/crypto/lms/LMSContext.cs14
-rw-r--r--crypto/src/pqc/crypto/lms/LMSException.cs10
-rw-r--r--crypto/src/pqc/crypto/lms/LMSKeyGenerationParameters.cs10
-rw-r--r--crypto/src/pqc/crypto/lms/LMSKeyPairGenerator.cs8
-rw-r--r--crypto/src/pqc/crypto/lms/LMSKeyParameters.cs4
-rw-r--r--crypto/src/pqc/crypto/lms/LMSParameters.cs4
-rw-r--r--crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs161
-rw-r--r--crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs62
-rw-r--r--crypto/src/pqc/crypto/lms/LMSSignature.cs24
-rw-r--r--crypto/src/pqc/crypto/lms/LMSSignedPubKey.cs14
-rw-r--r--crypto/src/pqc/crypto/lms/LMSSigner.cs14
-rw-r--r--crypto/src/pqc/crypto/lms/LM_OTS.cs24
-rw-r--r--crypto/src/pqc/crypto/lms/LmsUtils.cs4
-rw-r--r--crypto/src/pqc/crypto/saber/Poly.cs81
-rw-r--r--crypto/src/pqc/crypto/saber/SABEREngine.cs197
-rw-r--r--crypto/src/pqc/crypto/saber/SABERKEMExtractor.cs13
-rw-r--r--crypto/src/pqc/crypto/saber/SABERKEMGenerator.cs16
-rw-r--r--crypto/src/pqc/crypto/saber/SABERKeyGenerationParameters.cs9
-rw-r--r--crypto/src/pqc/crypto/saber/SABERKeyPairGenerator.cs7
-rw-r--r--crypto/src/pqc/crypto/saber/SABERKeyParameters.cs16
-rw-r--r--crypto/src/pqc/crypto/saber/SABERParameters.cs50
-rw-r--r--crypto/src/pqc/crypto/saber/SABERPrivateKeyParameters.cs16
-rw-r--r--crypto/src/pqc/crypto/saber/SABERPublicKeyParameters.cs19
-rw-r--r--crypto/src/pqc/crypto/saber/SaberUtilities.cs (renamed from crypto/src/pqc/crypto/saber/Utils.cs)153
-rw-r--r--crypto/src/pqc/crypto/saber/Symmetric.cs99
-rw-r--r--crypto/src/pqc/crypto/sike/Fpx.cs27
-rw-r--r--crypto/src/pqc/crypto/sike/Internal.cs401
-rw-r--r--crypto/src/pqc/crypto/sike/Isogeny.cs154
-rw-r--r--crypto/src/pqc/crypto/sike/PointProj.cs17
-rw-r--r--crypto/src/pqc/crypto/sike/PointProjFull.cs20
-rw-r--r--crypto/src/pqc/crypto/sike/SIDH.cs60
-rw-r--r--crypto/src/pqc/crypto/sike/SIDH_Compressed.cs232
-rw-r--r--crypto/src/pqc/crypto/sike/SIKEEngine.cs19
-rw-r--r--crypto/src/pqc/crypto/sike/SIKEKEMExtractor.cs65
-rw-r--r--crypto/src/pqc/crypto/sike/SIKEKEMGenerator.cs53
-rw-r--r--crypto/src/pqc/crypto/sike/SIKEKeyGenerationParameters.cs28
-rw-r--r--crypto/src/pqc/crypto/sike/SIKEKeyPairGenerator.cs16
-rw-r--r--crypto/src/pqc/crypto/sike/SIKEKeyParameters.cs27
-rw-r--r--crypto/src/pqc/crypto/sike/SIKEParameters.cs43
-rw-r--r--crypto/src/pqc/crypto/sike/SIKEPrivateKeyParameters.cs35
-rw-r--r--crypto/src/pqc/crypto/sike/SIKEPublicKeyParameters.cs35
-rw-r--r--crypto/src/pqc/crypto/sike/SikeUtilities.cs (renamed from crypto/src/pqc/crypto/sike/Utils.cs)14
-rw-r--r--crypto/src/pqc/crypto/sphincsplus/HarakaSBase.cs73
-rw-r--r--crypto/src/pqc/crypto/sphincsplus/HarakaS_X86.cs14
-rw-r--r--crypto/src/pqc/crypto/utils/PqcUtilities.cs76
-rw-r--r--crypto/src/pqc/crypto/utils/PrivateKeyFactory.cs73
-rw-r--r--crypto/src/pqc/crypto/utils/PrivateKeyInfoFactory.cs163
-rw-r--r--crypto/src/pqc/crypto/utils/PublicKeyFactory.cs190
-rw-r--r--crypto/src/pqc/crypto/utils/SecretWithEncapsulationImpl.cs76
-rw-r--r--crypto/src/pqc/crypto/utils/SubjectPublicKeyInfoFactory.cs155
-rw-r--r--crypto/src/security/CipherUtilities.cs2
-rw-r--r--crypto/src/security/DotNetUtilities.cs27
-rw-r--r--crypto/src/security/GeneratorUtilities.cs6
-rw-r--r--crypto/src/security/JksStore.cs99
-rw-r--r--crypto/src/security/ParameterUtilities.cs2
-rw-r--r--crypto/src/security/SecureRandom.cs43
-rw-r--r--crypto/src/security/SignerUtilities.cs30
-rw-r--r--crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs5
-rw-r--r--crypto/src/tsp/TimeStampTokenGenerator.cs65
-rw-r--r--crypto/src/util/Arrays.cs5
-rw-r--r--crypto/src/util/BigIntegers.cs2
-rw-r--r--crypto/src/util/Bytes.cs2
-rw-r--r--crypto/src/util/Integers.cs13
-rw-r--r--crypto/src/util/Longs.cs13
-rw-r--r--crypto/src/util/Platform.cs2
-rw-r--r--crypto/src/util/Shorts.cs54
-rw-r--r--crypto/src/util/Strings.cs2
-rw-r--r--crypto/src/util/bzip2/BZip2Constants.cs (renamed from crypto/src/bzip2/BZip2Constants.cs)4
-rw-r--r--crypto/src/util/bzip2/CBZip2InputStream.cs (renamed from crypto/src/bzip2/CBZip2InputStream.cs)3
-rw-r--r--crypto/src/util/bzip2/CBZip2OutputStream.cs (renamed from crypto/src/bzip2/CBZip2OutputStream.cs)22
-rw-r--r--crypto/src/util/bzip2/CRC.cs (renamed from crypto/src/bzip2/CRC.cs)5
-rw-r--r--crypto/src/util/date/DateTimeUtilities.cs58
-rw-r--r--crypto/src/util/io/BinaryReaders.cs94
-rw-r--r--crypto/src/util/io/BinaryWriters.cs86
-rw-r--r--crypto/src/util/io/Streams.cs13
-rw-r--r--crypto/src/util/io/compression/Bzip2.cs21
-rw-r--r--crypto/src/util/io/compression/ZLib.cs46
-rw-r--r--crypto/src/util/io/compression/Zip.cs33
-rw-r--r--crypto/src/util/zlib/ZOutputStream.cs34
-rw-r--r--crypto/src/x509/X509V2AttributeCertificateGenerator.cs4
-rw-r--r--crypto/src/x509/X509V2CRLGenerator.cs3
250 files changed, 7325 insertions, 3901 deletions
diff --git a/crypto/src/AssemblyInfo.cs b/crypto/src/AssemblyInfo.cs
index f89d58fbd..dfc22336a 100644
--- a/crypto/src/AssemblyInfo.cs
+++ b/crypto/src/AssemblyInfo.cs
@@ -3,29 +3,3 @@ using System.Runtime.InteropServices;
 
 [assembly: CLSCompliant(true)]
 [assembly: ComVisible(false)]
-
-// Start with no permissions
-//[assembly: PermissionSet(SecurityAction.RequestOptional, Unrestricted=false)]
-//...and explicitly add those we need
-
-// see Org.BouncyCastle.Crypto.Encodings.Pkcs1Encoding.StrictLengthEnabledProperty
-//[assembly: EnvironmentPermission(SecurityAction.RequestOptional, Read="Org.BouncyCastle.Pkcs1.Strict")]
-
-#if !(NET45_OR_GREATER || NETSTANDARD1_0_OR_GREATER)
-namespace System.Reflection
-{
-    [AttributeUsage(AttributeTargets.Assembly, AllowMultiple = true, Inherited = false)]
-    internal sealed class AssemblyMetadataAttribute : Attribute
-    {
-        public AssemblyMetadataAttribute(string key, string value)
-        {
-            Key = key;
-            Value = value;
-        }
-
-        public string Key { get; }
-
-        public string Value { get; }
-    }
-}
-#endif
diff --git a/crypto/src/BouncyCastle.Crypto.csproj b/crypto/src/BouncyCastle.Crypto.csproj
index 9786cd985..44925aebd 100644
--- a/crypto/src/BouncyCastle.Crypto.csproj
+++ b/crypto/src/BouncyCastle.Crypto.csproj
@@ -5,13 +5,32 @@
     <RootNamespace>Org.BouncyCastle</RootNamespace>
     <AssemblyOriginatorKeyFile>..\..\BouncyCastle.snk</AssemblyOriginatorKeyFile>
     <SignAssembly>true</SignAssembly>
+	<NoWarn>1591</NoWarn>
+
+    <Authors />
+    <Company>Legion of the Bouncy Castle Inc.</Company>
+    <Copyright>Copyright © Legion of the Bouncy Castle Inc. 2000-2022</Copyright>
+    <DebugType>embedded</DebugType>
+    <Description>BouncyCastle.NET is a popular cryptography library for .NET</Description>
+    <EmbedUntrackedSources>true</EmbedUntrackedSources>	  
+    <PackageIconUrl>https://www.bouncycastle.org/images/csharp_logo.gif</PackageIconUrl>
+    <PackageId>BouncyCastle.Cryptography</PackageId>
+    <PackageLicenseFile>License.html</PackageLicenseFile>
+    <PackageProjectUrl>https://www.bouncycastle.org/csharp/</PackageProjectUrl>
+    <PackageReleaseNotes>https://www.bouncycastle.org/csharp/</PackageReleaseNotes>
+    <PackageTags>bouncycastle cryptography dtls encryption security tls</PackageTags>
+	<Product>BouncyCastle.NET</Product>
+    <!--<PublishRepositoryUrl>true</PublishRepositoryUrl>-->
+    <RepositoryType>git</RepositoryType>
+    <RepositoryUrl>https://github.com/bcgit/bc-csharp</RepositoryUrl>
+    <Title>BouncyCastle.NET Cryptography</Title>
   </PropertyGroup>
 
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
+  <PropertyGroup Condition="'$(Configuration)'=='Debug'">
     <DefineConstants>DEBUG;TRACE</DefineConstants>
   </PropertyGroup>
 
-  <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
+  <PropertyGroup Condition="'$(Configuration)'=='Release'">
     <DefineConstants />
     <GenerateDocumentationFile>true</GenerateDocumentationFile>
   </PropertyGroup>
@@ -20,12 +39,23 @@
     <None Remove="**\*.properties" />
     <EmbeddedResource Include="**\*.properties" />
   </ItemGroup>
+
+  <ItemGroup>
+    <None Include="..\License.html">
+      <Pack>True</Pack>
+      <PackagePath>\</PackagePath>
+    </None>
+  </ItemGroup>
   <ItemGroup>
+    <PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies" Version="1.0.3">
+      <PrivateAssets>all</PrivateAssets>
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+    </PackageReference>
     <PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.1.1">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
-    <PackageReference Include="Nerdbank.GitVersioning" Version="3.5.113">
+    <PackageReference Include="Nerdbank.GitVersioning" Version="3.5.119">
       <PrivateAssets>all</PrivateAssets>
       <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
     </PackageReference>
diff --git a/crypto/src/asn1/Asn1GeneralizedTime.cs b/crypto/src/asn1/Asn1GeneralizedTime.cs
new file mode 100644
index 000000000..e844c8ca2
--- /dev/null
+++ b/crypto/src/asn1/Asn1GeneralizedTime.cs
@@ -0,0 +1,439 @@
+using System;
+using System.Globalization;
+using System.IO;
+using System.Text;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * Base class representing the ASN.1 GeneralizedTime type.
+     * <p>
+     * The main difference between these and UTC time is a 4 digit year.
+     * </p>
+     * <p>
+     * One second resolution date+time on UTC timezone (Z)
+     * with 4 digit year (valid from 0001 to 9999).
+     * </p><p>
+     * Timestamp format is:  yyyymmddHHMMSS'Z'
+     * </p><p>
+     * <h2>X.690</h2>
+     * This is what is called "restricted string",
+     * and it uses ASCII characters to encode digits and supplemental data.
+     *
+     * <h3>11: Restrictions on BER employed by both CER and DER</h3>
+     * <h4>11.7 GeneralizedTime </h4>
+     * <p>
+     * <b>11.7.1</b> The encoding shall terminate with a "Z",
+     * as described in the ITU-T Rec. X.680 | ISO/IEC 8824-1 clause on
+     * GeneralizedTime.
+     * </p><p>
+     * <b>11.7.2</b> The seconds element shall always be present.
+     * </p>
+     * <p>
+     * <b>11.7.3</b> The fractional-seconds elements, if present,
+     * shall omit all trailing zeros; if the elements correspond to 0,
+     * they shall be wholly omitted, and the decimal point element also
+     * shall be omitted.
+     */
+    public class Asn1GeneralizedTime
+        : Asn1Object
+    {
+        internal class Meta : Asn1UniversalType
+        {
+            internal static readonly Asn1UniversalType Instance = new Meta();
+
+            private Meta() : base(typeof(Asn1GeneralizedTime), Asn1Tags.GeneralizedTime) { }
+
+            internal override Asn1Object FromImplicitPrimitive(DerOctetString octetString)
+            {
+                return CreatePrimitive(octetString.GetOctets());
+            }
+        }
+
+        public static Asn1GeneralizedTime GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1GeneralizedTime asn1GeneralizedTime)
+                return asn1GeneralizedTime;
+
+            if (obj is IAsn1Convertible asn1Convertible)
+            {
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is Asn1GeneralizedTime converted)
+                    return converted;
+            }
+            else if (obj is byte[] bytes)
+            {
+                try
+                {
+                    return (Asn1GeneralizedTime)Meta.Instance.FromByteArray(bytes);
+                }
+                catch (IOException e)
+                {
+                    throw new ArgumentException("failed to construct generalized time from byte[]: " + e.Message);
+                }
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), nameof(obj));
+        }
+
+        public static Asn1GeneralizedTime GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return (Asn1GeneralizedTime)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
+        }
+
+        internal readonly byte[] m_contents;
+
+        public Asn1GeneralizedTime(string time)
+        {
+            m_contents = Strings.ToByteArray(time);
+
+            try
+            {
+                ToDateTime();
+            }
+            catch (FormatException e)
+            {
+                throw new ArgumentException("invalid date string: " + e.Message);
+            }
+        }
+
+        public Asn1GeneralizedTime(DateTime time)
+        {
+            DateTime utc = time.ToUniversalTime();
+            var formatStr = @"yyyyMMddHHmmss\Z";
+            var formatProvider = DateTimeFormatInfo.InvariantInfo;
+            string utcString = utc.ToString(formatStr, formatProvider);
+            m_contents = Strings.ToByteArray(utcString);
+        }
+
+        // TODO Custom locale constructor?
+        //public Asn1GeneralizedTime(DateTime time, Locale locale)
+        //{
+        //    SimpleDateFormat dateF = new SimpleDateFormat("yyyyMMddHHmmss\Z", locale);
+
+        //    dateF.setTimeZone(new SimpleTimeZone(0, "Z"));
+
+        //    this.contents = Strings.toByteArray(dateF.format(time));
+        //}
+
+        internal Asn1GeneralizedTime(byte[] bytes)
+        {
+            if (bytes == null)
+                throw new ArgumentNullException(nameof(bytes));
+            if (bytes.Length < 4)
+                throw new ArgumentException("GeneralizedTime string too short", nameof(bytes));
+
+            m_contents = bytes;
+
+            if (!(IsDigit(0) && IsDigit(1) && IsDigit(2) && IsDigit(3)))
+                throw new ArgumentException("illegal characters in GeneralizedTime string", nameof(bytes));
+        }
+
+        public string TimeString => Strings.FromByteArray(m_contents);
+
+        public string GetTime()
+        {
+            string stime = Strings.FromByteArray(m_contents);
+
+            //
+            // standardise the format.
+            //
+            if (stime[stime.Length - 1] == 'Z')
+                return stime.Substring(0, stime.Length - 1) + "GMT+00:00";
+
+            int signPos = stime.Length - 6;
+            char sign = stime[signPos];
+            if ((sign == '-' || sign == '+') && stime.IndexOf("GMT") == signPos - 3)
+            {
+                // already a GMT string!
+                return stime;
+            }
+
+            signPos = stime.Length - 5;
+            sign = stime[signPos];
+            if (sign == '-' || sign == '+')
+            {
+                return stime.Substring(0, signPos)
+                    + "GMT"
+                    + stime.Substring(signPos, 3)
+                    + ":"
+                    + stime.Substring(signPos + 3);
+            }
+
+            signPos = stime.Length - 3;
+            sign = stime[signPos];
+            if (sign == '-' || sign == '+')
+            {
+                return stime.Substring(0, signPos)
+                    + "GMT"
+                    + stime.Substring(signPos)
+                    + ":00";
+            }
+
+            return stime + CalculateGmtOffset(stime);
+        }
+
+        private string CalculateGmtOffset(string stime)
+        {
+            TimeZoneInfo timeZone = TimeZoneInfo.Local;
+            TimeSpan offset = timeZone.BaseUtcOffset;
+
+            string sign = "+";
+            if (offset.CompareTo(TimeSpan.Zero) < 0)
+            {
+                sign = "-";
+                offset = offset.Duration();
+            }
+
+            int hours = offset.Hours;
+            int minutes = offset.Minutes;
+
+            try
+            {
+                if (timeZone.SupportsDaylightSavingTime)
+                {
+                    string d = stime + "GMT" + sign + Convert(hours) + ":" + Convert(minutes);
+                    string formatStr = CalculateGmtFormatString(d);
+
+                    DateTime dateTime = ParseDateString(d, formatStr, makeUniversal: true);
+
+                    if (timeZone.IsDaylightSavingTime(dateTime))
+                    {
+                        hours += sign.Equals("+") ? 1 : -1;
+                    }
+                }
+            }
+            catch (Exception)
+            {
+                // we'll do our best and ignore daylight savings
+            }
+
+            return "GMT" + sign + Convert(hours) + ":" + Convert(minutes);
+        }
+
+        private string CalculateGmtFormatString(string d)
+        {
+            if (HasFractionalSeconds())
+            {
+                int fCount = Platform.IndexOf(d, "GMT") - 1 - d.IndexOf('.');
+                return @"yyyyMMddHHmmss." + FString(fCount) + @"'GMT'zzz";
+            }
+
+            if (HasSeconds())
+                return @"yyyyMMddHHmmss'GMT'zzz";
+
+            if (HasMinutes())
+                return @"yyyyMMddHHmm'GMT'zzz";
+
+            return @"yyyyMMddHH'GMT'zzz";
+        }
+
+        private string Convert(int time)
+        {
+            if (time < 10)
+                return "0" + time;
+
+            return time.ToString();
+        }
+
+        public DateTime ToDateTime()
+        {
+            string formatStr;
+            string stime = Strings.FromByteArray(m_contents);
+            string d = stime;
+            bool makeUniversal = false;
+
+            if (Platform.EndsWith(stime, "Z"))
+            {
+                if (HasFractionalSeconds())
+                {
+                    int fCount = d.Length - d.IndexOf('.') - 2;
+                    formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"\Z";
+                }
+                else if (HasSeconds())
+                {
+                    formatStr = @"yyyyMMddHHmmss\Z";
+                }
+                else if (HasMinutes())
+                {
+                    formatStr = @"yyyyMMddHHmm\Z";
+                }
+                else
+                {
+                    formatStr = @"yyyyMMddHH\Z";
+                }
+            }
+            else if (stime.IndexOf('-') > 0 || stime.IndexOf('+') > 0)
+            {
+                d = GetTime();
+                formatStr = CalculateGmtFormatString(d);
+                makeUniversal = true;
+            }
+            else
+            {
+                if (HasFractionalSeconds())
+                {
+                    int fCount = d.Length - 1 - d.IndexOf('.');
+                    formatStr = @"yyyyMMddHHmmss." + FString(fCount);
+                }
+                else if (HasSeconds())
+                {
+                    formatStr = @"yyyyMMddHHmmss";
+                }
+                else if (HasMinutes())
+                {
+                    formatStr = @"yyyyMMddHHmm";
+                }
+                else
+                {
+                    formatStr = @"yyyyMMddHH";
+                }
+            }
+
+            // TODO Epoch adjustment?
+            //return DateUtil.epochAdjust(dateF.parse(d));
+            return ParseDateString(d, formatStr, makeUniversal);
+        }
+
+        protected bool HasFractionalSeconds()
+        {
+            return m_contents.Length > 14 && m_contents[14] == '.';
+        }
+
+        protected bool HasSeconds()
+        {
+            return IsDigit(12) && IsDigit(13);
+        }
+
+        protected bool HasMinutes()
+        {
+            return IsDigit(10) && IsDigit(11);
+        }
+
+        private bool IsDigit(int pos)
+        {
+            return m_contents.Length > pos && m_contents[pos] >= '0' && m_contents[pos] <= '9';
+        }
+
+        internal override IAsn1Encoding GetEncoding(int encoding)
+        {
+            if (Asn1OutputStream.EncodingDer == encoding)
+                return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.GeneralizedTime, GetDerTime());
+
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.GeneralizedTime, m_contents);
+        }
+
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
+        {
+            if (Asn1OutputStream.EncodingDer == encoding)
+                return new PrimitiveEncoding(tagClass, tagNo, GetDerTime());
+
+            return new PrimitiveEncoding(tagClass, tagNo, m_contents);
+        }
+
+        protected override bool Asn1Equals(Asn1Object asn1Object)
+        {
+            if (!(asn1Object is Asn1GeneralizedTime that))
+                return false;
+
+            return Arrays.AreEqual(m_contents, that.m_contents);
+        }
+
+        protected override int Asn1GetHashCode()
+        {
+            return Arrays.GetHashCode(m_contents);
+        }
+
+        internal static Asn1GeneralizedTime CreatePrimitive(byte[] contents)
+        {
+            return new Asn1GeneralizedTime(contents);
+        }
+
+        internal byte[] GetDerTime()
+        {
+            if (m_contents[m_contents.Length - 1] != 'Z')
+            {
+                return m_contents; // TODO: is there a better way?
+            }
+
+            if (!HasMinutes())
+            {
+                byte[] derTime = new byte[m_contents.Length + 4];
+
+                Array.Copy(m_contents, 0, derTime, 0, m_contents.Length - 1);
+                Array.Copy(Strings.ToByteArray("0000Z"), 0, derTime, m_contents.Length - 1, 5);
+
+                return derTime;
+            }
+            else if (!HasSeconds())
+            {
+                byte[] derTime = new byte[m_contents.Length + 2];
+
+                Array.Copy(m_contents, 0, derTime, 0, m_contents.Length - 1);
+                Array.Copy(Strings.ToByteArray("00Z"), 0, derTime, m_contents.Length - 1, 3);
+
+                return derTime;
+            }
+            else if (HasFractionalSeconds())
+            {
+                int ind = m_contents.Length - 2;
+                while (ind > 0 && m_contents[ind] == '0')
+                {
+                    ind--;
+                }
+
+                if (m_contents[ind] == '.')
+                {
+                    byte[] derTime = new byte[ind + 1];
+
+                    Array.Copy(m_contents, 0, derTime, 0, ind);
+                    derTime[ind] = (byte)'Z';
+
+                    return derTime;
+                }
+                else
+                {
+                    byte[] derTime = new byte[ind + 2];
+
+                    Array.Copy(m_contents, 0, derTime, 0, ind + 1);
+                    derTime[ind + 1] = (byte)'Z';
+
+                    return derTime;
+                }
+            }
+            else
+            {
+                return m_contents;
+            }
+        }
+
+        private static string FString(int count)
+        {
+            StringBuilder sb = new StringBuilder();
+            for (int i = 0; i < count; ++i)
+            {
+                sb.Append('f');
+            }
+            return sb.ToString();
+        }
+
+        private static DateTime ParseDateString(string s, string format, bool makeUniversal)
+        {
+            DateTimeStyles dateTimeStyles = DateTimeStyles.None;
+            if (Platform.EndsWith(format, "Z"))
+            {
+                dateTimeStyles |= DateTimeStyles.AdjustToUniversal;
+                dateTimeStyles |= DateTimeStyles.AssumeUniversal;
+            }
+
+            DateTime dt = DateTime.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo, dateTimeStyles);
+
+            return makeUniversal ? dt.ToUniversalTime() : dt;
+        }
+    }
+}
diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs
index aa91cdf62..0e772010f 100644
--- a/crypto/src/asn1/Asn1InputStream.cs
+++ b/crypto/src/asn1/Asn1InputStream.cs
@@ -426,7 +426,7 @@ namespace Org.BouncyCastle.Asn1
             case Asn1Tags.BitString:
                 return DerBitString.CreatePrimitive(bytes);
             case Asn1Tags.GeneralizedTime:
-                return DerGeneralizedTime.CreatePrimitive(bytes);
+                return Asn1GeneralizedTime.CreatePrimitive(bytes);
             case Asn1Tags.GeneralString:
                 return DerGeneralString.CreatePrimitive(bytes);
             case Asn1Tags.GraphicString:
@@ -452,7 +452,7 @@ namespace Org.BouncyCastle.Asn1
             case Asn1Tags.UniversalString:
                 return DerUniversalString.CreatePrimitive(bytes);
             case Asn1Tags.UtcTime:
-                return DerUtcTime.CreatePrimitive(bytes);
+                return Asn1UtcTime.CreatePrimitive(bytes);
             case Asn1Tags.Utf8String:
                 return DerUtf8String.CreatePrimitive(bytes);
             case Asn1Tags.VideotexString:
diff --git a/crypto/src/asn1/Asn1UniversalTypes.cs b/crypto/src/asn1/Asn1UniversalTypes.cs
index 214918bcd..f5b5d0498 100644
--- a/crypto/src/asn1/Asn1UniversalTypes.cs
+++ b/crypto/src/asn1/Asn1UniversalTypes.cs
@@ -49,9 +49,9 @@ namespace Org.BouncyCastle.Asn1
             case Asn1Tags.IA5String:                // [UNIVERSAL 22] IMPLICIT OCTET STRING (encode as if)
                 return DerIA5String.Meta.Instance;
             case Asn1Tags.UtcTime:                  // [UNIVERSAL 23] IMPLICIT VisibleString (restricted values)
-                return DerUtcTime.Meta.Instance;
+                return Asn1UtcTime.Meta.Instance;
             case Asn1Tags.GeneralizedTime:          // [UNIVERSAL 24] IMPLICIT VisibleString (restricted values)
-                return DerGeneralizedTime.Meta.Instance;
+                return Asn1GeneralizedTime.Meta.Instance;
             case Asn1Tags.GraphicString:            // [UNIVERSAL 25] IMPLICIT OCTET STRING (encode as if)
                 return DerGraphicString.Meta.Instance;
             case Asn1Tags.VisibleString:            // [UNIVERSAL 26] IMPLICIT OCTET STRING (encode as if)
diff --git a/crypto/src/asn1/Asn1UtcTime.cs b/crypto/src/asn1/Asn1UtcTime.cs
new file mode 100644
index 000000000..05de430c4
--- /dev/null
+++ b/crypto/src/asn1/Asn1UtcTime.cs
@@ -0,0 +1,264 @@
+using System;
+using System.Globalization;
+using System.IO;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Asn1
+{
+    /**
+     * UTC time object.
+     */
+    public class Asn1UtcTime
+        : Asn1Object
+    {
+        internal class Meta : Asn1UniversalType
+        {
+            internal static readonly Asn1UniversalType Instance = new Meta();
+
+            private Meta() : base(typeof(Asn1UtcTime), Asn1Tags.UtcTime) {}
+
+            internal override Asn1Object FromImplicitPrimitive(DerOctetString octetString)
+            {
+                return CreatePrimitive(octetString.GetOctets());
+            }
+        }
+
+		/**
+         * return a UTC Time from the passed in object.
+         *
+         * @exception ArgumentException if the object cannot be converted.
+         */
+        public static Asn1UtcTime GetInstance(object obj)
+        {
+            if (obj == null)
+                return null;
+
+            if (obj is Asn1UtcTime asn1UtcTime)
+                return asn1UtcTime;
+
+            if (obj is IAsn1Convertible asn1Convertible)
+            {
+                Asn1Object asn1Object = asn1Convertible.ToAsn1Object();
+                if (asn1Object is Asn1UtcTime converted)
+                    return converted;
+            }
+            else if (obj is byte[] bytes)
+            {
+                try
+                {
+                    return (Asn1UtcTime)Meta.Instance.FromByteArray(bytes);
+                }
+                catch (IOException e)
+                {
+                    throw new ArgumentException("failed to construct UTC time from byte[]: " + e.Message);
+                }
+            }
+
+            throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
+        }
+
+        /**
+         * return a UTC Time from a tagged object.
+         *
+         * @param taggedObject the tagged object holding the object we want
+         * @param declaredExplicit true if the object is meant to be explicitly tagged false otherwise.
+         * @exception ArgumentException if the tagged object cannot be converted.
+         */
+        public static Asn1UtcTime GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        {
+            return (Asn1UtcTime)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
+        }
+
+        private readonly string time;
+
+        /**
+         * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
+         * never encoded. When you're creating one of these objects from scratch, that's
+         * what you want to use, otherwise we'll try to deal with whatever Gets read from
+         * the input stream... (this is why the input format is different from the GetTime()
+         * method output).
+         * <p>
+         * @param time the time string.</p>
+         */
+        public Asn1UtcTime(string time)
+        {
+			if (time == null)
+				throw new ArgumentNullException("time");
+
+			this.time = time;
+
+			try
+			{
+				ToDateTime();
+			}
+			catch (FormatException e)
+			{
+				throw new ArgumentException("invalid date string: " + e.Message);
+			}
+        }
+
+		/**
+         * base constructor from a DateTime object
+         */
+        public Asn1UtcTime(DateTime time)
+        {
+            this.time = time.ToUniversalTime().ToString("yyMMddHHmmss", CultureInfo.InvariantCulture) + "Z";
+        }
+
+		internal Asn1UtcTime(byte[] contents)
+        {
+            //
+            // explicitly convert to characters
+            //
+            this.time = Strings.FromAsciiByteArray(contents);
+        }
+
+		/**
+		 * return the time as a date based on whatever a 2 digit year will return. For
+		 * standardised processing use ToAdjustedDateTime().
+		 *
+		 * @return the resulting date
+		 * @exception ParseException if the date string cannot be parsed.
+		 */
+		public DateTime ToDateTime()
+		{
+			return ParseDateString(TimeString, @"yyMMddHHmmss'GMT'zzz");
+		}
+
+		/**
+		* return the time as an adjusted date
+		* in the range of 1950 - 2049.
+		*
+		* @return a date in the range of 1950 to 2049.
+		* @exception ParseException if the date string cannot be parsed.
+		*/
+		public DateTime ToAdjustedDateTime()
+		{
+			return ParseDateString(AdjustedTimeString, @"yyyyMMddHHmmss'GMT'zzz");
+		}
+
+		private DateTime ParseDateString(string dateStr, string formatStr)
+		{
+			DateTime dt = DateTime.ParseExact(
+				dateStr,
+				formatStr,
+				DateTimeFormatInfo.InvariantInfo);
+
+			return dt.ToUniversalTime();
+		}
+
+		/**
+         * return the time - always in the form of
+         *  YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
+         * <p>
+         * Normally in a certificate we would expect "Z" rather than "GMT",
+         * however adding the "GMT" means we can just use:
+         * <pre>
+         *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
+         * </pre>
+         * To read in the time and Get a date which is compatible with our local
+         * time zone.</p>
+         * <p>
+         * <b>Note:</b> In some cases, due to the local date processing, this
+         * may lead to unexpected results. If you want to stick the normal
+         * convention of 1950 to 2049 use the GetAdjustedTime() method.</p>
+         */
+        public string TimeString
+        {
+			get
+			{
+				//
+				// standardise the format.
+				//
+				if (time.IndexOf('-') < 0 && time.IndexOf('+') < 0)
+				{
+					if (time.Length == 11)
+					{
+						return time.Substring(0, 10) + "00GMT+00:00";
+					}
+					else
+					{
+						return time.Substring(0, 12) + "GMT+00:00";
+					}
+				}
+				else
+				{
+					int index = time.IndexOf('-');
+					if (index < 0)
+					{
+						index = time.IndexOf('+');
+					}
+					string d = time;
+
+					if (index == time.Length - 3)
+					{
+						d += "00";
+					}
+
+					if (index == 10)
+					{
+						return d.Substring(0, 10) + "00GMT" + d.Substring(10, 3) + ":" + d.Substring(13, 2);
+					}
+					else
+					{
+						return d.Substring(0, 12) + "GMT" + d.Substring(12, 3) + ":" +  d.Substring(15, 2);
+					}
+				}
+			}
+        }
+
+		/// <summary>
+		/// Return a time string as an adjusted date with a 4 digit year.
+		/// This goes in the range of 1950 - 2049.
+		/// </summary>
+		public string AdjustedTimeString
+		{
+			get
+			{
+				string d = TimeString;
+				string c = d[0] < '5' ? "20" : "19";
+
+				return c + d;
+			}
+		}
+
+        internal byte[] GetOctets()
+        {
+            return Strings.ToAsciiByteArray(time);
+        }
+
+        internal override IAsn1Encoding GetEncoding(int encoding)
+        {
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.UtcTime, GetOctets());
+        }
+
+        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
+        {
+            return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
+        }
+
+        protected override bool Asn1Equals(Asn1Object asn1Object)
+		{
+            if (!(asn1Object is Asn1UtcTime that))
+                return false;
+
+            return this.time == that.time;
+        }
+
+		protected override int Asn1GetHashCode()
+		{
+            return time.GetHashCode();
+        }
+
+		public override string ToString()
+		{
+			return time;
+		}
+
+        internal static Asn1UtcTime CreatePrimitive(byte[] contents)
+        {
+            return new Asn1UtcTime(contents);
+        }
+    }
+}
diff --git a/crypto/src/asn1/DerGeneralizedTime.cs b/crypto/src/asn1/DerGeneralizedTime.cs
index 898a3d585..0386ecb02 100644
--- a/crypto/src/asn1/DerGeneralizedTime.cs
+++ b/crypto/src/asn1/DerGeneralizedTime.cs
@@ -1,367 +1,33 @@
 using System;
-using System.Globalization;
-using System.IO;
-using System.Text;
-
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1
 {
-    /**
-     * Generalized time object.
-     */
     public class DerGeneralizedTime
-        : Asn1Object
+        : Asn1GeneralizedTime
     {
-        internal class Meta : Asn1UniversalType
-        {
-            internal static readonly Asn1UniversalType Instance = new Meta();
-
-            private Meta() : base(typeof(DerGeneralizedTime), Asn1Tags.GeneralizedTime) {}
-
-            internal override Asn1Object FromImplicitPrimitive(DerOctetString octetString)
-            {
-                return CreatePrimitive(octetString.GetOctets());
-            }
-        }
-
-        /**
-         * return a generalized time from the passed in object
-         *
-         * @exception ArgumentException if the object cannot be converted.
-         */
-        public static DerGeneralizedTime GetInstance(object obj)
-        {
-            if (obj == null || obj is DerGeneralizedTime)
-            {
-                return (DerGeneralizedTime)obj;
-            }
-            else if (obj is IAsn1Convertible)
-            {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerGeneralizedTime)
-                    return (DerGeneralizedTime)asn1Object;
-            }
-            else if (obj is byte[])
-            {
-                try
-                {
-                    return (DerGeneralizedTime)Meta.Instance.FromByteArray((byte[])obj);
-                }
-                catch (IOException e)
-                {
-                    throw new ArgumentException("failed to construct generalized time from byte[]: " + e.Message);
-                }
-            }
-
-            throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj), "obj");
-        }
-
-        /**
-         * return a generalized Time object from a tagged object.
-         *
-         * @param taggedObject the tagged object holding the object we want
-         * @param declaredExplicit true if the object is meant to be explicitly tagged false otherwise.
-         * @exception ArgumentException if the tagged object cannot be converted.
-         */
-        public static DerGeneralizedTime GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
+        public DerGeneralizedTime(byte[] time)
+            : base(time)
         {
-            return (DerGeneralizedTime)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
         }
 
-        private readonly string time;
-
-        /**
-         * The correct format for this is YYYYMMDDHHMMSS[.f]Z, or without the Z
-         * for local time, or Z+-HHMM on the end, for difference between local
-         * time and UTC time. The fractional second amount f must consist of at
-         * least one number with trailing zeroes removed.
-         *
-         * @param time the time string.
-         * @exception ArgumentException if string is an illegal format.
-         */
-        public DerGeneralizedTime(
-            string time)
-        {
-            this.time = time;
-
-            try
-            {
-                ToDateTime();
-            }
-            catch (FormatException e)
-            {
-                throw new ArgumentException("invalid date string: " + e.Message);
-            }
-        }
-
-        /**
-         * base constructor from a local time object
-         */
         public DerGeneralizedTime(DateTime time)
+            : base(time)
         {
-            this.time = time.ToUniversalTime().ToString(@"yyyyMMddHHmmss\Z");
-        }
-
-        internal DerGeneralizedTime(
-            byte[] bytes)
-        {
-            //
-            // explicitly convert to characters
-            //
-            this.time = Strings.FromAsciiByteArray(bytes);
         }
 
-        /**
-         * Return the time.
-         * @return The time string as it appeared in the encoded object.
-         */
-        public string TimeString
+        public DerGeneralizedTime(string time)
+            : base(time)
         {
-            get { return time; }
-        }
-
-        /**
-         * return the time - always in the form of
-         *  YYYYMMDDhhmmssGMT(+hh:mm|-hh:mm).
-         * <p>
-         * Normally in a certificate we would expect "Z" rather than "GMT",
-         * however adding the "GMT" means we can just use:
-         * <pre>
-         *     dateF = new SimpleDateFormat("yyyyMMddHHmmssz");
-         * </pre>
-         * To read in the time and Get a date which is compatible with our local
-         * time zone.</p>
-         */
-        public string GetTime()
-        {
-            //
-            // standardise the format.
-            //
-            if (time[time.Length - 1] == 'Z')
-                return time.Substring(0, time.Length - 1) + "GMT+00:00";
-
-            int signPos = time.Length - 5;
-            char sign = time[signPos];
-            if (sign == '-' || sign == '+')
-            {
-                return time.Substring(0, signPos)
-                    + "GMT"
-                    + time.Substring(signPos, 3)
-                    + ":"
-                    + time.Substring(signPos + 3);
-            }
-            else
-            {
-                signPos = time.Length - 3;
-                sign = time[signPos];
-                if (sign == '-' || sign == '+')
-                {
-                    return time.Substring(0, signPos)
-                        + "GMT"
-                        + time.Substring(signPos)
-                        + ":00";
-                }
-            }
-
-            return time + CalculateGmtOffset();
-        }
-
-        private string CalculateGmtOffset()
-        {
-            char sign = '+';
-            DateTime time = ToDateTime();
-
-            TimeSpan offset = TimeZoneInfo.Local.GetUtcOffset(time);
-            if (offset.CompareTo(TimeSpan.Zero) < 0)
-            {
-                sign = '-';
-                offset = offset.Duration();
-            }
-            int hours = offset.Hours;
-            int minutes = offset.Minutes;
-
-            return "GMT" + sign + Convert(hours) + ":" + Convert(minutes);
-        }
-
-        private static string Convert(
-            int time)
-        {
-            if (time < 10)
-            {
-                return "0" + time;
-            }
-
-            return time.ToString();
-        }
-
-        public DateTime ToDateTime()
-        {
-            string formatStr;
-            string d = time;
-            bool makeUniversal = false;
-
-            if (Platform.EndsWith(d, "Z"))
-            {
-                if (HasFractionalSeconds)
-                {
-                    int fCount = d.Length - d.IndexOf('.') - 2;
-                    formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"\Z";
-                }
-                else if (HasSeconds)
-                {
-                    formatStr = @"yyyyMMddHHmmss\Z";
-                }
-                else if (HasMinutes)
-                {
-                    formatStr = @"yyyyMMddHHmm\Z";
-                }
-                else
-                {
-                    formatStr = @"yyyyMMddHH\Z";
-                }
-            }
-            else if (time.IndexOf('-') > 0 || time.IndexOf('+') > 0)
-            {
-                d = GetTime();
-                makeUniversal = true;
-
-                if (HasFractionalSeconds)
-                {
-                    int fCount = Platform.IndexOf(d, "GMT") - 1 - d.IndexOf('.');
-                    formatStr = @"yyyyMMddHHmmss." + FString(fCount) + @"'GMT'zzz";
-                }
-                else
-                {
-                    formatStr = @"yyyyMMddHHmmss'GMT'zzz";
-                }
-            }
-            else
-            {
-                if (HasFractionalSeconds)
-                {
-                    int fCount = d.Length - 1 - d.IndexOf('.');
-                    formatStr = @"yyyyMMddHHmmss." + FString(fCount);
-                }
-                else if (HasSeconds)
-                {
-                    formatStr = @"yyyyMMddHHmmss";
-                }
-                else if (HasMinutes)
-                {
-                    formatStr = @"yyyyMMddHHmm";
-                }
-                else
-                {
-                    formatStr = @"yyyyMMddHH";
-                }
-
-                // TODO?
-//				dateF.setTimeZone(new SimpleTimeZone(0, TimeZone.getDefault().getID()));
-            }
-
-            return ParseDateString(d, formatStr, makeUniversal);
-        }
-
-        private string FString(
-            int count)
-        {
-            StringBuilder sb = new StringBuilder();
-            for (int i = 0; i < count; ++i)
-            {
-                sb.Append('f');
-            }
-            return sb.ToString();
-        }
-
-        private DateTime ParseDateString(string	s, string format, bool makeUniversal)
-        {
-            /*
-             * NOTE: DateTime.Kind and DateTimeStyles.AssumeUniversal not available in .NET 1.1
-             */
-            DateTimeStyles style = DateTimeStyles.None;
-            if (Platform.EndsWith(format, "Z"))
-            {
-                style |= DateTimeStyles.AdjustToUniversal;
-                style |= DateTimeStyles.AssumeUniversal;
-            }
-
-            DateTime dt = DateTime.ParseExact(s, format, DateTimeFormatInfo.InvariantInfo, style);
-
-            return makeUniversal ? dt.ToUniversalTime() : dt;
-        }
-
-        private bool HasFractionalSeconds
-        {
-            get { return time.IndexOf('.') == 14; }
-        }
-
-        private bool HasSeconds =>  IsDigit(12) && IsDigit(13);
-
-        private bool HasMinutes => IsDigit(10) && IsDigit(11);
-
-        private bool IsDigit(int pos)
-        {
-            return time.Length > pos && char.IsDigit(time[pos]);
-        }
-
-        private byte[] GetOctets(int encoding)
-        {
-            if (Asn1OutputStream.EncodingDer == encoding && time[time.Length - 1] == 'Z')
-            {
-                if (!HasMinutes)
-                    return Strings.ToAsciiByteArray(time.Insert(time.Length - 1, "0000"));
-                if (!HasSeconds)
-                    return Strings.ToAsciiByteArray(time.Insert(time.Length - 1, "00"));
-
-                if (HasFractionalSeconds)
-                {
-                    int ind = time.Length - 2;
-                    while (ind > 0 && time[ind] == '0')
-                    {
-                        --ind;
-                    }
-
-                    if (time[ind] != '.')
-                    {
-                        ++ind;
-                    }
-
-                    if (ind != time.Length - 1)
-                    {
-                        return Strings.ToAsciiByteArray(time.Remove(ind, time.Length - 1 - ind));
-                    }
-                }
-            }
-
-            return Strings.ToAsciiByteArray(time);
         }
 
         internal override IAsn1Encoding GetEncoding(int encoding)
         {
-            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.GeneralizedTime, GetOctets(encoding));
+            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.GeneralizedTime, GetDerTime());
         }
 
         internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
         {
-            return new PrimitiveEncoding(tagClass, tagNo, GetOctets(encoding));
-        }
-
-        protected override bool Asn1Equals(Asn1Object asn1Object)
-        {
-            DerGeneralizedTime that = asn1Object as DerGeneralizedTime;
-            return null != that
-                && this.time.Equals(that.time);
-        }
-
-        protected override int Asn1GetHashCode()
-        {
-            return time.GetHashCode();
-        }
-
-        internal static DerGeneralizedTime CreatePrimitive(byte[] contents)
-        {
-            return new DerGeneralizedTime(contents);
+            return new PrimitiveEncoding(tagClass, tagNo, GetDerTime());
         }
     }
 }
diff --git a/crypto/src/asn1/DerUTCTime.cs b/crypto/src/asn1/DerUTCTime.cs
index 7f7756d49..089285367 100644
--- a/crypto/src/asn1/DerUTCTime.cs
+++ b/crypto/src/asn1/DerUTCTime.cs
@@ -1,274 +1,25 @@
 using System;
-using System.Globalization;
-using System.IO;
-
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Asn1
 {
-    /**
-     * UTC time object.
-     */
     public class DerUtcTime
-        : Asn1Object
+        : Asn1UtcTime
     {
-        internal class Meta : Asn1UniversalType
-        {
-            internal static readonly Asn1UniversalType Instance = new Meta();
-
-            private Meta() : base(typeof(DerUtcTime), Asn1Tags.UtcTime) {}
-
-            internal override Asn1Object FromImplicitPrimitive(DerOctetString octetString)
-            {
-                return CreatePrimitive(octetString.GetOctets());
-            }
-        }
-
-		/**
-         * return a UTC Time from the passed in object.
-         *
-         * @exception ArgumentException if the object cannot be converted.
-         */
-        public static DerUtcTime GetInstance(object obj)
-        {
-            if (obj == null || obj is DerUtcTime)
-            {
-                return (DerUtcTime)obj;
-            }
-            else if (obj is IAsn1Convertible)
-            {
-                Asn1Object asn1Object = ((IAsn1Convertible)obj).ToAsn1Object();
-                if (asn1Object is DerUtcTime)
-                    return (DerUtcTime)asn1Object;
-            }
-            else if (obj is byte[])
-            {
-                try
-                {
-                    return (DerUtcTime)Meta.Instance.FromByteArray((byte[])obj);
-                }
-                catch (IOException e)
-                {
-                    throw new ArgumentException("failed to construct UTC time from byte[]: " + e.Message);
-                }
-            }
-
-            throw new ArgumentException("illegal object in GetInstance: " + Platform.GetTypeName(obj));
-        }
-
-        /**
-         * return a UTC Time from a tagged object.
-         *
-         * @param taggedObject the tagged object holding the object we want
-         * @param declaredExplicit true if the object is meant to be explicitly tagged false otherwise.
-         * @exception ArgumentException if the tagged object cannot be converted.
-         */
-        public static DerUtcTime GetInstance(Asn1TaggedObject taggedObject, bool declaredExplicit)
-        {
-            return (DerUtcTime)Meta.Instance.GetContextInstance(taggedObject, declaredExplicit);
-        }
-
-        private readonly string time;
-
-        /**
-         * The correct format for this is YYMMDDHHMMSSZ (it used to be that seconds were
-         * never encoded. When you're creating one of these objects from scratch, that's
-         * what you want to use, otherwise we'll try to deal with whatever Gets read from
-         * the input stream... (this is why the input format is different from the GetTime()
-         * method output).
-         * <p>
-         * @param time the time string.</p>
-         */
         public DerUtcTime(string time)
+			: base(time)
         {
-			if (time == null)
-				throw new ArgumentNullException("time");
-
-			this.time = time;
-
-			try
-			{
-				ToDateTime();
-			}
-			catch (FormatException e)
-			{
-				throw new ArgumentException("invalid date string: " + e.Message);
-			}
         }
 
-		/**
-         * base constructor from a DateTime object
-         */
         public DerUtcTime(DateTime time)
+			: base(time)
         {
-            this.time = time.ToUniversalTime().ToString("yyMMddHHmmss", CultureInfo.InvariantCulture) + "Z";
         }
 
 		internal DerUtcTime(byte[] contents)
+			: base(contents)
         {
-            //
-            // explicitly convert to characters
-            //
-            this.time = Strings.FromAsciiByteArray(contents);
-        }
-
-//		public DateTime ToDateTime()
-//		{
-//			string tm = this.AdjustedTimeString;
-//
-//			return new DateTime(
-//				Int16.Parse(tm.Substring(0, 4)),
-//				Int16.Parse(tm.Substring(4, 2)),
-//				Int16.Parse(tm.Substring(6, 2)),
-//				Int16.Parse(tm.Substring(8, 2)),
-//				Int16.Parse(tm.Substring(10, 2)),
-//				Int16.Parse(tm.Substring(12, 2)));
-//		}
-
-		/**
-		 * return the time as a date based on whatever a 2 digit year will return. For
-		 * standardised processing use ToAdjustedDateTime().
-		 *
-		 * @return the resulting date
-		 * @exception ParseException if the date string cannot be parsed.
-		 */
-		public DateTime ToDateTime()
-		{
-			return ParseDateString(TimeString, @"yyMMddHHmmss'GMT'zzz");
-		}
-
-		/**
-		* return the time as an adjusted date
-		* in the range of 1950 - 2049.
-		*
-		* @return a date in the range of 1950 to 2049.
-		* @exception ParseException if the date string cannot be parsed.
-		*/
-		public DateTime ToAdjustedDateTime()
-		{
-			return ParseDateString(AdjustedTimeString, @"yyyyMMddHHmmss'GMT'zzz");
-		}
-
-		private DateTime ParseDateString(string dateStr, string formatStr)
-		{
-			DateTime dt = DateTime.ParseExact(
-				dateStr,
-				formatStr,
-				DateTimeFormatInfo.InvariantInfo);
-
-			return dt.ToUniversalTime();
-		}
-
-		/**
-         * return the time - always in the form of
-         *  YYMMDDhhmmssGMT(+hh:mm|-hh:mm).
-         * <p>
-         * Normally in a certificate we would expect "Z" rather than "GMT",
-         * however adding the "GMT" means we can just use:
-         * <pre>
-         *     dateF = new SimpleDateFormat("yyMMddHHmmssz");
-         * </pre>
-         * To read in the time and Get a date which is compatible with our local
-         * time zone.</p>
-         * <p>
-         * <b>Note:</b> In some cases, due to the local date processing, this
-         * may lead to unexpected results. If you want to stick the normal
-         * convention of 1950 to 2049 use the GetAdjustedTime() method.</p>
-         */
-        public string TimeString
-        {
-			get
-			{
-				//
-				// standardise the format.
-				//
-				if (time.IndexOf('-') < 0 && time.IndexOf('+') < 0)
-				{
-					if (time.Length == 11)
-					{
-						return time.Substring(0, 10) + "00GMT+00:00";
-					}
-					else
-					{
-						return time.Substring(0, 12) + "GMT+00:00";
-					}
-				}
-				else
-				{
-					int index = time.IndexOf('-');
-					if (index < 0)
-					{
-						index = time.IndexOf('+');
-					}
-					string d = time;
-
-					if (index == time.Length - 3)
-					{
-						d += "00";
-					}
-
-					if (index == 10)
-					{
-						return d.Substring(0, 10) + "00GMT" + d.Substring(10, 3) + ":" + d.Substring(13, 2);
-					}
-					else
-					{
-						return d.Substring(0, 12) + "GMT" + d.Substring(12, 3) + ":" +  d.Substring(15, 2);
-					}
-				}
-			}
-        }
-
-		/// <summary>
-		/// Return a time string as an adjusted date with a 4 digit year.
-		/// This goes in the range of 1950 - 2049.
-		/// </summary>
-		public string AdjustedTimeString
-		{
-			get
-			{
-				string d = TimeString;
-				string c = d[0] < '5' ? "20" : "19";
-
-				return c + d;
-			}
-		}
-
-        private byte[] GetOctets()
-        {
-            return Strings.ToAsciiByteArray(time);
-        }
-
-        internal override IAsn1Encoding GetEncoding(int encoding)
-        {
-            return new PrimitiveEncoding(Asn1Tags.Universal, Asn1Tags.UtcTime, GetOctets());
-        }
-
-        internal override IAsn1Encoding GetEncodingImplicit(int encoding, int tagClass, int tagNo)
-        {
-            return new PrimitiveEncoding(tagClass, tagNo, GetOctets());
-        }
-
-        protected override bool Asn1Equals(Asn1Object asn1Object)
-		{
-			DerUtcTime that = asn1Object as DerUtcTime;
-            return null != that
-                && this.time.Equals(that.time);
         }
 
-		protected override int Asn1GetHashCode()
-		{
-            return time.GetHashCode();
-        }
-
-		public override string ToString()
-		{
-			return time;
-		}
-
-        internal static DerUtcTime CreatePrimitive(byte[] contents)
-        {
-            return new DerUtcTime(contents);
-        }
+        // TODO: create proper DER encoding.
     }
 }
diff --git a/crypto/src/asn1/bc/BCObjectIdentifiers.cs b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
index f3933af87..d526980e5 100644
--- a/crypto/src/asn1/bc/BCObjectIdentifiers.cs
+++ b/crypto/src/asn1/bc/BCObjectIdentifiers.cs
@@ -192,7 +192,16 @@ namespace Org.BouncyCastle.Asn1.BC
         public static readonly DerObjectIdentifier lightsaberkem256r3 = pqc_kem_saber.Branch("7");
         public static readonly DerObjectIdentifier saberkem256r3 = pqc_kem_saber.Branch("8");
         public static readonly DerObjectIdentifier firesaberkem256r3 = pqc_kem_saber.Branch("9");
-        
+        public static readonly DerObjectIdentifier ulightsaberkemr3 = pqc_kem_saber.Branch("10");
+        public static readonly DerObjectIdentifier usaberkemr3 = pqc_kem_saber.Branch("11");
+        public static readonly DerObjectIdentifier ufiresaberkemr3 = pqc_kem_saber.Branch("12");
+        public static readonly DerObjectIdentifier lightsaberkem90sr3 = pqc_kem_saber.Branch("13");
+        public static readonly DerObjectIdentifier saberkem90sr3 = pqc_kem_saber.Branch("14");
+        public static readonly DerObjectIdentifier firesaberkem90sr3 = pqc_kem_saber.Branch("15");
+        public static readonly DerObjectIdentifier ulightsaberkem90sr3 = pqc_kem_saber.Branch("16");
+        public static readonly DerObjectIdentifier usaberkem90sr3 = pqc_kem_saber.Branch("17");
+        public static readonly DerObjectIdentifier ufiresaberkem90sr3 = pqc_kem_saber.Branch("18");
+
         /**
          * SIKE
          */
diff --git a/crypto/src/asn1/cmp/PKIHeader.cs b/crypto/src/asn1/cmp/PKIHeader.cs
index 553a81bc0..7ed914e6a 100644
--- a/crypto/src/asn1/cmp/PKIHeader.cs
+++ b/crypto/src/asn1/cmp/PKIHeader.cs
@@ -19,7 +19,7 @@ namespace Org.BouncyCastle.Asn1.Cmp
         private readonly DerInteger pvno;
         private readonly GeneralName sender;
         private readonly GeneralName recipient;
-        private readonly DerGeneralizedTime messageTime;
+        private readonly Asn1GeneralizedTime messageTime;
         private readonly AlgorithmIdentifier protectionAlg;
         private readonly Asn1OctetString senderKID;       // KeyIdentifier
         private readonly Asn1OctetString recipKID;        // KeyIdentifier
@@ -42,7 +42,7 @@ namespace Org.BouncyCastle.Asn1.Cmp
                 switch (tObj.TagNo)
                 {
                 case 0:
-                    messageTime = DerGeneralizedTime.GetInstance(tObj, true);
+                    messageTime = Asn1GeneralizedTime.GetInstance(tObj, true);
                     break;
                 case 1:
                     protectionAlg = AlgorithmIdentifier.GetInstance(tObj, true);
@@ -118,7 +118,7 @@ namespace Org.BouncyCastle.Asn1.Cmp
             get { return recipient; }
         }
 
-        public virtual DerGeneralizedTime MessageTime
+        public virtual Asn1GeneralizedTime MessageTime
         {
             get { return messageTime; }
         }
diff --git a/crypto/src/asn1/cmp/PKIHeaderBuilder.cs b/crypto/src/asn1/cmp/PKIHeaderBuilder.cs
index d771dda4c..cbefc73b8 100644
--- a/crypto/src/asn1/cmp/PKIHeaderBuilder.cs
+++ b/crypto/src/asn1/cmp/PKIHeaderBuilder.cs
@@ -9,7 +9,7 @@ namespace Org.BouncyCastle.Asn1.Cmp
 		private DerInteger pvno;
 		private GeneralName sender;
 		private GeneralName recipient;
-		private DerGeneralizedTime messageTime;
+		private Asn1GeneralizedTime messageTime;
 		private AlgorithmIdentifier protectionAlg;
 		private Asn1OctetString senderKID;       // KeyIdentifier
 		private Asn1OctetString recipKID;        // KeyIdentifier
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Asn1.Cmp
 			this.recipient = recipient;
 		}
 
-		public virtual PkiHeaderBuilder SetMessageTime(DerGeneralizedTime time)
+		public virtual PkiHeaderBuilder SetMessageTime(Asn1GeneralizedTime time)
 		{
 			messageTime = time;
 			return this;
diff --git a/crypto/src/asn1/cmp/RevAnnContent.cs b/crypto/src/asn1/cmp/RevAnnContent.cs
index 4ef6fdbf7..cdd26c39f 100644
--- a/crypto/src/asn1/cmp/RevAnnContent.cs
+++ b/crypto/src/asn1/cmp/RevAnnContent.cs
@@ -19,18 +19,18 @@ namespace Org.BouncyCastle.Asn1.Cmp
 
         private readonly PkiStatusEncodable m_status;
 		private readonly CertId m_certID;
-		private readonly DerGeneralizedTime m_willBeRevokedAt;
-		private readonly DerGeneralizedTime m_badSinceDate;
+		private readonly Asn1GeneralizedTime m_willBeRevokedAt;
+		private readonly Asn1GeneralizedTime m_badSinceDate;
 		private readonly X509Extensions m_crlDetails;
 
-        public RevAnnContent(PkiStatusEncodable status, CertId certID, DerGeneralizedTime willBeRevokedAt,
-			DerGeneralizedTime badSinceDate)
+        public RevAnnContent(PkiStatusEncodable status, CertId certID, Asn1GeneralizedTime willBeRevokedAt,
+            Asn1GeneralizedTime badSinceDate)
             : this(status, certID, willBeRevokedAt, badSinceDate, null)
         {
 		}
 
-        public RevAnnContent(PkiStatusEncodable status, CertId certID, DerGeneralizedTime willBeRevokedAt,
-			DerGeneralizedTime badSinceDate, X509Extensions crlDetails)
+        public RevAnnContent(PkiStatusEncodable status, CertId certID, Asn1GeneralizedTime willBeRevokedAt,
+            Asn1GeneralizedTime badSinceDate, X509Extensions crlDetails)
         {
             m_status = status;
             m_certID = certID;
@@ -43,8 +43,8 @@ namespace Org.BouncyCastle.Asn1.Cmp
 		{
 			m_status = PkiStatusEncodable.GetInstance(seq[0]);
 			m_certID = CertId.GetInstance(seq[1]);
-			m_willBeRevokedAt = DerGeneralizedTime.GetInstance(seq[2]);
-			m_badSinceDate = DerGeneralizedTime.GetInstance(seq[3]);
+			m_willBeRevokedAt = Asn1GeneralizedTime.GetInstance(seq[2]);
+			m_badSinceDate = Asn1GeneralizedTime.GetInstance(seq[3]);
 
 			if (seq.Count > 4)
 			{
@@ -56,9 +56,9 @@ namespace Org.BouncyCastle.Asn1.Cmp
 
 		public virtual CertId CertID => m_certID;
 
-		public virtual DerGeneralizedTime WillBeRevokedAt => m_willBeRevokedAt;
+		public virtual Asn1GeneralizedTime WillBeRevokedAt => m_willBeRevokedAt;
 
-		public virtual DerGeneralizedTime BadSinceDate => m_badSinceDate;
+		public virtual Asn1GeneralizedTime BadSinceDate => m_badSinceDate;
 
 		public virtual X509Extensions CrlDetails => m_crlDetails;
 
diff --git a/crypto/src/asn1/cms/CMSObjectIdentifiers.cs b/crypto/src/asn1/cms/CMSObjectIdentifiers.cs
index 2ad0a3c7c..6f4f8fb5e 100644
--- a/crypto/src/asn1/cms/CMSObjectIdentifiers.cs
+++ b/crypto/src/asn1/cms/CMSObjectIdentifiers.cs
@@ -13,7 +13,8 @@ namespace Org.BouncyCastle.Asn1.Cms
         public static readonly DerObjectIdentifier AuthenticatedData = PkcsObjectIdentifiers.IdCTAuthData;
         public static readonly DerObjectIdentifier CompressedData = PkcsObjectIdentifiers.IdCTCompressedData;
         public static readonly DerObjectIdentifier AuthEnvelopedData = PkcsObjectIdentifiers.IdCTAuthEnvelopedData;
-        public static readonly DerObjectIdentifier timestampedData = PkcsObjectIdentifiers.IdCTTimestampedData;
+        public static readonly DerObjectIdentifier TimestampedData = PkcsObjectIdentifiers.IdCTTimestampedData;
+        public static readonly DerObjectIdentifier ZlibCompress = PkcsObjectIdentifiers.IdAlgZlibCompress;
 
         /**
          * The other Revocation Info arc
diff --git a/crypto/src/asn1/cms/KEKIdentifier.cs b/crypto/src/asn1/cms/KEKIdentifier.cs
index a42217440..36ab94f52 100644
--- a/crypto/src/asn1/cms/KEKIdentifier.cs
+++ b/crypto/src/asn1/cms/KEKIdentifier.cs
@@ -8,12 +8,12 @@ namespace Org.BouncyCastle.Asn1.Cms
         : Asn1Encodable
     {
         private Asn1OctetString		keyIdentifier;
-        private DerGeneralizedTime	date;
+        private Asn1GeneralizedTime date;
         private OtherKeyAttribute	other;
 
 		public KekIdentifier(
             byte[]              keyIdentifier,
-            DerGeneralizedTime  date,
+            Asn1GeneralizedTime date,
             OtherKeyAttribute   other)
         {
             this.keyIdentifier = new DerOctetString(keyIdentifier);
@@ -31,9 +31,9 @@ namespace Org.BouncyCastle.Asn1.Cms
             case 1:
 				break;
             case 2:
-				if (seq[1] is DerGeneralizedTime)
+				if (seq[1] is Asn1GeneralizedTime)
 				{
-					date = (DerGeneralizedTime) seq[1];
+					date = (Asn1GeneralizedTime) seq[1];
 				}
 				else
 				{
@@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Asn1.Cms
 				}
 				break;
             case 3:
-				date  = (DerGeneralizedTime) seq[1];
+				date  = (Asn1GeneralizedTime) seq[1];
 				other = OtherKeyAttribute.GetInstance(seq[2]);
 				break;
             default:
@@ -88,7 +88,7 @@ namespace Org.BouncyCastle.Asn1.Cms
 			get { return keyIdentifier; }
 		}
 
-		public DerGeneralizedTime Date
+		public Asn1GeneralizedTime Date
 		{
 			get { return date; }
 		}
diff --git a/crypto/src/asn1/cms/RecipientKeyIdentifier.cs b/crypto/src/asn1/cms/RecipientKeyIdentifier.cs
index 995ddab51..dea9ce09d 100644
--- a/crypto/src/asn1/cms/RecipientKeyIdentifier.cs
+++ b/crypto/src/asn1/cms/RecipientKeyIdentifier.cs
@@ -8,12 +8,12 @@ namespace Org.BouncyCastle.Asn1.Cms
         : Asn1Encodable
     {
         private Asn1OctetString      subjectKeyIdentifier;
-        private DerGeneralizedTime   date;
+        private Asn1GeneralizedTime  date;
         private OtherKeyAttribute    other;
 
 		public RecipientKeyIdentifier(
             Asn1OctetString         subjectKeyIdentifier,
-            DerGeneralizedTime      date,
+            Asn1GeneralizedTime     date,
             OtherKeyAttribute       other)
         {
             this.subjectKeyIdentifier = subjectKeyIdentifier;
@@ -29,7 +29,7 @@ namespace Org.BouncyCastle.Asn1.Cms
 
 		public RecipientKeyIdentifier(
 			byte[]				subjectKeyIdentifier,
-			DerGeneralizedTime	date,
+            Asn1GeneralizedTime date,
 			OtherKeyAttribute	other)
 		{
 			this.subjectKeyIdentifier = new DerOctetString(subjectKeyIdentifier);
@@ -48,9 +48,9 @@ namespace Org.BouncyCastle.Asn1.Cms
 				case 1:
 					break;
 				case 2:
-					if (seq[1] is DerGeneralizedTime)
+					if (seq[1] is Asn1GeneralizedTime)
 					{
-						date = (DerGeneralizedTime) seq[1];
+						date = (Asn1GeneralizedTime)seq[1];
 					}
 					else
 					{
@@ -58,7 +58,7 @@ namespace Org.BouncyCastle.Asn1.Cms
 					}
 					break;
 				case 3:
-					date  = (DerGeneralizedTime) seq[1];
+					date  = (Asn1GeneralizedTime)seq[1];
 					other = OtherKeyAttribute.GetInstance(seq[2]);
 					break;
 				default:
@@ -105,7 +105,7 @@ namespace Org.BouncyCastle.Asn1.Cms
 			get { return subjectKeyIdentifier; }
 		}
 
-		public DerGeneralizedTime Date
+		public Asn1GeneralizedTime Date
 		{
 			get { return date; }
 		}
diff --git a/crypto/src/asn1/cms/Time.cs b/crypto/src/asn1/cms/Time.cs
index 52fb4f937..89f1e4dae 100644
--- a/crypto/src/asn1/cms/Time.cs
+++ b/crypto/src/asn1/cms/Time.cs
@@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Asn1.Cms
         {
             if (time == null)
                 throw new ArgumentNullException("time");
-            if (!(time is DerUtcTime) && !(time is DerGeneralizedTime))
+            if (!(time is Asn1UtcTime) && !(time is Asn1GeneralizedTime))
                 throw new ArgumentException("unknown object passed to Time");
 
             this.time = time;
@@ -33,8 +33,7 @@ namespace Org.BouncyCastle.Asn1.Cms
          * and 2049 a UTCTime object is Generated, otherwise a GeneralizedTime
          * is used.
          */
-        public Time(
-            DateTime date)
+        public Time(DateTime date)
         {
             string d = date.ToString("yyyyMMddHHmmss", CultureInfo.InvariantCulture) + "Z";
 
@@ -50,15 +49,16 @@ namespace Org.BouncyCastle.Asn1.Cms
             }
         }
 
-		public static Time GetInstance(
-            object obj)
+		public static Time GetInstance(object obj)
         {
-            if (obj == null || obj is Time)
-                return (Time)obj;
-			if (obj is DerUtcTime)
-                return new Time((DerUtcTime)obj);
-			if (obj is DerGeneralizedTime)
-                return new Time((DerGeneralizedTime)obj);
+            if (obj == null)
+                return null;
+            if (obj is Time time)
+                return time;
+			if (obj is Asn1UtcTime utcTime)
+                return new Time(utcTime);
+			if (obj is Asn1GeneralizedTime generalizedTime)
+                return new Time(generalizedTime);
 
             throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
         }
@@ -67,14 +67,10 @@ namespace Org.BouncyCastle.Asn1.Cms
         {
 			get
 			{
-				if (time is DerUtcTime)
-				{
-					return ((DerUtcTime)time).AdjustedTimeString;
-				}
-				else
-				{
-					return ((DerGeneralizedTime)time).GetTime();
-				}
+				if (time is Asn1UtcTime utcTime)
+					return utcTime.AdjustedTimeString;
+
+                return ((Asn1GeneralizedTime)time).GetTime();
 			}
         }
 
@@ -84,12 +80,10 @@ namespace Org.BouncyCastle.Asn1.Cms
 			{
 				try
 				{
-					if (time is DerUtcTime)
-					{
-						return ((DerUtcTime)time).ToAdjustedDateTime();
-					}
+					if (time is Asn1UtcTime utcTime)
+						return utcTime.ToAdjustedDateTime();
 
-					return ((DerGeneralizedTime)time).ToDateTime();
+					return ((Asn1GeneralizedTime)time).ToDateTime();
 				}
 				catch (FormatException e)
 				{
diff --git a/crypto/src/asn1/esf/CrlIdentifier.cs b/crypto/src/asn1/esf/CrlIdentifier.cs
index a8e40c870..44c99170c 100644
--- a/crypto/src/asn1/esf/CrlIdentifier.cs
+++ b/crypto/src/asn1/esf/CrlIdentifier.cs
@@ -1,5 +1,5 @@
 using System;
-
+using System.Reflection;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Utilities;
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Asn1.Esf
 		: Asn1Encodable
 	{
 		private readonly X509Name	crlIssuer;
-		private readonly DerUtcTime	crlIssuedTime;
+		private readonly Asn1UtcTime crlIssuedTime;
 		private readonly DerInteger	crlNumber;
 
 		public static CrlIdentifier GetInstance(
@@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Asn1.Esf
 				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
 
 			this.crlIssuer = X509Name.GetInstance(seq[0]);
-			this.crlIssuedTime = DerUtcTime.GetInstance(seq[1]);
+			this.crlIssuedTime = Asn1UtcTime.GetInstance(seq[1]);
 
 			if (seq.Count > 2)
 			{
@@ -56,31 +56,36 @@ namespace Org.BouncyCastle.Asn1.Esf
 			}
 		}
 
-		public CrlIdentifier(
-			X509Name	crlIssuer,
-			DateTime	crlIssuedTime)
-			: this(crlIssuer, crlIssuedTime, null)
+        public CrlIdentifier(X509Name crlIssuer, DateTime crlIssuedTime)
+            : this(crlIssuer, crlIssuedTime, null)
 		{
 		}
 
-		public CrlIdentifier(
-			X509Name	crlIssuer,
-			DateTime	crlIssuedTime,
-			BigInteger	crlNumber)
+		public CrlIdentifier(X509Name crlIssuer, DateTime crlIssuedTime, BigInteger crlNumber)
+			: this(crlIssuer, new Asn1UtcTime(crlIssuedTime), crlNumber)
 		{
-			if (crlIssuer == null)
-				throw new ArgumentNullException("crlIssuer");
+		}
 
-			this.crlIssuer = crlIssuer;
-			this.crlIssuedTime = new DerUtcTime(crlIssuedTime);
+        public CrlIdentifier(X509Name crlIssuer, Asn1UtcTime crlIssuedTime)
+            : this(crlIssuer, crlIssuedTime, null)
+        {
+        }
 
-			if (crlNumber != null)
-			{
-				this.crlNumber = new DerInteger(crlNumber);
-			}
-		}
+        public CrlIdentifier(X509Name crlIssuer, Asn1UtcTime crlIssuedTime, BigInteger crlNumber)
+        {
+            if (crlIssuer == null)
+                throw new ArgumentNullException(nameof(crlIssuer));
+
+            this.crlIssuer = crlIssuer;
+            this.crlIssuedTime = crlIssuedTime;
+
+            if (null != crlNumber)
+            {
+                this.crlNumber = new DerInteger(crlNumber);
+            }
+        }
 
-		public X509Name CrlIssuer
+        public X509Name CrlIssuer
 		{
 			get { return crlIssuer; }
 		}
diff --git a/crypto/src/asn1/esf/OcspIdentifier.cs b/crypto/src/asn1/esf/OcspIdentifier.cs
index e65f1cfe7..fa7069aed 100644
--- a/crypto/src/asn1/esf/OcspIdentifier.cs
+++ b/crypto/src/asn1/esf/OcspIdentifier.cs
@@ -20,7 +20,7 @@ namespace Org.BouncyCastle.Asn1.Esf
 		: Asn1Encodable
 	{
 		private readonly ResponderID		ocspResponderID;
-		private readonly DerGeneralizedTime	producedAt;
+		private readonly Asn1GeneralizedTime producedAt;
 
 		public static OcspIdentifier GetInstance(
 			object obj)
@@ -46,21 +46,30 @@ namespace Org.BouncyCastle.Asn1.Esf
 				throw new ArgumentException("Bad sequence size: " + seq.Count, "seq");
 
 			this.ocspResponderID = ResponderID.GetInstance(seq[0].ToAsn1Object());
-			this.producedAt = (DerGeneralizedTime) seq[1].ToAsn1Object();
+			this.producedAt = (Asn1GeneralizedTime)seq[1].ToAsn1Object();
 		}
 
-		public OcspIdentifier(
-			ResponderID	ocspResponderID,
-			DateTime	producedAt)
+		public OcspIdentifier(ResponderID ocspResponderID, DateTime producedAt)
 		{
 			if (ocspResponderID == null)
-				throw new ArgumentNullException();
+				throw new ArgumentNullException(nameof(ocspResponderID));
 
 			this.ocspResponderID = ocspResponderID;
-			this.producedAt = new DerGeneralizedTime(producedAt);
+			this.producedAt = new Asn1GeneralizedTime(producedAt);
 		}
 
-		public ResponderID OcspResponderID
+        public OcspIdentifier(ResponderID ocspResponderID, Asn1GeneralizedTime producedAt)
+        {
+            if (ocspResponderID == null)
+                throw new ArgumentNullException(nameof(ocspResponderID));
+            if (producedAt == null)
+                throw new ArgumentNullException(nameof(producedAt));
+
+            this.ocspResponderID = ocspResponderID;
+            this.producedAt = producedAt;
+        }
+
+        public ResponderID OcspResponderID
 		{
 			get { return ocspResponderID; }
 		}
diff --git a/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs b/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
index b82c9373d..c9c96cbda 100644
--- a/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
+++ b/crypto/src/asn1/isismtt/x509/DeclarationOfMajority.cs
@@ -64,7 +64,7 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 		}
 
 		public DeclarationOfMajority(
-			DerGeneralizedTime dateOfBirth)
+            Asn1GeneralizedTime dateOfBirth)
 		{
 			this.declaration = new DerTaggedObject(false, 2, dateOfBirth);
 		}
@@ -155,14 +155,14 @@ namespace Org.BouncyCastle.Asn1.IsisMtt.X509
 			}
 		}
 
-		public virtual DerGeneralizedTime DateOfBirth
+		public virtual Asn1GeneralizedTime DateOfBirth
 		{
 			get
 			{
 				switch ((Choice) declaration.TagNo)
 				{
 					case Choice.DateOfBirth:
-						return DerGeneralizedTime.GetInstance(declaration, false);
+						return Asn1GeneralizedTime.GetInstance(declaration, false);
 					default:
 						return null;
 				}
diff --git a/crypto/src/asn1/ocsp/CrlID.cs b/crypto/src/asn1/ocsp/CrlID.cs
index fc1e59d22..24dda4edf 100644
--- a/crypto/src/asn1/ocsp/CrlID.cs
+++ b/crypto/src/asn1/ocsp/CrlID.cs
@@ -7,7 +7,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
     {
         private readonly DerIA5String		crlUrl;
         private readonly DerInteger			crlNum;
-        private readonly DerGeneralizedTime	crlTime;
+        private readonly Asn1GeneralizedTime crlTime;
 
 		// TODO Add GetInstance method(s) and make this private?
 		public CrlID(Asn1Sequence seq)
@@ -23,7 +23,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
                     crlNum = DerInteger.GetInstance(o, true);
                     break;
                 case 2:
-                    crlTime = DerGeneralizedTime.GetInstance(o, true);
+                    crlTime = Asn1GeneralizedTime.GetInstance(o, true);
                     break;
                 default:
                     throw new ArgumentException("unknown tag number: " + o.TagNo);
@@ -41,7 +41,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
 			get { return crlNum; }
 		}
 
-		public DerGeneralizedTime CrlTime
+		public Asn1GeneralizedTime CrlTime
 		{
 			get { return crlTime; }
 		}
diff --git a/crypto/src/asn1/ocsp/ResponseData.cs b/crypto/src/asn1/ocsp/ResponseData.cs
index a5769c0fa..dfb234bc1 100644
--- a/crypto/src/asn1/ocsp/ResponseData.cs
+++ b/crypto/src/asn1/ocsp/ResponseData.cs
@@ -13,7 +13,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
 		private readonly bool                versionPresent;
 		private readonly DerInteger          version;
 		private readonly ResponderID         responderID;
-		private readonly DerGeneralizedTime  producedAt;
+		private readonly Asn1GeneralizedTime producedAt;
 		private readonly Asn1Sequence        responses;
 		private readonly X509Extensions      responseExtensions;
 
@@ -43,7 +43,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
 		public ResponseData(
 			DerInteger          version,
 			ResponderID         responderID,
-			DerGeneralizedTime  producedAt,
+            Asn1GeneralizedTime producedAt,
 			Asn1Sequence        responses,
 			X509Extensions      responseExtensions)
 		{
@@ -56,7 +56,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
 
 		public ResponseData(
 			ResponderID         responderID,
-			DerGeneralizedTime  producedAt,
+            Asn1GeneralizedTime producedAt,
 			Asn1Sequence        responses,
 			X509Extensions      responseExtensions)
 			: this(V1, responderID, producedAt, responses, responseExtensions)
@@ -90,7 +90,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
 			}
 
 			this.responderID = ResponderID.GetInstance(seq[index++]);
-			this.producedAt = (DerGeneralizedTime)seq[index++];
+			this.producedAt = (Asn1GeneralizedTime)seq[index++];
 			this.responses = (Asn1Sequence)seq[index++];
 
 			if (seq.Count > index)
@@ -110,7 +110,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
 			get { return responderID; }
 		}
 
-		public DerGeneralizedTime ProducedAt
+		public Asn1GeneralizedTime ProducedAt
 		{
 			get { return producedAt; }
 		}
diff --git a/crypto/src/asn1/ocsp/RevokedInfo.cs b/crypto/src/asn1/ocsp/RevokedInfo.cs
index c67be0678..e6438dd08 100644
--- a/crypto/src/asn1/ocsp/RevokedInfo.cs
+++ b/crypto/src/asn1/ocsp/RevokedInfo.cs
@@ -8,7 +8,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
     public class RevokedInfo
         : Asn1Encodable
     {
-        private readonly DerGeneralizedTime revocationTime;
+        private readonly Asn1GeneralizedTime revocationTime;
         private readonly CrlReason revocationReason;
 
 		public static RevokedInfo GetInstance(
@@ -35,13 +35,13 @@ namespace Org.BouncyCastle.Asn1.Ocsp
 		}
 
 		public RevokedInfo(
-			DerGeneralizedTime revocationTime)
+            Asn1GeneralizedTime revocationTime)
 			: this(revocationTime, null)
 		{
 		}
 
 		public RevokedInfo(
-            DerGeneralizedTime  revocationTime,
+            Asn1GeneralizedTime revocationTime,
             CrlReason           revocationReason)
         {
 			if (revocationTime == null)
@@ -54,7 +54,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
 		private RevokedInfo(
             Asn1Sequence seq)
         {
-            this.revocationTime = (DerGeneralizedTime) seq[0];
+            this.revocationTime = (Asn1GeneralizedTime)seq[0];
 
 			if (seq.Count > 1)
             {
@@ -63,7 +63,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
             }
         }
 
-		public DerGeneralizedTime RevocationTime
+		public Asn1GeneralizedTime RevocationTime
 		{
 			get { return revocationTime; }
 		}
diff --git a/crypto/src/asn1/ocsp/SingleResponse.cs b/crypto/src/asn1/ocsp/SingleResponse.cs
index ecdf3dab0..42b451af7 100644
--- a/crypto/src/asn1/ocsp/SingleResponse.cs
+++ b/crypto/src/asn1/ocsp/SingleResponse.cs
@@ -10,15 +10,15 @@ namespace Org.BouncyCastle.Asn1.Ocsp
     {
         private readonly CertID              certID;
         private readonly CertStatus          certStatus;
-        private readonly DerGeneralizedTime  thisUpdate;
-        private readonly DerGeneralizedTime  nextUpdate;
+        private readonly Asn1GeneralizedTime thisUpdate;
+        private readonly Asn1GeneralizedTime nextUpdate;
         private readonly X509Extensions      singleExtensions;
 
 		public SingleResponse(
             CertID              certID,
             CertStatus          certStatus,
-            DerGeneralizedTime  thisUpdate,
-            DerGeneralizedTime  nextUpdate,
+            Asn1GeneralizedTime thisUpdate,
+            Asn1GeneralizedTime nextUpdate,
             X509Extensions      singleExtensions)
         {
             this.certID = certID;
@@ -33,11 +33,11 @@ namespace Org.BouncyCastle.Asn1.Ocsp
         {
             this.certID = CertID.GetInstance(seq[0]);
             this.certStatus = CertStatus.GetInstance(seq[1]);
-            this.thisUpdate = (DerGeneralizedTime)seq[2];
+            this.thisUpdate = (Asn1GeneralizedTime)seq[2];
 
 			if (seq.Count > 4)
             {
-                this.nextUpdate = DerGeneralizedTime.GetInstance(
+                this.nextUpdate = Asn1GeneralizedTime.GetInstance(
 					(Asn1TaggedObject) seq[3], true);
                 this.singleExtensions = X509Extensions.GetInstance(
 					(Asn1TaggedObject) seq[4], true);
@@ -48,7 +48,7 @@ namespace Org.BouncyCastle.Asn1.Ocsp
 
 				if (o.TagNo == 0)
                 {
-                    this.nextUpdate = DerGeneralizedTime.GetInstance(o, true);
+                    this.nextUpdate = Asn1GeneralizedTime.GetInstance(o, true);
                 }
                 else
                 {
@@ -90,12 +90,12 @@ namespace Org.BouncyCastle.Asn1.Ocsp
 			get { return certStatus; }
 		}
 
-		public DerGeneralizedTime ThisUpdate
+		public Asn1GeneralizedTime ThisUpdate
 		{
 			get { return thisUpdate; }
 		}
 
-		public DerGeneralizedTime NextUpdate
+		public Asn1GeneralizedTime NextUpdate
 		{
 			get { return nextUpdate; }
 		}
diff --git a/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs b/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
index 1a6a5417a..570e0ded7 100644
--- a/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
+++ b/crypto/src/asn1/pkcs/PKCSObjectIdentifiers.cs
@@ -138,11 +138,12 @@ namespace Org.BouncyCastle.Asn1.Pkcs
 
         public static readonly DerObjectIdentifier IdAlg = IdSmime.Branch("3");
 
-        public static readonly DerObjectIdentifier IdAlgEsdh        = IdAlg.Branch("5");
-        public static readonly DerObjectIdentifier IdAlgCms3DesWrap = IdAlg.Branch("6");
-        public static readonly DerObjectIdentifier IdAlgCmsRC2Wrap  = IdAlg.Branch("7");
-        public static readonly DerObjectIdentifier IdAlgPwriKek     = IdAlg.Branch("9");
-        public static readonly DerObjectIdentifier IdAlgSsdh        = IdAlg.Branch("10");
+        public static readonly DerObjectIdentifier IdAlgEsdh            = IdAlg.Branch("5");
+        public static readonly DerObjectIdentifier IdAlgCms3DesWrap     = IdAlg.Branch("6");
+        public static readonly DerObjectIdentifier IdAlgCmsRC2Wrap      = IdAlg.Branch("7");
+        public static readonly DerObjectIdentifier IdAlgZlibCompress    = IdAlg.Branch("8");
+        public static readonly DerObjectIdentifier IdAlgPwriKek         = IdAlg.Branch("9");
+        public static readonly DerObjectIdentifier IdAlgSsdh            = IdAlg.Branch("10");
 
         /*
          * <pre>
diff --git a/crypto/src/asn1/tsp/TSTInfo.cs b/crypto/src/asn1/tsp/TSTInfo.cs
index 28a840e77..dde11494c 100644
--- a/crypto/src/asn1/tsp/TSTInfo.cs
+++ b/crypto/src/asn1/tsp/TSTInfo.cs
@@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
 		private readonly DerObjectIdentifier	tsaPolicyId;
 		private readonly MessageImprint			messageImprint;
 		private readonly DerInteger				serialNumber;
-		private readonly DerGeneralizedTime		genTime;
+		private readonly Asn1GeneralizedTime	genTime;
 		private readonly Accuracy				accuracy;
 		private readonly DerBoolean				ordering;
 		private readonly DerInteger				nonce;
@@ -49,7 +49,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
 
 			// genTime
 			e.MoveNext();
-			genTime = DerGeneralizedTime.GetInstance(e.Current);
+			genTime = Asn1GeneralizedTime.GetInstance(e.Current);
 
 			// default for ordering
 			ordering = DerBoolean.False;
@@ -96,7 +96,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
 			DerObjectIdentifier	tsaPolicyId,
 			MessageImprint		messageImprint,
 			DerInteger			serialNumber,
-			DerGeneralizedTime	genTime,
+            Asn1GeneralizedTime genTime,
 			Accuracy			accuracy,
 			DerBoolean			ordering,
 			DerInteger			nonce,
@@ -140,7 +140,7 @@ namespace Org.BouncyCastle.Asn1.Tsp
 			get { return accuracy; }
 		}
 
-		public DerGeneralizedTime GenTime
+		public Asn1GeneralizedTime GenTime
 		{
 			get { return genTime; }
 		}
diff --git a/crypto/src/asn1/util/Asn1Dump.cs b/crypto/src/asn1/util/Asn1Dump.cs
index 7bae766c3..6c005f512 100644
--- a/crypto/src/asn1/util/Asn1Dump.cs
+++ b/crypto/src/asn1/util/Asn1Dump.cs
@@ -206,12 +206,12 @@ namespace Org.BouncyCastle.Asn1.Utilities
                 buf.Append(indent);
                 buf.AppendLine("VideotexString(" + videotexString.GetString() + ")");
             }
-            else if (obj is DerUtcTime utcTime)
+            else if (obj is Asn1UtcTime utcTime)
             {
                 buf.Append(indent);
                 buf.AppendLine("UTCTime(" + utcTime.TimeString + ")");
             }
-            else if (obj is DerGeneralizedTime generalizedTime)
+            else if (obj is Asn1GeneralizedTime generalizedTime)
             {
                 buf.Append(indent);
                 buf.AppendLine("GeneralizedTime(" + generalizedTime.GetTime() + ")");
diff --git a/crypto/src/asn1/x509/AttCertValidityPeriod.cs b/crypto/src/asn1/x509/AttCertValidityPeriod.cs
index d31e07402..893bc0838 100644
--- a/crypto/src/asn1/x509/AttCertValidityPeriod.cs
+++ b/crypto/src/asn1/x509/AttCertValidityPeriod.cs
@@ -7,8 +7,8 @@ namespace Org.BouncyCastle.Asn1.X509
     public class AttCertValidityPeriod
         : Asn1Encodable
     {
-        private readonly DerGeneralizedTime	notBeforeTime;
-        private readonly DerGeneralizedTime	notAfterTime;
+        private readonly Asn1GeneralizedTime notBeforeTime;
+        private readonly Asn1GeneralizedTime notAfterTime;
 
 		public static AttCertValidityPeriod GetInstance(
             object obj)
@@ -39,24 +39,24 @@ namespace Org.BouncyCastle.Asn1.X509
 			if (seq.Count != 2)
 				throw new ArgumentException("Bad sequence size: " + seq.Count);
 
-			notBeforeTime = DerGeneralizedTime.GetInstance(seq[0]);
-			notAfterTime = DerGeneralizedTime.GetInstance(seq[1]);
+			notBeforeTime = Asn1GeneralizedTime.GetInstance(seq[0]);
+			notAfterTime = Asn1GeneralizedTime.GetInstance(seq[1]);
         }
 
 		public AttCertValidityPeriod(
-            DerGeneralizedTime	notBeforeTime,
-            DerGeneralizedTime	notAfterTime)
+            Asn1GeneralizedTime notBeforeTime,
+            Asn1GeneralizedTime notAfterTime)
         {
             this.notBeforeTime = notBeforeTime;
             this.notAfterTime = notAfterTime;
         }
 
-		public DerGeneralizedTime NotBeforeTime
+		public Asn1GeneralizedTime NotBeforeTime
 		{
 			get { return notBeforeTime; }
 		}
 
-		public DerGeneralizedTime NotAfterTime
+		public Asn1GeneralizedTime NotAfterTime
 		{
 			get { return notAfterTime; }
 		}
diff --git a/crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs b/crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
index 89e8de6cb..a87c2ee9e 100644
--- a/crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
+++ b/crypto/src/asn1/x509/PrivateKeyUsagePeriod.cs
@@ -36,7 +36,7 @@ namespace Org.BouncyCastle.Asn1.X509
 			throw new ArgumentException("unknown object in GetInstance: " + Platform.GetTypeName(obj), "obj");
 		}
 
-		private DerGeneralizedTime _notBefore, _notAfter;
+		private Asn1GeneralizedTime _notBefore, _notAfter;
 
 		private PrivateKeyUsagePeriod(
 			Asn1Sequence seq)
@@ -45,21 +45,21 @@ namespace Org.BouncyCastle.Asn1.X509
 			{
 				if (tObj.TagNo == 0)
 				{
-					_notBefore = DerGeneralizedTime.GetInstance(tObj, false);
+					_notBefore = Asn1GeneralizedTime.GetInstance(tObj, false);
 				}
 				else if (tObj.TagNo == 1)
 				{
-					_notAfter = DerGeneralizedTime.GetInstance(tObj, false);
+					_notAfter = Asn1GeneralizedTime.GetInstance(tObj, false);
 				}
 			}
 		}
 
-		public DerGeneralizedTime NotBefore
+		public Asn1GeneralizedTime NotBefore
 		{
 			get { return _notBefore; }
 		}
 
-		public DerGeneralizedTime NotAfter
+		public Asn1GeneralizedTime NotAfter
 		{
 			get { return _notAfter; }
 		}
diff --git a/crypto/src/asn1/x509/TBSCertList.cs b/crypto/src/asn1/x509/TBSCertList.cs
index ab847d563..2b288850f 100644
--- a/crypto/src/asn1/x509/TBSCertList.cs
+++ b/crypto/src/asn1/x509/TBSCertList.cs
@@ -193,8 +193,8 @@ namespace Org.BouncyCastle.Asn1.X509
             thisUpdate = Time.GetInstance(seq[seqPos++]);
 
 			if (seqPos < seq.Count
-                && (seq[seqPos] is DerUtcTime
-                   || seq[seqPos] is DerGeneralizedTime
+                && (seq[seqPos] is Asn1UtcTime
+                   || seq[seqPos] is Asn1GeneralizedTime
                    || seq[seqPos] is Time))
             {
                 nextUpdate = Time.GetInstance(seq[seqPos++]);
diff --git a/crypto/src/asn1/x509/Time.cs b/crypto/src/asn1/x509/Time.cs
index efdf63850..1a6ac15c0 100644
--- a/crypto/src/asn1/x509/Time.cs
+++ b/crypto/src/asn1/x509/Time.cs
@@ -22,7 +22,7 @@ namespace Org.BouncyCastle.Asn1.X509
         {
             if (time == null)
                 throw new ArgumentNullException("time");
-            if (!(time is DerUtcTime) && !(time is DerGeneralizedTime))
+            if (!(time is Asn1UtcTime) && !(time is Asn1GeneralizedTime))
                 throw new ArgumentException("unknown object passed to Time");
 
             this.time = time;
@@ -49,27 +49,26 @@ namespace Org.BouncyCastle.Asn1.X509
             }
         }
 
-        public static Time GetInstance(
-            object obj)
+        public static Time GetInstance(object obj)
         {
-            if (obj == null || obj is Time)
-                return (Time)obj;
-            if (obj is DerUtcTime)
-                return new Time((DerUtcTime)obj);
-            if (obj is DerGeneralizedTime)
-                return new Time((DerGeneralizedTime)obj);
+            if (obj == null)
+                return null;
+            if (obj is Time time)
+                return time;
+            if (obj is Asn1UtcTime utcTime)
+                return new Time(utcTime);
+            if (obj is Asn1GeneralizedTime generalizedTime)
+                return new Time(generalizedTime);
 
             throw new ArgumentException("unknown object in factory: " + Platform.GetTypeName(obj), "obj");
         }
 
         public string GetTime()
         {
-            if (time is DerUtcTime)
-            {
-                return ((DerUtcTime) time).AdjustedTimeString;
-            }
+            if (time is Asn1UtcTime utcTime)
+                return utcTime.AdjustedTimeString;
 
-            return ((DerGeneralizedTime) time).GetTime();
+            return ((Asn1GeneralizedTime)time).GetTime();
         }
 
         /// <summary>
@@ -80,14 +79,10 @@ namespace Org.BouncyCastle.Asn1.X509
         {
             try
             {
-                if (time is DerUtcTime)
-                {
-                    return ((DerUtcTime)time).ToAdjustedDateTime();
-                }
-                else
-                {
-                    return ((DerGeneralizedTime)time).ToDateTime();
-                }
+                if (time is Asn1UtcTime utcTime)
+                    return utcTime.ToAdjustedDateTime();
+
+                return ((Asn1GeneralizedTime)time).ToDateTime();
             }
             catch (FormatException e)
             {
diff --git a/crypto/src/asn1/x509/V1TBSCertificateGenerator.cs b/crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
index 20b525a48..9cbff1ef0 100644
--- a/crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
+++ b/crypto/src/asn1/x509/V1TBSCertificateGenerator.cs
@@ -56,7 +56,7 @@ namespace Org.BouncyCastle.Asn1.X509
         }
 
 		public void SetStartDate(
-            DerUtcTime startDate)
+            Asn1UtcTime startDate)
         {
             this.startDate = new Time(startDate);
         }
@@ -68,7 +68,7 @@ namespace Org.BouncyCastle.Asn1.X509
         }
 
 		public void SetEndDate(
-            DerUtcTime endDate)
+            Asn1UtcTime endDate)
         {
             this.endDate = new Time(endDate);
         }
diff --git a/crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs b/crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
index 02580b5b8..c78c966b0 100644
--- a/crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
+++ b/crypto/src/asn1/x509/V2AttributeCertificateInfoGenerator.cs
@@ -26,11 +26,13 @@ namespace Org.BouncyCastle.Asn1.X509
         internal AttCertIssuer			issuer;
         internal AlgorithmIdentifier	signature;
         internal DerInteger				serialNumber;
-//        internal AttCertValidityPeriod	attrCertValidityPeriod;
         internal Asn1EncodableVector	attributes;
         internal DerBitString			issuerUniqueID;
         internal X509Extensions			extensions;
-        internal DerGeneralizedTime		startDate, endDate;
+
+        // Note: validity period start/end dates stored directly
+        //internal AttCertValidityPeriod attrCertValidityPeriod;
+        internal Asn1GeneralizedTime    startDate, endDate;
 
 		public V2AttributeCertificateInfoGenerator()
         {
@@ -78,13 +80,13 @@ namespace Org.BouncyCastle.Asn1.X509
         }
 
 		public void SetStartDate(
-            DerGeneralizedTime startDate)
+            Asn1GeneralizedTime startDate)
         {
             this.startDate = startDate;
         }
 
 		public void SetEndDate(
-            DerGeneralizedTime endDate)
+            Asn1GeneralizedTime endDate)
         {
             this.endDate = endDate;
         }
diff --git a/crypto/src/asn1/x509/V2TBSCertListGenerator.cs b/crypto/src/asn1/x509/V2TBSCertListGenerator.cs
index 1d58751fd..aa1a0b95d 100644
--- a/crypto/src/asn1/x509/V2TBSCertListGenerator.cs
+++ b/crypto/src/asn1/x509/V2TBSCertListGenerator.cs
@@ -55,13 +55,13 @@ namespace Org.BouncyCastle.Asn1.X509
         }
 
 		public void SetThisUpdate(
-            DerUtcTime thisUpdate)
+            Asn1UtcTime thisUpdate)
         {
             this.thisUpdate = new Time(thisUpdate);
         }
 
 		public void SetNextUpdate(
-            DerUtcTime nextUpdate)
+            Asn1UtcTime nextUpdate)
         {
             this.nextUpdate = (nextUpdate != null)
 				?	new Time(nextUpdate)
@@ -90,7 +90,7 @@ namespace Org.BouncyCastle.Asn1.X509
 			crlEntries.Add(crlEntry);
 		}
 
-		public void AddCrlEntry(DerInteger userCertificate, DerUtcTime revocationDate, int reason)
+		public void AddCrlEntry(DerInteger userCertificate, Asn1UtcTime revocationDate, int reason)
 		{
 			AddCrlEntry(userCertificate, new Time(revocationDate), reason);
 		}
@@ -101,7 +101,7 @@ namespace Org.BouncyCastle.Asn1.X509
 		}
 
 		public void AddCrlEntry(DerInteger userCertificate, Time revocationDate, int reason,
-			DerGeneralizedTime invalidityDate)
+            Asn1GeneralizedTime invalidityDate)
 		{
             var extOids = new List<DerObjectIdentifier>();
             var extValues = new List<X509Extension>();
diff --git a/crypto/src/asn1/x509/V3TBSCertificateGenerator.cs b/crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
index beb469a0d..544582ddb 100644
--- a/crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
+++ b/crypto/src/asn1/x509/V3TBSCertificateGenerator.cs
@@ -58,7 +58,7 @@ namespace Org.BouncyCastle.Asn1.X509
         }
 
 		public void SetStartDate(
-            DerUtcTime startDate)
+            Asn1UtcTime startDate)
         {
             this.startDate = new Time(startDate);
         }
@@ -70,7 +70,7 @@ namespace Org.BouncyCastle.Asn1.X509
         }
 
 		public void SetEndDate(
-            DerUtcTime endDate)
+            Asn1UtcTime endDate)
         {
             this.endDate = new Time(endDate);
         }
diff --git a/crypto/src/asn1/x509/X509DefaultEntryConverter.cs b/crypto/src/asn1/x509/X509DefaultEntryConverter.cs
index 7282ead26..d155efc5a 100644
--- a/crypto/src/asn1/x509/X509DefaultEntryConverter.cs
+++ b/crypto/src/asn1/x509/X509DefaultEntryConverter.cs
@@ -46,7 +46,7 @@ namespace Org.BouncyCastle.Asn1.X509
 
 			if (oid.Equals(X509Name.DateOfBirth)) // accept time string as well as # (for compatibility)
 			{
-				return new DerGeneralizedTime(value);
+				return new Asn1GeneralizedTime(value);
 			}
 
 			if (oid.Equals(X509Name.C)
diff --git a/crypto/src/asn1/x509/sigi/PersonalData.cs b/crypto/src/asn1/x509/sigi/PersonalData.cs
index 439039888..e8c75bf93 100644
--- a/crypto/src/asn1/x509/sigi/PersonalData.cs
+++ b/crypto/src/asn1/x509/sigi/PersonalData.cs
@@ -29,7 +29,7 @@ namespace Org.BouncyCastle.Asn1.X509.SigI
 	{
 		private readonly NameOrPseudonym	nameOrPseudonym;
 		private readonly BigInteger			nameDistinguisher;
-		private readonly DerGeneralizedTime	dateOfBirth;
+		private readonly Asn1GeneralizedTime dateOfBirth;
 		private readonly DirectoryString	placeOfBirth;
 		private readonly string				gender;
 		private readonly DirectoryString	postalAddress;
@@ -88,7 +88,7 @@ namespace Org.BouncyCastle.Asn1.X509.SigI
 					nameDistinguisher = DerInteger.GetInstance(o, false).Value;
 					break;
 				case 1:
-					dateOfBirth = DerGeneralizedTime.GetInstance(o, false);
+					dateOfBirth = Asn1GeneralizedTime.GetInstance(o, false);
 					break;
 				case 2:
 					placeOfBirth = DirectoryString.GetInstance(o, true);
@@ -118,7 +118,7 @@ namespace Org.BouncyCastle.Asn1.X509.SigI
 		public PersonalData(
 			NameOrPseudonym		nameOrPseudonym,
 			BigInteger			nameDistinguisher,
-			DerGeneralizedTime	dateOfBirth,
+            Asn1GeneralizedTime dateOfBirth,
 			DirectoryString		placeOfBirth,
 			string				gender,
 			DirectoryString		postalAddress)
@@ -141,7 +141,7 @@ namespace Org.BouncyCastle.Asn1.X509.SigI
 			get { return nameDistinguisher; }
 		}
 
-		public DerGeneralizedTime DateOfBirth
+		public Asn1GeneralizedTime DateOfBirth
 		{
 			get { return dateOfBirth; }
 		}
diff --git a/crypto/src/bcpg/SignaturePacket.cs b/crypto/src/bcpg/SignaturePacket.cs
index 3256ee35e..dd9cc78e3 100644
--- a/crypto/src/bcpg/SignaturePacket.cs
+++ b/crypto/src/bcpg/SignaturePacket.cs
@@ -237,7 +237,7 @@ namespace Org.BouncyCastle.Bcpg
 
 			if (hashedData != null)
 			{
-				setCreationTime();
+				SetCreationTime();
 			}
 		}
 
@@ -446,18 +446,18 @@ namespace Org.BouncyCastle.Bcpg
 			return sOut.ToArray();
 		}
 
-		private void setCreationTime()
+		private void SetCreationTime()
 		{
 			foreach (SignatureSubpacket p in hashedData)
 			{
-				if (p is SignatureCreationTime)
+				if (p is SignatureCreationTime signatureCreationTime)
 				{
-                    creationTime = DateTimeUtilities.DateTimeToUnixMs(
-						((SignatureCreationTime)p).GetTime());
+                    creationTime = DateTimeUtilities.DateTimeToUnixMs(signatureCreationTime.GetTime());
 					break;
 				}
 			}
 		}
+
         public static SignaturePacket FromByteArray(byte[] data)
         {
             BcpgInputStream input = BcpgInputStream.Wrap(new MemoryStream(data));
diff --git a/crypto/src/bcpg/sig/Exportable.cs b/crypto/src/bcpg/sig/Exportable.cs
index 4d030346f..8a9eafe09 100644
--- a/crypto/src/bcpg/sig/Exportable.cs
+++ b/crypto/src/bcpg/sig/Exportable.cs
@@ -10,17 +10,7 @@ namespace Org.BouncyCastle.Bcpg.Sig
     {
         private static byte[] BooleanToByteArray(bool val)
         {
-            byte[]    data = new byte[1];
-
-            if (val)
-            {
-                data[0] = 1;
-                return data;
-            }
-            else
-            {
-                return data;
-            }
+            return new byte[1]{ Convert.ToByte(val) };
         }
 
         public Exportable(
diff --git a/crypto/src/bcpg/sig/Features.cs b/crypto/src/bcpg/sig/Features.cs
index 135d7f54e..f6123d612 100644
--- a/crypto/src/bcpg/sig/Features.cs
+++ b/crypto/src/bcpg/sig/Features.cs
@@ -19,31 +19,25 @@ namespace Org.BouncyCastle.Bcpg.Sig
            fingerprint format */
         public static readonly byte FEATURE_VERSION_5_PUBLIC_KEY = 0x04;
 
-        private static byte[] featureToByteArray(byte feature)
+        private static byte[] FeatureToByteArray(byte feature)
         {
-            byte[] data = new byte[1];
-            data[0] = feature;
-            return data;
+            return new byte[1]{ feature };
         }
 
         public Features(
             bool critical,
             bool isLongLength,
-            byte[] data): base(SignatureSubpacketTag.Features, critical, isLongLength, data)
+            byte[] data)
+            : base(SignatureSubpacketTag.Features, critical, isLongLength, data)
         {
-
         }
-      
 
-        public Features(bool critical, byte features): this(critical, false, featureToByteArray(features))
+        public Features(bool critical, byte features): this(critical, false, FeatureToByteArray(features))
         {
-
         }
-   
 
-        public Features(bool critical, int features):  this(critical, false, featureToByteArray((byte)features))
+        public Features(bool critical, int features):  this(critical, false, FeatureToByteArray((byte)features))
         {
-           
         }
 
         /**
diff --git a/crypto/src/bcpg/sig/IssuerKeyId.cs b/crypto/src/bcpg/sig/IssuerKeyId.cs
index 627ea3ecf..1281a110e 100644
--- a/crypto/src/bcpg/sig/IssuerKeyId.cs
+++ b/crypto/src/bcpg/sig/IssuerKeyId.cs
@@ -1,6 +1,4 @@
-using System;
-
-
+using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Bcpg.Sig
 {
@@ -10,21 +8,9 @@ namespace Org.BouncyCastle.Bcpg.Sig
     public class IssuerKeyId
         : SignatureSubpacket
     {
-        protected static byte[] KeyIdToBytes(
-            long    keyId)
+        protected static byte[] KeyIdToBytes(long keyId)
         {
-            byte[]    data = new byte[8];
-
-            data[0] = (byte)(keyId >> 56);
-            data[1] = (byte)(keyId >> 48);
-            data[2] = (byte)(keyId >> 40);
-            data[3] = (byte)(keyId >> 32);
-            data[4] = (byte)(keyId >> 24);
-            data[5] = (byte)(keyId >> 16);
-            data[6] = (byte)(keyId >> 8);
-            data[7] = (byte)keyId;
-
-            return data;
+            return Pack.UInt64_To_BE((ulong)keyId);
         }
 
         public IssuerKeyId(
@@ -42,21 +28,6 @@ namespace Org.BouncyCastle.Bcpg.Sig
         {
         }
 
-        public long KeyId
-        {
-			get
-			{
-				long keyId = ((long)(data[0] & 0xff) << 56)
-					| ((long)(data[1] & 0xff) << 48)
-					| ((long)(data[2] & 0xff) << 40)
-					| ((long)(data[3] & 0xff) << 32)
-					| ((long)(data[4] & 0xff) << 24)
-					| ((long)(data[5] & 0xff) << 16)
-					| ((long)(data[6] & 0xff) << 8)
-					| ((long)data[7] & 0xff);
-
-				return keyId;
-			}
-        }
+        public long KeyId => (long)Pack.BE_To_UInt64(data);
     }
 }
diff --git a/crypto/src/bcpg/sig/KeyExpirationTime.cs b/crypto/src/bcpg/sig/KeyExpirationTime.cs
index dfd3e76fd..62184b2a1 100644
--- a/crypto/src/bcpg/sig/KeyExpirationTime.cs
+++ b/crypto/src/bcpg/sig/KeyExpirationTime.cs
@@ -1,4 +1,4 @@
-using System;
+using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Bcpg.Sig
 {
@@ -8,17 +8,9 @@ namespace Org.BouncyCastle.Bcpg.Sig
     public class KeyExpirationTime
         : SignatureSubpacket
     {
-        protected static byte[] TimeToBytes(
-            long    t)
+        protected static byte[] TimeToBytes(long t)
         {
-            byte[]    data = new byte[4];
-
-            data[0] = (byte)(t >> 24);
-            data[1] = (byte)(t >> 16);
-            data[2] = (byte)(t >> 8);
-            data[3] = (byte)t;
-
-            return data;
+            return Pack.UInt32_To_BE((uint)t);
         }
 
         public KeyExpirationTime(
@@ -41,15 +33,6 @@ namespace Org.BouncyCastle.Bcpg.Sig
         *
         * @return second count for key validity.
         */
-        public long Time
-        {
-			get
-			{
-				long time = ((long)(data[0] & 0xff) << 24) | ((long)(data[1] & 0xff) << 16)
-					| ((long)(data[2] & 0xff) << 8) | ((long)data[3] & 0xff);
-
-				return time;
-			}
-        }
+        public long Time => (long)Pack.BE_To_UInt32(data);
     }
 }
diff --git a/crypto/src/bcpg/sig/NotationData.cs b/crypto/src/bcpg/sig/NotationData.cs
index 9ac6f89cf..71c34d3de 100644
--- a/crypto/src/bcpg/sig/NotationData.cs
+++ b/crypto/src/bcpg/sig/NotationData.cs
@@ -79,7 +79,7 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
 		public bool IsHumanReadable
 		{
-			get { return data[0] == (byte)0x80; }
+			get { return data[0] == 0x80; }
 		}
 
 		public string GetNotationName()
diff --git a/crypto/src/bcpg/sig/PrimaryUserId.cs b/crypto/src/bcpg/sig/PrimaryUserId.cs
index 1f16f40eb..184dfe8f7 100644
--- a/crypto/src/bcpg/sig/PrimaryUserId.cs
+++ b/crypto/src/bcpg/sig/PrimaryUserId.cs
@@ -8,20 +8,9 @@ namespace Org.BouncyCastle.Bcpg.Sig
     public class PrimaryUserId
         : SignatureSubpacket
     {
-        private static byte[] BooleanToByteArray(
-            bool    val)
+        private static byte[] BooleanToByteArray(bool val)
         {
-            byte[]    data = new byte[1];
-
-            if (val)
-            {
-                data[0] = 1;
-                return data;
-            }
-            else
-            {
-                return data;
-            }
+            return new byte[1]{ Convert.ToByte(val) };
         }
 
         public PrimaryUserId(
diff --git a/crypto/src/bcpg/sig/Revocable.cs b/crypto/src/bcpg/sig/Revocable.cs
index 7aa91391f..6ded4d865 100644
--- a/crypto/src/bcpg/sig/Revocable.cs
+++ b/crypto/src/bcpg/sig/Revocable.cs
@@ -8,20 +8,9 @@ namespace Org.BouncyCastle.Bcpg.Sig
     public class Revocable
         : SignatureSubpacket
     {
-        private static byte[] BooleanToByteArray(
-            bool    value)
+        private static byte[] BooleanToByteArray(bool value)
         {
-            byte[]    data = new byte[1];
-
-            if (value)
-            {
-                data[0] = 1;
-                return data;
-            }
-            else
-            {
-                return data;
-            }
+            return new byte[1]{ Convert.ToByte(value) };
         }
 
         public Revocable(
diff --git a/crypto/src/bcpg/sig/RevocationReason.cs b/crypto/src/bcpg/sig/RevocationReason.cs
index 42afd5f5b..bd0c91428 100644
--- a/crypto/src/bcpg/sig/RevocationReason.cs
+++ b/crypto/src/bcpg/sig/RevocationReason.cs
@@ -46,9 +46,7 @@ namespace Org.BouncyCastle.Bcpg
         {
             byte[] data = GetData();
             if (data.Length == 1)
-            {
                 return string.Empty;
-            }
 
             byte[] description = new byte[data.Length - 1];
             Array.Copy(data, 1, description, 0, description.Length);
diff --git a/crypto/src/bcpg/sig/SignatureCreationTime.cs b/crypto/src/bcpg/sig/SignatureCreationTime.cs
index d172e5d52..233dd18e6 100644
--- a/crypto/src/bcpg/sig/SignatureCreationTime.cs
+++ b/crypto/src/bcpg/sig/SignatureCreationTime.cs
@@ -1,5 +1,6 @@
 using System;
 
+using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities.Date;
 
 namespace Org.BouncyCastle.Bcpg.Sig
@@ -10,41 +11,25 @@ namespace Org.BouncyCastle.Bcpg.Sig
     public class SignatureCreationTime
         : SignatureSubpacket
     {
-		protected static byte[] TimeToBytes(
-            DateTime time)
+		protected static byte[] TimeToBytes(DateTime time)
         {
 			long t = DateTimeUtilities.DateTimeToUnixMs(time) / 1000L;
-			byte[] data = new byte[4];
-			data[0] = (byte)(t >> 24);
-            data[1] = (byte)(t >> 16);
-            data[2] = (byte)(t >> 8);
-            data[3] = (byte)t;
-            return data;
+            return Pack.UInt32_To_BE((uint)t);
         }
 
-        public SignatureCreationTime(
-            bool    critical,
-            bool    isLongLength,
-            byte[]  data)
+        public SignatureCreationTime(bool critical, bool isLongLength, byte[] data)
             : base(SignatureSubpacketTag.CreationTime, critical, isLongLength, data)
         {
         }
 
-        public SignatureCreationTime(
-            bool        critical,
-            DateTime    date)
+        public SignatureCreationTime(bool critical, DateTime date)
             : base(SignatureSubpacketTag.CreationTime, critical, false, TimeToBytes(date))
         {
         }
 
         public DateTime GetTime()
         {
-			long time = (long)(
-					((uint)data[0] << 24)
-				|	((uint)data[1] << 16)
-				|	((uint)data[2] << 8)
-				|	((uint)data[3])
-				);
+            uint time = Pack.BE_To_UInt32(data, 0);
 			return DateTimeUtilities.UnixMsToDateTime(time * 1000L);
         }
     }
diff --git a/crypto/src/bcpg/sig/SignatureExpirationTime.cs b/crypto/src/bcpg/sig/SignatureExpirationTime.cs
index 24f0a9f8a..44c714f33 100644
--- a/crypto/src/bcpg/sig/SignatureExpirationTime.cs
+++ b/crypto/src/bcpg/sig/SignatureExpirationTime.cs
@@ -1,4 +1,4 @@
-using System;
+using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Bcpg.Sig
 {
@@ -8,28 +8,17 @@ namespace Org.BouncyCastle.Bcpg.Sig
     public class SignatureExpirationTime
         : SignatureSubpacket
     {
-        protected static byte[] TimeToBytes(
-            long    t)
+        protected static byte[] TimeToBytes(long t)
         {
-            byte[] data = new byte[4];
-            data[0] = (byte)(t >> 24);
-            data[1] = (byte)(t >> 16);
-            data[2] = (byte)(t >> 8);
-            data[3] = (byte)t;
-            return data;
+            return Pack.UInt32_To_BE((uint)t);
         }
 
-        public SignatureExpirationTime(
-            bool    critical,
-            bool    isLongLength,
-            byte[]  data)
+        public SignatureExpirationTime(bool critical, bool isLongLength, byte[] data)
             : base(SignatureSubpacketTag.ExpireTime, critical, isLongLength, data)
         {
         }
 
-        public SignatureExpirationTime(
-            bool    critical,
-            long    seconds)
+        public SignatureExpirationTime(bool critical, long seconds)
             : base(SignatureSubpacketTag.ExpireTime, critical, false, TimeToBytes(seconds))
         {
         }
@@ -37,15 +26,6 @@ namespace Org.BouncyCastle.Bcpg.Sig
         /**
         * return time in seconds before signature expires after creation time.
         */
-        public long Time
-        {
-            get
-            {
-                long time = ((long)(data[0] & 0xff) << 24) | ((long)(data[1] & 0xff) << 16)
-                    | ((long)(data[2] & 0xff) << 8) | ((long)data[3] & 0xff);
-
-                return time;
-            }
-        }
+        public long Time => Pack.BE_To_UInt32(data, 0);
     }
 }
diff --git a/crypto/src/bcpg/sig/SignerUserId.cs b/crypto/src/bcpg/sig/SignerUserId.cs
index 8ab62ed2e..6f812e210 100644
--- a/crypto/src/bcpg/sig/SignerUserId.cs
+++ b/crypto/src/bcpg/sig/SignerUserId.cs
@@ -1,7 +1,3 @@
-using System;
-
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
diff --git a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
index 837eb177f..505747960 100644
--- a/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
+++ b/crypto/src/cmp/ProtectedPkiMessageBuilder.cs
@@ -3,6 +3,7 @@ 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;
@@ -44,7 +45,13 @@ namespace Org.BouncyCastle.Cmp
             return this;
         }
 
-        public ProtectedPkiMessageBuilder SetMessageTime(DerGeneralizedTime generalizedTime)
+        public ProtectedPkiMessageBuilder SetMessageTime(DateTime time)
+        {
+            m_hdrBuilder.SetMessageTime(new Asn1GeneralizedTime(time));
+            return this;
+        }
+
+        public ProtectedPkiMessageBuilder SetMessageTime(Asn1GeneralizedTime generalizedTime)
         {
             m_hdrBuilder.SetMessageTime(generalizedTime);
             return this;
diff --git a/crypto/src/cms/CMSAuthenticatedDataGenerator.cs b/crypto/src/cms/CMSAuthenticatedDataGenerator.cs
index 9bfabe8b1..6c68bccd1 100644
--- a/crypto/src/cms/CMSAuthenticatedDataGenerator.cs
+++ b/crypto/src/cms/CMSAuthenticatedDataGenerator.cs
@@ -29,20 +29,14 @@ namespace Org.BouncyCastle.Cms
 	public class CmsAuthenticatedDataGenerator
 	    : CmsAuthenticatedGenerator
 	{
-	    /**
-	     * base constructor
-	     */
 	    public CmsAuthenticatedDataGenerator()
 	    {
 	    }
 
-	    /**
-	     * constructor allowing specific source of randomness
-	     * @param rand instance of SecureRandom to use
-	     */
-	    public CmsAuthenticatedDataGenerator(
-	        SecureRandom rand)
-	        : base(rand)
+        /// <summary>Constructor allowing specific source of randomness</summary>
+        /// <param name="random">Instance of <c>SecureRandom</c> to use.</param>
+	    public CmsAuthenticatedDataGenerator(SecureRandom random)
+	        : base(random)
 	    {
 	    }
 
@@ -109,7 +103,7 @@ namespace Org.BouncyCastle.Cms
 			{
 				try
 				{
-					recipientInfos.Add(rig.Generate(encKey, rand));
+					recipientInfos.Add(rig.Generate(encKey, m_random));
 				}
 				catch (InvalidKeyException e)
 				{
@@ -142,7 +136,7 @@ namespace Org.BouncyCastle.Cms
 				// FIXME Will this work for macs?
 				CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
 
-				keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+				keyGen.Init(new KeyGenerationParameters(m_random, keyGen.DefaultStrength));
 
 				return Generate(content, encryptionOid, keyGen);
             }
diff --git a/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs b/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs
index d66b0aea9..b2c5cac28 100644
--- a/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSAuthenticatedDataStreamGenerator.cs
@@ -42,20 +42,14 @@ namespace Org.BouncyCastle.Cms
 		private int                 _bufferSize;
 		private bool                _berEncodeRecipientSet;
 
-		/**
-		* base constructor
-		*/
 		public CmsAuthenticatedDataStreamGenerator()
 		{
 		}
 
-		/**
-		* constructor allowing specific source of randomness
-		* @param rand instance of SecureRandom to use
-		*/
-		public CmsAuthenticatedDataStreamGenerator(
-			SecureRandom rand)
-			: base(rand)
+        /// <summary>Constructor allowing specific source of randomness</summary>
+        /// <param name="random">Instance of <c>SecureRandom</c> to use.</param>
+		public CmsAuthenticatedDataStreamGenerator(SecureRandom random)
+			: base(random)
 		{
 		}
 
@@ -105,7 +99,7 @@ namespace Org.BouncyCastle.Cms
 			{
 				try
 				{
-					recipientInfos.Add(rig.Generate(encKey, rand));
+					recipientInfos.Add(rig.Generate(encKey, m_random));
 				}
 				catch (InvalidKeyException e)
 				{
@@ -195,7 +189,7 @@ namespace Org.BouncyCastle.Cms
 		{
 			CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
 
-			keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+			keyGen.Init(new KeyGenerationParameters(m_random, keyGen.DefaultStrength));
 
 			return Open(outStr, encryptionOid, keyGen);
 		}
@@ -210,7 +204,7 @@ namespace Org.BouncyCastle.Cms
 		{
 			CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
 
-			keyGen.Init(new KeyGenerationParameters(rand, keySize));
+			keyGen.Init(new KeyGenerationParameters(m_random, keySize));
 
 			return Open(outStr, encryptionOid, keyGen);
 		}
diff --git a/crypto/src/cms/CMSAuthenticatedGenerator.cs b/crypto/src/cms/CMSAuthenticatedGenerator.cs
index 8824d1913..1f73c9b19 100644
--- a/crypto/src/cms/CMSAuthenticatedGenerator.cs
+++ b/crypto/src/cms/CMSAuthenticatedGenerator.cs
@@ -14,21 +14,14 @@ namespace Org.BouncyCastle.Cms
 	public class CmsAuthenticatedGenerator
 		: CmsEnvelopedGenerator
 	{
-		/**
-		* base constructor
-		*/
 		public CmsAuthenticatedGenerator()
 		{
 		}
 
-		/**
-		* constructor allowing specific source of randomness
-		*
-		* @param rand instance of SecureRandom to use
-		*/
-		public CmsAuthenticatedGenerator(
-			SecureRandom rand)
-			: base(rand)
+        /// <summary>Constructor allowing specific source of randomness</summary>
+        /// <param name="random">Instance of <c>SecureRandom</c> to use.</param>
+        public CmsAuthenticatedGenerator(SecureRandom random)
+			: base(random)
 		{
 		}
 	}
diff --git a/crypto/src/cms/CMSCompressedData.cs b/crypto/src/cms/CMSCompressedData.cs
index 21651f041..5f8165005 100644
--- a/crypto/src/cms/CMSCompressedData.cs
+++ b/crypto/src/cms/CMSCompressedData.cs
@@ -1,10 +1,9 @@
-using System;
 using System.IO;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Cms;
 using Org.BouncyCastle.Utilities;
-using Org.BouncyCastle.Utilities.Zlib;
+using Org.BouncyCastle.Utilities.IO.Compression;
 
 namespace Org.BouncyCastle.Cms
 {
@@ -45,7 +44,7 @@ namespace Org.BouncyCastle.Cms
             ContentInfo content = comData.EncapContentInfo;
 
 			Asn1OctetString bytes = (Asn1OctetString) content.Content;
-			ZInputStream zIn = new ZInputStream(bytes.GetOctetStream());
+			Stream zIn = ZLib.DecompressInput(bytes.GetOctetStream());
 
 			try
 			{
@@ -76,8 +75,7 @@ namespace Org.BouncyCastle.Cms
 			ContentInfo     content = comData.EncapContentInfo;
 
 			Asn1OctetString bytes = (Asn1OctetString)content.Content;
-
-			ZInputStream zIn = new ZInputStream(new MemoryStream(bytes.GetOctets(), false));
+            Stream zIn = ZLib.DecompressInput(bytes.GetOctetStream());
 
 			try
 			{
diff --git a/crypto/src/cms/CMSCompressedDataGenerator.cs b/crypto/src/cms/CMSCompressedDataGenerator.cs
index bea04752a..70515e8d3 100644
--- a/crypto/src/cms/CMSCompressedDataGenerator.cs
+++ b/crypto/src/cms/CMSCompressedDataGenerator.cs
@@ -5,7 +5,6 @@ using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Cms;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Utilities;
-using Org.BouncyCastle.Utilities.Zlib;
 
 namespace Org.BouncyCastle.Cms
 {
@@ -22,32 +21,34 @@ namespace Org.BouncyCastle.Cms
     */
     public class CmsCompressedDataGenerator
     {
-        public const string ZLib = "1.2.840.113549.1.9.16.3.8";
+        public static readonly string ZLib = CmsObjectIdentifiers.ZlibCompress.Id;
 
-		public CmsCompressedDataGenerator()
+        public CmsCompressedDataGenerator()
         {
         }
 
 		/**
         * Generate an object that contains an CMS Compressed Data
         */
-        public CmsCompressedData Generate(
-            CmsProcessable	content,
-            string			compressionOid)
+        public CmsCompressedData Generate(CmsProcessable content, string compressionOid)
         {
+            if (ZLib != compressionOid)
+                throw new ArgumentException("Unsupported compression algorithm: " + compressionOid,
+                    nameof(compressionOid));
+
             AlgorithmIdentifier comAlgId;
             Asn1OctetString comOcts;
 
             try
             {
                 MemoryStream bOut = new MemoryStream();
-                ZOutputStream zOut = new ZOutputStream(bOut, JZlib.Z_DEFAULT_COMPRESSION);
+                Stream zOut = Utilities.IO.Compression.ZLib.CompressOutput(bOut, -1);
 
 				content.Write(zOut);
 
                 Platform.Dispose(zOut);
 
-                comAlgId = new AlgorithmIdentifier(new DerObjectIdentifier(compressionOid));
+                comAlgId = new AlgorithmIdentifier(CmsObjectIdentifiers.ZlibCompress);
 				comOcts = new BerOctetString(bOut.ToArray());
             }
             catch (IOException e)
diff --git a/crypto/src/cms/CMSCompressedDataParser.cs b/crypto/src/cms/CMSCompressedDataParser.cs
index b107ff608..38ff88968 100644
--- a/crypto/src/cms/CMSCompressedDataParser.cs
+++ b/crypto/src/cms/CMSCompressedDataParser.cs
@@ -3,7 +3,7 @@ using System.IO;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.Cms;
-using Org.BouncyCastle.Utilities.Zlib;
+using Org.BouncyCastle.Utilities.IO.Compression;
 
 namespace Org.BouncyCastle.Cms
 {
@@ -44,8 +44,9 @@ namespace Org.BouncyCastle.Cms
                 ContentInfoParser content = comData.GetEncapContentInfo();
 
                 Asn1OctetStringParser bytes = (Asn1OctetStringParser)content.GetContent(Asn1Tags.OctetString);
+                Stream zIn = ZLib.DecompressInput(bytes.GetOctetStream());
 
-                return new CmsTypedStream(content.ContentType.ToString(), new ZInputStream(bytes.GetOctetStream()));
+                return new CmsTypedStream(content.ContentType.ToString(), zIn);
             }
             catch (IOException e)
             {
diff --git a/crypto/src/cms/CMSCompressedDataStreamGenerator.cs b/crypto/src/cms/CMSCompressedDataStreamGenerator.cs
index 9a9c29b01..1594500cd 100644
--- a/crypto/src/cms/CMSCompressedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSCompressedDataStreamGenerator.cs
@@ -6,7 +6,6 @@ using Org.BouncyCastle.Asn1.Cms;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.IO;
-using Org.BouncyCastle.Utilities.Zlib;
 
 namespace Org.BouncyCastle.Cms
 {
@@ -27,10 +26,10 @@ namespace Org.BouncyCastle.Cms
 	*/
 	public class CmsCompressedDataStreamGenerator
 	{
-		public const string ZLib = "1.2.840.113549.1.9.16.3.8";
+        public static readonly string ZLib = CmsObjectIdentifiers.ZlibCompress.Id;
+
+        private int _bufferSize;
 
-		private int _bufferSize;
-		
 		/**
 		* base constructor
 		*/
@@ -43,24 +42,27 @@ namespace Org.BouncyCastle.Cms
 		*
 		* @param bufferSize length of octet strings to buffer the data.
 		*/
-		public void SetBufferSize(
-			int bufferSize)
+		public void SetBufferSize(int bufferSize)
 		{
 			_bufferSize = bufferSize;
 		}
 
-		public Stream Open(
-			Stream	outStream,
-			string	compressionOID)
+        public Stream Open(Stream outStream)
+        {
+            return Open(outStream, CmsObjectIdentifiers.Data.Id, ZLib);
+        }
+
+        public Stream Open(Stream outStream, string compressionOid)
 		{
-			return Open(outStream, CmsObjectIdentifiers.Data.Id, compressionOID);
+			return Open(outStream, CmsObjectIdentifiers.Data.Id, compressionOid);
 		}
 
-		public Stream Open(
-			Stream	outStream,
-			string	contentOID,
-			string	compressionOID)
+		public Stream Open(Stream outStream, string contentOid, string compressionOid)
 		{
+			if (ZLib != compressionOid)
+				throw new ArgumentException("Unsupported compression algorithm: " + compressionOid,
+					nameof(compressionOid));
+
 			BerSequenceGenerator sGen = new BerSequenceGenerator(outStream);
 
 			sGen.AddObject(CmsObjectIdentifiers.CompressedData);
@@ -75,32 +77,32 @@ namespace Org.BouncyCastle.Cms
 			cGen.AddObject(new DerInteger(0));
 
 			// CompressionAlgorithmIdentifier
-			cGen.AddObject(new AlgorithmIdentifier(new DerObjectIdentifier(ZLib)));
+			cGen.AddObject(new AlgorithmIdentifier(CmsObjectIdentifiers.ZlibCompress));
 
 			//
 			// Encapsulated ContentInfo
 			//
 			BerSequenceGenerator eiGen = new BerSequenceGenerator(cGen.GetRawOutputStream());
 
-			eiGen.AddObject(new DerObjectIdentifier(contentOID));
+			eiGen.AddObject(new DerObjectIdentifier(contentOid));
 
 			Stream octetStream = CmsUtilities.CreateBerOctetOutputStream(
 				eiGen.GetRawOutputStream(), 0, true, _bufferSize);
 
 			return new CmsCompressedOutputStream(
-				new ZOutputStream(octetStream, JZlib.Z_DEFAULT_COMPRESSION), sGen, cGen, eiGen);
+				Utilities.IO.Compression.ZLib.CompressOutput(octetStream, -1), sGen, cGen, eiGen);
 		}
 
 		private class CmsCompressedOutputStream
 			: BaseOutputStream
 		{
-			private ZOutputStream _out;
+			private Stream _out;
 			private BerSequenceGenerator _sGen;
 			private BerSequenceGenerator _cGen;
 			private BerSequenceGenerator _eiGen;
 
 			internal CmsCompressedOutputStream(
-				ZOutputStream			outStream,
+				Stream					outStream,
 				BerSequenceGenerator	sGen,
 				BerSequenceGenerator	cGen,
 				BerSequenceGenerator	eiGen)
diff --git a/crypto/src/cms/CMSEnvelopedDataGenerator.cs b/crypto/src/cms/CMSEnvelopedDataGenerator.cs
index d646480e0..1b618b331 100644
--- a/crypto/src/cms/CMSEnvelopedDataGenerator.cs
+++ b/crypto/src/cms/CMSEnvelopedDataGenerator.cs
@@ -33,10 +33,9 @@ namespace Org.BouncyCastle.Cms
         }
 
 		/// <summary>Constructor allowing specific source of randomness</summary>
-		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
-		public CmsEnvelopedDataGenerator(
-			SecureRandom rand)
-			: base(rand)
+		/// <param name="random">Instance of <c>SecureRandom</c> to use.</param>
+		public CmsEnvelopedDataGenerator(SecureRandom random)
+			: base(random)
 		{
 		}
 
@@ -65,7 +64,7 @@ namespace Org.BouncyCastle.Cms
 					encryptionOid, encKey, asn1Params, out cipherParameters);
 
 				IBufferedCipher cipher = CipherUtilities.GetCipher(encryptionOid);
-				cipher.Init(true, new ParametersWithRandom(cipherParameters, rand));
+				cipher.Init(true, new ParametersWithRandom(cipherParameters, m_random));
 
 				MemoryStream bOut = new MemoryStream();
 				CipherStream cOut = new CipherStream(bOut, null, cipher);
@@ -96,7 +95,7 @@ namespace Org.BouncyCastle.Cms
             {
                 try
                 {
-                    recipientInfos.Add(rig.Generate(encKey, rand));
+                    recipientInfos.Add(rig.Generate(encKey, m_random));
                 }
                 catch (InvalidKeyException e)
                 {
@@ -138,7 +137,7 @@ namespace Org.BouncyCastle.Cms
             {
 				CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
                
-				keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+				keyGen.Init(new KeyGenerationParameters(m_random, keyGen.DefaultStrength));
 
 				return Generate(content, encryptionOid, keyGen);
             }
@@ -185,7 +184,7 @@ namespace Org.BouncyCastle.Cms
             {
                 try
                 {
-                    recipientInfos.Add(rig.Generate(encKey, rand));
+                    recipientInfos.Add(rig.Generate(encKey, m_random));
                 }
                 catch (InvalidKeyException e)
                 {
@@ -228,7 +227,7 @@ namespace Org.BouncyCastle.Cms
             {
 				CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
 
-				keyGen.Init(new KeyGenerationParameters(rand, keySize));
+				keyGen.Init(new KeyGenerationParameters(m_random, keySize));
 
 				return Generate(content, encryptionOid, keyGen);
             }
diff --git a/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs b/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
index 4a8b57aad..6a362e13f 100644
--- a/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSEnvelopedDataStreamGenerator.cs
@@ -46,10 +46,9 @@ namespace Org.BouncyCastle.Cms
 		}
 
 		/// <summary>Constructor allowing specific source of randomness</summary>
-		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
-		public CmsEnvelopedDataStreamGenerator(
-			SecureRandom rand)
-			: base(rand)
+		/// <param name="random">Instance of <c>SecureRandom</c> to use.</param>
+		public CmsEnvelopedDataStreamGenerator(SecureRandom random)
+			: base(random)
 		{
 		}
 
@@ -104,7 +103,7 @@ namespace Org.BouncyCastle.Cms
 			{
 				try
 				{
-					recipientInfos.Add(rig.Generate(encKey, rand));
+					recipientInfos.Add(rig.Generate(encKey, m_random));
 				}
 				catch (InvalidKeyException e)
 				{
@@ -162,7 +161,7 @@ namespace Org.BouncyCastle.Cms
 					eiGen.GetRawOutputStream(), 0, false, _bufferSize);
 
                 IBufferedCipher cipher = CipherUtilities.GetCipher(encAlgID.Algorithm);
-				cipher.Init(true, new ParametersWithRandom(cipherParameters, rand));
+				cipher.Init(true, new ParametersWithRandom(cipherParameters, m_random));
 				CipherStream cOut = new CipherStream(octetOutputStream, null, cipher);
 
 				return new CmsEnvelopedDataOutputStream(this, cOut, cGen, envGen, eiGen);
@@ -191,7 +190,7 @@ namespace Org.BouncyCastle.Cms
 		{
 			CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
 
-			keyGen.Init(new KeyGenerationParameters(rand, keyGen.DefaultStrength));
+			keyGen.Init(new KeyGenerationParameters(m_random, keyGen.DefaultStrength));
 
 			return Open(outStream, encryptionOid, keyGen);
 		}
@@ -207,7 +206,7 @@ namespace Org.BouncyCastle.Cms
 		{
 			CipherKeyGenerator keyGen = GeneratorUtilities.GetKeyGenerator(encryptionOid);
 
-			keyGen.Init(new KeyGenerationParameters(rand, keySize));
+			keyGen.Init(new KeyGenerationParameters(m_random, keySize));
 
 			return Open(outStream, encryptionOid, keyGen);
 		}
diff --git a/crypto/src/cms/CMSEnvelopedGenerator.cs b/crypto/src/cms/CMSEnvelopedGenerator.cs
index e0a94c4d3..eef572878 100644
--- a/crypto/src/cms/CMSEnvelopedGenerator.cs
+++ b/crypto/src/cms/CMSEnvelopedGenerator.cs
@@ -30,7 +30,7 @@ namespace Org.BouncyCastle.Cms
 	*      CMSEnvelopedData         data = fact.generate(content, algorithm, "BC");
 	* </pre>
 	*/
-	public class CmsEnvelopedGenerator
+	public abstract class CmsEnvelopedGenerator
 	{
 		// Note: These tables are complementary: If rc2Table[i]==j, then rc2Ekb[j]==i
 		internal static readonly short[] rc2Table =
@@ -100,21 +100,23 @@ namespace Org.BouncyCastle.Cms
 		public static readonly string ECMqvSha1Kdf		= X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id;
 
 		internal readonly IList<RecipientInfoGenerator> recipientInfoGenerators = new List<RecipientInfoGenerator>();
-		internal readonly SecureRandom rand;
+		internal readonly SecureRandom m_random;
 
         internal CmsAttributeTableGenerator unprotectedAttributeGenerator = null;
 
-		public CmsEnvelopedGenerator()
-			: this(new SecureRandom())
+        protected CmsEnvelopedGenerator()
+			: this(CryptoServicesRegistrar.GetSecureRandom())
 		{
 		}
 
 		/// <summary>Constructor allowing specific source of randomness</summary>
-		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
-		public CmsEnvelopedGenerator(
-			SecureRandom rand)
+		/// <param name="random">Instance of <c>SecureRandom</c> to use.</param>
+		protected CmsEnvelopedGenerator(SecureRandom random)
 		{
-			this.rand = rand;
+			if (random == null)
+				throw new ArgumentNullException(nameof(random));
+
+			m_random = random;
 		}
 
         public CmsAttributeTableGenerator UnprotectedAttributeGenerator
@@ -304,7 +306,7 @@ namespace Org.BouncyCastle.Cms
 				if (encryptionOid.Equals(RC2Cbc))
 				{
 					byte[] iv = new byte[8];
-					rand.NextBytes(iv);
+                    m_random.NextBytes(iv);
 
 					// TODO Is this detailed repeat of Java version really necessary?
 					int effKeyBits = encKeyBytes.Length * 8;
@@ -323,7 +325,7 @@ namespace Org.BouncyCastle.Cms
 				}
 				else
 				{
-					asn1Params = ParameterUtilities.GenerateParameters(encryptionOid, rand);
+					asn1Params = ParameterUtilities.GenerateParameters(encryptionOid, m_random);
 				}
 			}
 			catch (SecurityUtilityException)
diff --git a/crypto/src/cms/CMSSignedDataGenerator.cs b/crypto/src/cms/CMSSignedDataGenerator.cs
index c2304a09b..fff22e057 100644
--- a/crypto/src/cms/CMSSignedDataGenerator.cs
+++ b/crypto/src/cms/CMSSignedDataGenerator.cs
@@ -55,6 +55,7 @@ namespace Org.BouncyCastle.Cms
 			internal SignerInf(
                 CmsSignedGenerator			outer,
 	            AsymmetricKeyParameter		key,
+				SecureRandom                random,
 	            SignerIdentifier			signerIdentifier,
 	            string						digestOID,
 	            string						encOID,
@@ -67,7 +68,7 @@ namespace Org.BouncyCastle.Cms
                 string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(encOID);
 
                 this.outer = outer;
-                this.sigCalc = new Asn1SignatureFactory(signatureName, key);
+                this.sigCalc = new Asn1SignatureFactory(signatureName, key, random);
                 this.signerIdentifier = signerIdentifier;
                 this.digestOID = digestOID;
                 this.encOID = encOID;
@@ -110,10 +111,7 @@ namespace Org.BouncyCastle.Cms
 				get { return unsAttr; }
             }
 
-			internal SignerInfo ToSignerInfo(
-                DerObjectIdentifier	contentType,
-                CmsProcessable		content,
-				SecureRandom		random)
+			internal SignerInfo ToSignerInfo(DerObjectIdentifier contentType, CmsProcessable content)
             {
                 AlgorithmIdentifier digAlgId = DigestAlgorithmID;
 				string digestName = Helper.GetDigestAlgName(digestOID);
@@ -196,10 +194,9 @@ namespace Org.BouncyCastle.Cms
         }
 
 		/// <summary>Constructor allowing specific source of randomness</summary>
-		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
-		public CmsSignedDataGenerator(
-			SecureRandom rand)
-			: base(rand)
+		/// <param name="random">Instance of <c>SecureRandom</c> to use.</param>
+		public CmsSignedDataGenerator(SecureRandom random)
+			: base(random)
 		{
 		}
 
@@ -425,7 +422,7 @@ namespace Org.BouncyCastle.Cms
 			CmsAttributeTableGenerator  unsignedAttrGen,
 			Asn1.Cms.AttributeTable		baseSignedTable)
 		{
-			signerInfs.Add(new SignerInf(this, privateKey, signerIdentifier, digestOID, encryptionOID,
+			signerInfs.Add(new SignerInf(this, privateKey, m_random, signerIdentifier, digestOID, encryptionOID,
 				signedAttrGen, unsignedAttrGen, baseSignedTable));
 		}
 
@@ -480,7 +477,7 @@ namespace Org.BouncyCastle.Cms
 				try
                 {
 					digestAlgs.Add(signer.DigestAlgorithmID);
-                    signerInfos.Add(signer.ToSignerInfo(contentTypeOid, content, rand));
+                    signerInfos.Add(signer.ToSignerInfo(contentTypeOid, content));
 				}
                 catch (IOException e)
                 {
diff --git a/crypto/src/cms/CMSSignedDataStreamGenerator.cs b/crypto/src/cms/CMSSignedDataStreamGenerator.cs
index 96200fc8c..f934b9259 100644
--- a/crypto/src/cms/CMSSignedDataStreamGenerator.cs
+++ b/crypto/src/cms/CMSSignedDataStreamGenerator.cs
@@ -137,7 +137,7 @@ namespace Org.BouncyCastle.Cms
 					}
 				}
 
-				_sig.Init(true, new ParametersWithRandom(key, outer.rand));
+				_sig.Init(true, new ParametersWithRandom(key, outer.m_random));
 			}
 
 			public SignerInfo Generate(DerObjectIdentifier contentType, AlgorithmIdentifier digestAlgorithm,
@@ -234,10 +234,9 @@ namespace Org.BouncyCastle.Cms
         }
 
 		/// <summary>Constructor allowing specific source of randomness</summary>
-		/// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
-		public CmsSignedDataStreamGenerator(
-			SecureRandom rand)
-			: base(rand)
+		/// <param name="random">Instance of <c>SecureRandom</c> to use.</param>
+		public CmsSignedDataStreamGenerator(SecureRandom random)
+			: base(random)
 		{
 		}
 
diff --git a/crypto/src/cms/CMSSignedGenerator.cs b/crypto/src/cms/CMSSignedGenerator.cs
index 58f66f214..c16f6e83c 100644
--- a/crypto/src/cms/CMSSignedGenerator.cs
+++ b/crypto/src/cms/CMSSignedGenerator.cs
@@ -15,6 +15,7 @@ using Org.BouncyCastle.Asn1.Rosstandart;
 using Org.BouncyCastle.Asn1.TeleTrust;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities.Collections;
 using Org.BouncyCastle.X509;
@@ -481,7 +482,7 @@ namespace Org.BouncyCastle.Cms
         }
     }
 
-    public class CmsSignedGenerator
+    public abstract class CmsSignedGenerator
     {
         /**
         * Default type for the signed data.
@@ -516,19 +517,21 @@ namespace Org.BouncyCastle.Cms
         internal bool _useDerForCerts = false;
         internal bool _useDerForCrls = false;
 
-        protected readonly SecureRandom rand;
+        protected readonly SecureRandom m_random;
 
         protected CmsSignedGenerator()
-            : this(new SecureRandom())
+            : this(CryptoServicesRegistrar.GetSecureRandom())
         {
         }
 
         /// <summary>Constructor allowing specific source of randomness</summary>
-        /// <param name="rand">Instance of <c>SecureRandom</c> to use.</param>
-        protected CmsSignedGenerator(
-            SecureRandom rand)
+        /// <param name="random">Instance of <c>SecureRandom</c> to use.</param>
+        protected CmsSignedGenerator(SecureRandom random)
         {
-            this.rand = rand;
+            if (random == null)
+                throw new ArgumentNullException(nameof(random));
+
+            m_random = random;
         }
 
         internal protected virtual IDictionary<CmsAttributeTableParameter, object> GetBaseParameters(
diff --git a/crypto/src/cms/CMSSignedHelper.cs b/crypto/src/cms/CMSSignedHelper.cs
index 0ab7790d1..8df9e8f01 100644
--- a/crypto/src/cms/CMSSignedHelper.cs
+++ b/crypto/src/cms/CMSSignedHelper.cs
@@ -7,6 +7,7 @@ using Org.BouncyCastle.Asn1.Eac;
 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;
@@ -82,15 +83,21 @@ namespace Org.BouncyCastle.Cms
 			AddEntries(EacObjectIdentifiers.id_TA_RSA_v1_5_SHA_256, "SHA256", "RSA");
 			AddEntries(EacObjectIdentifiers.id_TA_RSA_PSS_SHA_1, "SHA1", "RSAandMGF1");
 			AddEntries(EacObjectIdentifiers.id_TA_RSA_PSS_SHA_256, "SHA256", "RSAandMGF1");
+            AddEntries(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94, "GOST3411", "GOST3410");
+            AddEntries(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001, "GOST3411", "ECGOST3410");
+            AddEntries(RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256, "GOST3411_2012_256", "ECGOST3410");
+            AddEntries(RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512, "GOST3411_2012_512", "ECGOST3410");
 
-			m_encryptionAlgs.Add(X9ObjectIdentifiers.IdDsa.Id, "DSA");
+            m_encryptionAlgs.Add(X9ObjectIdentifiers.IdDsa.Id, "DSA");
 			m_encryptionAlgs.Add(PkcsObjectIdentifiers.RsaEncryption.Id, "RSA");
 			m_encryptionAlgs.Add(TeleTrusTObjectIdentifiers.TeleTrusTRsaSignatureAlgorithm.Id, "RSA");
 			m_encryptionAlgs.Add(X509ObjectIdentifiers.IdEARsa.Id, "RSA");
 			m_encryptionAlgs.Add(CmsSignedGenerator.EncryptionRsaPss, "RSAandMGF1");
 			m_encryptionAlgs.Add(CryptoProObjectIdentifiers.GostR3410x94.Id, "GOST3410");
 			m_encryptionAlgs.Add(CryptoProObjectIdentifiers.GostR3410x2001.Id, "ECGOST3410");
-			m_encryptionAlgs.Add("1.3.6.1.4.1.5849.1.6.2", "ECGOST3410");
+            m_encryptionAlgs.Add(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_256.Id, "ECGOST3410");
+            m_encryptionAlgs.Add(RosstandartObjectIdentifiers.id_tc26_gost_3410_12_512.Id, "ECGOST3410");
+            m_encryptionAlgs.Add("1.3.6.1.4.1.5849.1.6.2", "ECGOST3410");
 			m_encryptionAlgs.Add("1.3.6.1.4.1.5849.1.1.5", "GOST3410");
 
 			m_digestAlgs.Add(PkcsObjectIdentifiers.MD2.Id, "MD2");
@@ -112,15 +119,17 @@ namespace Org.BouncyCastle.Cms
 			m_digestAlgs.Add(TeleTrusTObjectIdentifiers.RipeMD256.Id, "RIPEMD256");
 			m_digestAlgs.Add(CryptoProObjectIdentifiers.GostR3411.Id,  "GOST3411");
 			m_digestAlgs.Add("1.3.6.1.4.1.5849.1.2.1",  "GOST3411");
+            m_digestAlgs.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_256.Id, "GOST3411_2012_256");
+            m_digestAlgs.Add(RosstandartObjectIdentifiers.id_tc26_gost_3411_12_512.Id, "GOST3411_2012_512");
 
-			m_digestAliases.Add("SHA1", new string[]{ "SHA-1" });
+            m_digestAliases.Add("SHA1", new string[]{ "SHA-1" });
 			m_digestAliases.Add("SHA224", new string[]{ "SHA-224" });
 			m_digestAliases.Add("SHA256", new string[]{ "SHA-256" });
 			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(EncryptionECDsa);
             noParams.Add(EncryptionECDsaWithSha1);
             noParams.Add(EncryptionECDsaWithSha224);
             noParams.Add(EncryptionECDsaWithSha256);
diff --git a/crypto/src/crmf/PKMacBuilder.cs b/crypto/src/crmf/PKMacBuilder.cs
index bce26b825..ae9baa3d0 100644
--- a/crypto/src/crmf/PKMacBuilder.cs
+++ b/crypto/src/crmf/PKMacBuilder.cs
@@ -224,10 +224,7 @@ namespace Org.BouncyCastle.Crmf
 
             byte[] salt = new byte[saltLength];
 
-            if (random == null)
-            {
-                this.random = new SecureRandom();
-            }
+            this.random = CryptoServicesRegistrar.GetSecureRandom(random);
 
             random.NextBytes(salt);
 
diff --git a/crypto/src/crypto/CipherKeyGenerator.cs b/crypto/src/crypto/CipherKeyGenerator.cs
index 80d4782db..2d5d8c2e0 100644
--- a/crypto/src/crypto/CipherKeyGenerator.cs
+++ b/crypto/src/crypto/CipherKeyGenerator.cs
@@ -67,7 +67,7 @@ namespace Org.BouncyCastle.Crypto
 
 				uninitialised = false;
 
-				EngineInit(new KeyGenerationParameters(new SecureRandom(), defaultStrength));
+				EngineInit(new KeyGenerationParameters(CryptoServicesRegistrar.GetSecureRandom(), defaultStrength));
 			}
 
 			return EngineGenerateKey();
diff --git a/crypto/src/crypto/Security.cs b/crypto/src/crypto/Security.cs
deleted file mode 100644
index 7eb595f8e..000000000
--- a/crypto/src/crypto/Security.cs
+++ /dev/null
@@ -1,74 +0,0 @@
-using System.Text;
-
-using Org.BouncyCastle.Crypto.Digests;
-using Org.BouncyCastle.Crypto.Engines;
-using Org.BouncyCastle.Crypto.Generators;
-using Org.BouncyCastle.Crypto.Modes;
-using Org.BouncyCastle.Crypto.Paddings;
-using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Utilities.Encoders;
-
-namespace Org.BouncyCastle.Crypto
-{
-    public static class Security
-    {
-        // USAGE
-        //var key = Security.GenerateText(32);
-        //var iv = Security.GenerateText(16);
-        //var encrypted = Security.Encrypt("MY SECRET", key, iv);
-        //var decrypted = Security.Decrypt(encrypted, key, iv);
-
-        /// <summary>
-        /// Return a salted hash based on PBKDF2 for the UTF-8 encoding of the argument text.
-        /// </summary>
-        /// <param name="text">Provided key text</param>
-        /// <param name="salt">Base64 encoded string representing the salt</param>
-        /// <returns></returns>
-        public static string ComputeHash(string text, string salt)
-        {
-            byte[] data = Encoding.UTF8.GetBytes(text);
-            Sha512Digest sha = new Sha512Digest();
-            Pkcs5S2ParametersGenerator gen = new Pkcs5S2ParametersGenerator(sha);
-
-            gen.Init(data, Base64.Decode(salt), 2048);
-
-            return Base64.ToBase64String(((KeyParameter)gen.GenerateDerivedParameters("AES", sha.GetDigestSize() * 8)).GetKey());
-        }
-
-        public static string Decrypt(string cipherText, string key, string iv)
-        {
-            IBufferedCipher cipher = CreateCipher(false, key, iv);
-            byte[] textAsBytes = cipher.DoFinal(Base64.Decode(cipherText));
-
-            return Encoding.UTF8.GetString(textAsBytes, 0, textAsBytes.Length);
-        }
-
-        public static string Encrypt(string plainText, string key, string iv)
-        {
-            IBufferedCipher cipher = CreateCipher(true, key, iv);
-
-            return Base64.ToBase64String(cipher.DoFinal(Encoding.UTF8.GetBytes(plainText)));
-        }
-
-        public static string GenerateText(int size)
-        {
-            byte[] textAsBytes = new byte[size];
-            SecureRandom secureRandom = SecureRandom.GetInstance("SHA256PRNG", true);
-
-            secureRandom.NextBytes(textAsBytes);
-            return Base64.ToBase64String(textAsBytes);
-        }
-
-        private static IBufferedCipher CreateCipher(bool isEncryption, string key, string iv)
-        {
-            IBufferedCipher cipher = new PaddedBufferedBlockCipher(new CbcBlockCipher(new RijndaelEngine()), new ISO10126d2Padding());
-            KeyParameter keyParam = new KeyParameter(Base64.Decode(key));
-            ICipherParameters cipherParams = (null == iv || iv.Length < 1)
-                ? (ICipherParameters)keyParam
-                : new ParametersWithIV(keyParam, Base64.Decode(iv));
-            cipher.Init(isEncryption, cipherParams);
-            return cipher;
-        }
-    }
-}
diff --git a/crypto/src/crypto/agreement/DHAgreement.cs b/crypto/src/crypto/agreement/DHAgreement.cs
index e988c0d53..6032c237a 100644
--- a/crypto/src/crypto/agreement/DHAgreement.cs
+++ b/crypto/src/crypto/agreement/DHAgreement.cs
@@ -26,30 +26,25 @@ namespace Org.BouncyCastle.Crypto.Agreement
 		private BigInteger				privateValue;
 		private SecureRandom			random;
 
-		public void Init(
-			ICipherParameters parameters)
+		public void Init(ICipherParameters parameters)
 		{
 			AsymmetricKeyParameter kParam;
-			if (parameters is ParametersWithRandom)
+			if (parameters is ParametersWithRandom rParam)
 			{
-				ParametersWithRandom rParam = (ParametersWithRandom)parameters;
-
 				this.random = rParam.Random;
 				kParam = (AsymmetricKeyParameter)rParam.Parameters;
 			}
 			else
 			{
-				this.random = new SecureRandom();
+				this.random = CryptoServicesRegistrar.GetSecureRandom();
 				kParam = (AsymmetricKeyParameter)parameters;
 			}
 
-			if (!(kParam is DHPrivateKeyParameters))
-			{
+			if (!(kParam is DHPrivateKeyParameters dhPrivateKeyParameters))
 				throw new ArgumentException("DHEngine expects DHPrivateKeyParameters");
-			}
 
-			this.key = (DHPrivateKeyParameters)kParam;
-			this.dhParams = key.Parameters;
+			this.key = dhPrivateKeyParameters;
+			this.dhParams = dhPrivateKeyParameters.Parameters;
 		}
 
 		/**
diff --git a/crypto/src/crypto/agreement/jpake/JPakeParticipant.cs b/crypto/src/crypto/agreement/jpake/JPakeParticipant.cs
index 794284866..d6ed37032 100755
--- a/crypto/src/crypto/agreement/jpake/JPakeParticipant.cs
+++ b/crypto/src/crypto/agreement/jpake/JPakeParticipant.cs
@@ -142,7 +142,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.JPake
         ///      Caller should clear the input password as soon as possible.</param>
         /// <param name="group">Prime order group. See JPakePrimeOrderGroups for standard groups.</param>
         public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group)
-            : this(participantId, password, group, new Sha256Digest(), new SecureRandom()) { }
+            : this(participantId, password, group, new Sha256Digest(), CryptoServicesRegistrar.GetSecureRandom()) { }
 
 
         /// <summary>
@@ -162,7 +162,8 @@ namespace Org.BouncyCastle.Crypto.Agreement.JPake
         /// <param name="digest">Digest to use during zero knowledge proofs and key confirmation
         ///     (SHA-256 or stronger preferred).</param>
         /// <param name="random">Source of secure random data for x1 and x2, and for the zero knowledge proofs.</param>
-        public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group, IDigest digest, SecureRandom random)
+        public JPakeParticipant(string participantId, char[] password, JPakePrimeOrderGroup group, IDigest digest,
+            SecureRandom random)
         {
             JPakeUtilities.ValidateNotNull(participantId, "participantId");
             JPakeUtilities.ValidateNotNull(password, "password");
@@ -171,9 +172,7 @@ namespace Org.BouncyCastle.Crypto.Agreement.JPake
             JPakeUtilities.ValidateNotNull(random, "random");
 
             if (password.Length == 0)
-            {
                 throw new ArgumentException("Password must not be empty.");
-            }
 
             this.participantId = participantId;
 
diff --git a/crypto/src/crypto/digests/Haraka256_X86.cs b/crypto/src/crypto/digests/Haraka256_X86.cs
index ab64f91ae..4c9a798c0 100644
--- a/crypto/src/crypto/digests/Haraka256_X86.cs
+++ b/crypto/src/crypto/digests/Haraka256_X86.cs
@@ -1,6 +1,8 @@
 #if NETCOREAPP3_0_OR_GREATER
 using System;
+using System.Buffers.Binary;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Runtime.Intrinsics;
 
 namespace Org.BouncyCastle.Crypto.Digests
@@ -115,33 +117,27 @@ namespace Org.BouncyCastle.Crypto.Digests
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static Vector128<byte> Load128(ReadOnlySpan<byte> t)
         {
-#if NET7_0_OR_GREATER
-            return Vector128.Create<byte>(t);
-#else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
-                return Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(t[0]));
+                return MemoryMarshal.Read<Vector128<byte>>(t);
 
-            return Vector128.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12],
-                t[13], t[14], t[15]);
-#endif
+            return Vector128.Create(
+                BinaryPrimitives.ReadUInt64LittleEndian(t[..8]),
+                BinaryPrimitives.ReadUInt64LittleEndian(t[8..])
+            ).AsByte();
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void Store128(Vector128<byte> s, Span<byte> t)
         {
-#if NET7_0_OR_GREATER
-            Vector128.CopyTo(s, t);
-#else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
             {
-                Unsafe.WriteUnaligned(ref t[0], s);
+                MemoryMarshal.Write(t, ref s);
                 return;
             }
 
             var u = s.AsUInt64();
-            Utilities.Pack.UInt64_To_LE(u.GetElement(0), t);
-            Utilities.Pack.UInt64_To_LE(u.GetElement(1), t[8..]);
-#endif
+            BinaryPrimitives.WriteUInt64LittleEndian(t[..8], u.GetElement(0));
+            BinaryPrimitives.WriteUInt64LittleEndian(t[8..], u.GetElement(1));
         }
     }
 }
diff --git a/crypto/src/crypto/digests/Haraka512_X86.cs b/crypto/src/crypto/digests/Haraka512_X86.cs
index 8e67228ae..6dcd3e782 100644
--- a/crypto/src/crypto/digests/Haraka512_X86.cs
+++ b/crypto/src/crypto/digests/Haraka512_X86.cs
@@ -1,6 +1,8 @@
 #if NETCOREAPP3_0_OR_GREATER
 using System;
+using System.Buffers.Binary;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Runtime.Intrinsics;
 
 namespace Org.BouncyCastle.Crypto.Digests
@@ -198,50 +200,40 @@ namespace Org.BouncyCastle.Crypto.Digests
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static Vector128<byte> Load128(ReadOnlySpan<byte> t)
         {
-#if NET7_0_OR_GREATER
-            return Vector128.Create<byte>(t);
-#else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
-                return Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(t[0]));
+                return MemoryMarshal.Read<Vector128<byte>>(t);
 
-            return Vector128.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12],
-                t[13], t[14], t[15]);
-#endif
+            return Vector128.Create(
+                BinaryPrimitives.ReadUInt64LittleEndian(t[..8]),
+                BinaryPrimitives.ReadUInt64LittleEndian(t[8..])
+            ).AsByte();
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void Store128(Vector128<byte> s, Span<byte> t)
         {
-#if NET7_0_OR_GREATER
-            Vector128.CopyTo(s, t);
-#else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
             {
-                Unsafe.WriteUnaligned(ref t[0], s);
+                MemoryMarshal.Write(t, ref s);
                 return;
             }
 
             var u = s.AsUInt64();
-            Utilities.Pack.UInt64_To_LE(u.GetElement(0), t);
-            Utilities.Pack.UInt64_To_LE(u.GetElement(1), t[8..]);
-#endif
+            BinaryPrimitives.WriteUInt64LittleEndian(t[..8], u.GetElement(0));
+            BinaryPrimitives.WriteUInt64LittleEndian(t[8..], u.GetElement(1));
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void Store64(Vector64<byte> s, Span<byte> t)
         {
-#if NET7_0_OR_GREATER
-            Vector64.CopyTo(s, t);
-#else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector64<byte>>() == 8)
             {
-                Unsafe.WriteUnaligned(ref t[0], s);
+                MemoryMarshal.Write(t, ref s);
                 return;
             }
 
             var u = s.AsUInt64();
-            Utilities.Pack.UInt64_To_LE(u.ToScalar(), t);
-#endif
+            BinaryPrimitives.WriteUInt64LittleEndian(t, u.ToScalar());
         }
     }
 }
diff --git a/crypto/src/crypto/digests/HarakaBase.cs b/crypto/src/crypto/digests/HarakaBase.cs
index 37dda2163..1ca688914 100644
--- a/crypto/src/crypto/digests/HarakaBase.cs
+++ b/crypto/src/crypto/digests/HarakaBase.cs
@@ -102,7 +102,7 @@ namespace Org.BouncyCastle.Crypto.Digests
             s = SubBytes(s);
             s = ShiftRows(s);
             s = MixColumns(s);
-            XorWith(rk, s);
+            XorTo(rk, s);
             return s;
         }
 
@@ -131,11 +131,14 @@ namespace Org.BouncyCastle.Crypto.Digests
         }
 #endif
 
-        private static void XorWith(byte[] x, byte[] z)
+        private static void XorTo(byte[] x, byte[] z)
         {
-            for (int i = 0; i < 16; ++i)
+            for (int i = 0; i < 16; i += 4)
             {
-                z[i] ^= x[i];
+                z[i + 0] ^= x[i + 0];
+                z[i + 1] ^= x[i + 1];
+                z[i + 2] ^= x[i + 2];
+                z[i + 3] ^= x[i + 3];
             }
         }
 
diff --git a/crypto/src/crypto/digests/KeccakDigest.cs b/crypto/src/crypto/digests/KeccakDigest.cs
index b8305cc13..9f4a36b88 100644
--- a/crypto/src/crypto/digests/KeccakDigest.cs
+++ b/crypto/src/crypto/digests/KeccakDigest.cs
@@ -407,11 +407,11 @@ namespace Org.BouncyCastle.Crypto.Digests
                 ulong c3 = a03 ^ a08 ^ a13 ^ a18 ^ a23;
                 ulong c4 = a04 ^ a09 ^ a14 ^ a19 ^ a24;
 
-                ulong d1 = (c1 << 1 | c1 >> -1) ^ c4;
-                ulong d2 = (c2 << 1 | c2 >> -1) ^ c0;
-                ulong d3 = (c3 << 1 | c3 >> -1) ^ c1;
-                ulong d4 = (c4 << 1 | c4 >> -1) ^ c2;
-                ulong d0 = (c0 << 1 | c0 >> -1) ^ c3;
+                ulong d1 = Longs.RotateLeft(c1, 1) ^ c4;
+                ulong d2 = Longs.RotateLeft(c2, 1) ^ c0;
+                ulong d3 = Longs.RotateLeft(c3, 1) ^ c1;
+                ulong d4 = Longs.RotateLeft(c4, 1) ^ c2;
+                ulong d0 = Longs.RotateLeft(c0, 1) ^ c3;
 
                 a00 ^= d1; a05 ^= d1; a10 ^= d1; a15 ^= d1; a20 ^= d1;
                 a01 ^= d2; a06 ^= d2; a11 ^= d2; a16 ^= d2; a21 ^= d2;
@@ -420,30 +420,30 @@ namespace Org.BouncyCastle.Crypto.Digests
                 a04 ^= d0; a09 ^= d0; a14 ^= d0; a19 ^= d0; a24 ^= d0;
 
                 // rho/pi
-                c1  = a01 <<  1 | a01 >> 63;
-                a01 = a06 << 44 | a06 >> 20;
-                a06 = a09 << 20 | a09 >> 44;
-                a09 = a22 << 61 | a22 >>  3;
-                a22 = a14 << 39 | a14 >> 25;
-                a14 = a20 << 18 | a20 >> 46;
-                a20 = a02 << 62 | a02 >>  2;
-                a02 = a12 << 43 | a12 >> 21;
-                a12 = a13 << 25 | a13 >> 39;
-                a13 = a19 <<  8 | a19 >> 56;
-                a19 = a23 << 56 | a23 >>  8;
-                a23 = a15 << 41 | a15 >> 23;
-                a15 = a04 << 27 | a04 >> 37;
-                a04 = a24 << 14 | a24 >> 50;
-                a24 = a21 <<  2 | a21 >> 62;
-                a21 = a08 << 55 | a08 >>  9;
-                a08 = a16 << 45 | a16 >> 19;
-                a16 = a05 << 36 | a05 >> 28;
-                a05 = a03 << 28 | a03 >> 36;
-                a03 = a18 << 21 | a18 >> 43;
-                a18 = a17 << 15 | a17 >> 49;
-                a17 = a11 << 10 | a11 >> 54;
-                a11 = a07 <<  6 | a07 >> 58;
-                a07 = a10 <<  3 | a10 >> 61;
+                c1  = Longs.RotateLeft(a01,  1);
+                a01 = Longs.RotateLeft(a06, 44);
+                a06 = Longs.RotateLeft(a09, 20);
+                a09 = Longs.RotateLeft(a22, 61);
+                a22 = Longs.RotateLeft(a14, 39);
+                a14 = Longs.RotateLeft(a20, 18);
+                a20 = Longs.RotateLeft(a02, 62);
+                a02 = Longs.RotateLeft(a12, 43);
+                a12 = Longs.RotateLeft(a13, 25);
+                a13 = Longs.RotateLeft(a19,  8);
+                a19 = Longs.RotateLeft(a23, 56);
+                a23 = Longs.RotateLeft(a15, 41);
+                a15 = Longs.RotateLeft(a04, 27);
+                a04 = Longs.RotateLeft(a24, 14);
+                a24 = Longs.RotateLeft(a21,  2);
+                a21 = Longs.RotateLeft(a08, 55);
+                a08 = Longs.RotateLeft(a16, 45);
+                a16 = Longs.RotateLeft(a05, 36);
+                a05 = Longs.RotateLeft(a03, 28);
+                a03 = Longs.RotateLeft(a18, 21);
+                a18 = Longs.RotateLeft(a17, 15);
+                a17 = Longs.RotateLeft(a11, 10);
+                a11 = Longs.RotateLeft(a07,  6);
+                a07 = Longs.RotateLeft(a10,  3);
                 a10 = c1;
 
                 // chi
diff --git a/crypto/src/crypto/encodings/OaepEncoding.cs b/crypto/src/crypto/encodings/OaepEncoding.cs
index c151b7ac5..6871a039a 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 = new SecureRandom();
+                this.random = CryptoServicesRegistrar.GetSecureRandom();
             }
 
             engine.Init(forEncryption, parameters);
diff --git a/crypto/src/crypto/encodings/Pkcs1Encoding.cs b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
index 5faf7f385..06e59d4f3 100644
--- a/crypto/src/crypto/encodings/Pkcs1Encoding.cs
+++ b/crypto/src/crypto/encodings/Pkcs1Encoding.cs
@@ -110,7 +110,7 @@ namespace Org.BouncyCastle.Crypto.Encodings
             }
             else
             {
-                this.random = new SecureRandom();
+                this.random = CryptoServicesRegistrar.GetSecureRandom();
                 kParam = (AsymmetricKeyParameter)parameters;
             }
 
diff --git a/crypto/src/crypto/engines/AesEngine_X86.cs b/crypto/src/crypto/engines/AesEngine_X86.cs
index 32a58f2e3..e61deb174 100644
--- a/crypto/src/crypto/engines/AesEngine_X86.cs
+++ b/crypto/src/crypto/engines/AesEngine_X86.cs
@@ -1,6 +1,8 @@
 #if NETCOREAPP3_0_OR_GREATER
 using System;
+using System.Buffers.Binary;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Runtime.Intrinsics;
 
 using Org.BouncyCastle.Crypto.Parameters;
@@ -16,7 +18,6 @@ namespace Org.BouncyCastle.Crypto.Engines
     {
         public static bool IsSupported => Aes.IsSupported;
 
-        [MethodImpl(MethodImplOptions.AggressiveOptimization)]
         private static Vector128<byte>[] CreateRoundKeys(byte[] key, bool forEncryption)
         {
             Vector128<byte>[] K;
@@ -217,7 +218,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             return 64;
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private void ImplRounds(ref Vector128<byte> state)
         {
             switch (m_mode)
@@ -232,7 +233,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private void ImplRounds(
             ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
         {
@@ -248,7 +249,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             }
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void Decrypt128(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
         {
             state = Sse2.Xor(state, roundKeys[0]);
@@ -264,7 +265,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             state = Aes.DecryptLast(state, roundKeys[10]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void Decrypt192(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
         {
             state = Sse2.Xor(state, roundKeys[0]);
@@ -282,7 +283,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             state = Aes.DecryptLast(state, roundKeys[12]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void Decrypt256(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
         {
             state = Sse2.Xor(state, roundKeys[0]);
@@ -302,7 +303,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             state = Aes.DecryptLast(state, roundKeys[14]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void DecryptFour128(Vector128<byte>[] rk,
             ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
         {
@@ -362,7 +363,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             s4 = Aes.DecryptLast(s4, rk[10]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void DecryptFour192(Vector128<byte>[] rk,
             ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
         {
@@ -432,7 +433,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             s4 = Aes.DecryptLast(s4, rk[12]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void DecryptFour256(Vector128<byte>[] rk,
             ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
         {
@@ -512,7 +513,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             s4 = Aes.DecryptLast(s4, rk[14]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void Encrypt128(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
         {
             state = Sse2.Xor(state, roundKeys[0]);
@@ -528,7 +529,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             state = Aes.EncryptLast(state, roundKeys[10]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void Encrypt192(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
         {
             state = Sse2.Xor(state, roundKeys[0]);
@@ -546,7 +547,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             state = Aes.EncryptLast(state, roundKeys[12]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void Encrypt256(Vector128<byte>[] roundKeys, ref Vector128<byte> state)
         {
             state = Sse2.Xor(state, roundKeys[0]);
@@ -566,7 +567,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             state = Aes.EncryptLast(state, roundKeys[14]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void EncryptFour128(Vector128<byte>[] rk,
             ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
         {
@@ -626,7 +627,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             s4 = Aes.EncryptLast(s4, rk[10]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void EncryptFour192(Vector128<byte>[] rk,
             ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
         {
@@ -696,7 +697,7 @@ namespace Org.BouncyCastle.Crypto.Engines
             s4 = Aes.EncryptLast(s4, rk[12]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void EncryptFour256(Vector128<byte>[] rk,
             ref Vector128<byte> s1, ref Vector128<byte> s2, ref Vector128<byte> s3, ref Vector128<byte> s4)
         {
@@ -776,34 +777,38 @@ namespace Org.BouncyCastle.Crypto.Engines
             s4 = Aes.EncryptLast(s4, rk[14]);
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static Vector128<byte> Load128(ReadOnlySpan<byte> t)
         {
 #if NET7_0_OR_GREATER
             return Vector128.Create<byte>(t);
 #else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
-                return Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(t[0]));
+                return MemoryMarshal.Read<Vector128<byte>>(t);
 
-            return Vector128.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12],
-                t[13], t[14], t[15]);
+            return Vector128.Create(
+                BinaryPrimitives.ReadUInt64LittleEndian(t[..8]),
+                BinaryPrimitives.ReadUInt64LittleEndian(t[8..])
+            ).AsByte();
 #endif
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static Vector64<byte> Load64(ReadOnlySpan<byte> t)
         {
 #if NET7_0_OR_GREATER
             return Vector64.Create<byte>(t);
 #else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector64<byte>>() == 8)
-                return Unsafe.ReadUnaligned<Vector64<byte>>(ref Unsafe.AsRef(t[0]));
+                return MemoryMarshal.Read<Vector64<byte>>(t);
 
-            return Vector64.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7]);
+            return Vector64.Create(
+                BinaryPrimitives.ReadUInt64LittleEndian(t[..8])
+            ).AsByte();
 #endif
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveInlining | MethodImplOptions.AggressiveOptimization)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static void Store128(Vector128<byte> s, Span<byte> t)
         {
 #if NET7_0_OR_GREATER
@@ -811,13 +816,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 #else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
             {
-                Unsafe.WriteUnaligned(ref t[0], s);
+                MemoryMarshal.Write(t, ref s);
                 return;
             }
 
             var u = s.AsUInt64();
-            Utilities.Pack.UInt64_To_LE(u.GetElement(0), t);
-            Utilities.Pack.UInt64_To_LE(u.GetElement(1), t[8..]);
+            BinaryPrimitives.WriteUInt64LittleEndian(t[..8], u.GetElement(0));
+            BinaryPrimitives.WriteUInt64LittleEndian(t[8..], u.GetElement(1));
 #endif
         }
     }
diff --git a/crypto/src/crypto/engines/ChaCha7539Engine.cs b/crypto/src/crypto/engines/ChaCha7539Engine.cs
index f6e34b93a..d9cdac541 100644
--- a/crypto/src/crypto/engines/ChaCha7539Engine.cs
+++ b/crypto/src/crypto/engines/ChaCha7539Engine.cs
@@ -4,6 +4,8 @@ using System.Diagnostics;
 using System.Runtime.CompilerServices;
 #endif
 #if NETCOREAPP3_0_OR_GREATER
+using System.Buffers.Binary;
+using System.Runtime.InteropServices;
 using System.Runtime.Intrinsics;
 using System.Runtime.Intrinsics.X86;
 #endif
@@ -453,18 +455,20 @@ namespace Org.BouncyCastle.Crypto.Engines
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
 		private static Vector128<byte> Load128_Byte(ReadOnlySpan<byte> t)
 		{
-			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
-				return Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(t[0]));
+            if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
+                return MemoryMarshal.Read<Vector128<byte>>(t);
 
-			return Vector128.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12],
-				t[13], t[14], t[15]);
-		}
+            return Vector128.Create(
+                BinaryPrimitives.ReadUInt64LittleEndian(t[..8]),
+                BinaryPrimitives.ReadUInt64LittleEndian(t[8..])
+            ).AsByte();
+        }
 
-		[MethodImpl(MethodImplOptions.AggressiveInlining)]
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
 		private static Vector128<uint> Load128_UInt32(ReadOnlySpan<uint> t)
 		{
 			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<uint>>() == 16)
-				return Unsafe.ReadUnaligned<Vector128<uint>>(ref Unsafe.As<uint, byte>(ref Unsafe.AsRef(t[0])));
+                return MemoryMarshal.Read<Vector128<uint>>(MemoryMarshal.AsBytes(t));
 
 			return Vector128.Create(t[0], t[1], t[2], t[3]);
 		}
@@ -472,42 +476,45 @@ namespace Org.BouncyCastle.Crypto.Engines
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
 		private static Vector256<byte> Load256_Byte(ReadOnlySpan<byte> t)
         {
-			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector256<byte>>() == 32)
-				return Unsafe.ReadUnaligned<Vector256<byte>>(ref Unsafe.AsRef(t[0]));
-
-			return Vector256.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12],
-				t[13], t[14], t[15], t[16], t[17], t[18], t[19], t[20], t[21], t[22], t[23], t[24], t[25], t[26], t[27],
-				t[28], t[29], t[30], t[31]);
+            if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector256<byte>>() == 32)
+                return MemoryMarshal.Read<Vector256<byte>>(t);
+
+            return Vector256.Create(
+                BinaryPrimitives.ReadUInt64LittleEndian(t[ 0.. 8]),
+                BinaryPrimitives.ReadUInt64LittleEndian(t[ 8..16]),
+                BinaryPrimitives.ReadUInt64LittleEndian(t[16..24]),
+                BinaryPrimitives.ReadUInt64LittleEndian(t[24..32])
+            ).AsByte();
 		}
 
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
 		private static void Store128_Byte(Vector128<byte> s, Span<byte> t)
 		{
-			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
-			{
-				Unsafe.WriteUnaligned(ref t[0], s);
-				return;
-			}
+            if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
+            {
+                MemoryMarshal.Write(t, ref s);
+                return;
+            }
 
-			var u = s.AsUInt64();
-			Pack.UInt64_To_LE(u.GetElement(0), t);
-			Pack.UInt64_To_LE(u.GetElement(1), t[8..]);
+            var u = s.AsUInt64();
+            BinaryPrimitives.WriteUInt64LittleEndian(t[..8], u.GetElement(0));
+            BinaryPrimitives.WriteUInt64LittleEndian(t[8..], u.GetElement(1));
 		}
 
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
 		private static void Store256_Byte(Vector256<byte> s, Span<byte> t)
 		{
-			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector256<byte>>() == 32)
+            if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector256<byte>>() == 32)
 			{
-				Unsafe.WriteUnaligned(ref t[0], s);
+                MemoryMarshal.Write(t, ref s);
 				return;
 			}
 
 			var u = s.AsUInt64();
-			Pack.UInt64_To_LE(u.GetElement(0), t);
-			Pack.UInt64_To_LE(u.GetElement(1), t[8..]);
-			Pack.UInt64_To_LE(u.GetElement(2), t[16..]);
-			Pack.UInt64_To_LE(u.GetElement(3), t[24..]);
+            BinaryPrimitives.WriteUInt64LittleEndian(t[ 0.. 8], u.GetElement(0));
+            BinaryPrimitives.WriteUInt64LittleEndian(t[ 8..16], u.GetElement(1));
+            BinaryPrimitives.WriteUInt64LittleEndian(t[16..24], u.GetElement(2));
+            BinaryPrimitives.WriteUInt64LittleEndian(t[24..32], u.GetElement(3));
 		}
 #endif
 	}
diff --git a/crypto/src/crypto/engines/ChaChaEngine.cs b/crypto/src/crypto/engines/ChaChaEngine.cs
index 2683e335a..093e1a250 100644
--- a/crypto/src/crypto/engines/ChaChaEngine.cs
+++ b/crypto/src/crypto/engines/ChaChaEngine.cs
@@ -1,7 +1,9 @@
 using System;
 using System.Diagnostics;
 #if NETCOREAPP3_0_OR_GREATER
+using System.Buffers.Binary;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Runtime.Intrinsics;
 using System.Runtime.Intrinsics.X86;
 #endif
@@ -215,10 +217,10 @@ namespace Org.BouncyCastle.Crypto.Engines
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
 		private static Vector128<uint> Load128_UInt32(ReadOnlySpan<uint> t)
 		{
-			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<uint>>() == 16)
-				return Unsafe.ReadUnaligned<Vector128<uint>>(ref Unsafe.As<uint, byte>(ref Unsafe.AsRef(t[0])));
+            if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<uint>>() == 16)
+                return MemoryMarshal.Read<Vector128<uint>>(MemoryMarshal.AsBytes(t));
 
-			return Vector128.Create(t[0], t[1], t[2], t[3]);
+            return Vector128.Create(t[0], t[1], t[2], t[3]);
 		}
 
 		[MethodImpl(MethodImplOptions.AggressiveInlining)]
@@ -226,13 +228,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 		{
 			if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<uint>>() == 16)
 			{
-				Unsafe.WriteUnaligned(ref t[0], s);
+				MemoryMarshal.Write(t, ref s);
 				return;
 			}
 
 			var u = s.AsUInt64();
-			Pack.UInt64_To_LE(u.GetElement(0), t);
-			Pack.UInt64_To_LE(u.GetElement(1), t[8..]);
+            BinaryPrimitives.WriteUInt64LittleEndian(t[..8], u.GetElement(0));
+            BinaryPrimitives.WriteUInt64LittleEndian(t[8..], u.GetElement(1));
 		}
 #endif
 	}
diff --git a/crypto/src/crypto/engines/DesEdeWrapEngine.cs b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
index 43100a9bd..e05f9f555 100644
--- a/crypto/src/crypto/engines/DesEdeWrapEngine.cs
+++ b/crypto/src/crypto/engines/DesEdeWrapEngine.cs
@@ -60,15 +60,14 @@ namespace Org.BouncyCastle.Crypto.Engines
             this.engine = new CbcBlockCipher(new DesEdeEngine());
 
 			SecureRandom sr;
-			if (parameters is ParametersWithRandom)
+			if (parameters is ParametersWithRandom pr)
 			{
-				ParametersWithRandom pr = (ParametersWithRandom) parameters;
 				parameters = pr.Parameters;
 				sr = pr.Random;
 			}
 			else
 			{
-				sr = new SecureRandom();
+				sr = CryptoServicesRegistrar.GetSecureRandom();
 			}
 
 			if (parameters is KeyParameter)
diff --git a/crypto/src/crypto/engines/ElGamalEngine.cs b/crypto/src/crypto/engines/ElGamalEngine.cs
index 197d7bc15..ea5e5bc30 100644
--- a/crypto/src/crypto/engines/ElGamalEngine.cs
+++ b/crypto/src/crypto/engines/ElGamalEngine.cs
@@ -28,22 +28,18 @@ namespace Org.BouncyCastle.Crypto.Engines
 		* @param forEncryption true if we are encrypting, false otherwise.
 		* @param param the necessary ElGamal key parameters.
 		*/
-        public virtual void Init(
-			bool				forEncryption,
-			ICipherParameters	parameters)
+        public virtual void Init(bool forEncryption, ICipherParameters parameters)
 		{
-			if (parameters is ParametersWithRandom)
+			if (parameters is ParametersWithRandom withRandom)
 			{
-				ParametersWithRandom p = (ParametersWithRandom) parameters;
-
-				this.key = (ElGamalKeyParameters) p.Parameters;
-				this.random = p.Random;
+				this.key = (ElGamalKeyParameters)withRandom.Parameters;
+				this.random = withRandom.Random;
 			}
 			else
 			{
-				this.key = (ElGamalKeyParameters) parameters;
-				this.random = new SecureRandom();
-			}
+				this.key = (ElGamalKeyParameters)parameters;
+				this.random = CryptoServicesRegistrar.GetSecureRandom();
+            }
 
 			this.forEncryption = forEncryption;
 			this.bitSize = key.Parameters.P.BitLength;
@@ -51,16 +47,12 @@ namespace Org.BouncyCastle.Crypto.Engines
 			if (forEncryption)
 			{
 				if (!(key is ElGamalPublicKeyParameters))
-				{
 					throw new ArgumentException("ElGamalPublicKeyParameters are required for encryption.");
-				}
 			}
 			else
 			{
 				if (!(key is ElGamalPrivateKeyParameters))
-				{
 					throw new ArgumentException("ElGamalPrivateKeyParameters are required for decryption.");
-				}
 			}
 		}
 
diff --git a/crypto/src/crypto/engines/RC2WrapEngine.cs b/crypto/src/crypto/engines/RC2WrapEngine.cs
index 5742aa8b7..91ac7ded2 100644
--- a/crypto/src/crypto/engines/RC2WrapEngine.cs
+++ b/crypto/src/crypto/engines/RC2WrapEngine.cs
@@ -42,8 +42,8 @@ namespace Org.BouncyCastle.Crypto.Engines
 		//
 		// checksum digest
 		//
-		IDigest sha1 = new Sha1Digest();
-		byte[] digest = new byte[20];
+		private readonly IDigest sha1 = new Sha1Digest();
+		private readonly byte[] digest = new byte[20];
 
 		/**
 			* Method init
@@ -51,22 +51,19 @@ 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 RC2Engine());
 
-			if (parameters is ParametersWithRandom)
+			if (parameters is ParametersWithRandom pWithR)
 			{
-				ParametersWithRandom pWithR = (ParametersWithRandom)parameters;
 				sr = pWithR.Random;
 				parameters = pWithR.Parameters;
 			}
 			else
 			{
-				sr = new SecureRandom();
+				sr = CryptoServicesRegistrar.GetSecureRandom();
 			}
 
 			if (parameters is ParametersWithIV)
diff --git a/crypto/src/crypto/engines/RFC3211WrapEngine.cs b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
index 3fc7b3191..42027cf25 100644
--- a/crypto/src/crypto/engines/RFC3211WrapEngine.cs
+++ b/crypto/src/crypto/engines/RFC3211WrapEngine.cs
@@ -24,24 +24,20 @@ namespace Org.BouncyCastle.Crypto.Engines
 			this.engine = new CbcBlockCipher(engine);
 		}
 
-        public virtual void Init(
-			bool				forWrapping,
-			ICipherParameters	param)
+        public virtual void Init(bool forWrapping, ICipherParameters param)
 		{
 			this.forWrapping = forWrapping;
 
-			if (param is ParametersWithRandom)
+			if (param is ParametersWithRandom withRandom)
 			{
-				ParametersWithRandom p = (ParametersWithRandom)param;
-
-                this.rand = p.Random;
-                this.param = p.Parameters as ParametersWithIV;
+                this.rand = withRandom.Random;
+                this.param = withRandom.Parameters as ParametersWithIV;
 			}
 			else
 			{
 				if (forWrapping)
 				{
-					rand = new SecureRandom();
+					rand = CryptoServicesRegistrar.GetSecureRandom();
 				}
 
                 this.param = param as ParametersWithIV;
diff --git a/crypto/src/crypto/engines/RSABlindedEngine.cs b/crypto/src/crypto/engines/RSABlindedEngine.cs
index 637bf3cc0..cdc0a7844 100644
--- a/crypto/src/crypto/engines/RSABlindedEngine.cs
+++ b/crypto/src/crypto/engines/RSABlindedEngine.cs
@@ -39,16 +39,12 @@ namespace Org.BouncyCastle.Crypto.Engines
          * @param forEncryption true if we are encrypting, false otherwise.
          * @param param the necessary RSA key parameters.
          */
-        public virtual void Init(
-            bool forEncryption,
-            ICipherParameters param)
+        public virtual void Init(bool forEncryption, ICipherParameters param)
         {
             core.Init(forEncryption, param);
 
-            if (param is ParametersWithRandom)
+            if (param is ParametersWithRandom rParam)
             {
-                ParametersWithRandom rParam = (ParametersWithRandom)param;
-
                 this.key = (RsaKeyParameters)rParam.Parameters;
 
                 if (key is RsaPrivateCrtKeyParameters)
@@ -66,7 +62,7 @@ namespace Org.BouncyCastle.Crypto.Engines
 
                 if (key is RsaPrivateCrtKeyParameters)
                 {
-                    this.random = new SecureRandom();
+                    this.random = CryptoServicesRegistrar.GetSecureRandom();
                 }
                 else
                 {
diff --git a/crypto/src/crypto/engines/Salsa20Engine.cs b/crypto/src/crypto/engines/Salsa20Engine.cs
index c3e44f645..1ccf68902 100644
--- a/crypto/src/crypto/engines/Salsa20Engine.cs
+++ b/crypto/src/crypto/engines/Salsa20Engine.cs
@@ -1,5 +1,12 @@
 using System;
-using System.Text;
+#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER
+using System.Runtime.CompilerServices;
+#endif
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
@@ -254,7 +261,71 @@ namespace Org.BouncyCastle.Crypto.Engines
 			if (rounds % 2 != 0)
 				throw new ArgumentException("Number of rounds must be even");
 
-            uint x00 = input[ 0];
+#if NETCOREAPP3_0_OR_GREATER
+            if (Sse41.IsSupported && BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<short>>() == 16)
+			{
+				Vector128<uint> b0, b1, b2, b3;
+				{
+                    var I = MemoryMarshal.AsBytes(input.AsSpan(0, 16));
+					var t0 = MemoryMarshal.Read<Vector128<short>>(I[0x00..0x10]);
+                    var t1 = MemoryMarshal.Read<Vector128<short>>(I[0x10..0x20]);
+                    var t2 = MemoryMarshal.Read<Vector128<short>>(I[0x20..0x30]);
+                    var t3 = MemoryMarshal.Read<Vector128<short>>(I[0x30..0x40]);
+
+                    var u0 = Sse41.Blend(t0, t2, 0xF0);
+					var u1 = Sse41.Blend(t1, t3, 0xC3);
+					var u2 = Sse41.Blend(t0, t2, 0x0F);
+					var u3 = Sse41.Blend(t1, t3, 0x3C);
+
+					b0 = Sse41.Blend(u0, u1, 0xCC).AsUInt32();
+					b1 = Sse41.Blend(u0, u1, 0x33).AsUInt32();
+					b2 = Sse41.Blend(u2, u3, 0xCC).AsUInt32();
+					b3 = Sse41.Blend(u2, u3, 0x33).AsUInt32();
+				}
+
+                var c0 = b0;
+                var c1 = b1;
+                var c2 = b2;
+                var c3 = b3;
+
+                for (int i = rounds; i > 0; i -= 2)
+				{
+                    QuarterRound_Sse2(ref c0, ref c3, ref c2, ref c1);
+                    QuarterRound_Sse2(ref c0, ref c1, ref c2, ref c3);
+                }
+
+                b0 = Sse2.Add(b0, c0);
+                b1 = Sse2.Add(b1, c1);
+                b2 = Sse2.Add(b2, c2);
+                b3 = Sse2.Add(b3, c3);
+
+                {
+					var t0 = b0.AsUInt16();
+                    var t1 = b1.AsUInt16();
+                    var t2 = b2.AsUInt16();
+                    var t3 = b3.AsUInt16();
+
+					var u0 = Sse41.Blend(t0, t1, 0xCC);
+					var u1 = Sse41.Blend(t0, t1, 0x33);
+					var u2 = Sse41.Blend(t2, t3, 0xCC);
+					var u3 = Sse41.Blend(t2, t3, 0x33);
+
+					var v0 = Sse41.Blend(u0, u2, 0xF0);
+                    var v1 = Sse41.Blend(u1, u3, 0xC3);
+                    var v2 = Sse41.Blend(u0, u2, 0x0F);
+                    var v3 = Sse41.Blend(u1, u3, 0x3C);
+
+                    var X = MemoryMarshal.AsBytes(x.AsSpan(0, 16));
+                    MemoryMarshal.Write(X[0x00..0x10], ref v0);
+                    MemoryMarshal.Write(X[0x10..0x20], ref v1);
+                    MemoryMarshal.Write(X[0x20..0x30], ref v2);
+                    MemoryMarshal.Write(X[0x30..0x40], ref v3);
+                }
+                return;
+			}
+#endif
+
+			uint x00 = input[ 0];
 			uint x01 = input[ 1];
 			uint x02 = input[ 2];
 			uint x03 = input[ 3];
@@ -273,39 +344,15 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 			for (int i = rounds; i > 0; i -= 2)
 			{
-				x04 ^= Integers.RotateLeft((x00+x12), 7);
-				x08 ^= Integers.RotateLeft((x04+x00), 9);
-				x12 ^= Integers.RotateLeft((x08+x04),13);
-				x00 ^= Integers.RotateLeft((x12+x08),18);
-				x09 ^= Integers.RotateLeft((x05+x01), 7);
-				x13 ^= Integers.RotateLeft((x09+x05), 9);
-				x01 ^= Integers.RotateLeft((x13+x09),13);
-				x05 ^= Integers.RotateLeft((x01+x13),18);
-				x14 ^= Integers.RotateLeft((x10+x06), 7);
-				x02 ^= Integers.RotateLeft((x14+x10), 9);
-				x06 ^= Integers.RotateLeft((x02+x14),13);
-				x10 ^= Integers.RotateLeft((x06+x02),18);
-				x03 ^= Integers.RotateLeft((x15+x11), 7);
-				x07 ^= Integers.RotateLeft((x03+x15), 9);
-				x11 ^= Integers.RotateLeft((x07+x03),13);
-				x15 ^= Integers.RotateLeft((x11+x07),18);
-
-				x01 ^= Integers.RotateLeft((x00+x03), 7);
-				x02 ^= Integers.RotateLeft((x01+x00), 9);
-				x03 ^= Integers.RotateLeft((x02+x01),13);
-				x00 ^= Integers.RotateLeft((x03+x02),18);
-				x06 ^= Integers.RotateLeft((x05+x04), 7);
-				x07 ^= Integers.RotateLeft((x06+x05), 9);
-				x04 ^= Integers.RotateLeft((x07+x06),13);
-				x05 ^= Integers.RotateLeft((x04+x07),18);
-				x11 ^= Integers.RotateLeft((x10+x09), 7);
-				x08 ^= Integers.RotateLeft((x11+x10), 9);
-				x09 ^= Integers.RotateLeft((x08+x11),13);
-				x10 ^= Integers.RotateLeft((x09+x08),18);
-				x12 ^= Integers.RotateLeft((x15+x14), 7);
-				x13 ^= Integers.RotateLeft((x12+x15), 9);
-				x14 ^= Integers.RotateLeft((x13+x12),13);
-				x15 ^= Integers.RotateLeft((x14+x13),18);
+				QuarterRound(ref x00, ref x04, ref x08, ref x12);
+                QuarterRound(ref x05, ref x09, ref x13, ref x01);
+                QuarterRound(ref x10, ref x14, ref x02, ref x06);
+                QuarterRound(ref x15, ref x03, ref x07, ref x11);
+
+                QuarterRound(ref x00, ref x01, ref x02, ref x03);
+                QuarterRound(ref x05, ref x06, ref x07, ref x04);
+                QuarterRound(ref x10, ref x11, ref x08, ref x09);
+                QuarterRound(ref x15, ref x12, ref x13, ref x14);
 			}
 
 			x[ 0] = x00 + input[ 0];
@@ -364,5 +411,39 @@ namespace Org.BouncyCastle.Crypto.Engines
 
 			return false;
 		}
-	}
+
+#if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+#endif
+        private static void QuarterRound(ref uint a, ref uint b, ref uint c, ref uint d)
+		{
+            b ^= Integers.RotateLeft(a + d,  7);
+            c ^= Integers.RotateLeft(b + a,  9);
+            d ^= Integers.RotateLeft(c + b, 13);
+            a ^= Integers.RotateLeft(d + c, 18);
+        }
+
+#if NETCOREAPP3_0_OR_GREATER
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static void QuarterRound_Sse2(ref Vector128<uint> a, ref Vector128<uint> b, ref Vector128<uint> c,
+			ref Vector128<uint> d)
+        {
+			b = Sse2.Xor(b, Rotate_Sse2(Sse2.Add(a, d), 7));
+			c = Sse2.Xor(c, Rotate_Sse2(Sse2.Add(b, a), 9));
+			d = Sse2.Xor(d, Rotate_Sse2(Sse2.Add(c, b), 13));
+			a = Sse2.Xor(a, Rotate_Sse2(Sse2.Add(d, c), 18));
+
+            b = Sse2.Shuffle(b, 0x93);
+			c = Sse2.Shuffle(c, 0x4E);
+			d = Sse2.Shuffle(d, 0x39);
+		}
+
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static Vector128<uint> Rotate_Sse2(Vector128<uint> x, byte sl)
+        {
+			byte sr = (byte)(32 - sl);
+            return Sse2.Xor(Sse2.ShiftLeftLogical(x, sl), Sse2.ShiftRightLogical(x, sr));
+        }
+#endif
+    }
 }
diff --git a/crypto/src/crypto/engines/VMPCEngine.cs b/crypto/src/crypto/engines/VMPCEngine.cs
index d8974b6ce..f34259248 100644
--- a/crypto/src/crypto/engines/VMPCEngine.cs
+++ b/crypto/src/crypto/engines/VMPCEngine.cs
@@ -97,16 +97,17 @@ namespace Org.BouncyCastle.Crypto.Engines
 
             for (int i = 0; i < len; i++)
             {
-                s = P[(s + P[n & 0xff]) & 0xff];
-                byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+                byte pn = P[n];
+                s = P[(s + pn) & 0xff];
+                byte ps = P[s];
+                byte z = P[(P[ps] + 1) & 0xff];
                 // encryption
-                byte temp = P[n & 0xff];
-                P[n & 0xff] = P[s & 0xff];
-                P[s & 0xff] = temp;
-                n = (byte) ((n + 1) & 0xff);
+                P[n] = ps;
+                P[s] = pn;
+                n = (byte)(n + 1);
 
                 // xor
-                output[i + outOff] = (byte) (input[i + inOff] ^ z);
+                output[i + outOff] = (byte)(input[i + inOff] ^ z);
             }
         }
 
@@ -117,13 +118,14 @@ namespace Org.BouncyCastle.Crypto.Engines
 
             for (int i = 0; i < input.Length; i++)
             {
-                s = P[(s + P[n & 0xff]) & 0xff];
-                byte z = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
+                byte pn = P[n];
+                s = P[(s + pn) & 0xff];
+                byte ps = P[s];
+                byte z = P[(P[ps] + 1) & 0xff];
                 // encryption
-                byte temp = P[n & 0xff];
-                P[n & 0xff] = P[s & 0xff];
-                P[s & 0xff] = temp;
-                n = (byte)((n + 1) & 0xff);
+                P[n] = ps;
+                P[s] = pn;
+                n = (byte)(n + 1);
 
                 // xor
                 output[i] = (byte)(input[i] ^ z);
diff --git a/crypto/src/crypto/fpe/SP80038G.cs b/crypto/src/crypto/fpe/SP80038G.cs
index 53efc1499..a9dc7f144 100644
--- a/crypto/src/crypto/fpe/SP80038G.cs
+++ b/crypto/src/crypto/fpe/SP80038G.cs
@@ -301,14 +301,13 @@ namespace Org.BouncyCastle.Crypto.Fpe
             int t = T.Length;
 
             // i.
-            BigInteger numAB = num(bigRadix, AB);
-            byte[] bytesAB = BigIntegers.AsUnsignedByteArray(numAB);
-
             int zeroes = -(t + b + 1) & 15;
             byte[] Q = new byte[t + zeroes + 1 + b];
             Array.Copy(T, 0, Q, 0, t);
             Q[t + zeroes] = (byte)round;
-            Array.Copy(bytesAB, 0, Q, Q.Length - bytesAB.Length, bytesAB.Length);
+
+            BigInteger numAB = num(bigRadix, AB);
+            BigIntegers.AsUnsignedByteArray(numAB, Q, Q.Length - b, b);
 
             // ii.
             byte[] R = prf(cipher, Arrays.Concatenate(P, Q));
@@ -319,47 +318,43 @@ namespace Org.BouncyCastle.Crypto.Fpe
             {
                 int sBlocksLen = (d + BLOCK_SIZE - 1) / BLOCK_SIZE;
                 sBlocks = new byte[sBlocksLen * BLOCK_SIZE];
+
+                uint j0 = Pack.BE_To_UInt32(R, BLOCK_SIZE - 4);
                 Array.Copy(R, 0, sBlocks, 0, BLOCK_SIZE);
 
-                byte[] uint32 = new byte[4];
                 for (uint j = 1; j < sBlocksLen; ++j)
                 {
                     int sOff = (int)(j * BLOCK_SIZE);
-                    Array.Copy(R, 0, sBlocks, sOff, BLOCK_SIZE);
-                    Pack.UInt32_To_BE(j, uint32, 0);
-                    xor(uint32, 0, sBlocks, sOff + BLOCK_SIZE - 4, 4);
+
+                    Array.Copy(R, 0, sBlocks, sOff, BLOCK_SIZE - 4);
+                    Pack.UInt32_To_BE(j0 ^ j, sBlocks, sOff + BLOCK_SIZE - 4);
+
                     cipher.ProcessBlock(sBlocks, sOff, sBlocks, sOff);
                 }
             }
 
             // iv.
-            return num(sBlocks, 0, d);
+            return new BigInteger(1, sBlocks, 0, d);
         }
 
-        protected static BigInteger calculateY_FF3(IBlockCipher cipher, BigInteger bigRadix, byte[] T, int wOff, uint round, ushort[] AB)
+        protected static BigInteger calculateY_FF3(IBlockCipher cipher, BigInteger bigRadix, byte[] T, int wOff,
+            uint round, ushort[] AB)
         {
             // ii.
             byte[] P = new byte[BLOCK_SIZE];
-            Pack.UInt32_To_BE(round, P, 0);
-            xor(T, wOff, P, 0, 4);
-            BigInteger numAB = num(bigRadix, AB);
-
-            byte[] bytesAB = BigIntegers.AsUnsignedByteArray(numAB);
+            Pack.UInt32_To_BE(Pack.BE_To_UInt32(T, wOff) ^ round, P, 0);
 
-            if ((P.Length - bytesAB.Length) < 4)  // to be sure...
-            {
-                throw new InvalidOperationException("input out of range");
-            }
-            Array.Copy(bytesAB, 0, P, P.Length - bytesAB.Length, bytesAB.Length);
+            BigInteger numAB = num(bigRadix, AB);
+            BigIntegers.AsUnsignedByteArray(numAB, P, 4, BLOCK_SIZE - 4);
 
             // iii.
-            rev(P);
+            Array.Reverse(P);
             cipher.ProcessBlock(P, 0, P, 0);
-            rev(P);
+            Array.Reverse(P);
             byte[] S = P;
 
             // iv.
-            return num(S, 0, S.Length);
+            return new BigInteger(1, S);
         }
 
         protected static void checkArgs(IBlockCipher cipher, bool isFF1, int radix, ushort[] buf, int off, int len)
@@ -471,8 +466,8 @@ namespace Org.BouncyCastle.Crypto.Fpe
             int m = u;
 
             // Note we keep A, B in reverse order throughout
-            rev(A);
-            rev(B);
+            Array.Reverse(A);
+            Array.Reverse(B);
 
             for (int i = 7; i >= 0; --i)
             {
@@ -494,8 +489,8 @@ namespace Org.BouncyCastle.Crypto.Fpe
                 str(bigRadix, c, m, C, 0);
             }
 
-            rev(A);
-            rev(B);
+            Array.Reverse(A);
+            Array.Reverse(B);
 
             return Arrays.Concatenate(A, B);
         }
@@ -539,8 +534,8 @@ namespace Org.BouncyCastle.Crypto.Fpe
             int m = v;
 
             // Note we keep A, B in reverse order throughout
-            rev(a);
-            rev(b);
+            Array.Reverse(a);
+            Array.Reverse(b);
 
             for (uint i = 0; i < 8; ++i)
             {
@@ -562,17 +557,12 @@ namespace Org.BouncyCastle.Crypto.Fpe
                 str(bigRadix, c, m, C, 0);
             }
 
-            rev(a);
-            rev(b);
+            Array.Reverse(a);
+            Array.Reverse(b);
 
             return Arrays.Concatenate(a, b);
         }
 
-        protected static BigInteger num(byte[] buf, int off, int len)
-        {
-            return new BigInteger(1, Arrays.CopyOfRange(buf, off, off + len));
-        }
-
         protected static BigInteger num(BigInteger R, ushort[] x)
         {
             BigInteger result = BigInteger.Zero;
@@ -586,9 +576,7 @@ namespace Org.BouncyCastle.Crypto.Fpe
         protected static byte[] prf(IBlockCipher c, byte[] x)
         {
             if ((x.Length % BLOCK_SIZE) != 0)
-            {
                 throw new ArgumentException();
-            }
 
             int m = x.Length / BLOCK_SIZE;
             byte[] y = new byte[BLOCK_SIZE];
@@ -602,42 +590,11 @@ namespace Org.BouncyCastle.Crypto.Fpe
             return y;
         }
 
-        //    protected static void rev(byte[] x, int xOff, byte[] y, int yOff, int len)
-        //    {
-        //        for (int i = 1; i <= len; ++i)
-        //        {
-        //            y[yOff + len - i] = x[xOff + i - 1];
-        //        }
-        //    }
-
-        protected static void rev(byte[] x)
-        {
-            int half = x.Length / 2, end = x.Length - 1;
-            for (int i = 0; i < half; ++i)
-            {
-                byte tmp = x[i];
-                x[i] = x[end - i];
-                x[end - i] = tmp;
-            }
-        }
-
-        protected static void rev(ushort[] x)
-        {
-            int half = x.Length / 2, end = x.Length - 1;
-            for (int i = 0; i < half; ++i)
-            {
-                ushort tmp = x[i];
-                x[i] = x[end - i];
-                x[end - i] = tmp;
-            }
-        }
-
         protected static void str(BigInteger R, BigInteger x, int m, ushort[] output, int off)
         {
             if (x.SignValue < 0)
-            {
                 throw new ArgumentException();
-            }
+
             for (int i = 1; i <= m; ++i)
             {
                 BigInteger[] qr = x.DivideAndRemainder(R);
@@ -645,9 +602,7 @@ namespace Org.BouncyCastle.Crypto.Fpe
                 x = qr[0];
             }
             if (x.SignValue != 0)
-            {
                 throw new ArgumentException();
-            }
         }
 
         protected static void xor(byte[] x, int xOff, byte[] y, int yOff, int len)
diff --git a/crypto/src/crypto/generators/ECKeyPairGenerator.cs b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
index 7b6ee168b..6aba6921e 100644
--- a/crypto/src/crypto/generators/ECKeyPairGenerator.cs
+++ b/crypto/src/crypto/generators/ECKeyPairGenerator.cs
@@ -83,7 +83,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 
             if (this.random == null)
             {
-                this.random = new SecureRandom();
+                this.random = CryptoServicesRegistrar.GetSecureRandom();
             }
         }
 
diff --git a/crypto/src/crypto/generators/RSABlindingFactorGenerator.cs b/crypto/src/crypto/generators/RSABlindingFactorGenerator.cs
index e2f63face..a9eeb46df 100644
--- a/crypto/src/crypto/generators/RSABlindingFactorGenerator.cs
+++ b/crypto/src/crypto/generators/RSABlindingFactorGenerator.cs
@@ -21,20 +21,17 @@ namespace Org.BouncyCastle.Crypto.Generators
 		*
 		* @param param the necessary RSA key parameters.
 		*/
-		public void Init(
-			ICipherParameters param)
+		public void Init(ICipherParameters param)
 		{
-			if (param is ParametersWithRandom)
+			if (param is ParametersWithRandom rParam)
 			{
-				ParametersWithRandom rParam = (ParametersWithRandom)param;
-
 				key = (RsaKeyParameters)rParam.Parameters;
 				random = rParam.Random;
 			}
 			else
 			{
 				key = (RsaKeyParameters)param;
-				random = new SecureRandom();
+				random = CryptoServicesRegistrar.GetSecureRandom();
 			}
 
 			if (key.IsPrivate)
diff --git a/crypto/src/crypto/generators/SCrypt.cs b/crypto/src/crypto/generators/SCrypt.cs
index 0c51d89bc..1a8d4a003 100644
--- a/crypto/src/crypto/generators/SCrypt.cs
+++ b/crypto/src/crypto/generators/SCrypt.cs
@@ -5,6 +5,7 @@ using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Crypto.Engines;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Crypto.Utilities;
+using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Generators
@@ -143,8 +144,8 @@ namespace Org.BouncyCastle.Crypto.Generators
                     int j = (int)(X[BCount - 16] & mask);
                     uint[] V = VV[j >> chunkPow];
                     int VOff = (j & chunkMask) * BCount;
-                    Array.Copy(V, VOff, blockY, 0, BCount);
-                    Xor(blockY, X, 0, blockY);
+                    Nat.Xor(BCount, V, VOff, X, 0, blockY, 0);
+
                     BlockMix(blockY, blockX1, blockX2, X, r);
                 }
 
@@ -165,7 +166,7 @@ namespace Org.BouncyCastle.Crypto.Generators
 
 			for (int i = 2 * r; i > 0; --i)
 			{
-				Xor(X1, B, BOff, X2);
+                Nat512.Xor(X1, 0, B, BOff, X2, 0);
 
 				Salsa20Engine.SalsaCore(8, X2, X1);
 				Array.Copy(X1, 0, Y, YOff, 16);
@@ -175,14 +176,6 @@ namespace Org.BouncyCastle.Crypto.Generators
 			}
 		}
 
-		private static void Xor(uint[] a, uint[] b, int bOff, uint[] output)
-		{
-			for (int i = output.Length - 1; i >= 0; --i)
-			{
-				output[i] = a[i] ^ b[bOff + i];
-			}
-		}
-
 		private static void Clear(Array array)
 		{
 			if (array != null)
diff --git a/crypto/src/crypto/macs/Poly1305.cs b/crypto/src/crypto/macs/Poly1305.cs
index eb90e387e..d02216309 100644
--- a/crypto/src/crypto/macs/Poly1305.cs
+++ b/crypto/src/crypto/macs/Poly1305.cs
@@ -196,21 +196,13 @@ namespace Org.BouncyCastle.Crypto.Macs
             {
                 Array.Copy(input, inOff, currentBlock, currentBlockOffset, available);
                 pos = available;
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-                ProcessBlock(currentBlock);
-#else
                 ProcessBlock(currentBlock, 0);
-#endif
             }
 
             int remaining;
             while ((remaining = len - pos) >= BlockSize)
             {
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-                ProcessBlock(input.AsSpan(inOff + pos));
-#else
                 ProcessBlock(input, inOff + pos);
-#endif
                 pos += BlockSize;
             }
 
@@ -253,62 +245,24 @@ namespace Org.BouncyCastle.Crypto.Macs
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         private void ProcessBlock(ReadOnlySpan<byte> block)
         {
-#if NETCOREAPP3_0_OR_GREATER
-            if (BitConverter.IsLittleEndian)
-            {
-                Span<uint> t = stackalloc uint[4];
-                Unsafe.CopyBlockUnaligned(ref Unsafe.As<uint, byte>(ref t[0]), ref Unsafe.AsRef(block[0]), 16);
-
-                h0 +=   t[0]                        & 0x3ffffffU;
-                h1 += ((t[1] <<  6) | (t[0] >> 26)) & 0x3ffffffU;
-                h2 += ((t[2] << 12) | (t[1] >> 20)) & 0x3ffffffU;
-                h3 += ((t[3] << 18) | (t[2] >> 14)) & 0x3ffffffU;
-                h4 += (1 << 24) | (t[3] >> 8);
-            }
-            else
-#endif
-            {
-                uint t0 = Pack.LE_To_UInt32(block);
-                uint t1 = Pack.LE_To_UInt32(block[4..]);
-                uint t2 = Pack.LE_To_UInt32(block[8..]);
-                uint t3 = Pack.LE_To_UInt32(block[12..]);
-
-                h0 +=   t0                      & 0x3ffffffU;
-                h1 += ((t1 <<  6) | (t0 >> 26)) & 0x3ffffffU;
-                h2 += ((t2 << 12) | (t1 >> 20)) & 0x3ffffffU;
-                h3 += ((t3 << 18) | (t2 >> 14)) & 0x3ffffffU;
-                h4 +=  ( 1 << 24) | (t3 >>  8);
-            }
-
-            ulong tp0 = (ulong)h0 * r0 + (ulong)h1 * s4 + (ulong)h2 * s3 + (ulong)h3 * s2 + (ulong)h4 * s1;
-            ulong tp1 = (ulong)h0 * r1 + (ulong)h1 * r0 + (ulong)h2 * s4 + (ulong)h3 * s3 + (ulong)h4 * s2;
-            ulong tp2 = (ulong)h0 * r2 + (ulong)h1 * r1 + (ulong)h2 * r0 + (ulong)h3 * s4 + (ulong)h4 * s3;
-            ulong tp3 = (ulong)h0 * r3 + (ulong)h1 * r2 + (ulong)h2 * r1 + (ulong)h3 * r0 + (ulong)h4 * s4;
-            ulong tp4 = (ulong)h0 * r4 + (ulong)h1 * r3 + (ulong)h2 * r2 + (ulong)h3 * r1 + (ulong)h4 * r0;
-
-            h0 = (uint)tp0 & 0x3ffffff; tp1 += (tp0 >> 26);
-            h1 = (uint)tp1 & 0x3ffffff; tp2 += (tp1 >> 26);
-            h2 = (uint)tp2 & 0x3ffffff; tp3 += (tp2 >> 26);
-            h3 = (uint)tp3 & 0x3ffffff; tp4 += (tp3 >> 26);
-            h4 = (uint)tp4 & 0x3ffffff;
-            h0 += (uint)(tp4 >> 26) * 5;
-            h1 += h0 >> 26; h0 &= 0x3ffffff;
-        }
+            uint t0 = Pack.LE_To_UInt32(block);
+            uint t1 = Pack.LE_To_UInt32(block[4..]);
+            uint t2 = Pack.LE_To_UInt32(block[8..]);
+            uint t3 = Pack.LE_To_UInt32(block[12..]);
 #else
         private void ProcessBlock(byte[] buf, int off)
         {
-            {
-                uint t0 = Pack.LE_To_UInt32(buf, off +  0);
-                uint t1 = Pack.LE_To_UInt32(buf, off +  4);
-                uint t2 = Pack.LE_To_UInt32(buf, off +  8);
-                uint t3 = Pack.LE_To_UInt32(buf, off + 12);
-
-                h0 +=   t0                      & 0x3ffffffU;
-                h1 += ((t1 <<  6) | (t0 >> 26)) & 0x3ffffffU;
-                h2 += ((t2 << 12) | (t1 >> 20)) & 0x3ffffffU;
-                h3 += ((t3 << 18) | (t2 >> 14)) & 0x3ffffffU;
-                h4 +=  ( 1 << 24) | (t3 >>  8);
-            }
+            uint t0 = Pack.LE_To_UInt32(buf, off +  0);
+            uint t1 = Pack.LE_To_UInt32(buf, off +  4);
+            uint t2 = Pack.LE_To_UInt32(buf, off +  8);
+            uint t3 = Pack.LE_To_UInt32(buf, off + 12);
+#endif
+
+            h0 +=   t0                      & 0x3ffffffU;
+            h1 += ((t1 <<  6) | (t0 >> 26)) & 0x3ffffffU;
+            h2 += ((t2 << 12) | (t1 >> 20)) & 0x3ffffffU;
+            h3 += ((t3 << 18) | (t2 >> 14)) & 0x3ffffffU;
+            h4 +=  ( 1 << 24) | (t3 >>  8);
 
             ulong tp0 = (ulong)h0 * r0 + (ulong)h1 * s4 + (ulong)h2 * s3 + (ulong)h3 * s2 + (ulong)h4 * s1;
             ulong tp1 = (ulong)h0 * r1 + (ulong)h1 * r0 + (ulong)h2 * s4 + (ulong)h3 * s3 + (ulong)h4 * s2;
@@ -324,7 +278,6 @@ namespace Org.BouncyCastle.Crypto.Macs
             h0 += (uint)(tp4 >> 26) * 5;
             h1 += h0 >> 26; h0 &= 0x3ffffff;
         }
-#endif
 
         public int DoFinal(byte[] output, int outOff)
         {
diff --git a/crypto/src/crypto/modes/GCMBlockCipher.cs b/crypto/src/crypto/modes/GCMBlockCipher.cs
index 2255b6276..ce5faf91f 100644
--- a/crypto/src/crypto/modes/GCMBlockCipher.cs
+++ b/crypto/src/crypto/modes/GCMBlockCipher.cs
@@ -3,6 +3,7 @@ using System;
 using System.Runtime.CompilerServices;
 #endif
 #if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.InteropServices;
 using System.Runtime.Intrinsics;
 using System.Runtime.Intrinsics.X86;
 #endif
@@ -897,7 +898,6 @@ namespace Org.BouncyCastle.Crypto.Modes
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        [MethodImpl(MethodImplOptions.AggressiveOptimization)]
         private void DecryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
         {
             Check.OutputLength(output, BlockSize, "output buffer too short");
@@ -913,15 +913,15 @@ namespace Org.BouncyCastle.Crypto.Modes
 #if NETCOREAPP3_0_OR_GREATER
             if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
             {
-                var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
-                var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
-                var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
+                var t0 = MemoryMarshal.Read<Vector128<byte>>(input);
+                var t1 = MemoryMarshal.Read<Vector128<byte>>(ctrBlock);
+                var t2 = MemoryMarshal.Read<Vector128<byte>>(S.AsSpan());
 
                 t1 = Sse2.Xor(t1, t0);
                 t2 = Sse2.Xor(t2, t0);
 
-                Unsafe.WriteUnaligned(ref output[0], t1);
-                Unsafe.WriteUnaligned(ref S[0], t2);
+                MemoryMarshal.Write(output, ref t1);
+                MemoryMarshal.Write(S.AsSpan(), ref t2);
             }
             else
 #endif
@@ -949,7 +949,6 @@ namespace Org.BouncyCastle.Crypto.Modes
             totalLength += BlockSize;
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveOptimization)]
         private void DecryptBlocks2(ReadOnlySpan<byte> input, Span<byte> output)
         {
             Check.OutputLength(output, BlockSize * 2, "output buffer too short");
@@ -965,15 +964,15 @@ namespace Org.BouncyCastle.Crypto.Modes
 #if NETCOREAPP3_0_OR_GREATER
             if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
             {
-                var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
-                var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
-                var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
+                var t0 = MemoryMarshal.Read<Vector128<byte>>(input);
+                var t1 = MemoryMarshal.Read<Vector128<byte>>(ctrBlock);
+                var t2 = MemoryMarshal.Read<Vector128<byte>>(S.AsSpan());
 
                 t1 = Sse2.Xor(t1, t0);
                 t2 = Sse2.Xor(t2, t0);
 
-                Unsafe.WriteUnaligned(ref output[0], t1);
-                Unsafe.WriteUnaligned(ref S[0], t2);
+                MemoryMarshal.Write(output, ref t1);
+                MemoryMarshal.Write(S.AsSpan(), ref t2);
             }
             else
 #endif
@@ -1005,15 +1004,15 @@ namespace Org.BouncyCastle.Crypto.Modes
 #if NETCOREAPP3_0_OR_GREATER
             if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
             {
-                var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
-                var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
-                var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
+                var t0 = MemoryMarshal.Read<Vector128<byte>>(input);
+                var t1 = MemoryMarshal.Read<Vector128<byte>>(ctrBlock);
+                var t2 = MemoryMarshal.Read<Vector128<byte>>(S.AsSpan());
 
                 t1 = Sse2.Xor(t1, t0);
                 t2 = Sse2.Xor(t2, t0);
 
-                Unsafe.WriteUnaligned(ref output[0], t1);
-                Unsafe.WriteUnaligned(ref S[0], t2);
+                MemoryMarshal.Write(output, ref t1);
+                MemoryMarshal.Write(S.AsSpan(), ref t2);
             }
             else
 #endif
@@ -1041,7 +1040,6 @@ namespace Org.BouncyCastle.Crypto.Modes
             totalLength += BlockSize * 2;
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveOptimization)]
         private void EncryptBlock(ReadOnlySpan<byte> input, Span<byte> output)
         {
             Check.OutputLength(output, BlockSize, "output buffer too short");
@@ -1057,15 +1055,15 @@ namespace Org.BouncyCastle.Crypto.Modes
 #if NETCOREAPP3_0_OR_GREATER
             if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
             {
-                var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
-                var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
-                var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
+                var t0 = MemoryMarshal.Read<Vector128<byte>>(input);
+                var t1 = MemoryMarshal.Read<Vector128<byte>>(ctrBlock);
+                var t2 = MemoryMarshal.Read<Vector128<byte>>(S.AsSpan());
 
                 t1 = Sse2.Xor(t1, t0);
                 t2 = Sse2.Xor(t2, t1);
 
-                Unsafe.WriteUnaligned(ref output[0], t1);
-                Unsafe.WriteUnaligned(ref S[0], t2);
+                MemoryMarshal.Write(output, ref t1);
+                MemoryMarshal.Write(S.AsSpan(), ref t2);
             }
             else
 #endif
@@ -1093,7 +1091,6 @@ namespace Org.BouncyCastle.Crypto.Modes
             totalLength += BlockSize;
         }
 
-        [MethodImpl(MethodImplOptions.AggressiveOptimization)]
         private void EncryptBlocks2(ReadOnlySpan<byte> input, Span<byte> output)
         {
             Check.OutputLength(output, BlockSize * 2, "Output buffer too short");
@@ -1109,15 +1106,15 @@ namespace Org.BouncyCastle.Crypto.Modes
 #if NETCOREAPP3_0_OR_GREATER
             if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
             {
-                var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
-                var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
-                var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
+                var t0 = MemoryMarshal.Read<Vector128<byte>>(input);
+                var t1 = MemoryMarshal.Read<Vector128<byte>>(ctrBlock);
+                var t2 = MemoryMarshal.Read<Vector128<byte>>(S.AsSpan());
 
                 t1 = Sse2.Xor(t1, t0);
                 t2 = Sse2.Xor(t2, t1);
 
-                Unsafe.WriteUnaligned(ref output[0], t1);
-                Unsafe.WriteUnaligned(ref S[0], t2);
+                MemoryMarshal.Write(output, ref t1);
+                MemoryMarshal.Write(S.AsSpan(), ref t2);
             }
             else
 #endif
@@ -1149,15 +1146,15 @@ namespace Org.BouncyCastle.Crypto.Modes
 #if NETCOREAPP3_0_OR_GREATER
             if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == BlockSize)
             {
-                var t0 = Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(input[0]));
-                var t1 = Unsafe.ReadUnaligned<Vector128<byte>>(ref ctrBlock[0]);
-                var t2 = Unsafe.ReadUnaligned<Vector128<byte>>(ref S[0]);
+                var t0 = MemoryMarshal.Read<Vector128<byte>>(input);
+                var t1 = MemoryMarshal.Read<Vector128<byte>>(ctrBlock);
+                var t2 = MemoryMarshal.Read<Vector128<byte>>(S.AsSpan());
 
                 t1 = Sse2.Xor(t1, t0);
                 t2 = Sse2.Xor(t2, t1);
 
-                Unsafe.WriteUnaligned(ref output[0], t1);
-                Unsafe.WriteUnaligned(ref S[0], t2);
+                MemoryMarshal.Write(output, ref t1);
+                MemoryMarshal.Write(S.AsSpan(), ref t2);
             }
             else
 #endif
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index 1aa437fcd..97b34fb61 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -16,12 +16,6 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
 {
     internal abstract class GcmUtilities
     {
-#if NETCOREAPP3_0_OR_GREATER
-        private static readonly Vector128<byte> EndianMask = Vector128.Create(
-            (byte)0x07, (byte)0x06, (byte)0x05, (byte)0x04, (byte)0x03, (byte)0x02, (byte)0x01, (byte)0x00,
-            (byte)0x0F, (byte)0x0E, (byte)0x0D, (byte)0x0C, (byte)0x0B, (byte)0x0A, (byte)0x09, (byte)0x08);
-#endif
-
         internal struct FieldElement
         {
             internal ulong n0, n1;
@@ -41,17 +35,6 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
 #endif
         internal static void AsBytes(ulong x0, ulong x1, byte[] z)
         {
-#if NETCOREAPP3_0_OR_GREATER
-            if (Ssse3.IsSupported && BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
-            {
-                var X = Vector128.Create(x0, x1).AsByte();
-                // TODO[Arm] System.Runtime.Intrinsics.Arm.AdvSimd.Reverse8
-                var Z = Ssse3.Shuffle(X, EndianMask);
-                Unsafe.WriteUnaligned(ref z[0], Z);
-                return;
-            }
-#endif
-
             Pack.UInt64_To_BE(x0, z, 0);
             Pack.UInt64_To_BE(x1, z, 8);
         }
@@ -69,17 +52,6 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
 #endif
         internal static void AsFieldElement(byte[] x, out FieldElement z)
         {
-#if NETCOREAPP3_0_OR_GREATER
-            if (Ssse3.IsSupported && BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
-            {
-                var X = Unsafe.ReadUnaligned<Vector128<byte>>(ref x[0]);
-                var Z = Ssse3.Shuffle(X, EndianMask).AsUInt64();
-                z.n0 = Z.GetElement(0);
-                z.n1 = Z.GetElement(1);
-                return;
-            }
-#endif
-
             z.n0 = Pack.BE_To_UInt64(x, 0);
             z.n1 = Pack.BE_To_UInt64(x, 8);
         }
diff --git a/crypto/src/crypto/operators/Asn1CipherBuilder.cs b/crypto/src/crypto/operators/Asn1CipherBuilder.cs
index 0561bee4f..b151dfcc2 100644
--- a/crypto/src/crypto/operators/Asn1CipherBuilder.cs
+++ b/crypto/src/crypto/operators/Asn1CipherBuilder.cs
@@ -18,10 +18,7 @@ namespace Org.BouncyCastle.Crypto.Operators
 
         public Asn1CipherBuilderWithKey(DerObjectIdentifier encryptionOID, int keySize, SecureRandom random)
         {
-            if (random == null)
-            {
-                random = new SecureRandom();
-            }
+            random = CryptoServicesRegistrar.GetSecureRandom(random);
 
             CipherKeyGenerator keyGen = CipherKeyGeneratorFactory.CreateKeyGenerator(encryptionOID, random);
 
diff --git a/crypto/src/crypto/paddings/ISO10126d2Padding.cs b/crypto/src/crypto/paddings/ISO10126d2Padding.cs
index 317b5db8c..21e007f1b 100644
--- a/crypto/src/crypto/paddings/ISO10126d2Padding.cs
+++ b/crypto/src/crypto/paddings/ISO10126d2Padding.cs
@@ -21,7 +21,7 @@ namespace Org.BouncyCastle.Crypto.Paddings
 			SecureRandom random)
             //throws ArgumentException
         {
-			this.random = (random != null) ? random : new SecureRandom();
+            this.random = CryptoServicesRegistrar.GetSecureRandom(random);
         }
 
 		/**
diff --git a/crypto/src/crypto/parameters/ParametersWithRandom.cs b/crypto/src/crypto/parameters/ParametersWithRandom.cs
index e20ddd7ce..2fe885a8a 100644
--- a/crypto/src/crypto/parameters/ParametersWithRandom.cs
+++ b/crypto/src/crypto/parameters/ParametersWithRandom.cs
@@ -11,7 +11,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
 		private readonly SecureRandom m_random;
 
         public ParametersWithRandom(ICipherParameters parameters)
-            : this(parameters, new SecureRandom())
+            : this(parameters, CryptoServicesRegistrar.GetSecureRandom())
         {
         }
 
diff --git a/crypto/src/crypto/prng/BasicEntropySourceProvider.cs b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
index 485cf25ab..5de1e4e5e 100644
--- a/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
+++ b/crypto/src/crypto/prng/BasicEntropySourceProvider.cs
@@ -21,6 +21,9 @@ namespace Org.BouncyCastle.Crypto.Prng
          */
         public BasicEntropySourceProvider(SecureRandom secureRandom, bool isPredictionResistant)
         {
+            if (secureRandom == null)
+                throw new ArgumentNullException(nameof(secureRandom));
+
             mSecureRandom = secureRandom;
             mPredictionResistant = isPredictionResistant;
         }
@@ -46,6 +49,9 @@ namespace Org.BouncyCastle.Crypto.Prng
 
             internal BasicEntropySource(SecureRandom secureRandom, bool predictionResistant, int entropySize)
             {
+                if (secureRandom == null)
+                    throw new ArgumentNullException(nameof(secureRandom));
+
                 this.mSecureRandom = secureRandom;
                 this.mPredictionResistant = predictionResistant;
                 this.mEntropySize = entropySize;
diff --git a/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs b/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
index 7199f1ae7..8159f4822 100644
--- a/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
+++ b/crypto/src/crypto/prng/SP800SecureRandomBuilder.cs
@@ -26,7 +26,7 @@ namespace Org.BouncyCastle.Crypto.Prng
          * </p>
          */
         public SP800SecureRandomBuilder()
-            : this(new SecureRandom(), false)
+            : this(CryptoServicesRegistrar.GetSecureRandom(), false)
         {
         }
 
@@ -42,6 +42,9 @@ namespace Org.BouncyCastle.Crypto.Prng
          */
         public SP800SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
         {
+            if (entropySource == null)
+                throw new ArgumentNullException(nameof(entropySource));
+
             this.mRandom = entropySource;
             this.mEntropySourceProvider = new BasicEntropySourceProvider(entropySource, predictionResistant);
         }
diff --git a/crypto/src/crypto/prng/VMPCRandomGenerator.cs b/crypto/src/crypto/prng/VMPCRandomGenerator.cs
index 13b097789..92d163710 100644
--- a/crypto/src/crypto/prng/VMPCRandomGenerator.cs
+++ b/crypto/src/crypto/prng/VMPCRandomGenerator.cs
@@ -4,11 +4,9 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Prng
 {
-    public class VmpcRandomGenerator
+    public sealed class VmpcRandomGenerator
         : IRandomGenerator 
     {
-        private byte n = 0;
-
         /// <remarks>
         /// Permutation generated by code:
         /// <code>
@@ -28,77 +26,61 @@ namespace Org.BouncyCastle.Crypto.Prng
         ///     P[s &amp; 0xff] = temp;
         /// } </code>
         /// </remarks>
-        private byte[] P =
+        private readonly byte[] P =
         {
-            (byte) 0xbb, (byte) 0x2c, (byte) 0x62, (byte) 0x7f, (byte) 0xb5, (byte) 0xaa, (byte) 0xd4,
-            (byte) 0x0d, (byte) 0x81, (byte) 0xfe, (byte) 0xb2, (byte) 0x82, (byte) 0xcb, (byte) 0xa0, (byte) 0xa1,
-            (byte) 0x08, (byte) 0x18, (byte) 0x71, (byte) 0x56, (byte) 0xe8, (byte) 0x49, (byte) 0x02, (byte) 0x10,
-            (byte) 0xc4, (byte) 0xde, (byte) 0x35, (byte) 0xa5, (byte) 0xec, (byte) 0x80, (byte) 0x12, (byte) 0xb8,
-            (byte) 0x69, (byte) 0xda, (byte) 0x2f, (byte) 0x75, (byte) 0xcc, (byte) 0xa2, (byte) 0x09, (byte) 0x36,
-            (byte) 0x03, (byte) 0x61, (byte) 0x2d, (byte) 0xfd, (byte) 0xe0, (byte) 0xdd, (byte) 0x05, (byte) 0x43,
-            (byte) 0x90, (byte) 0xad, (byte) 0xc8, (byte) 0xe1, (byte) 0xaf, (byte) 0x57, (byte) 0x9b, (byte) 0x4c,
-            (byte) 0xd8, (byte) 0x51, (byte) 0xae, (byte) 0x50, (byte) 0x85, (byte) 0x3c, (byte) 0x0a, (byte) 0xe4,
-            (byte) 0xf3, (byte) 0x9c, (byte) 0x26, (byte) 0x23, (byte) 0x53, (byte) 0xc9, (byte) 0x83, (byte) 0x97,
-            (byte) 0x46, (byte) 0xb1, (byte) 0x99, (byte) 0x64, (byte) 0x31, (byte) 0x77, (byte) 0xd5, (byte) 0x1d,
-            (byte) 0xd6, (byte) 0x78, (byte) 0xbd, (byte) 0x5e, (byte) 0xb0, (byte) 0x8a, (byte) 0x22, (byte) 0x38,
-            (byte) 0xf8, (byte) 0x68, (byte) 0x2b, (byte) 0x2a, (byte) 0xc5, (byte) 0xd3, (byte) 0xf7, (byte) 0xbc,
-            (byte) 0x6f, (byte) 0xdf, (byte) 0x04, (byte) 0xe5, (byte) 0x95, (byte) 0x3e, (byte) 0x25, (byte) 0x86,
-            (byte) 0xa6, (byte) 0x0b, (byte) 0x8f, (byte) 0xf1, (byte) 0x24, (byte) 0x0e, (byte) 0xd7, (byte) 0x40,
-            (byte) 0xb3, (byte) 0xcf, (byte) 0x7e, (byte) 0x06, (byte) 0x15, (byte) 0x9a, (byte) 0x4d, (byte) 0x1c,
-            (byte) 0xa3, (byte) 0xdb, (byte) 0x32, (byte) 0x92, (byte) 0x58, (byte) 0x11, (byte) 0x27, (byte) 0xf4,
-            (byte) 0x59, (byte) 0xd0, (byte) 0x4e, (byte) 0x6a, (byte) 0x17, (byte) 0x5b, (byte) 0xac, (byte) 0xff,
-            (byte) 0x07, (byte) 0xc0, (byte) 0x65, (byte) 0x79, (byte) 0xfc, (byte) 0xc7, (byte) 0xcd, (byte) 0x76,
-            (byte) 0x42, (byte) 0x5d, (byte) 0xe7, (byte) 0x3a, (byte) 0x34, (byte) 0x7a, (byte) 0x30, (byte) 0x28,
-            (byte) 0x0f, (byte) 0x73, (byte) 0x01, (byte) 0xf9, (byte) 0xd1, (byte) 0xd2, (byte) 0x19, (byte) 0xe9,
-            (byte) 0x91, (byte) 0xb9, (byte) 0x5a, (byte) 0xed, (byte) 0x41, (byte) 0x6d, (byte) 0xb4, (byte) 0xc3,
-            (byte) 0x9e, (byte) 0xbf, (byte) 0x63, (byte) 0xfa, (byte) 0x1f, (byte) 0x33, (byte) 0x60, (byte) 0x47,
-            (byte) 0x89, (byte) 0xf0, (byte) 0x96, (byte) 0x1a, (byte) 0x5f, (byte) 0x93, (byte) 0x3d, (byte) 0x37,
-            (byte) 0x4b, (byte) 0xd9, (byte) 0xa8, (byte) 0xc1, (byte) 0x1b, (byte) 0xf6, (byte) 0x39, (byte) 0x8b,
-            (byte) 0xb7, (byte) 0x0c, (byte) 0x20, (byte) 0xce, (byte) 0x88, (byte) 0x6e, (byte) 0xb6, (byte) 0x74,
-            (byte) 0x8e, (byte) 0x8d, (byte) 0x16, (byte) 0x29, (byte) 0xf2, (byte) 0x87, (byte) 0xf5, (byte) 0xeb,
-            (byte) 0x70, (byte) 0xe3, (byte) 0xfb, (byte) 0x55, (byte) 0x9f, (byte) 0xc6, (byte) 0x44, (byte) 0x4a,
-            (byte) 0x45, (byte) 0x7d, (byte) 0xe2, (byte) 0x6b, (byte) 0x5c, (byte) 0x6c, (byte) 0x66, (byte) 0xa9,
-            (byte) 0x8c, (byte) 0xee, (byte) 0x84, (byte) 0x13, (byte) 0xa7, (byte) 0x1e, (byte) 0x9d, (byte) 0xdc,
-            (byte) 0x67, (byte) 0x48, (byte) 0xba, (byte) 0x2e, (byte) 0xe6, (byte) 0xa4, (byte) 0xab, (byte) 0x7c,
-            (byte) 0x94, (byte) 0x00, (byte) 0x21, (byte) 0xef, (byte) 0xea, (byte) 0xbe, (byte) 0xca, (byte) 0x72,
-            (byte) 0x4f, (byte) 0x52, (byte) 0x98, (byte) 0x3f, (byte) 0xc2, (byte) 0x14, (byte) 0x7b, (byte) 0x3b,
-            (byte) 0x54
+            0xbb, 0x2c, 0x62, 0x7f, 0xb5, 0xaa, 0xd4, 0x0d, 0x81, 0xfe, 0xb2, 0x82, 0xcb, 0xa0, 0xa1, 0x08,
+            0x18, 0x71, 0x56, 0xe8, 0x49, 0x02, 0x10, 0xc4, 0xde, 0x35, 0xa5, 0xec, 0x80, 0x12, 0xb8, 0x69,
+            0xda, 0x2f, 0x75, 0xcc, 0xa2, 0x09, 0x36, 0x03, 0x61, 0x2d, 0xfd, 0xe0, 0xdd, 0x05, 0x43, 0x90,
+            0xad, 0xc8, 0xe1, 0xaf, 0x57, 0x9b, 0x4c, 0xd8, 0x51, 0xae, 0x50, 0x85, 0x3c, 0x0a, 0xe4, 0xf3,
+            0x9c, 0x26, 0x23, 0x53, 0xc9, 0x83, 0x97, 0x46, 0xb1, 0x99, 0x64, 0x31, 0x77, 0xd5, 0x1d, 0xd6,
+            0x78, 0xbd, 0x5e, 0xb0, 0x8a, 0x22, 0x38, 0xf8, 0x68, 0x2b, 0x2a, 0xc5, 0xd3, 0xf7, 0xbc, 0x6f,
+            0xdf, 0x04, 0xe5, 0x95, 0x3e, 0x25, 0x86, 0xa6, 0x0b, 0x8f, 0xf1, 0x24, 0x0e, 0xd7, 0x40, 0xb3,
+            0xcf, 0x7e, 0x06, 0x15, 0x9a, 0x4d, 0x1c, 0xa3, 0xdb, 0x32, 0x92, 0x58, 0x11, 0x27, 0xf4, 0x59,
+            0xd0, 0x4e, 0x6a, 0x17, 0x5b, 0xac, 0xff, 0x07, 0xc0, 0x65, 0x79, 0xfc, 0xc7, 0xcd, 0x76, 0x42,
+            0x5d, 0xe7, 0x3a, 0x34, 0x7a, 0x30, 0x28, 0x0f, 0x73, 0x01, 0xf9, 0xd1, 0xd2, 0x19, 0xe9, 0x91,
+            0xb9, 0x5a, 0xed, 0x41, 0x6d, 0xb4, 0xc3, 0x9e, 0xbf, 0x63, 0xfa, 0x1f, 0x33, 0x60, 0x47, 0x89,
+            0xf0, 0x96, 0x1a, 0x5f, 0x93, 0x3d, 0x37, 0x4b, 0xd9, 0xa8, 0xc1, 0x1b, 0xf6, 0x39, 0x8b, 0xb7,
+            0x0c, 0x20, 0xce, 0x88, 0x6e, 0xb6, 0x74, 0x8e, 0x8d, 0x16, 0x29, 0xf2, 0x87, 0xf5, 0xeb, 0x70,
+            0xe3, 0xfb, 0x55, 0x9f, 0xc6, 0x44, 0x4a, 0x45, 0x7d, 0xe2, 0x6b, 0x5c, 0x6c, 0x66, 0xa9, 0x8c,
+            0xee, 0x84, 0x13, 0xa7, 0x1e, 0x9d, 0xdc, 0x67, 0x48, 0xba, 0x2e, 0xe6, 0xa4, 0xab, 0x7c, 0x94,
+            0x00, 0x21, 0xef, 0xea, 0xbe, 0xca, 0x72, 0x4f, 0x52, 0x98, 0x3f, 0xc2, 0x14, 0x7b, 0x3b, 0x54,
         };
 
         /// <remarks>Value generated in the same way as <c>P</c>.</remarks>
-        private byte s = (byte) 0xbe;
+        private byte s = 0xbe;
+        private byte n = 0;
 
         public VmpcRandomGenerator()
         {
         }
 
-        public virtual void AddSeedMaterial(byte[] seed) 
+        public void AddSeedMaterial(byte[] seed) 
         {
             for (int m = 0; m < seed.Length; m++) 
             {
-                s = P[(s + P[n & 0xff] + seed[m]) & 0xff];
-                byte temp = P[n & 0xff];
-                P[n & 0xff] = P[s & 0xff];
-                P[s & 0xff] = temp;
-                n = (byte) ((n + 1) & 0xff);
+                byte pn = P[n];
+                s = P[(s + pn + seed[m]) & 0xff];
+                P[n] = P[s];
+                P[s] = pn;
+                n = (byte)(n + 1);
             }
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        public virtual void AddSeedMaterial(ReadOnlySpan<byte> seed)
+        public void AddSeedMaterial(ReadOnlySpan<byte> seed)
         {
             for (int m = 0; m < seed.Length; m++)
             {
-                s = P[(s + P[n & 0xff] + seed[m]) & 0xff];
-                byte temp = P[n & 0xff];
-                P[n & 0xff] = P[s & 0xff];
-                P[s & 0xff] = temp;
-                n = (byte)((n + 1) & 0xff);
+                byte pn = P[n];
+                s = P[(s + pn + seed[m]) & 0xff];
+                P[n] = P[s];
+                P[s] = pn;
+                n = (byte)(n + 1);
             }
         }
 #endif
 
-        public virtual void AddSeedMaterial(long seed) 
+        public void AddSeedMaterial(long seed) 
         {
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
             Span<byte> bytes = stackalloc byte[8];
@@ -109,41 +91,47 @@ namespace Org.BouncyCastle.Crypto.Prng
 #endif
         }
 
-        public virtual void NextBytes(byte[] bytes) 
+        public void NextBytes(byte[] bytes) 
         {
             NextBytes(bytes, 0, bytes.Length);
         }
 
-        public virtual void NextBytes(byte[] bytes, int start, int len) 
+        public void NextBytes(byte[] bytes, int start, int len) 
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            NextBytes(bytes.AsSpan(start, len));
+#else
             lock (P) 
             {
                 int end = start + len;
                 for (int i = start; i != end; i++) 
                 {
-                    s = P[(s + P[n & 0xff]) & 0xff];
-                    bytes[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
-                    byte temp = P[n & 0xff];
-                    P[n & 0xff] = P[s & 0xff];
-                    P[s & 0xff] = temp;
-                    n = (byte) ((n + 1) & 0xff);
+                    byte pn = P[n];
+                    s = P[(s + pn) & 0xFF];
+                    byte ps = P[s];
+                    bytes[i] = P[(P[ps] + 1) & 0xFF];
+                    P[s] = pn;
+                    P[n] = ps;
+                    n = (byte)(n + 1);
                 }
             }
+#endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        public virtual void NextBytes(Span<byte> bytes)
+        public void NextBytes(Span<byte> bytes)
         {
             lock (P) 
             {
-                for (int i = 0; i != bytes.Length; i++) 
+                for (int i = 0; i < bytes.Length; ++i) 
                 {
-                    s = P[(s + P[n & 0xff]) & 0xff];
-                    bytes[i] = P[(P[(P[s & 0xff]) & 0xff] + 1) & 0xff];
-                    byte temp = P[n & 0xff];
-                    P[n & 0xff] = P[s & 0xff];
-                    P[s & 0xff] = temp;
-                    n = (byte) ((n + 1) & 0xff);
+                    byte pn = P[n];
+                    s = P[(s + pn) & 0xFF];
+                    byte ps = P[s];
+                    bytes[i] = P[(P[ps] + 1) & 0xFF];
+                    P[s] = pn;
+                    P[n] = ps;
+                    n = (byte)(n + 1);
                 }
             }
         }
diff --git a/crypto/src/crypto/prng/X931SecureRandomBuilder.cs b/crypto/src/crypto/prng/X931SecureRandomBuilder.cs
index 31e94312e..025eac1bb 100644
--- a/crypto/src/crypto/prng/X931SecureRandomBuilder.cs
+++ b/crypto/src/crypto/prng/X931SecureRandomBuilder.cs
@@ -23,7 +23,7 @@ namespace Org.BouncyCastle.Crypto.Prng
          * </p>
          */
         public X931SecureRandomBuilder()
-            : this(new SecureRandom(), false)
+            : this(CryptoServicesRegistrar.GetSecureRandom(), false)
         {
         }
 
@@ -39,6 +39,9 @@ namespace Org.BouncyCastle.Crypto.Prng
          */
         public X931SecureRandomBuilder(SecureRandom entropySource, bool predictionResistant)
         {
+            if (entropySource == null)
+                throw new ArgumentNullException(nameof(entropySource));
+
             this.mRandom = entropySource;
             this.mEntropySourceProvider = new BasicEntropySourceProvider(mRandom, predictionResistant);
         }
diff --git a/crypto/src/crypto/signers/DsaSigner.cs b/crypto/src/crypto/signers/DsaSigner.cs
index 7799edc0e..318eeeb48 100644
--- a/crypto/src/crypto/signers/DsaSigner.cs
+++ b/crypto/src/crypto/signers/DsaSigner.cs
@@ -155,7 +155,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 
         protected virtual SecureRandom InitSecureRandom(bool needed, SecureRandom provided)
         {
-            return !needed ? null : (provided != null) ? provided : new SecureRandom();
+            return !needed ? null : CryptoServicesRegistrar.GetSecureRandom(provided);
         }
     }
 }
diff --git a/crypto/src/crypto/signers/ECDsaSigner.cs b/crypto/src/crypto/signers/ECDsaSigner.cs
index 590c3236b..d78e92516 100644
--- a/crypto/src/crypto/signers/ECDsaSigner.cs
+++ b/crypto/src/crypto/signers/ECDsaSigner.cs
@@ -239,7 +239,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 
         protected virtual SecureRandom InitSecureRandom(bool needed, SecureRandom provided)
         {
-            return !needed ? null : (provided != null) ? provided : new SecureRandom();
+            return !needed ? null : CryptoServicesRegistrar.GetSecureRandom(provided);
         }
     }
 }
diff --git a/crypto/src/crypto/signers/ECGOST3410Signer.cs b/crypto/src/crypto/signers/ECGOST3410Signer.cs
index 2defa943f..fd5fa4818 100644
--- a/crypto/src/crypto/signers/ECGOST3410Signer.cs
+++ b/crypto/src/crypto/signers/ECGOST3410Signer.cs
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Crypto.Signers
                 }
                 else
                 {
-                    this.random = new SecureRandom();
+                    this.random = CryptoServicesRegistrar.GetSecureRandom();
                 }
 
                 if (!(parameters is ECPrivateKeyParameters ecPrivateKeyParameters))
diff --git a/crypto/src/crypto/signers/ECNRSigner.cs b/crypto/src/crypto/signers/ECNRSigner.cs
index b22d7a977..d7790386a 100644
--- a/crypto/src/crypto/signers/ECNRSigner.cs
+++ b/crypto/src/crypto/signers/ECNRSigner.cs
@@ -24,24 +24,20 @@ namespace Org.BouncyCastle.Crypto.Signers
             get { return "ECNR"; }
         }
 
-        public virtual void Init(
-            bool				forSigning,
-            ICipherParameters	parameters)
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
         {
             this.forSigning = forSigning;
 
             if (forSigning)
             {
-                if (parameters is ParametersWithRandom)
+                if (parameters is ParametersWithRandom rParam)
                 {
-                    ParametersWithRandom rParam = (ParametersWithRandom) parameters;
-
                     this.random = rParam.Random;
                     parameters = rParam.Parameters;
                 }
                 else
                 {
-                    this.random = new SecureRandom();
+                    this.random = CryptoServicesRegistrar.GetSecureRandom();
                 }
 
                 if (!(parameters is ECPrivateKeyParameters))
diff --git a/crypto/src/crypto/signers/GOST3410Signer.cs b/crypto/src/crypto/signers/GOST3410Signer.cs
index a0d8f8a1f..03aab0b04 100644
--- a/crypto/src/crypto/signers/GOST3410Signer.cs
+++ b/crypto/src/crypto/signers/GOST3410Signer.cs
@@ -21,22 +21,18 @@ namespace Org.BouncyCastle.Crypto.Signers
 			get { return "GOST3410"; }
 		}
 
-        public virtual void Init(
-			bool				forSigning,
-			ICipherParameters	parameters)
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
 		{
 			if (forSigning)
 			{
-				if (parameters is ParametersWithRandom)
+				if (parameters is ParametersWithRandom rParam)
 				{
-					ParametersWithRandom rParam = (ParametersWithRandom)parameters;
-
 					this.random = rParam.Random;
 					parameters = rParam.Parameters;
 				}
 				else
 				{
-					this.random = new SecureRandom();
+					this.random = CryptoServicesRegistrar.GetSecureRandom();
 				}
 
 				if (!(parameters is Gost3410PrivateKeyParameters))
diff --git a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
index 573765c1a..72afabf4c 100644
--- a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
+++ b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -109,42 +109,36 @@ namespace Org.BouncyCastle.Crypto.Signers
         /// <exception cref="ArgumentException">if wrong parameter type or a fixed
         /// salt is passed in which is the wrong length.
         /// </exception>
-        public virtual void Init(
-            bool				forSigning,
-            ICipherParameters	parameters)
+        public virtual void Init(bool forSigning, ICipherParameters parameters)
         {
             RsaKeyParameters kParam;
-            if (parameters is ParametersWithRandom)
+            if (parameters is ParametersWithRandom withRandom)
             {
-                ParametersWithRandom p = (ParametersWithRandom) parameters;
-
-                kParam = (RsaKeyParameters) p.Parameters;
+                kParam = (RsaKeyParameters)withRandom.Parameters;
 
                 if (forSigning)
                 {
-                    random = p.Random;
+                    random = withRandom.Random;
                 }
             }
-            else if (parameters is ParametersWithSalt)
+            else if (parameters is ParametersWithSalt withSalt)
             {
                 if (!forSigning)
-                    throw new ArgumentException("ParametersWithSalt only valid for signing", "parameters");
-
-                ParametersWithSalt p = (ParametersWithSalt) parameters;
+                    throw new ArgumentException("ParametersWithSalt only valid for signing", nameof(parameters));
 
-                kParam = (RsaKeyParameters) p.Parameters;
-                standardSalt = p.GetSalt();
+                kParam = (RsaKeyParameters)withSalt.Parameters;
+                standardSalt = withSalt.GetSalt();
 
                 if (standardSalt.Length != saltLength)
                     throw new ArgumentException("Fixed salt is of wrong length");
             }
             else
             {
-                kParam = (RsaKeyParameters) parameters;
+                kParam = (RsaKeyParameters)parameters;
 
                 if (forSigning)
                 {
-                    random = new SecureRandom();
+                    random = CryptoServicesRegistrar.GetSecureRandom();
                 }
             }
 
diff --git a/crypto/src/crypto/signers/PssSigner.cs b/crypto/src/crypto/signers/PssSigner.cs
index 6d34e6edd..df73a7472 100644
--- a/crypto/src/crypto/signers/PssSigner.cs
+++ b/crypto/src/crypto/signers/PssSigner.cs
@@ -152,22 +152,18 @@ namespace Org.BouncyCastle.Crypto.Signers
 			get { return mgfDigest.AlgorithmName + "withRSAandMGF1"; }
 		}
 
-		public virtual void Init(
-			bool				forSigning,
-			ICipherParameters	parameters)
+		public virtual void Init(bool forSigning, ICipherParameters parameters)
 		{
-			if (parameters is ParametersWithRandom)
+			if (parameters is ParametersWithRandom withRandom)
 			{
-				ParametersWithRandom p = (ParametersWithRandom) parameters;
-
-				parameters = p.Parameters;
-				random = p.Random;
+				parameters = withRandom.Parameters;
+				random = withRandom.Random;
 			}
 			else
 			{
 				if (forSigning)
 				{
-					random = new SecureRandom();
+					random = CryptoServicesRegistrar.GetSecureRandom();
 				}
 			}
 
@@ -176,11 +172,11 @@ namespace Org.BouncyCastle.Crypto.Signers
 			RsaKeyParameters kParam;
 			if (parameters is RsaBlindingParameters)
 			{
-				kParam = ((RsaBlindingParameters) parameters).PublicKey;
+				kParam = ((RsaBlindingParameters)parameters).PublicKey;
 			}
 			else
 			{
-				kParam = (RsaKeyParameters) parameters;
+				kParam = (RsaKeyParameters)parameters;
 			}
 
 			emBits = kParam.Modulus.BitLength - 1;
diff --git a/crypto/src/crypto/signers/SM2Signer.cs b/crypto/src/crypto/signers/SM2Signer.cs
index 24aedd970..07b41bd30 100644
--- a/crypto/src/crypto/signers/SM2Signer.cs
+++ b/crypto/src/crypto/signers/SM2Signer.cs
@@ -72,10 +72,8 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             if (forSigning)
             {
-                if (baseParam is ParametersWithRandom)
+                if (baseParam is ParametersWithRandom rParam)
                 {
-                    ParametersWithRandom rParam = (ParametersWithRandom)baseParam;
-
                     ecKey = (ECKeyParameters)rParam.Parameters;
                     ecParams = ecKey.Parameters;
                     kCalculator.Init(ecParams.N, rParam.Random);
@@ -84,7 +82,7 @@ namespace Org.BouncyCastle.Crypto.Signers
                 {
                     ecKey = (ECKeyParameters)baseParam;
                     ecParams = ecKey.Parameters;
-                    kCalculator.Init(ecParams.N, new SecureRandom());
+                    kCalculator.Init(ecParams.N, CryptoServicesRegistrar.GetSecureRandom());
                 }
                 pubPoint = CreateBasePointMultiplier().Multiply(ecParams.G, ((ECPrivateKeyParameters)ecKey).D).Normalize();
             }
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index 98504a605..a12253e59 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -7,12 +7,8 @@ using System.Runtime.CompilerServices;
 
 namespace Org.BouncyCastle.Crypto.Utilities
 {
-    internal sealed class Pack
+    internal static class Pack
     {
-        private Pack()
-        {
-        }
-
         internal static void UInt16_To_BE(ushort n, byte[] bs)
         {
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
diff --git a/crypto/src/math/BigInteger.cs b/crypto/src/math/BigInteger.cs
index dd8b3a85b..caf78843e 100644
--- a/crypto/src/math/BigInteger.cs
+++ b/crypto/src/math/BigInteger.cs
@@ -7,7 +7,7 @@ using System.Runtime.Intrinsics.X86;
 #endif
 using System.Runtime.Serialization;
 using System.Text;
-
+using Org.BouncyCastle.Crypto.Prng;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
@@ -163,8 +163,6 @@ namespace Org.BouncyCastle.Math
         private const int chunk2 = 1, chunk8 = 1, chunk10 = 19, chunk16 = 16;
         private static readonly BigInteger radix2, radix2E, radix8, radix8E, radix10, radix10E, radix16, radix16E;
 
-        private static readonly SecureRandom RandomSource = new SecureRandom();
-
         /*
          * These are the threshold bit-lengths (of an exponent) where we increase the window size.
          * They are calculated according to the expected savings in multiplications.
@@ -244,7 +242,7 @@ namespace Org.BouncyCastle.Math
 
         public static BigInteger Arbitrary(int sizeInBits)
         {
-            return new BigInteger(sizeInBits, RandomSource);
+            return new BigInteger(sizeInBits, SecureRandom.ArbitraryRandom);
         }
 
         private BigInteger(
@@ -1460,7 +1458,7 @@ namespace Org.BouncyCastle.Math
             if (n.Equals(One))
                 return false;
 
-            return n.CheckProbablePrime(certainty, RandomSource, randomlySelected);
+            return n.CheckProbablePrime(certainty, SecureRandom.ArbitraryRandom, randomlySelected);
         }
 
         private bool CheckProbablePrime(int certainty, Random random, bool randomlySelected)
@@ -2633,7 +2631,7 @@ namespace Org.BouncyCastle.Math
 
             BigInteger n = Inc().SetBit(0);
 
-            while (!n.CheckProbablePrime(100, RandomSource, false))
+            while (!n.CheckProbablePrime(100, SecureRandom.ArbitraryRandom, false))
             {
                 n = n.Add(Two);
             }
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index d17c6b1c1..b37d62721 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -737,7 +737,6 @@ namespace Org.BouncyCastle.Math.EC
         private const int FP_DEFAULT_COORDS = COORD_JACOBIAN_MODIFIED;
 
         private static readonly HashSet<BigInteger> KnownQs = new HashSet<BigInteger>();
-        private static readonly SecureRandom random = new SecureRandom();
 
         protected readonly BigInteger m_q, m_r;
         protected readonly FpPoint m_infinity;
@@ -771,7 +770,8 @@ namespace Org.BouncyCastle.Math.EC
                         throw new ArgumentException("Fp q value out of range");
 
                     if (Primes.HasAnySmallFactors(q) ||
-                        !Primes.IsMRProbablePrime(q, random, GetNumberOfIterations(qBitLength, certainty)))
+                        !Primes.IsMRProbablePrime(q, SecureRandom.ArbitraryRandom,
+                            GetNumberOfIterations(qBitLength, certainty)))
                     {
                         throw new ArgumentException("Fp q value not prime");
                     }
diff --git a/crypto/src/math/ec/ECPoint.cs b/crypto/src/math/ec/ECPoint.cs
index fc0ddf035..ee7cf9a92 100644
--- a/crypto/src/math/ec/ECPoint.cs
+++ b/crypto/src/math/ec/ECPoint.cs
@@ -12,8 +12,6 @@ namespace Org.BouncyCastle.Math.EC
      */
     public abstract class ECPoint
     {
-        private static readonly SecureRandom Random = new SecureRandom();
-
         protected static ECFieldElement[] EMPTY_ZS = new ECFieldElement[0];
 
         protected static ECFieldElement[] GetInitialZCoords(ECCurve curve)
@@ -246,10 +244,7 @@ namespace Org.BouncyCastle.Math.EC
                      * Any side-channel in the implementation of 'inverse' now only leaks information about
                      * the value (z * b), and no longer reveals information about 'z' itself.
                      */
-                    // TODO Add CryptoServicesRegistrar class and use here
-                    //SecureRandom r = CryptoServicesRegistrar.GetSecureRandom();
-                    SecureRandom r = Random;
-                    ECFieldElement b = m_curve.RandomFieldElementMult(r);
+                    ECFieldElement b = m_curve.RandomFieldElementMult(SecureRandom.ArbitraryRandom);
                     ECFieldElement zInv = z.Multiply(b).Invert().Multiply(b);
                     return Normalize(zInv);
                 }
diff --git a/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs b/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs
index 25cb24932..e3de6c594 100644
--- a/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs
+++ b/crypto/src/math/ec/custom/gm/SM2P256V1FieldElement.cs
@@ -115,7 +115,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.GM
 
         public override ECFieldElement Invert()
         {
-            //return new SM2P256V1FieldElement(ToBigInteger().ModInverse(Q));
             uint[] z = Nat256.Create();
             SM2P256V1Field.Inv(x, z);
             return new SM2P256V1FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
index e9235c2f3..1db449442 100644
--- a/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP128R1FieldElement.cs
@@ -115,7 +115,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-    //        return new SecP128R1FieldElement(toBigInteger().modInverse(Q));
             uint[] z = Nat128.Create();
             SecP128R1Field.Inv(x, z);
             return new SecP128R1FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
index 4876fafa9..a4307cbaf 100644
--- a/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP160R1FieldElement.cs
@@ -115,7 +115,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-    //        return new SecP160R1FieldElement(ToBigInteger().modInverse(Q));
             uint[] z = Nat160.Create();
             SecP160R1Field.Inv(x, z);
             return new SecP160R1FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
index 795fe3b2e..9237c0778 100644
--- a/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP160R2FieldElement.cs
@@ -115,7 +115,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-    //        return new SecP160R2FieldElement(ToBigInteger().modInverse(Q));
             uint[] z = Nat160.Create();
             SecP160R2Field.Inv(x, z);
             return new SecP160R2FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
index c933ffc8d..a37bc1539 100644
--- a/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192K1FieldElement.cs
@@ -116,7 +116,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            //return new SecP192K1FieldElement(ToBigInteger().ModInverse(Q));
             uint[] z = Nat192.Create();
             SecP192K1Field.Inv(x, z);
             return new SecP192K1FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
index e61c2251b..a8c7ae83c 100644
--- a/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP192R1FieldElement.cs
@@ -115,7 +115,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            //return new SecP192R1FieldElement(ToBigInteger().ModInverse(Q));
             uint[] z = Nat192.Create();
             SecP192R1Field.Inv(x, z);
             return new SecP192R1FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
index eb740419f..24de7112a 100644
--- a/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224K1FieldElement.cs
@@ -120,7 +120,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            //return new SecP224K1FieldElement(ToBigInteger().ModInverse(Q));
             uint[] z = Nat224.Create();
             SecP224K1Field.Inv(x, z);
             return new SecP224K1FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
index bb60edaf6..e53f44164 100644
--- a/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP224R1FieldElement.cs
@@ -1,6 +1,7 @@
 using System;
 
 using Org.BouncyCastle.Math.Raw;
+using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Encoders;
 
@@ -115,7 +116,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            //return new SecP224R1FieldElement(ToBigInteger().ModInverse(Q));
             uint[] z = Nat224.Create();
             SecP224R1Field.Inv(x, z);
             return new SecP224R1FieldElement(z);
@@ -134,7 +134,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             uint[] nc = Nat224.Create();
             SecP224R1Field.Negate(c, nc);
 
-            uint[] r = Mod.Random(SecP224R1Field.P);
+            uint[] r = Mod.Random(SecureRandom.ArbitraryRandom, SecP224R1Field.P);
             uint[] t = Nat224.Create();
 
             if (!IsSquare(c))
diff --git a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
index 2bb83d5e9..055df0d06 100644
--- a/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256K1FieldElement.cs
@@ -115,7 +115,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            //return new SecP256K1FieldElement(ToBigInteger().ModInverse(Q));
             uint[] z = Nat256.Create();
             SecP256K1Field.Inv(x, z);
             return new SecP256K1FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
index 928461ec6..e09cd8c8d 100644
--- a/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP256R1FieldElement.cs
@@ -115,7 +115,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            //return new SecP256R1FieldElement(ToBigInteger().ModInverse(Q));
             uint[] z = Nat256.Create();
             SecP256R1Field.Inv(x, z);
             return new SecP256R1FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
index d190c4ae9..33f251b76 100644
--- a/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP384R1FieldElement.cs
@@ -115,7 +115,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            //return new SecP384R1FieldElement(ToBigInteger().ModInverse(Q));
             uint[] z = Nat.Create(12);
             SecP384R1Field.Inv(x, z);
             return new SecP384R1FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
index 409352586..1169d41a9 100644
--- a/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecP521R1FieldElement.cs
@@ -115,7 +115,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            //return new SecP521R1FieldElement(ToBigInteger().ModInverse(Q));
             uint[] z = Nat.Create(17);
             SecP521R1Field.Inv(x, z);
             return new SecP521R1FieldElement(z);
diff --git a/crypto/src/math/ec/custom/sec/SecT571Field.cs b/crypto/src/math/ec/custom/sec/SecT571Field.cs
index 5a393409a..49eaae2d4 100644
--- a/crypto/src/math/ec/custom/sec/SecT571Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571Field.cs
@@ -19,18 +19,12 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public static void Add(ulong[] x, ulong[] y, ulong[] z)
         {
-            for (int i = 0; i < 9; ++i)
-            {
-                z[i] = x[i] ^ y[i]; 
-            }
+            Nat.Xor64(9, x, y, z);
         }
 
         private static void Add(ulong[] x, int xOff, ulong[] y, int yOff, ulong[] z, int zOff)
         {
-            for (int i = 0; i < 9; ++i)
-            {
-                z[zOff + i] = x[xOff + i] ^ y[yOff + i];
-            }
+            Nat.Xor64(9, x, xOff, y, yOff, z, zOff);
         }
 
         public static void AddBothTo(ulong[] x, ulong[] y, ulong[] z)
@@ -51,10 +45,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public static void AddExt(ulong[] xx, ulong[] yy, ulong[] zz)
         {
-            for (int i = 0; i < 18; ++i)
-            {
-                zz[i] = xx[i] ^ yy[i]; 
-            }
+            Nat.Xor64(18, xx, yy, zz);
         }
 
         public static void AddOne(ulong[] x, ulong[] z)
@@ -68,10 +59,7 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         private static void AddTo(ulong[] x, ulong[] z)
         {
-            for (int i = 0; i < 9; ++i)
-            {
-                z[i] ^= x[i];
-            }
+            Nat.XorTo64(9, x, z);
         }
 
         public static ulong[] FromBigInteger(BigInteger x)
diff --git a/crypto/src/math/raw/Mod.cs b/crypto/src/math/raw/Mod.cs
index ea61bdd83..721134b0c 100644
--- a/crypto/src/math/raw/Mod.cs
+++ b/crypto/src/math/raw/Mod.cs
@@ -12,10 +12,8 @@ namespace Org.BouncyCastle.Math.Raw
      * computation and modular inversion" by Daniel J. Bernstein and Bo-Yin Yang.
      */
 
-    internal abstract class Mod
+    internal static class Mod
     {
-        private static readonly SecureRandom RandomSource = new SecureRandom();
-
         private const int M30 = 0x3FFFFFFF;
         private const ulong M32UL = 0xFFFFFFFFUL;
 
@@ -41,7 +39,7 @@ namespace Org.BouncyCastle.Math.Raw
 
         public static uint Inverse32(uint d)
         {
-            Debug.Assert((d & 1) == 1);
+            Debug.Assert((d & 1U) == 1U);
 
             //int x = d + (((d + 1) & 4) << 1);   // d.x == 1 mod 2**4
             uint x = d;                         // d.x == 1 mod 2**3
@@ -53,6 +51,21 @@ namespace Org.BouncyCastle.Math.Raw
             return x;
         }
 
+        public static ulong Inverse64(ulong d)
+        {
+            Debug.Assert((d & 1UL) == 1UL);
+
+            //ulong x = d + (((d + 1) & 4) << 1);   // d.x == 1 mod 2**4
+            ulong x = d;                            // d.x == 1 mod 2**3
+            x *= 2 - d * x;                         // d.x == 1 mod 2**6
+            x *= 2 - d * x;                         // d.x == 1 mod 2**12
+            x *= 2 - d * x;                         // d.x == 1 mod 2**24
+            x *= 2 - d * x;                         // d.x == 1 mod 2**48
+            x *= 2 - d * x;                         // d.x == 1 mod 2**96
+            Debug.Assert(d * x == 1UL);
+            return x;
+        }
+
         public static uint ModOddInverse(uint[] m, uint[] x, uint[] z)
         {
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
@@ -349,7 +362,7 @@ namespace Org.BouncyCastle.Math.Raw
         }
 #endif
 
-        public static uint[] Random(uint[] p)
+        public static uint[] Random(SecureRandom random, uint[] p)
         {
             int len = p.Length;
             uint[] s = Nat.Create(len);
@@ -364,7 +377,7 @@ namespace Org.BouncyCastle.Math.Raw
             byte[] bytes = new byte[len << 2];
             do
             {
-                RandomSource.NextBytes(bytes);
+                random.NextBytes(bytes);
                 Pack.BE_To_UInt32(bytes, 0, s);
                 s[len - 1] &= m;
             }
@@ -374,7 +387,7 @@ namespace Org.BouncyCastle.Math.Raw
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        public static void Random(ReadOnlySpan<uint> p, Span<uint> z)
+        public static void Random(SecureRandom random, ReadOnlySpan<uint> p, Span<uint> z)
         {
             int len = p.Length;
             if (z.Length < len)
@@ -395,7 +408,7 @@ namespace Org.BouncyCastle.Math.Raw
 
             do
             {
-                RandomSource.NextBytes(bytes);
+                random.NextBytes(bytes);
                 Pack.BE_To_UInt32(bytes, s);
                 s[len - 1] &= m;
             }
diff --git a/crypto/src/math/raw/Nat.cs b/crypto/src/math/raw/Nat.cs
index 09c263f4d..3bc983430 100644
--- a/crypto/src/math/raw/Nat.cs
+++ b/crypto/src/math/raw/Nat.cs
@@ -1580,34 +1580,87 @@ namespace Org.BouncyCastle.Math.Raw
 
         public static uint ShiftUpBit(int len, uint[] z, uint c)
         {
-            for (int i = 0; i < len; ++i)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBit(len, z.AsSpan(0, len), c);
+#else
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = z[i + 0];
+                uint next1 = z[i + 1];
+                uint next2 = z[i + 2];
+                uint next3 = z[i + 3];
+                z[i + 0] = (next0 << 1) | (c     >> 31);
+                z[i + 1] = (next1 << 1) | (next0 >> 31);
+                z[i + 2] = (next2 << 1) | (next1 >> 31);
+                z[i + 3] = (next3 << 1) | (next2 >> 31);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = z[i];
                 z[i] = (next << 1) | (c >> 31);
                 c = next;
+                ++i;
             }
             return c >> 31;
+#endif
         }
 
         public static uint ShiftUpBit(int len, uint[] z, int zOff, uint c)
         {
-            for (int i = 0; i < len; ++i)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBit(len, z.AsSpan(zOff, len), c);
+#else
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = z[zOff + i + 0];
+                uint next1 = z[zOff + i + 1];
+                uint next2 = z[zOff + i + 2];
+                uint next3 = z[zOff + i + 3];
+                z[zOff + i + 0] = (next0 << 1) | (c     >> 31);
+                z[zOff + i + 1] = (next1 << 1) | (next0 >> 31);
+                z[zOff + i + 2] = (next2 << 1) | (next1 >> 31);
+                z[zOff + i + 3] = (next3 << 1) | (next2 >> 31);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = z[zOff + i];
                 z[zOff + i] = (next << 1) | (c >> 31);
                 c = next;
+                ++i;
             }
             return c >> 31;
+#endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public static uint ShiftUpBit(int len, Span<uint> z, uint c)
         {
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = z[i + 0];
+                uint next1 = z[i + 1];
+                uint next2 = z[i + 2];
+                uint next3 = z[i + 3];
+                z[i + 0] = (next0 << 1) | (c     >> 31);
+                z[i + 1] = (next1 << 1) | (next0 >> 31);
+                z[i + 2] = (next2 << 1) | (next1 >> 31);
+                z[i + 3] = (next3 << 1) | (next2 >> 31);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = z[i];
                 z[i] = (next << 1) | (c >> 31);
                 c = next;
+                ++i;
             }
             return c >> 31;
         }
@@ -1615,34 +1668,87 @@ namespace Org.BouncyCastle.Math.Raw
 
         public static uint ShiftUpBit(int len, uint[] x, uint c, uint[] z)
         {
-            for (int i = 0; i < len; ++i)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBit(len, x.AsSpan(0, len), c, z.AsSpan(0, len));
+#else
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = x[i + 0];
+                uint next1 = x[i + 1];
+                uint next2 = x[i + 2];
+                uint next3 = x[i + 3];
+                z[i + 0] = (next0 << 1) | (c     >> 31);
+                z[i + 1] = (next1 << 1) | (next0 >> 31);
+                z[i + 2] = (next2 << 1) | (next1 >> 31);
+                z[i + 3] = (next3 << 1) | (next2 >> 31);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = x[i];
                 z[i] = (next << 1) | (c >> 31);
                 c = next;
+                ++i;
             }
             return c >> 31;
+#endif
         }
 
         public static uint ShiftUpBit(int len, uint[] x, int xOff, uint c, uint[] z, int zOff)
         {
-            for (int i = 0; i < len; ++i)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBit(len, x.AsSpan(xOff, len), c, z.AsSpan(zOff, len));
+#else
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = x[xOff + i + 0];
+                uint next1 = x[xOff + i + 1];
+                uint next2 = x[xOff + i + 2];
+                uint next3 = x[xOff + i + 3];
+                z[zOff + i + 0] = (next0 << 1) | (c     >> 31);
+                z[zOff + i + 1] = (next1 << 1) | (next0 >> 31);
+                z[zOff + i + 2] = (next2 << 1) | (next1 >> 31);
+                z[zOff + i + 3] = (next3 << 1) | (next2 >> 31);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = x[xOff + i];
                 z[zOff + i] = (next << 1) | (c >> 31);
                 c = next;
+                ++i;
             }
             return c >> 31;
+#endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public static uint ShiftUpBit(int len, ReadOnlySpan<uint> x, uint c, Span<uint> z)
         {
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = x[i + 0];
+                uint next1 = x[i + 1];
+                uint next2 = x[i + 2];
+                uint next3 = x[i + 3];
+                z[i + 0] = (next0 << 1) | (c     >> 31);
+                z[i + 1] = (next1 << 1) | (next0 >> 31);
+                z[i + 2] = (next2 << 1) | (next1 >> 31);
+                z[i + 3] = (next3 << 1) | (next2 >> 31);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = x[i];
                 z[i] = (next << 1) | (c >> 31);
                 c = next;
+                ++i;
             }
             return c >> 31;
         }
@@ -1650,34 +1756,87 @@ namespace Org.BouncyCastle.Math.Raw
 
         public static ulong ShiftUpBit64(int len, ulong[] x, ulong c, ulong[] z)
         {
-            for (int i = 0; i < len; ++i)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBit64(len, x.AsSpan(0, len), c, z.AsSpan(0, len));
+#else
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                ulong next0 = x[i + 0];
+                ulong next1 = x[i + 1];
+                ulong next2 = x[i + 2];
+                ulong next3 = x[i + 3];
+                z[i + 0] = (next0 << 1) | (c     >> 63);
+                z[i + 1] = (next1 << 1) | (next0 >> 63);
+                z[i + 2] = (next2 << 1) | (next1 >> 63);
+                z[i + 3] = (next3 << 1) | (next2 >> 63);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 ulong next = x[i];
                 z[i] = (next << 1) | (c >> 63);
                 c = next;
+                ++i;
             }
             return c >> 63;
+#endif
         }
 
         public static ulong ShiftUpBit64(int len, ulong[] x, int xOff, ulong c, ulong[] z, int zOff)
         {
-            for (int i = 0; i < len; ++i)
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBit64(len, x.AsSpan(xOff, len), c, z.AsSpan(zOff, len));
+#else
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                ulong next0 = x[xOff + i + 0];
+                ulong next1 = x[xOff + i + 1];
+                ulong next2 = x[xOff + i + 2];
+                ulong next3 = x[xOff + i + 3];
+                z[zOff + i + 0] = (next0 << 1) | (c     >> 63);
+                z[zOff + i + 1] = (next1 << 1) | (next0 >> 63);
+                z[zOff + i + 2] = (next2 << 1) | (next1 >> 63);
+                z[zOff + i + 3] = (next3 << 1) | (next2 >> 63);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 ulong next = x[xOff + i];
                 z[zOff + i] = (next << 1) | (c >> 63);
                 c = next;
+                ++i;
             }
             return c >> 63;
+#endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public static ulong ShiftUpBit64(int len, ReadOnlySpan<ulong> x, ulong c, Span<ulong> z)
         {
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                ulong next0 = x[i + 0];
+                ulong next1 = x[i + 1];
+                ulong next2 = x[i + 2];
+                ulong next3 = x[i + 3];
+                z[i + 0] = (next0 << 1) | (c     >> 63);
+                z[i + 1] = (next1 << 1) | (next0 >> 63);
+                z[i + 2] = (next2 << 1) | (next1 >> 63);
+                z[i + 3] = (next3 << 1) | (next2 >> 63);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 ulong next = x[i];
                 z[i] = (next << 1) | (c >> 63);
                 c = next;
+                ++i;
             }
             return c >> 63;
         }
@@ -1685,37 +1844,90 @@ namespace Org.BouncyCastle.Math.Raw
 
         public static uint ShiftUpBits(int len, uint[] z, int bits, uint c)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBits(len, z.AsSpan(0, len), bits, c);
+#else
             Debug.Assert(bits > 0 && bits < 32);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = z[i + 0];
+                uint next1 = z[i + 1];
+                uint next2 = z[i + 2];
+                uint next3 = z[i + 3];
+                z[i + 0] = (next0 << bits) | (c     >> -bits);
+                z[i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = z[i];
                 z[i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
+#endif
         }
 
         public static uint ShiftUpBits(int len, uint[] z, int zOff, int bits, uint c)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBits(len, z.AsSpan(zOff, len), bits, c);
+#else
             Debug.Assert(bits > 0 && bits < 32);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = z[zOff + i + 0];
+                uint next1 = z[zOff + i + 1];
+                uint next2 = z[zOff + i + 2];
+                uint next3 = z[zOff + i + 3];
+                z[zOff + i + 0] = (next0 << bits) | (c     >> -bits);
+                z[zOff + i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[zOff + i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[zOff + i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = z[zOff + i];
                 z[zOff + i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
+#endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public static uint ShiftUpBits(int len, Span<uint> z, int bits, uint c)
         {
             Debug.Assert(bits > 0 && bits < 32);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = z[i + 0];
+                uint next1 = z[i + 1];
+                uint next2 = z[i + 2];
+                uint next3 = z[i + 3];
+                z[i + 0] = (next0 << bits) | (c     >> -bits);
+                z[i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = z[i];
                 z[i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
         }
@@ -1723,37 +1935,90 @@ namespace Org.BouncyCastle.Math.Raw
 
         public static uint ShiftUpBits(int len, uint[] x, int bits, uint c, uint[] z)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBits(len, x.AsSpan(0, len), bits, c, z.AsSpan(0, len));
+#else
             Debug.Assert(bits > 0 && bits < 32);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = x[i + 0];
+                uint next1 = x[i + 1];
+                uint next2 = x[i + 2];
+                uint next3 = x[i + 3];
+                z[i + 0] = (next0 << bits) | (c     >> -bits);
+                z[i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = x[i];
                 z[i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
+#endif
         }
 
         public static uint ShiftUpBits(int len, uint[] x, int xOff, int bits, uint c, uint[] z, int zOff)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBits(len, x.AsSpan(xOff, len), bits, c, z.AsSpan(zOff, len));
+#else
             Debug.Assert(bits > 0 && bits < 32);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = x[xOff + i + 0];
+                uint next1 = x[xOff + i + 1];
+                uint next2 = x[xOff + i + 2];
+                uint next3 = x[xOff + i + 3];
+                z[zOff + i + 0] = (next0 << bits) | (c     >> -bits);
+                z[zOff + i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[zOff + i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[zOff + i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = x[xOff + i];
                 z[zOff + i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
+#endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public static uint ShiftUpBits(int len, ReadOnlySpan<uint> x, int bits, uint c, Span<uint> z)
         {
             Debug.Assert(bits > 0 && bits < 32);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                uint next0 = x[i + 0];
+                uint next1 = x[i + 1];
+                uint next2 = x[i + 2];
+                uint next3 = x[i + 3];
+                z[i + 0] = (next0 << bits) | (c     >> -bits);
+                z[i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 uint next = x[i];
                 z[i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
         }
@@ -1761,37 +2026,90 @@ namespace Org.BouncyCastle.Math.Raw
 
         public static ulong ShiftUpBits64(int len, ulong[] z, int bits, ulong c)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBits64(len, z.AsSpan(0, len), bits, c);
+#else
             Debug.Assert(bits > 0 && bits < 64);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                ulong next0 = z[i + 0];
+                ulong next1 = z[i + 1];
+                ulong next2 = z[i + 2];
+                ulong next3 = z[i + 3];
+                z[i + 0] = (next0 << bits) | (c     >> -bits);
+                z[i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 ulong next = z[i];
                 z[i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
+#endif
         }
 
         public static ulong ShiftUpBits64(int len, ulong[] z, int zOff, int bits, ulong c)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBits64(len, z.AsSpan(zOff, len), bits, c);
+#else
             Debug.Assert(bits > 0 && bits < 64);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                ulong next0 = z[zOff + i + 0];
+                ulong next1 = z[zOff + i + 1];
+                ulong next2 = z[zOff + i + 2];
+                ulong next3 = z[zOff + i + 3];
+                z[zOff + i + 0] = (next0 << bits) | (c     >> -bits);
+                z[zOff + i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[zOff + i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[zOff + i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 ulong next = z[zOff + i];
                 z[zOff + i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
+#endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public static ulong ShiftUpBits64(int len, Span<ulong> z, int bits, ulong c)
         {
             Debug.Assert(bits > 0 && bits < 64);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                ulong next0 = z[i + 0];
+                ulong next1 = z[i + 1];
+                ulong next2 = z[i + 2];
+                ulong next3 = z[i + 3];
+                z[i + 0] = (next0 << bits) | (c     >> -bits);
+                z[i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 ulong next = z[i];
                 z[i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
         }
@@ -1799,37 +2117,90 @@ namespace Org.BouncyCastle.Math.Raw
 
         public static ulong ShiftUpBits64(int len, ulong[] x, int bits, ulong c, ulong[] z)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBits64(len, x.AsSpan(0, len), bits, c, z.AsSpan(0, len));
+#else
             Debug.Assert(bits > 0 && bits < 64);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                ulong next0 = x[i + 0];
+                ulong next1 = x[i + 1];
+                ulong next2 = x[i + 2];
+                ulong next3 = x[i + 3];
+                z[i + 0] = (next0 << bits) | (c     >> -bits);
+                z[i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 ulong next = x[i];
                 z[i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
+#endif
         }
 
         public static ulong ShiftUpBits64(int len, ulong[] x, int xOff, int bits, ulong c, ulong[] z, int zOff)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return ShiftUpBits64(len, x.AsSpan(xOff, len), bits, c, z.AsSpan(zOff, len));
+#else
             Debug.Assert(bits > 0 && bits < 64);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                ulong next0 = x[xOff + i + 0];
+                ulong next1 = x[xOff + i + 1];
+                ulong next2 = x[xOff + i + 2];
+                ulong next3 = x[xOff + i + 3];
+                z[zOff + i + 0] = (next0 << bits) | (c     >> -bits);
+                z[zOff + i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[zOff + i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[zOff + i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 ulong next = x[xOff + i];
                 z[zOff + i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
+#endif
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public static ulong ShiftUpBits64(int len, ReadOnlySpan<ulong> x, int bits, ulong c, Span<ulong> z)
         {
             Debug.Assert(bits > 0 && bits < 64);
-            for (int i = 0; i < len; ++i)
+            int i = 0, limit4 = len - 4;
+            while (i <= limit4)
+            {
+                ulong next0 = x[i + 0];
+                ulong next1 = x[i + 1];
+                ulong next2 = x[i + 2];
+                ulong next3 = x[i + 3];
+                z[i + 0] = (next0 << bits) | (c     >> -bits);
+                z[i + 1] = (next1 << bits) | (next0 >> -bits);
+                z[i + 2] = (next2 << bits) | (next1 >> -bits);
+                z[i + 3] = (next3 << bits) | (next2 >> -bits);
+                c = next3;
+                i += 4;
+            }
+            while (i < len)
             {
                 ulong next = x[i];
                 z[i] = (next << bits) | (c >> -bits);
                 c = next;
+                ++i;
             }
             return c >> -bits;
         }
@@ -2325,39 +2696,205 @@ namespace Org.BouncyCastle.Math.Raw
         }
 #endif
 
-        public static void Zero(int len, uint[] z)
+        public static void Xor(int len, uint[] x, uint[] y, uint[] z)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Xor(len, x.AsSpan(0, len), y.AsSpan(0, len), z.AsSpan(0, len));
+#else
             for (int i = 0; i < len; ++i)
             {
-                z[i] = 0U;
+                z[i] = x[i] ^ y[i];
             }
+#endif
         }
 
+        public static void Xor(int len, uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        public static void Zero(int len, Span<uint> z)
+            Xor(len, x.AsSpan(xOff, len), y.AsSpan(yOff, len), z.AsSpan(zOff, len));
+#else
+            for (int i = 0; i < len; ++i)
+            {
+                z[zOff + i] = x[xOff + i] ^ y[yOff + i];
+            }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void Xor(int len, ReadOnlySpan<uint> x, ReadOnlySpan<uint> y, Span<uint> z)
+        {
+            int i = 0, limit16 = len - 16;
+            while (i <= limit16)
+            {
+                Nat512.Xor(x[i..], y[i..], z[i..]);
+                i += 16;
+            }
+            while (i < len)
+            {
+                z[i] = x[i] ^ y[i];
+                ++i;
+            }
+        }
+#endif
+
+        public static void Xor64(int len, ulong[] x, ulong[] y, ulong[] z)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Xor64(len, x.AsSpan(0, len), y.AsSpan(0, len), z.AsSpan(0, len));
+#else
             for (int i = 0; i < len; ++i)
             {
-                z[i] = 0U;
+                z[i] = x[i] ^ y[i];
+            }
+#endif
+        }
+
+        public static void Xor64(int len, ulong[] x, int xOff, ulong[] y, int yOff, ulong[] z, int zOff)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Xor64(len, x.AsSpan(xOff, len), y.AsSpan(yOff, len), z.AsSpan(zOff, len));
+#else
+            for (int i = 0; i < len; ++i)
+            {
+                z[zOff + i] = x[xOff + i] ^ y[yOff + i];
+            }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void Xor64(int len, ReadOnlySpan<ulong> x, ReadOnlySpan<ulong> y, Span<ulong> z)
+        {
+            int i = 0, limit8 = len - 8;
+            while (i <= limit8)
+            {
+                Nat512.Xor64(x[i..], y[i..], z[i..]);
+                i += 8;
+            }
+            while (i < len)
+            {
+                z[i] = x[i] ^ y[i];
+                ++i;
             }
         }
 #endif
 
-        public static void Zero64(int len, ulong[] z)
+        public static void XorTo(int len, uint[] x, uint[] z)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            XorTo(len, x.AsSpan(0, len), z.AsSpan(0, len));
+#else
             for (int i = 0; i < len; ++i)
             {
-                z[i] = 0UL;
+                z[i] ^= x[i];
             }
+#endif
         }
 
+        public static void XorTo(int len, uint[] x, int xOff, uint[] z, int zOff)
+        {
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-        public static void Zero64(int len, Span<ulong> z)
+            XorTo(len, x.AsSpan(xOff, len), z.AsSpan(zOff, len));
+#else
+            for (int i = 0; i < len; ++i)
+            {
+                z[zOff + i] ^= x[xOff + i];
+            }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void XorTo(int len, ReadOnlySpan<uint> x, Span<uint> z)
+        {
+            int i = 0, limit16 = len - 16;
+            while (i <= limit16)
+            {
+                Nat512.XorTo(x[i..], z[i..]);
+                i += 16;
+            }
+            while (i < len)
+            {
+                z[i] ^= x[i];
+                ++i;
+            }
+        }
+#endif
+
+        public static void XorTo64(int len, ulong[] x, ulong[] z)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            XorTo64(len, x.AsSpan(0, len), z.AsSpan(0, len));
+#else
+            for (int i = 0; i < len; ++i)
+            {
+                z[i] ^= x[i];
+            }
+#endif
+        }
+
+        public static void XorTo64(int len, ulong[] x, int xOff, ulong[] z, int zOff)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            XorTo64(len, x.AsSpan(xOff, len), z.AsSpan(zOff, len));
+#else
+            for (int i = 0; i < len; ++i)
+            {
+                z[zOff + i] ^= x[xOff + i];
+            }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void XorTo64(int len, ReadOnlySpan<ulong> x, Span<ulong> z)
+        {
+            int i = 0, limit8 = len - 8;
+            while (i <= limit8)
+            {
+                Nat512.XorTo64(x[i..], z[i..]);
+                i += 8;
+            }
+            while (i < len)
+            {
+                z[i] ^= x[i];
+                ++i;
+            }
+        }
+#endif
+
+        public static void Zero(int len, uint[] z)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            z.AsSpan(0, len).Fill(0U);
+#else
+            for (int i = 0; i < len; ++i)
+            {
+                z[i] = 0U;
+            }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void Zero(int len, Span<uint> z)
+        {
+            z[..len].Fill(0U);
+        }
+#endif
+
+        public static void Zero64(int len, ulong[] z)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            z.AsSpan(0, len).Fill(0UL);
+#else
             for (int i = 0; i < len; ++i)
             {
                 z[i] = 0UL;
             }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void Zero64(int len, Span<ulong> z)
+        {
+            z[..len].Fill(0UL);
         }
 #endif
     }
diff --git a/crypto/src/math/raw/Nat256.cs b/crypto/src/math/raw/Nat256.cs
index 710060bee..47e0644f6 100644
--- a/crypto/src/math/raw/Nat256.cs
+++ b/crypto/src/math/raw/Nat256.cs
@@ -1,5 +1,11 @@
 using System;
 using System.Diagnostics;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 using Org.BouncyCastle.Crypto.Utilities;
 
@@ -1364,6 +1370,71 @@ namespace Org.BouncyCastle.Math.Raw
             return new BigInteger(1, bs);
         }
 
+        public static void Xor(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Xor(x.AsSpan(xOff), y.AsSpan(yOff), z.AsSpan(zOff));
+#else
+            for (int i = 0; i < 8; i += 4)
+            {
+                z[zOff + i + 0] = x[xOff + i + 0] ^ y[yOff + i + 0];
+                z[zOff + i + 1] = x[xOff + i + 1] ^ y[yOff + i + 1];
+                z[zOff + i + 2] = x[xOff + i + 2] ^ y[yOff + i + 2];
+                z[zOff + i + 3] = x[xOff + i + 3] ^ y[yOff + i + 3];
+            }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void Xor(ReadOnlySpan<uint> x, ReadOnlySpan<uint> y, Span<uint> z)
+        {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Avx2.IsSupported && Unsafe.SizeOf<Vector256<byte>>() == 32)
+            {
+                var X = MemoryMarshal.AsBytes(x[..8]);
+                var Y = MemoryMarshal.AsBytes(y[..8]);
+                var Z = MemoryMarshal.AsBytes(z[..8]);
+
+                var X0 = MemoryMarshal.Read<Vector256<byte>>(X[0x00..0x20]);
+                var Y0 = MemoryMarshal.Read<Vector256<byte>>(Y[0x00..0x20]);
+
+                var Z0 = Avx2.Xor(X0, Y0);
+
+                MemoryMarshal.Write(Z[0x00..0x20], ref Z0);
+                return;
+            }
+
+            if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == 16)
+            {
+                var X = MemoryMarshal.AsBytes(x[..8]);
+                var Y = MemoryMarshal.AsBytes(y[..8]);
+                var Z = MemoryMarshal.AsBytes(z[..8]);
+
+                var X0 = MemoryMarshal.Read<Vector128<byte>>(X[0x00..0x10]);
+                var X1 = MemoryMarshal.Read<Vector128<byte>>(X[0x10..0x20]);
+
+                var Y0 = MemoryMarshal.Read<Vector128<byte>>(Y[0x00..0x10]);
+                var Y1 = MemoryMarshal.Read<Vector128<byte>>(Y[0x10..0x20]);
+
+                var Z0 = Sse2.Xor(X0, Y0);
+                var Z1 = Sse2.Xor(X1, Y1);
+
+                MemoryMarshal.Write(Z[0x00..0x10], ref Z0);
+                MemoryMarshal.Write(Z[0x10..0x20], ref Z1);
+                return;
+            }
+#endif
+
+            for (int i = 0; i < 8; i += 4)
+            {
+                z[i + 0] = x[i + 0] ^ y[i + 0];
+                z[i + 1] = x[i + 1] ^ y[i + 1];
+                z[i + 2] = x[i + 2] ^ y[i + 2];
+                z[i + 3] = x[i + 3] ^ y[i + 3];
+            }
+        }
+#endif
+
         public static void Zero(uint[] z)
         {
             z[0] = 0;
diff --git a/crypto/src/math/raw/Nat512.cs b/crypto/src/math/raw/Nat512.cs
index a9ef2b3b6..2312e1cf2 100644
--- a/crypto/src/math/raw/Nat512.cs
+++ b/crypto/src/math/raw/Nat512.cs
@@ -1,5 +1,10 @@
 using System;
-using System.Diagnostics;
+#if NETCOREAPP3_0_OR_GREATER
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+#endif
 
 namespace Org.BouncyCastle.Math.Raw
 {
@@ -42,5 +47,313 @@ namespace Org.BouncyCastle.Math.Raw
             c24 += (uint)Nat.SubFrom(16, m, 0, zz, 8);
             Nat.AddWordAt(32, c24, zz, 24); 
         }
+
+        public static void Xor(uint[] x, int xOff, uint[] y, int yOff, uint[] z, int zOff)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Xor(x.AsSpan(xOff), y.AsSpan(yOff), z.AsSpan(zOff));
+#else
+            for (int i = 0; i < 16; i += 4)
+            {
+                z[zOff + i + 0] = x[xOff + i + 0] ^ y[yOff + i + 0];
+                z[zOff + i + 1] = x[xOff + i + 1] ^ y[yOff + i + 1];
+                z[zOff + i + 2] = x[xOff + i + 2] ^ y[yOff + i + 2];
+                z[zOff + i + 3] = x[xOff + i + 3] ^ y[yOff + i + 3];
+            }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void Xor(ReadOnlySpan<uint> x, ReadOnlySpan<uint> y, Span<uint> z)
+        {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Avx2.IsSupported && Unsafe.SizeOf<Vector256<byte>>() == 32)
+            {
+                var X = MemoryMarshal.AsBytes(x[..16]);
+                var Y = MemoryMarshal.AsBytes(y[..16]);
+                var Z = MemoryMarshal.AsBytes(z[..16]);
+
+                var X0 = MemoryMarshal.Read<Vector256<byte>>(X[0x00..0x20]);
+                var X1 = MemoryMarshal.Read<Vector256<byte>>(X[0x20..0x40]);
+
+                var Y0 = MemoryMarshal.Read<Vector256<byte>>(Y[0x00..0x20]);
+                var Y1 = MemoryMarshal.Read<Vector256<byte>>(Y[0x20..0x40]);
+
+                var Z0 = Avx2.Xor(X0, Y0);
+                var Z1 = Avx2.Xor(X1, Y1);
+
+                MemoryMarshal.Write(Z[0x00..0x20], ref Z0);
+                MemoryMarshal.Write(Z[0x20..0x40], ref Z1);
+                return;
+            }
+
+            if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == 16)
+            {
+                var X = MemoryMarshal.AsBytes(x[..16]);
+                var Y = MemoryMarshal.AsBytes(y[..16]);
+                var Z = MemoryMarshal.AsBytes(z[..16]);
+
+                var X0 = MemoryMarshal.Read<Vector128<byte>>(X[0x00..0x10]);
+                var X1 = MemoryMarshal.Read<Vector128<byte>>(X[0x10..0x20]);
+                var X2 = MemoryMarshal.Read<Vector128<byte>>(X[0x20..0x30]);
+                var X3 = MemoryMarshal.Read<Vector128<byte>>(X[0x30..0x40]);
+
+                var Y0 = MemoryMarshal.Read<Vector128<byte>>(Y[0x00..0x10]);
+                var Y1 = MemoryMarshal.Read<Vector128<byte>>(Y[0x10..0x20]);
+                var Y2 = MemoryMarshal.Read<Vector128<byte>>(Y[0x20..0x30]);
+                var Y3 = MemoryMarshal.Read<Vector128<byte>>(Y[0x30..0x40]);
+
+                var Z0 = Sse2.Xor(X0, Y0);
+                var Z1 = Sse2.Xor(X1, Y1);
+                var Z2 = Sse2.Xor(X2, Y2);
+                var Z3 = Sse2.Xor(X3, Y3);
+
+                MemoryMarshal.Write(Z[0x00..0x10], ref Z0);
+                MemoryMarshal.Write(Z[0x10..0x20], ref Z1);
+                MemoryMarshal.Write(Z[0x20..0x30], ref Z2);
+                MemoryMarshal.Write(Z[0x30..0x40], ref Z3);
+                return;
+            }
+#endif
+
+            for (int i = 0; i < 16; i += 4)
+            {
+                z[i + 0] = x[i + 0] ^ y[i + 0];
+                z[i + 1] = x[i + 1] ^ y[i + 1];
+                z[i + 2] = x[i + 2] ^ y[i + 2];
+                z[i + 3] = x[i + 3] ^ y[i + 3];
+            }
+        }
+#endif
+
+        public static void XorTo(uint[] x, int xOff, uint[] z, int zOff)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            XorTo(x.AsSpan(xOff), z.AsSpan(zOff));
+#else
+            for (int i = 0; i < 16; i += 4)
+            {
+                z[zOff + i + 0] ^= x[xOff + i + 0];
+                z[zOff + i + 1] ^= x[xOff + i + 1];
+                z[zOff + i + 2] ^= x[xOff + i + 2];
+                z[zOff + i + 3] ^= x[xOff + i + 3];
+            }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void XorTo(ReadOnlySpan<uint> x, Span<uint> z)
+        {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Avx2.IsSupported && Unsafe.SizeOf<Vector256<byte>>() == 32)
+            {
+                var X = MemoryMarshal.AsBytes(x[..16]);
+                var Z = MemoryMarshal.AsBytes(z[..16]);
+
+                var X0 = MemoryMarshal.Read<Vector256<byte>>(X[0x00..0x20]);
+                var X1 = MemoryMarshal.Read<Vector256<byte>>(X[0x20..0x40]);
+
+                var Y0 = MemoryMarshal.Read<Vector256<byte>>(Z[0x00..0x20]);
+                var Y1 = MemoryMarshal.Read<Vector256<byte>>(Z[0x20..0x40]);
+
+                var Z0 = Avx2.Xor(X0, Y0);
+                var Z1 = Avx2.Xor(X1, Y1);
+
+                MemoryMarshal.Write(Z[0x00..0x20], ref Z0);
+                MemoryMarshal.Write(Z[0x20..0x40], ref Z1);
+                return;
+            }
+
+            if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == 16)
+            {
+                var X = MemoryMarshal.AsBytes(x[..16]);
+                var Z = MemoryMarshal.AsBytes(z[..16]);
+
+                var X0 = MemoryMarshal.Read<Vector128<byte>>(X[0x00..0x10]);
+                var X1 = MemoryMarshal.Read<Vector128<byte>>(X[0x10..0x20]);
+                var X2 = MemoryMarshal.Read<Vector128<byte>>(X[0x20..0x30]);
+                var X3 = MemoryMarshal.Read<Vector128<byte>>(X[0x30..0x40]);
+
+                var Y0 = MemoryMarshal.Read<Vector128<byte>>(Z[0x00..0x10]);
+                var Y1 = MemoryMarshal.Read<Vector128<byte>>(Z[0x10..0x20]);
+                var Y2 = MemoryMarshal.Read<Vector128<byte>>(Z[0x20..0x30]);
+                var Y3 = MemoryMarshal.Read<Vector128<byte>>(Z[0x30..0x40]);
+
+                var Z0 = Sse2.Xor(X0, Y0);
+                var Z1 = Sse2.Xor(X1, Y1);
+                var Z2 = Sse2.Xor(X2, Y2);
+                var Z3 = Sse2.Xor(X3, Y3);
+
+                MemoryMarshal.Write(Z[0x00..0x10], ref Z0);
+                MemoryMarshal.Write(Z[0x10..0x20], ref Z1);
+                MemoryMarshal.Write(Z[0x20..0x30], ref Z2);
+                MemoryMarshal.Write(Z[0x30..0x40], ref Z3);
+                return;
+            }
+#endif
+
+            for (int i = 0; i < 16; i += 4)
+            {
+                z[i + 0] ^= x[i + 0];
+                z[i + 1] ^= x[i + 1];
+                z[i + 2] ^= x[i + 2];
+                z[i + 3] ^= x[i + 3];
+            }
+        }
+#endif
+
+        public static void Xor64(ulong[] x, int xOff, ulong[] y, int yOff, ulong[] z, int zOff)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Xor64(x.AsSpan(xOff), y.AsSpan(yOff), z.AsSpan(zOff));
+#else
+            for (int i = 0; i < 8; i += 4)
+            {
+                z[zOff + i + 0] = x[xOff + i + 0] ^ y[yOff + i + 0];
+                z[zOff + i + 1] = x[xOff + i + 1] ^ y[yOff + i + 1];
+                z[zOff + i + 2] = x[xOff + i + 2] ^ y[yOff + i + 2];
+                z[zOff + i + 3] = x[xOff + i + 3] ^ y[yOff + i + 3];
+            }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void Xor64(ReadOnlySpan<ulong> x, ReadOnlySpan<ulong> y, Span<ulong> z)
+        {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Avx2.IsSupported && Unsafe.SizeOf<Vector256<byte>>() == 32)
+            {
+                var X = MemoryMarshal.AsBytes(x[..8]);
+                var Y = MemoryMarshal.AsBytes(y[..8]);
+                var Z = MemoryMarshal.AsBytes(z[..8]);
+
+                var X0 = MemoryMarshal.Read<Vector256<byte>>(X[0x00..0x20]);
+                var X1 = MemoryMarshal.Read<Vector256<byte>>(X[0x20..0x40]);
+
+                var Y0 = MemoryMarshal.Read<Vector256<byte>>(Y[0x00..0x20]);
+                var Y1 = MemoryMarshal.Read<Vector256<byte>>(Y[0x20..0x40]);
+
+                var Z0 = Avx2.Xor(X0, Y0);
+                var Z1 = Avx2.Xor(X1, Y1);
+
+                MemoryMarshal.Write(Z[0x00..0x20], ref Z0);
+                MemoryMarshal.Write(Z[0x20..0x40], ref Z1);
+                return;
+            }
+
+            if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == 16)
+            {
+                var X = MemoryMarshal.AsBytes(x[..8]);
+                var Y = MemoryMarshal.AsBytes(y[..8]);
+                var Z = MemoryMarshal.AsBytes(z[..8]);
+
+                var X0 = MemoryMarshal.Read<Vector128<byte>>(X[0x00..0x10]);
+                var X1 = MemoryMarshal.Read<Vector128<byte>>(X[0x10..0x20]);
+                var X2 = MemoryMarshal.Read<Vector128<byte>>(X[0x20..0x30]);
+                var X3 = MemoryMarshal.Read<Vector128<byte>>(X[0x30..0x40]);
+
+                var Y0 = MemoryMarshal.Read<Vector128<byte>>(Y[0x00..0x10]);
+                var Y1 = MemoryMarshal.Read<Vector128<byte>>(Y[0x10..0x20]);
+                var Y2 = MemoryMarshal.Read<Vector128<byte>>(Y[0x20..0x30]);
+                var Y3 = MemoryMarshal.Read<Vector128<byte>>(Y[0x30..0x40]);
+
+                var Z0 = Sse2.Xor(X0, Y0);
+                var Z1 = Sse2.Xor(X1, Y1);
+                var Z2 = Sse2.Xor(X2, Y2);
+                var Z3 = Sse2.Xor(X3, Y3);
+
+                MemoryMarshal.Write(Z[0x00..0x10], ref Z0);
+                MemoryMarshal.Write(Z[0x10..0x20], ref Z1);
+                MemoryMarshal.Write(Z[0x20..0x30], ref Z2);
+                MemoryMarshal.Write(Z[0x30..0x40], ref Z3);
+                return;
+            }
+#endif
+
+            for (int i = 0; i < 8; i += 4)
+            {
+                z[i + 0] = x[i + 0] ^ y[i + 0];
+                z[i + 1] = x[i + 1] ^ y[i + 1];
+                z[i + 2] = x[i + 2] ^ y[i + 2];
+                z[i + 3] = x[i + 3] ^ y[i + 3];
+            }
+        }
+#endif
+
+        public static void XorTo64(ulong[] x, int xOff, ulong[] z, int zOff)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            XorTo64(x.AsSpan(xOff), z.AsSpan(zOff));
+#else
+            for (int i = 0; i < 8; i += 4)
+            {
+                z[zOff + i + 0] ^= x[xOff + i + 0];
+                z[zOff + i + 1] ^= x[xOff + i + 1];
+                z[zOff + i + 2] ^= x[xOff + i + 2];
+                z[zOff + i + 3] ^= x[xOff + i + 3];
+            }
+#endif
+        }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static void XorTo64(ReadOnlySpan<ulong> x, Span<ulong> z)
+        {
+#if NETCOREAPP3_0_OR_GREATER
+            if (Avx2.IsSupported && Unsafe.SizeOf<Vector256<byte>>() == 32)
+            {
+                var X = MemoryMarshal.AsBytes(x[..8]);
+                var Z = MemoryMarshal.AsBytes(z[..8]);
+
+                var X0 = MemoryMarshal.Read<Vector256<byte>>(X[0x00..0x20]);
+                var X1 = MemoryMarshal.Read<Vector256<byte>>(X[0x20..0x40]);
+
+                var Y0 = MemoryMarshal.Read<Vector256<byte>>(Z[0x00..0x20]);
+                var Y1 = MemoryMarshal.Read<Vector256<byte>>(Z[0x20..0x40]);
+
+                var Z0 = Avx2.Xor(X0, Y0);
+                var Z1 = Avx2.Xor(X1, Y1);
+
+                MemoryMarshal.Write(Z[0x00..0x20], ref Z0);
+                MemoryMarshal.Write(Z[0x20..0x40], ref Z1);
+                return;
+            }
+
+            if (Sse2.IsSupported && Unsafe.SizeOf<Vector128<byte>>() == 16)
+            {
+                var X = MemoryMarshal.AsBytes(x[..8]);
+                var Z = MemoryMarshal.AsBytes(z[..8]);
+
+                var X0 = MemoryMarshal.Read<Vector128<byte>>(X[0x00..0x10]);
+                var X1 = MemoryMarshal.Read<Vector128<byte>>(X[0x10..0x20]);
+                var X2 = MemoryMarshal.Read<Vector128<byte>>(X[0x20..0x30]);
+                var X3 = MemoryMarshal.Read<Vector128<byte>>(X[0x30..0x40]);
+
+                var Y0 = MemoryMarshal.Read<Vector128<byte>>(Z[0x00..0x10]);
+                var Y1 = MemoryMarshal.Read<Vector128<byte>>(Z[0x10..0x20]);
+                var Y2 = MemoryMarshal.Read<Vector128<byte>>(Z[0x20..0x30]);
+                var Y3 = MemoryMarshal.Read<Vector128<byte>>(Z[0x30..0x40]);
+
+                var Z0 = Sse2.Xor(X0, Y0);
+                var Z1 = Sse2.Xor(X1, Y1);
+                var Z2 = Sse2.Xor(X2, Y2);
+                var Z3 = Sse2.Xor(X3, Y3);
+
+                MemoryMarshal.Write(Z[0x00..0x10], ref Z0);
+                MemoryMarshal.Write(Z[0x10..0x20], ref Z1);
+                MemoryMarshal.Write(Z[0x20..0x30], ref Z2);
+                MemoryMarshal.Write(Z[0x30..0x40], ref Z3);
+                return;
+            }
+#endif
+
+            for (int i = 0; i < 8; i += 4)
+            {
+                z[i + 0] ^= x[i + 0];
+                z[i + 1] ^= x[i + 1];
+                z[i + 2] ^= x[i + 2];
+                z[i + 3] ^= x[i + 3];
+            }
+        }
+#endif
     }
 }
diff --git a/crypto/src/ocsp/BasicOCSPRespGenerator.cs b/crypto/src/ocsp/BasicOCSPRespGenerator.cs
index 6cbba997d..ff7ae33d3 100644
--- a/crypto/src/ocsp/BasicOCSPRespGenerator.cs
+++ b/crypto/src/ocsp/BasicOCSPRespGenerator.cs
@@ -9,7 +9,6 @@ using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Operators;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Security.Certificates;
-using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.X509;
 
 namespace Org.BouncyCastle.Ocsp
@@ -28,8 +27,8 @@ namespace Org.BouncyCastle.Ocsp
 		{
 			internal CertificateID         certId;
 			internal CertStatus            certStatus;
-			internal DerGeneralizedTime    thisUpdate;
-			internal DerGeneralizedTime    nextUpdate;
+			internal Asn1GeneralizedTime   thisUpdate;
+			internal Asn1GeneralizedTime   nextUpdate;
 			internal X509Extensions        extensions;
 
 			internal ResponseObject(
@@ -57,7 +56,7 @@ namespace Org.BouncyCastle.Ocsp
 						:	null;
 
 					this.certStatus = new CertStatus(
-						new RevokedInfo(new DerGeneralizedTime(rs.RevocationTime), revocationReason));
+						new RevokedInfo(new Asn1GeneralizedTime(rs.RevocationTime), revocationReason));
 				}
 
 				this.thisUpdate = new DerGeneralizedTime(thisUpdate);
@@ -187,7 +186,7 @@ namespace Org.BouncyCastle.Ocsp
 				}
 			}
 
-			ResponseData tbsResp = new ResponseData(responderID.ToAsn1Object(), new DerGeneralizedTime(producedAt),
+			ResponseData tbsResp = new ResponseData(responderID.ToAsn1Object(), new Asn1GeneralizedTime(producedAt),
 				new DerSequence(responses), responseExtensions);
 			DerBitString bitSig;
 
diff --git a/crypto/src/ocsp/RevokedStatus.cs b/crypto/src/ocsp/RevokedStatus.cs
index edbeb57da..903e50ef5 100644
--- a/crypto/src/ocsp/RevokedStatus.cs
+++ b/crypto/src/ocsp/RevokedStatus.cs
@@ -24,7 +24,7 @@ namespace Org.BouncyCastle.Ocsp
 			DateTime	revocationDate,
 			int			reason)
 		{
-			this.info = new RevokedInfo(new DerGeneralizedTime(revocationDate), new CrlReason(reason));
+			this.info = new RevokedInfo(new Asn1GeneralizedTime(revocationDate), new CrlReason(reason));
 		}
 
 		public DateTime RevocationTime
diff --git a/crypto/src/openpgp/PgpCompressedData.cs b/crypto/src/openpgp/PgpCompressedData.cs
index fc7d200d0..346b0b1a1 100644
--- a/crypto/src/openpgp/PgpCompressedData.cs
+++ b/crypto/src/openpgp/PgpCompressedData.cs
@@ -1,7 +1,6 @@
 using System.IO;
 
-using Org.BouncyCastle.Bzip2;
-using Org.BouncyCastle.Utilities.Zlib;
+using Org.BouncyCastle.Utilities.IO.Compression;
 
 namespace Org.BouncyCastle.Bcpg.OpenPgp
 {
@@ -38,16 +37,16 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         {
             switch (Algorithm)
             {
-				case CompressionAlgorithmTag.Uncompressed:
-					return GetInputStream();
-				case CompressionAlgorithmTag.Zip:
-					return new ZInputStream(GetInputStream(), true);
-                case CompressionAlgorithmTag.ZLib:
-					return new ZInputStream(GetInputStream());
-				case CompressionAlgorithmTag.BZip2:
-					return new CBZip2InputStream(GetInputStream());
-                default:
-                    throw new PgpException("can't recognise compression algorithm: " + Algorithm);
+			case CompressionAlgorithmTag.Uncompressed:
+				return GetInputStream();
+			case CompressionAlgorithmTag.Zip:
+                return Zip.DecompressInput(GetInputStream());
+            case CompressionAlgorithmTag.ZLib:
+				return ZLib.DecompressInput(GetInputStream());
+			case CompressionAlgorithmTag.BZip2:
+                return Bzip2.DecompressInput(GetInputStream());
+            default:
+                throw new PgpException("can't recognise compression algorithm: " + Algorithm);
             }
         }
     }
diff --git a/crypto/src/openpgp/PgpCompressedDataGenerator.cs b/crypto/src/openpgp/PgpCompressedDataGenerator.cs
index 791aac0bf..d13d7402b 100644
--- a/crypto/src/openpgp/PgpCompressedDataGenerator.cs
+++ b/crypto/src/openpgp/PgpCompressedDataGenerator.cs
@@ -1,8 +1,8 @@
 using System;
 using System.IO;
 
-using Org.BouncyCastle.Bzip2;
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO.Compression;
 using Org.BouncyCastle.Utilities.Zlib;
 
 namespace Org.BouncyCastle.Bcpg.OpenPgp
@@ -131,21 +131,21 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
 			switch (algorithm)
 			{
-				case CompressionAlgorithmTag.Uncompressed:
-					dOut = pkOut;
-					break;
-				case CompressionAlgorithmTag.Zip:
-					dOut = new SafeZOutputStream(pkOut, compression, true);
-					break;
-				case CompressionAlgorithmTag.ZLib:
-					dOut = new SafeZOutputStream(pkOut, compression, false);
-					break;
-				case CompressionAlgorithmTag.BZip2:
-					dOut = new SafeCBZip2OutputStream(pkOut);
-					break;
-				default:
-					// Constructor should guard against this possibility
-					throw new InvalidOperationException();
+			case CompressionAlgorithmTag.Uncompressed:
+				dOut = pkOut;
+				break;
+			case CompressionAlgorithmTag.Zip:
+                dOut = Zip.CompressOutput(pkOut, compression, true);
+                break;
+			case CompressionAlgorithmTag.ZLib:
+				dOut = ZLib.CompressOutput(pkOut, compression, true);
+				break;
+			case CompressionAlgorithmTag.BZip2:
+				dOut = Bzip2.CompressOutput(pkOut, true);
+				break;
+			default:
+				// Constructor should guard against this possibility
+				throw new InvalidOperationException();
 			}
 		}
 
@@ -165,31 +165,5 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 				pkOut = null;
 			}
 		}
-
-		private class SafeCBZip2OutputStream : CBZip2OutputStream
-		{
-			public SafeCBZip2OutputStream(Stream output)
-				: base(output)
-			{
-			}
-
-            protected override void Dispose(bool disposing)
-            {
-                Detach(disposing);
-            }
-		}
-
-		private class SafeZOutputStream : ZOutputStream
-		{
-			public SafeZOutputStream(Stream output, int level, bool nowrap)
-				: base(output, level, nowrap)
-			{
-			}
-
-            protected override void Dispose(bool disposing)
-            {
-				Detach(disposing);
-            }
-		}
 	}
 }
diff --git a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
index a86dce42d..589895522 100644
--- a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
+++ b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
@@ -219,7 +219,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			SymmetricKeyAlgorithmTag encAlgorithm)
 		{
 			this.defAlgorithm = encAlgorithm;
-			this.rand = new SecureRandom();
+            this.rand = CryptoServicesRegistrar.GetSecureRandom();
 		}
 
 		public PgpEncryptedDataGenerator(
@@ -228,42 +228,51 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		{
 			this.defAlgorithm = encAlgorithm;
 			this.withIntegrityPacket = withIntegrityPacket;
-			this.rand = new SecureRandom();
-		}
+            this.rand = CryptoServicesRegistrar.GetSecureRandom();
+        }
 
-		/// <summary>Existing SecureRandom constructor.</summary>
-		/// <param name="encAlgorithm">The symmetric algorithm to use.</param>
-		/// <param name="rand">Source of randomness.</param>
+        /// <summary>Existing SecureRandom constructor.</summary>
+        /// <param name="encAlgorithm">The symmetric algorithm to use.</param>
+        /// <param name="random">Source of randomness.</param>
         public PgpEncryptedDataGenerator(
             SymmetricKeyAlgorithmTag	encAlgorithm,
-            SecureRandom				rand)
+            SecureRandom				random)
         {
+            if (random == null)
+                throw new ArgumentNullException(nameof(random));
+
             this.defAlgorithm = encAlgorithm;
-            this.rand = rand;
+            this.rand = random;
         }
 
 		/// <summary>Creates a cipher stream which will have an integrity packet associated with it.</summary>
         public PgpEncryptedDataGenerator(
             SymmetricKeyAlgorithmTag	encAlgorithm,
             bool						withIntegrityPacket,
-            SecureRandom				rand)
+            SecureRandom				random)
         {
+            if (random == null)
+                throw new ArgumentNullException(nameof(random));
+
             this.defAlgorithm = encAlgorithm;
-            this.rand = rand;
+            this.rand = random;
             this.withIntegrityPacket = withIntegrityPacket;
         }
 
-		/// <summary>Base constructor.</summary>
-		/// <param name="encAlgorithm">The symmetric algorithm to use.</param>
-		/// <param name="rand">Source of randomness.</param>
-		/// <param name="oldFormat">PGP 2.6.x compatibility required.</param>
+        /// <summary>Base constructor.</summary>
+        /// <param name="encAlgorithm">The symmetric algorithm to use.</param>
+        /// <param name="random">Source of randomness.</param>
+        /// <param name="oldFormat">PGP 2.6.x compatibility required.</param>
         public PgpEncryptedDataGenerator(
             SymmetricKeyAlgorithmTag	encAlgorithm,
-            SecureRandom				rand,
+            SecureRandom				random,
             bool						oldFormat)
         {
+            if (random == null)
+                throw new ArgumentNullException(nameof(random));
+
             this.defAlgorithm = encAlgorithm;
-            this.rand = rand;
+            this.rand = random;
             this.oldFormat = oldFormat;
         }
 
diff --git a/crypto/src/openssl/Pkcs8Generator.cs b/crypto/src/openssl/Pkcs8Generator.cs
index 0674cce15..242c966d0 100644
--- a/crypto/src/openssl/Pkcs8Generator.cs
+++ b/crypto/src/openssl/Pkcs8Generator.cs
@@ -83,10 +83,7 @@ namespace Org.BouncyCastle.OpenSsl
 
 			// TODO Theoretically, the amount of salt needed depends on the algorithm
 			byte[] salt = new byte[20];
-			if (random == null)
-			{
-				random = new SecureRandom();
-			}
+			random = CryptoServicesRegistrar.GetSecureRandom(random);
 			random.NextBytes(salt);
 
 			try
diff --git a/crypto/src/pkix/PkixCertPathValidatorUtilities.cs b/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
index a1c3ce734..88affe53d 100644
--- a/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
+++ b/crypto/src/pkix/PkixCertPathValidatorUtilities.cs
@@ -630,11 +630,11 @@ namespace Org.BouncyCastle.Pkix
 
 			if (index - 1 == 0)
 			{
-				DerGeneralizedTime dateOfCertgen;
+                Asn1GeneralizedTime dateOfCertgen;
 				try
 				{
 					Asn1OctetString extVal = cert.GetExtensionValue(IsisMttObjectIdentifiers.IdIsisMttATDateOfCertGen);
-					dateOfCertgen = DerGeneralizedTime.GetInstance(extVal);
+					dateOfCertgen = Asn1GeneralizedTime.GetInstance(extVal);
 				}
 				catch (ArgumentException)
 				{
diff --git a/crypto/src/pqc/crypto/bike/BikeEngine.cs b/crypto/src/pqc/crypto/bike/BikeEngine.cs
index 94f073bbb..f7c126c66 100644
--- a/crypto/src/pqc/crypto/bike/BikeEngine.cs
+++ b/crypto/src/pqc/crypto/bike/BikeEngine.cs
@@ -1,5 +1,6 @@
 using System;
 using System.Diagnostics;
+
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Security;
@@ -22,7 +23,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
         private readonly int t;
 
         //the shared secret size
-        private readonly int l;
+        //private readonly int l;
 
         // number of iterations in BGF decoder
         private readonly int nbIter;
@@ -39,7 +40,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
             this.r = r;
             this.w = w;
             this.t = t;
-            this.l = l;
+            //this.l = l;
             this.nbIter = nbIter;
             this.tau = tau;
             this.hw = this.w / 2;
diff --git a/crypto/src/pqc/crypto/bike/BikeKeyPairGenerator.cs b/crypto/src/pqc/crypto/bike/BikeKeyPairGenerator.cs
index 5636458fd..f621306bc 100644
--- a/crypto/src/pqc/crypto/bike/BikeKeyPairGenerator.cs
+++ b/crypto/src/pqc/crypto/bike/BikeKeyPairGenerator.cs
@@ -12,22 +12,22 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
         private int r;
 
         // the row weight
-        private int w;
+        //private int w;
 
         // Hamming weight of h0, h1
-        private int hw;
+        //private int hw;
 
         // the error weight
-        private int t;
+        //private int t;
 
         //the shared secret size
         private int l;
 
         // number of iterations in BGF decoder
-        private int nbIter;
+        //private int nbIter;
 
         // tau
-        private int tau;
+        //private int tau;
         private int L_BYTE;
         private int R_BYTE;
 
@@ -40,12 +40,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
 
             // get parameters
             this.r = this.bikeKeyGenerationParameters.Parameters.R;
-            this.w = this.bikeKeyGenerationParameters.Parameters.W;
+            //this.w = this.bikeKeyGenerationParameters.Parameters.W;
             this.l = this.bikeKeyGenerationParameters.Parameters.L;
-            this.t = this.bikeKeyGenerationParameters.Parameters.T;
-            this.nbIter = this.bikeKeyGenerationParameters.Parameters.NbIter;
-            this.tau = this.bikeKeyGenerationParameters.Parameters.Tau;
-            this.hw = w / 2;
+            //this.t = this.bikeKeyGenerationParameters.Parameters.T;
+            //this.nbIter = this.bikeKeyGenerationParameters.Parameters.NbIter;
+            //this.tau = this.bikeKeyGenerationParameters.Parameters.Tau;
+            //this.hw = w / 2;
             this.L_BYTE = l / 8;
             this.R_BYTE = (r + 7) / 8;
         }
diff --git a/crypto/src/pqc/crypto/bike/BikeRing.cs b/crypto/src/pqc/crypto/bike/BikeRing.cs
index c2b2102b8..a519595af 100644
--- a/crypto/src/pqc/crypto/bike/BikeRing.cs
+++ b/crypto/src/pqc/crypto/bike/BikeRing.cs
@@ -30,10 +30,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
 
         internal void Add(ulong[] x, ulong[] y, ulong[] z)
         {
-            for (int i = 0; i < Size; ++i)
-            {
-                z[i] = x[i] ^ y[i];
-            }
+            Nat.Xor64(Size, x, y, z);
+        }
+
+        internal void AddTo(ulong[] x, ulong[] z)
+        {
+            Nat.XorTo64(Size, x, z);
         }
 
         internal void Copy(ulong[] x, ulong[] z)
@@ -54,23 +56,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
             return new ulong[SizeExt];
         }
 
-        internal ulong[] DecodeBits(byte[] bs)
-        {
-            if (bs.Length > m_bits)
-                throw new ArgumentException();
-
-            ulong[] z = Create();
-            for (int i = 0; i < bs.Length; ++i)
-            {
-                ulong bit = bs[i];
-                if ((bit >> 1) != 0UL)
-                    throw new ArgumentException();
-
-                z[i >> 6] |= bit << (i & 63);
-            }
-            return z;
-        }
-
         internal void DecodeBytes(byte[] bs, ulong[] z)
         {
             int partialBits = m_bits & 63;
@@ -78,7 +63,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
             byte[] last = new byte[8];
             Array.Copy(bs, (Size - 1) << 3, last, 0, (partialBits + 7) >> 3);
             z[Size - 1] = Pack.LE_To_UInt64(last);
-            Debug.Assert((z[Size - 1] >> partialBits) == 0);
+            Debug.Assert((z[Size - 1] >> partialBits) == 0UL);
         }
 
         internal byte[] EncodeBits(ulong[] x)
@@ -94,7 +79,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
         internal void EncodeBytes(ulong[] x, byte[] bs)
         {
             int partialBits = m_bits & 63;
-            Debug.Assert((x[Size - 1] >> partialBits) == 0);
+            Debug.Assert((x[Size - 1] >> partialBits) == 0UL);
             Pack.UInt64_To_LE(x, 0, Size - 1, bs, 0);
             byte[] last = new byte[8];
             Pack.UInt64_To_LE(x[Size - 1], last);
@@ -170,12 +155,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
 
             ulong c = Nat.ShiftUpBits64(Size, tt, Size, excessBits, tt[Size - 1], z, 0);
             Debug.Assert(c == 0UL);
-
-            for (int i = 0; i < Size; ++i)
-            {
-                z[i] ^= tt[i];
-            }
-
+            AddTo(tt, z);
             z[Size - 1] &= partialMask;
         }
 
@@ -192,6 +172,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Bike
 
         internal void SquareN(ulong[] x, int n, ulong[] z)
         {
+            /*
+             * TODO In these polynomial rings, 'squareN' for some 'n' is equivalent to a fixed permutation of the
+             * coefficients. For 'squareN' with 'n' above some cutoff value, this permutation could be precomputed
+             * and then applied in place of explicit squaring for that 'n'. This is particularly relevant to the
+             * calls generated by 'inv'.
+             */
+
             Debug.Assert(n > 0);
 
             ulong[] tt = CreateExt();
diff --git a/crypto/src/pqc/crypto/cmce/CmceEngine.cs b/crypto/src/pqc/crypto/cmce/CmceEngine.cs
index 7dd404427..10b08e708 100644
--- a/crypto/src/pqc/crypto/cmce/CmceEngine.cs
+++ b/crypto/src/pqc/crypto/cmce/CmceEngine.cs
@@ -1,4 +1,7 @@
 using System;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+using System.Runtime.InteropServices;
+#endif
 
 using Org.BouncyCastle.Asn1.Nist;
 using Org.BouncyCastle.Crypto;
@@ -1460,9 +1463,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce
                     row = i * 8 + j;
 
                     if (row >= PK_NROWS)
-                    {
                         break;
-                    }
+
+                    byte[] mat_row = mat[row];
 
                     if (usePivots)
                     {
@@ -1470,7 +1473,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce
                         {
                             if (MovColumns(mat, pi, pivots) != 0)
                             {
-                                //                            System.out.println("failed mov column!");
+                                //System.out.println("failed mov column!");
                                 return -1;
                             }
                         }
@@ -1478,21 +1481,37 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce
 
                     for (k = row + 1; k < PK_NROWS; k++)
                     {
-                        mask = (byte)(mat[row][i] ^ mat[k][i]);
+                        byte[] mat_k = mat[k];
+                        mask = (byte)(mat_row[i] ^ mat_k[i]);
                         mask >>= j;
                         mask &= 1;
-                        mask = (byte)-mask;
 
-                        for (c = 0; c < SYS_N / 8; c++)
+                        c = 0;
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                        ulong mask64 = 0UL - mask;
+                        int limit64 = (SYS_N / 8) - 8;
+                        while (c <= limit64)
                         {
-                            mat[row][c] ^= (byte)(mat[k][c] & mask);
+                            ulong t0 = MemoryMarshal.Read<ulong>(mat_k.AsSpan(c)) & mask64;
+                            ulong t1 = MemoryMarshal.Read<ulong>(mat_row.AsSpan(c)) ^ t0;
+                            MemoryMarshal.Write(mat_row.AsSpan(c), ref t1);
+                            c += 8;
+                        }
+#endif
+                        byte maskByte = (byte)-mask;
+                        while (c < SYS_N / 8)
+                        {
+                            mat_row[c] ^= (byte)(mat_k[c] & maskByte);
+                            ++c;
                         }
                     }
+
                     // 7. Compute (T,cn−k−μ+1,...,cn−k,Γ′) ← MatGen(Γ). If this fails, set δ ← δ′ and
                     // restart the algorithm.
-                    if (((mat[row][i] >> j) & 1) == 0) // return if not systematic
+                    if (((mat_row[i] >> j) & 1) == 0) // return if not systematic
                     {
-                        //                    System.out.println("FAIL 2\n");
+                        //System.out.println("FAIL 2\n");
                         return -1;
                     }
 
@@ -1500,14 +1519,35 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce
                     {
                         if (k != row)
                         {
-                            mask = (byte)(mat[k][i] >> j);
+                            byte[] mat_k = mat[k];
+                            mask = (byte)(mat_k[i] >> j);
                             mask &= 1;
-                            mask = (byte)-mask;
 
-                            for (c = 0; c < SYS_N / 8; c++)
-                            {
-                                mat[k][c] ^= (byte)(mat[row][c] & mask);
+                            //mask = (byte)-mask;
+
+                            //for (c = 0; c < SYS_N / 8; c++)
+                            //{
+                            //    mat_k[c] ^= (byte)(mat_row[c] & mask);
+                            //}
 
+                            c = 0;
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+                            ulong mask64 = 0UL - mask;
+                            int limit64 = (SYS_N / 8) - 8;
+                            while (c <= limit64)
+                            {
+                                ulong t0 = MemoryMarshal.Read<ulong>(mat_row.AsSpan(c)) & mask64;
+                                ulong t1 = MemoryMarshal.Read<ulong>(mat_k.AsSpan(c)) ^ t0;
+                                MemoryMarshal.Write(mat_k.AsSpan(c), ref t1);
+                                c += 8;
+                            }
+#endif
+                            byte maskByte = (byte)-mask;
+                            while (c < SYS_N / 8)
+                            {
+                                mat_k[c] ^= (byte)(mat_row[c] & maskByte);
+                                ++c;
                             }
                         }
                     }
@@ -1546,7 +1586,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Cmce
             return 0;
         }
 
-
         private ushort Eval(ushort[] f, ushort a)
         {
             ushort r;
diff --git a/crypto/src/pqc/crypto/falcon/FalconFPR.cs b/crypto/src/pqc/crypto/falcon/FalconFPR.cs
index b3f99f944..bab3d8fcb 100644
--- a/crypto/src/pqc/crypto/falcon/FalconFPR.cs
+++ b/crypto/src/pqc/crypto/falcon/FalconFPR.cs
@@ -2,11 +2,12 @@ using System;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Falcon
 {
-    class FalconFPR
+    internal struct FalconFPR
     {
         internal double v;
 
-        internal FalconFPR(double v) {
+        internal FalconFPR(double v)
+        {
             this.v = v;
         }
     }
diff --git a/crypto/src/pqc/crypto/falcon/FalconSigner.cs b/crypto/src/pqc/crypto/falcon/FalconSigner.cs
index 4c2362503..f581386ee 100644
--- a/crypto/src/pqc/crypto/falcon/FalconSigner.cs
+++ b/crypto/src/pqc/crypto/falcon/FalconSigner.cs
@@ -1,9 +1,7 @@
 using System;
+
 using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Pqc.Crypto;
-using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Crypto.Parameters;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Falcon
 {
@@ -17,12 +15,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon
         {
             if (forSigning)
             {
-                if (param is ParametersWithRandom)
+                if (param is ParametersWithRandom withRandom)
                 {
-                    FalconPrivateKeyParameters skparam = ((FalconPrivateKeyParameters)((ParametersWithRandom)param).Parameters);
+                    FalconPrivateKeyParameters skparam = (FalconPrivateKeyParameters)withRandom.Parameters;
                     encodedkey = skparam.GetEncoded();
                     nist = new FalconNIST(
-                        ((ParametersWithRandom)param).Random, 
+                        withRandom.Random,
                         skparam.Parameters.LogN,
                         skparam.Parameters.NonceLength);
                 }
@@ -31,13 +29,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon
                     FalconPrivateKeyParameters skparam = (FalconPrivateKeyParameters)param;
                     encodedkey = ((FalconPrivateKeyParameters)param).GetEncoded();
                     nist = new FalconNIST(
-                        new SecureRandom(),
-                        // CryptoServicesRegistrar.GetSecureRandom(),
+                        CryptoServicesRegistrar.GetSecureRandom(),
                         skparam.Parameters.LogN,
-                        skparam.Parameters.NonceLength
-                        ); 
-                        // TODO when CryptoServicesRegistrar has been implemented, use that instead
-
+                        skparam.Parameters.NonceLength);
                 }
             }
             else
@@ -45,8 +39,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Falcon
                 FalconPublicKeyParameters pkparam = (FalconPublicKeyParameters)param;
                 encodedkey = pkparam.GetEncoded();
                 nist = new FalconNIST(
-                    new SecureRandom(),
-                    // CryptoServicesRegistrar.GetSecureRandom()
+                    CryptoServicesRegistrar.GetSecureRandom(),
                     pkparam.Parameters.LogN,
                     pkparam.Parameters.NonceLength);
             }
diff --git a/crypto/src/pqc/crypto/hqc/FastFourierTransform.cs b/crypto/src/pqc/crypto/hqc/FastFourierTransform.cs
new file mode 100644
index 000000000..be7e822d0
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/FastFourierTransform.cs
@@ -0,0 +1,279 @@
+using System;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    internal class FastFourierTransform
+    {
+        internal static void FFT(int[] output, int[] elements, int noCoefs, int fft)
+        {
+            int m = HqcParameters.PARAM_M;
+            int mSize = 1 << (HqcParameters.PARAM_M - 1);
+
+            int fftSize = 1 << fft;
+
+            int[] f0 = new int[fftSize];
+            int[] f1 = new int[fftSize];
+            int[] deltas = new int[m - 1];
+            int[] u = new int[mSize];
+            int[] v = new int[mSize];
+
+            // Step 1: Compute betas
+            int[] betas = new int[m - 1];
+            int[] betaSum = new int[mSize];
+
+            ComputeFFTBetas(betas, m);
+            ComputeSubsetSum(betaSum, betas, m - 1);
+
+            // Step 2: Compute radix
+            ComputeRadix(f0, f1, elements, fft, fft);
+
+            // Step 3: Compute deltas
+            for (int i = 0; i < m - 1; i++)
+            {
+                deltas[i] = GFCalculator.mult(betas[i], betas[i]) ^ betas[i];
+            }
+
+            // Step 5:
+            ComputeFFTRec(u, f0, (noCoefs + 1) / 2, m - 1, fft - 1, deltas, fft, m);
+            ComputeFFTRec(v, f1, noCoefs / 2, m - 1, fft - 1, deltas, fft, m);
+
+            // Step 6.7
+            int k = 1;
+            k = 1 << (m - 1);
+
+            Array.Copy(v, 0, output, k, k);
+
+            output[0] = u[0];
+            output[k] ^= u[0];
+
+            for (int i = 1; i < k; i++)
+            {
+                output[i] = u[i] ^ GFCalculator.mult(betaSum[i], v[i]);
+                output[k + i] ^= output[i];
+            }
+        }
+
+        internal static void ComputeFFTBetas(int[] betas, int m)
+        {
+            for (int i = 0; i < m - 1; i++)
+            {
+                betas[i] = 1 << (m - 1 - i);
+            }
+        }
+
+        internal static void ComputeSubsetSum(int[] subsetSum, int[] set, int size)
+        {
+            subsetSum[0] = 0;
+
+            for (int i = 0; i < size; i++)
+            {
+                for (int j = 0; j < (1 << i); j++)
+                {
+                    subsetSum[(1 << i) + j] = set[i] ^ subsetSum[j];
+                }
+            }
+        }
+
+        internal static void ComputeRadix(int[] f0, int[] f1, int[] f, int mf, int fft)
+        {
+            switch (mf)
+            {
+                case 4:
+                    f0[4] = f[8] ^ f[12];
+                    f0[6] = f[12] ^ f[14];
+                    f0[7] = f[14] ^ f[15];
+                    f1[5] = f[11] ^ f[13];
+                    f1[6] = f[13] ^ f[14];
+                    f1[7] = f[15];
+                    f0[5] = f[10] ^ f[12] ^ f1[5];
+                    f1[4] = f[9] ^ f[13] ^ f0[5];
+
+                    f0[0] = f[0];
+                    f1[3] = f[7] ^ f[11] ^ f[15];
+                    f0[3] = f[6] ^ f[10] ^ f[14] ^ f1[3];
+                    f0[2] = f[4] ^ f0[4] ^ f0[3] ^ f1[3];
+                    f1[1] = f[3] ^ f[5] ^ f[9] ^ f[13] ^ f1[3];
+                    f1[2] = f[3] ^ f1[1] ^ f0[3];
+                    f0[1] = f[2] ^ f0[2] ^ f1[1];
+                    f1[0] = f[1] ^ f0[1];
+                    return;
+
+                case 3:
+                    f0[0] = f[0];
+                    f0[2] = f[4] ^ f[6];
+                    f0[3] = f[6] ^ f[7];
+                    f1[1] = f[3] ^ f[5] ^ f[7];
+                    f1[2] = f[5] ^ f[6];
+                    f1[3] = f[7];
+                    f0[1] = f[2] ^ f0[2] ^ f1[1];
+                    f1[0] = f[1] ^ f0[1];
+                    return;
+
+                case 2:
+                    f0[0] = f[0];
+                    f0[1] = f[2] ^ f[3];
+                    f1[0] = f[1] ^ f0[1];
+                    f1[1] = f[3];
+                    return;
+
+                case 1:
+                    f0[0] = f[0];
+                    f1[0] = f[1];
+                    return;
+
+                default:
+                    ComputeRadixBig(f0, f1, f, mf, fft);
+                    break;
+            }
+        }
+
+        internal static void ComputeRadixBig(int[] f0, int[] f1, int[] f, int mf, int fft)
+        {
+            int n = 1;
+            n <<= (mf - 2);
+            int fftSize = 1 << (fft - 2);
+
+            int[] Q = new int[2 * fftSize];
+            int[] R = new int[2 * fftSize];
+
+            int[] Q0 = new int[fftSize];
+            int[] Q1 = new int[fftSize];
+            int[] R0 = new int[fftSize];
+            int[] R1 = new int[fftSize];
+
+
+            Utils.CopyBytes(f, 3 * n, Q, 0, 2 * n);
+            Utils.CopyBytes(f, 3 * n, Q, n, 2 * n);
+            Utils.CopyBytes(f, 0, R, 0, 4 * n);
+
+            for (int i = 0; i < n; ++i)
+            {
+                Q[i] ^= f[2 * n + i];
+                R[n + i] ^= Q[i];
+            }
+
+            ComputeRadix(Q0, Q1, Q, mf - 1, fft);
+            ComputeRadix(R0, R1, R, mf - 1, fft);
+
+            Utils.CopyBytes(R0, 0, f0, 0, 2 * n);
+            Utils.CopyBytes(Q0, 0, f0, n, 2 * n);
+            Utils.CopyBytes(R1, 0, f1, 0, 2 * n);
+            Utils.CopyBytes(Q1, 0, f1, n, 2 * n);
+        }
+
+        internal static void ComputeFFTRec(int[] output, int[] func, int noCoeffs, int noOfBetas, int noCoeffsPlus, int[] betaSet, int fft, int m)
+        {
+            int fftSize = 1 << (fft - 2);
+            int mSize = 1 << (m - 2);
+
+            int[] fx0 = new int[fftSize];
+            int[] fx1 = new int[fftSize];
+            int[] gammaSet = new int[m - 2];
+            int[] deltaSet = new int[m - 2];
+            int k = 1;
+            int[] gammaSumSet = new int[mSize];
+            int[] uSet = new int[mSize];
+            int[] vSet = new int[mSize];
+            int[] tempSet = new int[m - fft + 1];
+
+            int x = 0;
+            if (noCoeffsPlus == 1)
+            {
+                for (int i = 0; i < noOfBetas; i++)
+                {
+                    tempSet[i] = GFCalculator.mult(betaSet[i], func[1]);
+                }
+
+                output[0] = func[0];
+                x = 1;
+                for (int j = 0; j < noOfBetas; j++)
+                {
+                    for (int t = 0; t < x; t++)
+                    {
+                        output[x + t] = output[t] ^ tempSet[j];
+                    }
+                    x <<= 1;
+                }
+                return;
+            }
+
+            if (betaSet[noOfBetas - 1] != 1)
+            {
+                int betaMPow = 1;
+                x = 1;
+                x <<= noCoeffsPlus;
+                for (int i = 1; i < x; i++)
+                {
+                    betaMPow = GFCalculator.mult(betaMPow, betaSet[noOfBetas - 1]);
+                    func[i] = GFCalculator.mult(betaMPow, func[i]);
+                }
+            }
+
+            ComputeRadix(fx0, fx1, func, noCoeffsPlus, fft);
+
+            for (int i = 0; i < noOfBetas - 1; i++)
+            {
+                gammaSet[i] = GFCalculator.mult(betaSet[i], GFCalculator.inverse(betaSet[noOfBetas - 1]));
+                deltaSet[i] = GFCalculator.mult(gammaSet[i], gammaSet[i]) ^ gammaSet[i];
+            }
+
+            ComputeSubsetSum(gammaSumSet, gammaSet, noOfBetas - 1);
+
+            ComputeFFTRec(uSet, fx0, (noCoeffs + 1) / 2, noOfBetas - 1, noCoeffsPlus - 1, deltaSet, fft, m);
+
+            k = 1;
+            k <<= ((noOfBetas - 1) & 0xf);
+            if (noCoeffs <= 3)
+            {
+                output[0] = uSet[0];
+                output[k] = uSet[0] ^ fx1[0];
+                for (int i = 1; i < k; i++)
+                {
+                    output[i] = uSet[i] ^ GFCalculator.mult(gammaSumSet[i], fx1[0]);
+                    output[k + i] = output[i] ^ fx1[0];
+                }
+            }
+            else
+            {
+                ComputeFFTRec(vSet, fx1, noCoeffs / 2, noOfBetas - 1, noCoeffsPlus - 1, deltaSet, fft, m);
+
+                Array.Copy(vSet, 0, output, k, k);
+
+                output[0] = uSet[0];
+                output[k] ^= uSet[0];
+                for (int i = 1; i < k; i++)
+                {
+                    output[i] = uSet[i] ^ GFCalculator.mult(gammaSumSet[i], vSet[i]);
+                    output[k + i] ^= output[i];
+                }
+
+
+            }
+        }
+
+        internal static void FastFourierTransformGetError(byte[] errorSet, int[] input, int mSize, int[] logArrays)
+        {
+            int m = HqcParameters.PARAM_M;
+            int gfMulOrder = HqcParameters.GF_MUL_ORDER;
+
+            int[] gammaSet = new int[m - 1];
+            int[] gammaSumSet = new int[mSize];
+            int k = mSize;
+
+            ComputeFFTBetas(gammaSet, m);
+            ComputeSubsetSum(gammaSumSet, gammaSet, m - 1);
+
+            errorSet[0] ^= (byte) (1 ^ Utils.ToUnsigned16Bits(-input[0] >> 15));
+            errorSet[0] ^= (byte) (1 ^ Utils.ToUnsigned16Bits(-input[k] >> 15));
+
+            for (int i = 1; i < k; i++)
+            {
+                int tmp = gfMulOrder - logArrays[gammaSumSet[i]];
+                errorSet[tmp] ^= (byte) (1 ^ System.Math.Abs(-input[i] >> 15));
+
+                tmp = gfMulOrder - logArrays[gammaSumSet[i] ^ 1];
+                errorSet[tmp] ^= (byte) (1 ^ System.Math.Abs(-input[k + i] >> 15));
+            }
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/GF2PolynomialCalculator.cs b/crypto/src/pqc/crypto/hqc/GF2PolynomialCalculator.cs
new file mode 100644
index 000000000..0c01ade96
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/GF2PolynomialCalculator.cs
@@ -0,0 +1,134 @@
+using System;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+using System.Buffers.Binary;
+using System.Runtime.InteropServices;
+#endif
+
+using Org.BouncyCastle.Math.Raw;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    internal class GF2PolynomialCalculator
+    {
+        private const int TABLE = 16;
+
+        static void Mod(ulong[] res, ulong[] a, int n, int nByte64)
+        {
+            for (int i = 0; i < nByte64; i++)
+            {
+                ulong r = a[i + nByte64 - 1] >> (n & 0x3F);
+                ulong carry = a[i + nByte64] << (64 - (n & 0x3F));
+                res[i] = a[i] ^ r ^ carry;
+            }
+            res[nByte64 - 1] &= Utils.BitMask((ulong)n, 64);
+        }
+
+        static void Swap(int[] table, int firstIndex, int secondIndex)
+        {
+            int tmp = table[firstIndex];
+            table[firstIndex] = table[secondIndex];
+            table[secondIndex] = tmp;
+        }
+
+        static void FastConvolutionMult(ulong[] res, int[] a, ulong[] b, int weight, int nByte64, int we,
+            HqcKeccakRandomGenerator random)
+        {
+            int[] permutedTable = new int[TABLE];
+            for (int i = 0; i < 16; i++)
+            {
+                permutedTable[i] = i;
+            }
+
+            byte[] permutationTableByte = new byte[TABLE*2];
+            random.ExpandSeed(permutationTableByte, TABLE << 1);
+
+            int[] permutationTable = new int[TABLE];
+            Utils.FromByteArrayToByte16Array(permutationTable, permutationTableByte);
+
+            for (int i = 0; i < TABLE - 1; i++)
+            {
+                Swap(permutedTable, i, i + permutationTable[i] % (TABLE - i));
+            }
+
+            ulong[] table = new ulong[TABLE * (nByte64 + 1)];
+            int idx = permutedTable[0] * (nByte64 + 1);
+            Array.Copy(b, 0, table, idx, nByte64);
+            table[idx + nByte64] = 0UL;
+
+            for (int i = 1; i < TABLE; i++)
+            {
+                idx = permutedTable[i] * (nByte64 + 1);
+                table[idx + nByte64] = Nat.ShiftUpBits64(nByte64, b, 0, i, 0UL, table, idx);
+            }
+
+            int[] permutedSparseVect = new int[we];
+            for (int i = 0; i < weight; i++)
+            {
+                permutedSparseVect[i] = i;
+            }
+
+            byte[] permutationSparseVectBytes = new byte[we * 2];
+            random.ExpandSeed(permutationSparseVectBytes, weight << 1);
+
+            int[] permutationSparseVect = new int[we];
+            Utils.FromByteArrayToByte16Array(permutationSparseVect, permutationSparseVectBytes);
+
+            for (int i = 0; i < (weight - 1); i++)
+            {
+                Swap(permutedSparseVect, i, i + permutationSparseVect[i] % (weight - i));
+            }
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Span<byte> resBytes = MemoryMarshal.AsBytes(res.AsSpan());
+            for (int i = 0; i < weight; i++)
+            {
+                int dec = a[permutedSparseVect[i]] & 0xf;
+                int s = a[permutedSparseVect[i]] >> 4;
+
+                idx = permutedTable[dec] * (nByte64 + 1);
+
+                int count = s * 2 + nByte64 * 8;
+                for (int j = nByte64; j >= 0; --j)
+                {
+                    ulong tmp = BinaryPrimitives.ReadUInt64LittleEndian(resBytes[count..]);
+                    BinaryPrimitives.WriteUInt64LittleEndian(resBytes[count..], tmp ^ table[idx + j]);
+                    count -= 8;
+                }
+            }
+#else
+            ushort[] resByte16 = new ushort[res.Length * 4];
+            for (int i = 0; i < weight; i++)
+            {
+                int dec = a[permutedSparseVect[i]] & 0xf;
+                int s = a[permutedSparseVect[i]] >> 4;
+
+                idx = permutedTable[dec] * (nByte64 + 1);
+
+                int count = s;
+                for (int j = 0; j <= nByte64; j++)
+                {
+                    Utils.XorULongToByte16Array(resByte16, count, table[idx + j]);
+                    count += 4;
+                }
+            }
+            Utils.FromByte16ArrayToULongArray(res, resByte16);
+#endif
+        }
+
+        internal static void ModMult(ulong[] res, int[] a, ulong[] b, int weight,int n,  int nByte64, int we,
+            HqcKeccakRandomGenerator random)
+        {
+            ulong[] tmp = new ulong[(nByte64 << 1) + 1];
+            FastConvolutionMult(tmp, a, b, weight, nByte64, we, random);
+            Mod(res, tmp, n, nByte64);
+        }
+
+        internal static void AddULongs(ulong[] res, ulong[] a, ulong[] b)
+        {
+            for (int i = 0; i < a.Length; i++)
+            {
+                res[i] = a[i] ^ b[i];
+            }
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/GFCalculator.cs b/crypto/src/pqc/crypto/hqc/GFCalculator.cs
new file mode 100644
index 000000000..d63e70513
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/GFCalculator.cs
@@ -0,0 +1,29 @@
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    internal class GFCalculator
+    {
+        static int[] exp = new int[] { 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4 };
+        static int[] log = new int[] { 0, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 };
+
+        internal static int mult(int a, int b)
+        {
+            int mask;
+            mask = Utils.ToUnsigned16Bits(-a >> 31); // a != 0
+            mask &= Utils.ToUnsigned16Bits(-b >> 31); // b != 0
+            return Utils.ToUnsigned16Bits(mask & exp[mod(log[a] + log[b])]);
+        }
+
+        internal static int mod(int a)
+        {
+            int tmp = Utils.ToUnsigned16Bits(a - HqcParameters.GF_MUL_ORDER);
+            int mask = Utils.ToUnsigned8bits(-(tmp >> 15));
+            return Utils.ToUnsigned16Bits(tmp + (mask & HqcParameters.GF_MUL_ORDER));
+        }
+
+        internal static int inverse(int a)
+        {
+            int mask = Utils.ToUnsigned16Bits(-a >> 31);
+            return mask & exp[HqcParameters.GF_MUL_ORDER - log[a]];
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/HqcEngine.cs b/crypto/src/pqc/crypto/hqc/HqcEngine.cs
new file mode 100644
index 000000000..ac1a96f00
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/HqcEngine.cs
@@ -0,0 +1,436 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    internal class HqcEngine
+    {
+        private int n;
+        private int n1;
+        private int n2;
+        private int k;
+        private int delta;
+        private int w;
+        private int wr;
+        private int we;
+        private int g;
+        private int rejectionThreshold;
+        private int fft;
+        private int mulParam;
+
+        private int SEED_SIZE = 40;
+        private byte G_FCT_DOMAIN = 3;
+        private byte H_FCT_DOMAIN = 4;
+        private byte K_FCT_DOMAIN = 5;
+
+        private int N_BYTE;
+        private int n1n2;
+        private int N_BYTE_64;
+        private int K_BYTE;
+        private int K_BYTE_64;
+        private int N1_BYTE_64;
+        private int N1N2_BYTE_64;
+        private int N1N2_BYTE;
+        private int N1_BYTE;
+
+        private int[] generatorPoly;
+        private int SHA512_BYTES = 512 / 8;
+
+        public HqcEngine(int n, int n1, int n2, int k, int g, int delta, int w, int wr, int we, int rejectionThreshold, int fft, int[] generatorPoly)
+        {
+            this.n = n;
+            this.k = k;
+            this.delta = delta;
+            this.w = w;
+            this.wr = wr;
+            this.we = we;
+            this.n1 = n1;
+            this.n2 = n2;
+            this.n1n2 = n1 * n2;
+            this.generatorPoly = generatorPoly;
+            this.g = g;
+            this.rejectionThreshold = rejectionThreshold;
+            this.fft = fft;
+
+            this.mulParam = (n2 + 127) / 128;
+            this.N_BYTE = Utils.GetByteSizeFromBitSize(n);
+            this.K_BYTE = k;
+            this.N_BYTE_64 = Utils.GetByte64SizeFromBitSize(n);
+            this.K_BYTE_64 = Utils.GetByteSizeFromBitSize(k);
+            this.N1_BYTE_64 = Utils.GetByteSizeFromBitSize(n1);
+            this.N1N2_BYTE_64 = Utils.GetByte64SizeFromBitSize(n1 * n2);
+            this.N1N2_BYTE = Utils.GetByteSizeFromBitSize(n1 * n2);
+            this.N1_BYTE = Utils.GetByteSizeFromBitSize(n1);
+        }
+
+        /**
+         * Generate key pairs
+         * - Secret key : (x,y)
+         * - Public key: (h,s)
+         *  @param pk     output pk = (publicSeed||s)
+         *
+         **/
+        public void GenKeyPair(byte[] pk, byte[] sk, byte[] seed)
+        {
+            // Randomly generate seeds for secret keys and public keys
+            byte[] secretKeySeed = new byte[SEED_SIZE];
+
+            HqcKeccakRandomGenerator randomGenerator = new HqcKeccakRandomGenerator(256);
+            randomGenerator.RandomGeneratorInit(seed, null, seed.Length, 0);
+            randomGenerator.Squeeze(secretKeySeed, 40);
+
+            // 1. Randomly generate secret keys x, y
+            HqcKeccakRandomGenerator secretKeySeedExpander = new HqcKeccakRandomGenerator(256);
+            secretKeySeedExpander.SeedExpanderInit(secretKeySeed, secretKeySeed.Length);
+
+            ulong[] xLongBytes = new ulong[N_BYTE_64];
+            int[] yPos = new int[this.w];
+
+            GenerateSecretKey(xLongBytes, secretKeySeedExpander, w);
+            GenerateSecretKeyByCoordinates(yPos, secretKeySeedExpander, w);
+
+            // 2. Randomly generate h
+            byte[] publicKeySeed = new byte[SEED_SIZE];
+            randomGenerator.Squeeze(publicKeySeed, 40);
+
+            HqcKeccakRandomGenerator randomPublic = new HqcKeccakRandomGenerator(256);
+            randomPublic.SeedExpanderInit(publicKeySeed, publicKeySeed.Length);
+
+            ulong[] hLongBytes = new ulong[N_BYTE_64];
+            GeneratePublicKeyH(hLongBytes, randomPublic);
+
+            // 3. Compute s
+            ulong[] s = new ulong[N_BYTE_64];
+            GF2PolynomialCalculator.ModMult(s, yPos, hLongBytes, w, n, N_BYTE_64, we, secretKeySeedExpander);
+            GF2PolynomialCalculator.AddULongs(s, s, xLongBytes);
+            byte[] sBytes = new byte[N_BYTE];
+            Utils.FromULongArrayToByteArray(sBytes, s);
+
+            byte[] tmpPk = Arrays.Concatenate(publicKeySeed, sBytes);
+            byte[] tmpSk = Arrays.Concatenate(secretKeySeed, tmpPk);
+
+            Array.Copy(tmpPk, 0, pk, 0, tmpPk.Length);
+            Array.Copy(tmpSk, 0, sk, 0, tmpSk.Length);
+        }
+
+        /**
+         * HQC Encapsulation
+         * - Input: pk, seed
+         * - Output: c = (u,v,d), K
+         *
+         * @param u    u
+         * @param v    v
+         * @param d    d
+         * @param K    session key
+         * @param pk   public key
+         * @param seed seed
+         **/
+        public void Encaps(byte[] u, byte[] v, byte[] K, byte[] d, byte[] pk, byte[] seed)
+        {
+            // 1. Randomly generate m
+            byte[] m = new byte[K_BYTE];
+
+            // TODO: no way to gen m without seed and gen skseed, pkseed. In reference implementation they use the same
+            byte[] secretKeySeed = new byte[SEED_SIZE];
+            HqcKeccakRandomGenerator randomGenerator = new HqcKeccakRandomGenerator(256);
+            randomGenerator.RandomGeneratorInit(seed, null, seed.Length, 0);
+            randomGenerator.Squeeze(secretKeySeed, 40);
+
+            byte[] publicKeySeed = new byte[SEED_SIZE];
+            randomGenerator.Squeeze(publicKeySeed, 40);
+
+            // gen m
+            randomGenerator.Squeeze(m, K_BYTE);
+
+            // 2. Generate theta
+            byte[] theta = new byte[SHA512_BYTES];
+            HqcKeccakRandomGenerator shakeDigest = new HqcKeccakRandomGenerator(256);
+            shakeDigest.SHAKE256_512_ds(theta, m, m.Length, new byte[] { G_FCT_DOMAIN });
+
+            // 3. Generate ciphertext c = (u,v)
+            // Extract public keys
+            ulong[] h = new ulong[N_BYTE_64];
+            byte[] s = new byte[N_BYTE];
+            ExtractPublicKeys(h, s, pk);
+
+            ulong[] vTmp = new ulong[N1N2_BYTE_64];
+            Encrypt(u, vTmp, h, s, m, theta);
+            Utils.FromULongArrayToByteArray(v, vTmp);
+
+            // 4. Compute d
+            shakeDigest.SHAKE256_512_ds(d, m, m.Length, new byte[] { H_FCT_DOMAIN });
+
+            // 5. Compute session key K
+            byte[] hashInputK = new byte[K_BYTE + N_BYTE + N1N2_BYTE];
+            hashInputK = Arrays.Concatenate(m, u);
+            hashInputK = Arrays.Concatenate(hashInputK, v);
+            shakeDigest.SHAKE256_512_ds(K, hashInputK, hashInputK.Length, new byte[] { K_FCT_DOMAIN });
+        }
+
+        /**
+         * HQC Decapsulation
+         * - Input: ct, sk
+         * - Output: ss
+         *
+         * @param ss session key
+         * @param ct ciphertext
+         * @param sk secret key
+         **/
+        public void Decaps(byte[] ss, byte[] ct, byte[] sk)
+        {
+            //Extract Y and Public Keys from sk
+            int[] yPos = new int[this.w];
+            byte[] pk = new byte[40 + N_BYTE];
+            ExtractKeysFromSecretKeys(yPos, pk, sk);
+
+            // Extract u, v, d from ciphertext
+            byte[] u = new byte[N_BYTE];
+            byte[] v = new byte[N1N2_BYTE];
+            byte[] d = new byte[SHA512_BYTES];
+            HqcEngine.ExtractCiphertexts(u, v, d, ct);
+
+            // 1. Decrypt -> m'
+            byte[] mPrimeBytes = new byte[k];
+            Decrypt(mPrimeBytes, mPrimeBytes, u, v, yPos);
+
+            // 2. Compute theta'
+            byte[] theta = new byte[SHA512_BYTES];
+            HqcKeccakRandomGenerator shakeDigest = new HqcKeccakRandomGenerator(256);
+            shakeDigest.SHAKE256_512_ds(theta, mPrimeBytes, mPrimeBytes.Length, new byte[] { G_FCT_DOMAIN });
+
+            // 3. Compute c' = Enc(pk, m', theta')
+            // Extract public keys
+            ulong[] h = new ulong[N_BYTE_64];
+            byte[] s = new byte[N_BYTE];
+            ExtractPublicKeys(h, s, pk);
+
+            byte[] u2Bytes = new byte[N_BYTE];
+            byte[] v2Bytes = new byte[N1N2_BYTE];
+            ulong[] vTmp = new ulong[N1N2_BYTE_64];
+            Encrypt(u2Bytes, vTmp, h, s, mPrimeBytes, theta);
+            Utils.FromULongArrayToByteArray(v2Bytes, vTmp);
+
+            // 4. Compute d' = H(m')
+            byte[] dPrime = new byte[SHA512_BYTES];
+            shakeDigest.SHAKE256_512_ds(dPrime, mPrimeBytes, mPrimeBytes.Length, new byte[] { H_FCT_DOMAIN });
+
+            // 5. Compute session key KPrime
+            byte[] hashInputK = new byte[K_BYTE + N_BYTE + N1N2_BYTE];
+            hashInputK = Arrays.Concatenate(mPrimeBytes, u);
+            hashInputK = Arrays.Concatenate(hashInputK, v);
+            shakeDigest.SHAKE256_512_ds(ss, hashInputK, hashInputK.Length, new byte[] { K_FCT_DOMAIN });
+
+            int result = 1;
+            // Compare u, v, d
+            if (!Arrays.AreEqual(u, u2Bytes))
+            {
+                result = 0;
+            }
+
+            if (!Arrays.AreEqual(v, v2Bytes))
+            {
+                result = 0;
+            }
+
+            if (!Arrays.AreEqual(d, dPrime))
+            {
+                result = 0;
+            }
+
+            if (result == 0)
+            { //abort
+                for (int i = 0; i < GetSessionKeySize(); i++)
+                {
+                    ss[i] = 0;
+                }
+            }
+        }
+
+        internal int GetSessionKeySize()
+        {
+            return SHA512_BYTES;
+        }
+
+        /**
+         * HQC Encryption
+         * - Input: (h,s, m)
+         * - Output: (u,v) = c
+         *
+         * @param h public key
+         * @param s public key
+         * @param m message
+         * @param u ciphertext
+         * @param v ciphertext
+         **/
+        private void Encrypt(byte[] u, ulong[] v, ulong[] h, byte[] s, byte[] m, byte[] theta)
+        {
+            // Randomly generate e, r1, r2
+            HqcKeccakRandomGenerator randomGenerator = new HqcKeccakRandomGenerator(256);
+            randomGenerator.SeedExpanderInit(theta, SEED_SIZE);
+            ulong[] e = new ulong[N_BYTE_64];
+            ulong[] r1 = new ulong[N_BYTE_64];
+            int[] r2 = new int[wr];
+            GenerateSecretKey(r1, randomGenerator, wr);
+            GenerateSecretKeyByCoordinates(r2, randomGenerator, wr);
+            GenerateSecretKey(e, randomGenerator, we);
+
+            // Calculate u
+            ulong[] uLong = new ulong[N_BYTE_64];
+            GF2PolynomialCalculator.ModMult(uLong, r2, h, wr, n, N_BYTE_64, we, randomGenerator);
+            GF2PolynomialCalculator.AddULongs(uLong, uLong, r1);
+            Utils.FromULongArrayToByteArray(u, uLong);
+
+            // Calculate v
+            // encode m
+            byte[] res = new byte[n1];
+            ulong[] vLong = new ulong[N1N2_BYTE_64];
+            ulong[] tmpVLong = new ulong[N_BYTE_64];
+            ReedSolomon.Encode(res, m, K_BYTE * 8, n1, k, g, generatorPoly);
+            ReedMuller.Encode(vLong, res, n1, mulParam);
+            Array.Copy(vLong, 0, tmpVLong, 0, vLong.Length);
+
+            //Compute v
+            ulong[] sLong = new ulong[N_BYTE_64];
+            Utils.FromByteArrayToULongArray(sLong, s);
+
+            ulong[] tmpLong = new ulong[N_BYTE_64];
+            GF2PolynomialCalculator.ModMult(tmpLong, r2, sLong, wr, n, N_BYTE_64, we, randomGenerator);
+            GF2PolynomialCalculator.AddULongs(tmpLong, tmpLong, tmpVLong);
+            GF2PolynomialCalculator.AddULongs(tmpLong, tmpLong, e);
+
+            Utils.ResizeArray(v, n1n2, tmpLong, n, N1N2_BYTE_64, N1N2_BYTE_64);
+        }
+
+        private void Decrypt(byte[] output, byte[] m, byte[] u, byte[] v, int[] y)
+        {
+            byte[] tmpSeed = new byte[SEED_SIZE];
+            HqcKeccakRandomGenerator randomGenerator = new HqcKeccakRandomGenerator(256);
+            randomGenerator.SeedExpanderInit(tmpSeed, SEED_SIZE);
+
+            ulong[] uLongs = new ulong[N_BYTE_64];
+            Utils.FromByteArrayToULongArray(uLongs, u);
+
+            ulong[] vLongs = new ulong[N1N2_BYTE_64];
+            Utils.FromByteArrayToULongArray(vLongs, v);
+
+            ulong[] tmpV = new ulong[N_BYTE_64];
+            Array.Copy(vLongs, 0, tmpV, 0, vLongs.Length);
+
+            ulong[] tmpLong = new ulong[N_BYTE_64];
+            GF2PolynomialCalculator.ModMult(tmpLong, y, uLongs, w, n, N_BYTE_64, we, randomGenerator);
+            GF2PolynomialCalculator.AddULongs(tmpLong, tmpLong, tmpV);
+
+            // Decode res
+            byte[] tmp = new byte[n1];
+            ReedMuller.Decode(tmp, tmpLong, n1, mulParam);
+            ReedSolomon.Decode(m, tmp, n1, fft, delta, k, g);
+
+            Array.Copy(m, 0, output, 0, output.Length);
+        }
+
+        private void GenerateSecretKey(ulong[] output, HqcKeccakRandomGenerator random, int w)
+        {
+            int[] tmp = new int[w];
+            GenerateSecretKeyByCoordinates(tmp, random, w);
+
+            for (int i = 0; i < w; ++i)
+            {
+                int index = tmp[i] / 64;
+                int pos = tmp[i] % 64;
+                ulong t = 1UL << pos;
+                output[index] |= t;
+            }
+        }
+
+        private void GenerateSecretKeyByCoordinates(int[] output, HqcKeccakRandomGenerator random, int w)
+        {
+            int randomByteSize = 3 * w;
+            byte[] randomBytes = new byte[3 * this.wr];
+            int inc;
+
+            int i = 0;
+            int j = randomByteSize;
+            while (i < w)
+            {
+                do
+                {
+                    if (j == randomByteSize)
+                    {
+                        random.ExpandSeed(randomBytes, randomByteSize);
+
+                        j = 0;
+                    }
+
+                    output[i] = (randomBytes[j++] & 0xff) << 16;
+                    output[i] |= (randomBytes[j++] & 0xff) << 8;
+                    output[i] |= (randomBytes[j++] & 0xff);
+
+                }
+                while (output[i] >= this.rejectionThreshold);
+
+                output[i] = output[i] % this.n;
+                inc = 1;
+                for (int k = 0; k < i; k++)
+                {
+                    if (output[k] == output[i])
+                    {
+                        inc = 0;
+                    }
+                }
+                i += inc;
+            }
+        }
+
+        void GeneratePublicKeyH(ulong[] output, HqcKeccakRandomGenerator random)
+        {
+            byte[] randBytes = new byte[N_BYTE];
+            random.ExpandSeed(randBytes, N_BYTE);
+            ulong[] tmp = new ulong[N_BYTE_64];
+            Utils.FromByteArrayToULongArray(tmp, randBytes);
+            tmp[N_BYTE_64 - 1] &= Utils.BitMask((ulong)n, 64);
+            Array.Copy(tmp, 0, output, 0, output.Length);
+        }
+
+        private void ExtractPublicKeys(ulong[] h, byte[] s, byte[] pk)
+        {
+            byte[] publicKeySeed = new byte[SEED_SIZE];
+            Array.Copy(pk, 0, publicKeySeed, 0, publicKeySeed.Length);
+
+            HqcKeccakRandomGenerator randomPublic = new HqcKeccakRandomGenerator(256);
+            randomPublic.SeedExpanderInit(publicKeySeed, publicKeySeed.Length);
+
+            ulong[] hLongBytes = new ulong[N_BYTE_64];
+            GeneratePublicKeyH(hLongBytes, randomPublic);
+
+            Array.Copy(hLongBytes, 0, h, 0, h.Length);
+            Array.Copy(pk, 40, s, 0, s.Length);
+        }
+
+        private void ExtractKeysFromSecretKeys(int[] y, byte[] pk, byte[] sk)
+        {
+            byte[] secretKeySeed = new byte[SEED_SIZE];
+            Array.Copy(sk, 0, secretKeySeed, 0, secretKeySeed.Length);
+
+            // Randomly generate secret keys x, y
+            HqcKeccakRandomGenerator secretKeySeedExpander = new HqcKeccakRandomGenerator(256);
+            secretKeySeedExpander.SeedExpanderInit(secretKeySeed, secretKeySeed.Length);
+
+            ulong[] xLongBytes = new ulong[N_BYTE_64];
+            int[] yPos = new int[this.w];
+
+            GenerateSecretKey(xLongBytes, secretKeySeedExpander, w);
+            GenerateSecretKeyByCoordinates(yPos, secretKeySeedExpander, w);
+
+            Array.Copy(yPos, 0, y, 0, yPos.Length);
+            Array.Copy(sk, SEED_SIZE, pk, 0, pk.Length);
+        }
+
+        private static void ExtractCiphertexts(byte[] u, byte[] v, byte[] d, byte[] ct)
+        {
+            Array.Copy(ct, 0, u, 0, u.Length);
+            Array.Copy(ct, u.Length, v, 0, v.Length);
+            Array.Copy(ct, u.Length + v.Length, d, 0, d.Length);
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/HqcKeccakRandomGenerator.cs b/crypto/src/pqc/crypto/hqc/HqcKeccakRandomGenerator.cs
new file mode 100644
index 000000000..090f5a9c0
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/HqcKeccakRandomGenerator.cs
@@ -0,0 +1,321 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    internal class HqcKeccakRandomGenerator
+    {
+        private static readonly ulong[] KeccakRoundConstants =
+        {
+            0x0000000000000001L, 0x0000000000008082L, 0x800000000000808aL, 0x8000000080008000L,
+            0x000000000000808bL, 0x0000000080000001L, 0x8000000080008081L, 0x8000000000008009L,
+            0x000000000000008aL, 0x0000000000000088L, 0x0000000080008009L, 0x000000008000000aL,
+            0x000000008000808bL, 0x800000000000008bL, 0x8000000000008089L, 0x8000000000008003L,
+            0x8000000000008002L, 0x8000000000000080L, 0x000000000000800aL, 0x800000008000000aL,
+            0x8000000080008081L, 0x8000000000008080L, 0x0000000080000001L, 0x8000000080008008L
+        };
+
+        protected long[] state = new long[26];
+        protected byte[] dataQueue = new byte[192];
+        protected int rate;
+        protected int bitsInQueue;
+        protected int fixedOutputLength;
+        protected bool squeezing;
+
+        public HqcKeccakRandomGenerator()
+        {
+            Init(288);
+        }
+
+        public HqcKeccakRandomGenerator(int bitLength)
+        {
+            Init(bitLength);
+        }
+
+        private void Init(int bitLength)
+        {
+            switch (bitLength)
+            {
+            case 128:
+            case 224:
+            case 256:
+            case 288:
+            case 384:
+            case 512:
+                InitSponge(1600 - (bitLength << 1));
+                break;
+            default:
+                throw new ArgumentException("bitLength must be one of 128, 224, 256, 288, 384, or 512.");
+            }
+        }
+
+        private void InitSponge(int rate)
+        {
+            if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
+                throw new InvalidOperationException("invalid rate value");
+
+            this.rate = rate;
+            for (int i = 0; i < state.Length; ++i)
+            {
+                state[i] = 0L;
+            }
+            Arrays.Fill(this.dataQueue, 0);
+            this.bitsInQueue = 0;
+            this.squeezing = false;
+            this.fixedOutputLength = (1600 - rate) / 2;
+        }
+
+        private void KeccakPermutation()
+        {
+            long[] A = state;
+
+            long a00 = A[ 0], a01 = A[ 1], a02 = A[ 2], a03 = A[ 3], a04 = A[ 4];
+            long a05 = A[ 5], a06 = A[ 6], a07 = A[ 7], a08 = A[ 8], a09 = A[ 9];
+            long a10 = A[10], a11 = A[11], a12 = A[12], a13 = A[13], a14 = A[14];
+            long a15 = A[15], a16 = A[16], a17 = A[17], a18 = A[18], a19 = A[19];
+            long a20 = A[20], a21 = A[21], a22 = A[22], a23 = A[23], a24 = A[24];
+
+            for (int i = 0; i < 24; i++)
+            {
+                // theta
+                long c0 = a00 ^ a05 ^ a10 ^ a15 ^ a20;
+                long c1 = a01 ^ a06 ^ a11 ^ a16 ^ a21;
+                long c2 = a02 ^ a07 ^ a12 ^ a17 ^ a22;
+                long c3 = a03 ^ a08 ^ a13 ^ a18 ^ a23;
+                long c4 = a04 ^ a09 ^ a14 ^ a19 ^ a24;
+
+                long d1 = Longs.RotateLeft(c1, 1) ^ c4;
+                long d2 = Longs.RotateLeft(c2, 1) ^ c0;
+                long d3 = Longs.RotateLeft(c3, 1) ^ c1;
+                long d4 = Longs.RotateLeft(c4, 1) ^ c2;
+                long d0 = Longs.RotateLeft(c0, 1) ^ c3;
+
+                a00 ^= d1; a05 ^= d1; a10 ^= d1; a15 ^= d1; a20 ^= d1;
+                a01 ^= d2; a06 ^= d2; a11 ^= d2; a16 ^= d2; a21 ^= d2;
+                a02 ^= d3; a07 ^= d3; a12 ^= d3; a17 ^= d3; a22 ^= d3;
+                a03 ^= d4; a08 ^= d4; a13 ^= d4; a18 ^= d4; a23 ^= d4;
+                a04 ^= d0; a09 ^= d0; a14 ^= d0; a19 ^= d0; a24 ^= d0;
+
+                // rho/pi
+                c1  = Longs.RotateLeft(a01,  1);
+                a01 = Longs.RotateLeft(a06, 44);
+                a06 = Longs.RotateLeft(a09, 20);
+                a09 = Longs.RotateLeft(a22, 61);
+                a22 = Longs.RotateLeft(a14, 39);
+                a14 = Longs.RotateLeft(a20, 18);
+                a20 = Longs.RotateLeft(a02, 62);
+                a02 = Longs.RotateLeft(a12, 43);
+                a12 = Longs.RotateLeft(a13, 25);
+                a13 = Longs.RotateLeft(a19,  8);
+                a19 = Longs.RotateLeft(a23, 56);
+                a23 = Longs.RotateLeft(a15, 41);
+                a15 = Longs.RotateLeft(a04, 27);
+                a04 = Longs.RotateLeft(a24, 14);
+                a24 = Longs.RotateLeft(a21,  2);
+                a21 = Longs.RotateLeft(a08, 55);
+                a08 = Longs.RotateLeft(a16, 45);
+                a16 = Longs.RotateLeft(a05, 36);
+                a05 = Longs.RotateLeft(a03, 28);
+                a03 = Longs.RotateLeft(a18, 21);
+                a18 = Longs.RotateLeft(a17, 15);
+                a17 = Longs.RotateLeft(a11, 10);
+                a11 = Longs.RotateLeft(a07,  6);
+                a07 = Longs.RotateLeft(a10,  3);
+                a10 = c1;
+
+                // chi
+                c0 = a00 ^ (~a01 & a02);
+                c1 = a01 ^ (~a02 & a03);
+                a02 ^= ~a03 & a04;
+                a03 ^= ~a04 & a00;
+                a04 ^= ~a00 & a01;
+                a00 = c0;
+                a01 = c1;
+
+                c0 = a05 ^ (~a06 & a07);
+                c1 = a06 ^ (~a07 & a08);
+                a07 ^= ~a08 & a09;
+                a08 ^= ~a09 & a05;
+                a09 ^= ~a05 & a06;
+                a05 = c0;
+                a06 = c1;
+
+                c0 = a10 ^ (~a11 & a12);
+                c1 = a11 ^ (~a12 & a13);
+                a12 ^= ~a13 & a14;
+                a13 ^= ~a14 & a10;
+                a14 ^= ~a10 & a11;
+                a10 = c0;
+                a11 = c1;
+
+                c0 = a15 ^ (~a16 & a17);
+                c1 = a16 ^ (~a17 & a18);
+                a17 ^= ~a18 & a19;
+                a18 ^= ~a19 & a15;
+                a19 ^= ~a15 & a16;
+                a15 = c0;
+                a16 = c1;
+
+                c0 = a20 ^ (~a21 & a22);
+                c1 = a21 ^ (~a22 & a23);
+                a22 ^= ~a23 & a24;
+                a23 ^= ~a24 & a20;
+                a24 ^= ~a20 & a21;
+                a20 = c0;
+                a21 = c1;
+
+                // iota
+                a00 ^= (long) KeccakRoundConstants[i];
+            }
+
+            A[0] = a00;
+            A[1] = a01;
+            A[2] = a02;
+            A[3] = a03;
+            A[4] = a04;
+            A[5] = a05;
+            A[6] = a06;
+            A[7] = a07;
+            A[8] = a08;
+            A[9] = a09;
+            A[10] = a10;
+            A[11] = a11;
+            A[12] = a12;
+            A[13] = a13;
+            A[14] = a14;
+            A[15] = a15;
+            A[16] = a16;
+            A[17] = a17;
+            A[18] = a18;
+            A[19] = a19;
+            A[20] = a20;
+            A[21] = a21;
+            A[22] = a22;
+            A[23] = a23;
+            A[24] = a24;
+        }
+
+        private void KeccakIncAbsorb(byte[] input, int inputLen)
+        {
+            if (input == null)
+            {
+                return;
+            }
+
+            int count = 0;
+            int rateBytes = rate >> 3;
+            while (inputLen + state[25] >= rateBytes)
+            {
+                for (int i = 0; i < rateBytes - state[25]; i++)
+                {
+                    int tmp = (int)(state[25] + i) >> 3;
+                    state[tmp] ^= (long) (((ulong) (input[i + count] & 0xff)) << (int) (8 * ((state[25] + i) & 0x07)));
+                }
+                inputLen -= (int) (rateBytes - state[25]);
+                count += (int) (rateBytes - state[25]);
+                state[25] = 0;
+                KeccakPermutation();
+            }
+
+            for (int i = 0; i < inputLen; i++)
+            {
+                int tmp = (int)(state[25] + i) >> 3;
+                state[tmp] ^= (long) (((ulong) (input[i + count] & 0xff)) << (int) (8 * ((state[25] + i) & 0x07)));
+            }
+
+            state[25] += inputLen;
+        }
+
+        private void KeccakIncFinalize(int p)
+        {
+            int rateBytes = rate >> 3;
+
+            state[(int)state[25] >> 3] ^= (long) (((ulong) (p)) << (int) (8 * ((state[25]) & 0x07)));
+            state[(rateBytes - 1) >> 3] ^=((long) (128)) << (8 * ((rateBytes - 1) & 0x07));
+
+
+            state[25] = 0;
+        }
+
+        private void KeccakIncSqueeze(byte[] output, int outLen)
+        {
+            int rateBytes = rate >> 3;
+            int i;
+            for (i = 0; i < outLen && i < state[25]; i++)
+            {
+                output[i] = (byte)(state[(int)((rateBytes - state[25] + i) >> 3)] >> (int) (8 * ((rateBytes - state[25] + i) & 0x07)));
+            }
+
+            int count = i;
+            outLen -= i;
+            state[25] -= i;
+
+            while (outLen > 0)
+            {
+                KeccakPermutation();
+
+                for (i = 0; i < outLen && i < rateBytes; i++)
+                {
+                    byte t = (byte)(state[i >> 3] >> (8 * (i & 0x07)));
+                    output[count + i] = (byte)(state[i >> 3] >> (8 * (i & 0x07)));
+                }
+                count = count + i;
+                outLen -= i;
+                state[25] = rateBytes - i;
+            }
+        }
+
+        public void Squeeze(byte[] output, int outLen)
+        {
+            KeccakIncSqueeze(output, outLen);
+        }
+
+        public void RandomGeneratorInit(byte[] entropyInput, byte[] personalizationString, int entropyLen, int perLen)
+        {
+            byte[] domain = new byte[] { 1 };
+            KeccakIncAbsorb(entropyInput, entropyLen);
+            KeccakIncAbsorb(personalizationString, perLen);
+            KeccakIncAbsorb(domain, domain.Length);
+            KeccakIncFinalize(0x1F);
+        }
+
+        public void SeedExpanderInit(byte[] seed, int seedLen)
+        {
+            byte[] domain = new byte[] { 2 };
+            KeccakIncAbsorb(seed, seedLen);
+            KeccakIncAbsorb(domain, 1);
+            KeccakIncFinalize(0x1F);
+        }
+
+        public void ExpandSeed(byte[] output, int outLen)
+        {
+            int bSize = 8;
+            int r = outLen % bSize;
+            byte[] tmp = new byte[bSize];
+            KeccakIncSqueeze(output, outLen - r);
+
+            if (r != 0)
+            {
+                KeccakIncSqueeze(tmp, bSize);
+                int count = outLen - r;
+                for (int i = 0; i < r; i++)
+                {
+                    output[count + i] = tmp[i];
+                }
+            }
+        }
+
+        public void SHAKE256_512_ds(byte[] output, byte[] input, int inLen, byte[] domain)
+        {
+            for (int i = 0; i < state.Length; i++)
+            {
+                state[i] = 0;
+            }
+            KeccakIncAbsorb(input, inLen);
+            KeccakIncAbsorb(domain, domain.Length);
+            KeccakIncFinalize(0x1F);
+            KeccakIncSqueeze(output, 512 / 8);
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/HqcKemExtractor.cs b/crypto/src/pqc/crypto/hqc/HqcKemExtractor.cs
new file mode 100644
index 000000000..32890f80b
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/HqcKemExtractor.cs
@@ -0,0 +1,37 @@
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    public class HqcKemExtractor : IEncapsulatedSecretExtractor
+    {
+        private HqcEngine engine;
+
+        private HqcKeyParameters key;
+
+        public HqcKemExtractor(HqcPrivateKeyParameters privParams)
+        {
+            this.key = privParams;
+            InitCipher(key.Parameters);
+        }
+
+        private void InitCipher(HqcParameters param)
+        {
+            engine = param.Engine;
+        }
+
+        
+        public byte[] ExtractSecret(byte[] encapsulation)
+        {
+            byte[] session_key = new byte[engine.GetSessionKeySize()];
+            HqcPrivateKeyParameters secretKey = (HqcPrivateKeyParameters)key;
+            byte[] sk = secretKey.PrivateKey;
+
+            engine.Decaps(session_key, encapsulation, sk);
+
+            return session_key;
+        }
+
+        public int EncapsulationLength => key.Parameters.NBytes + key.Parameters.N1n2Bytes + 64;
+ 
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/HqcKemGenerator.cs b/crypto/src/pqc/crypto/hqc/HqcKemGenerator.cs
new file mode 100644
index 000000000..918dadd38
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/HqcKemGenerator.cs
@@ -0,0 +1,89 @@
+using System;
+
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    public class HqcKemGenerator : IEncapsulatedSecretGenerator
+    {
+        private SecureRandom sr;
+        public HqcKemGenerator(SecureRandom random)
+        {
+            this.sr = random;
+        }
+
+        public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey)
+        {
+            HqcPublicKeyParameters key = (HqcPublicKeyParameters)recipientKey;
+            HqcEngine engine = key.Parameters.Engine;
+
+            byte[] K = new byte[key.Parameters.Sha512Bytes];
+            byte[] u = new byte[key.Parameters.NBytes];
+            byte[] v = new byte[key.Parameters.N1n2Bytes];
+            byte[] d = new byte[key.Parameters.Sha512Bytes];
+            byte[] pk = key.PublicKey;
+            byte[] seed = new byte[48];
+
+            sr.NextBytes(seed);
+
+            engine.Encaps(u, v, K, d, pk, seed);
+
+            byte[] cipherText = Arrays.Concatenate(u, v);
+            cipherText = Arrays.Concatenate(cipherText, d);
+
+            return new HqcKemGenerator.SecretWithEncapsulationImpl(K, cipherText);
+        }
+
+        private class SecretWithEncapsulationImpl : ISecretWithEncapsulation
+        {
+            private volatile bool hasBeenDestroyed = false;
+
+            private byte[] sessionKey;
+            private byte[] cipher_text;
+
+            public SecretWithEncapsulationImpl(byte[] sessionKey, byte[] cipher_text)
+            {
+                this.sessionKey = sessionKey;
+                this.cipher_text = cipher_text;
+            }
+
+            public byte[] GetSecret()
+            {
+                CheckDestroyed();
+                return Arrays.Clone(sessionKey);
+            }
+
+            public byte[] GetEncapsulation()
+            {
+                CheckDestroyed();
+
+                return Arrays.Clone(cipher_text);
+            }
+
+            public void Dispose()
+            {
+                if (!hasBeenDestroyed)
+                {
+                    hasBeenDestroyed = true;
+                    Arrays.Clear(sessionKey);
+                    Arrays.Clear(cipher_text);
+                }
+            }
+
+            public bool IsDestroyed()
+            {
+                return hasBeenDestroyed;
+            }
+
+            void CheckDestroyed()
+            {
+                if (IsDestroyed())
+                {
+                    throw new Exception("data has been destroyed");
+                }
+            }
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/HqcKeyGenerationParameters.cs b/crypto/src/pqc/crypto/hqc/HqcKeyGenerationParameters.cs
new file mode 100644
index 000000000..e548e1999
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/HqcKeyGenerationParameters.cs
@@ -0,0 +1,19 @@
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    public class HqcKeyGenerationParameters : KeyGenerationParameters
+    {
+        private HqcParameters param;
+
+        public HqcKeyGenerationParameters(
+            SecureRandom random,
+            HqcParameters param) : base(random, 256)
+            {
+                this.param = param;
+            }
+
+            public HqcParameters Parameters => param;
+        }
+}
diff --git a/crypto/src/pqc/crypto/hqc/HqcKeyPairGenerator.cs b/crypto/src/pqc/crypto/hqc/HqcKeyPairGenerator.cs
new file mode 100644
index 000000000..243b0d850
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/HqcKeyPairGenerator.cs
@@ -0,0 +1,69 @@
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+
+{
+    public class HqcKeyPairGenerator : IAsymmetricCipherKeyPairGenerator
+    {
+        private int n;
+
+        private int k;
+
+        private int delta;
+
+        private int w;
+
+        private int wr;
+
+        private int we;
+        private int N_BYTE;
+        private HqcKeyGenerationParameters hqcKeyGenerationParameters;
+
+        private SecureRandom random;
+
+        public AsymmetricCipherKeyPair GenerateKeyPair()
+        {
+            byte[] seed = new byte[48];
+            random.NextBytes(seed);
+            return GenKeyPair(seed);
+        }
+
+        public AsymmetricCipherKeyPair GenerateKeyPairWithSeed(byte[] seed)
+        {
+            return GenKeyPair(seed);
+        }
+
+        public void Init(KeyGenerationParameters parameters)
+        {
+            this.hqcKeyGenerationParameters = (HqcKeyGenerationParameters)parameters;
+            this.random = parameters.Random;
+
+            // get parameters
+            this.n = this.hqcKeyGenerationParameters.Parameters.N;
+            this.k = this.hqcKeyGenerationParameters.Parameters.K;
+            this.delta = this.hqcKeyGenerationParameters.Parameters.Delta;
+            this.w = this.hqcKeyGenerationParameters.Parameters.W;
+            this.wr = this.hqcKeyGenerationParameters.Parameters.Wr;
+            this.we = this.hqcKeyGenerationParameters.Parameters.We;
+            this.N_BYTE = (n + 7) / 8;
+        }
+        private AsymmetricCipherKeyPair GenKeyPair(byte[] seed)
+        {
+            HqcEngine engine = hqcKeyGenerationParameters.Parameters.Engine;
+            byte[] pk = new byte[40 + N_BYTE];
+            byte[] sk = new byte[40 + 40 + N_BYTE];
+
+            engine.GenKeyPair(pk, sk, seed);
+
+            // form keys
+            HqcPublicKeyParameters publicKey = new HqcPublicKeyParameters(hqcKeyGenerationParameters.Parameters, pk);
+            HqcPrivateKeyParameters privateKey = new HqcPrivateKeyParameters(hqcKeyGenerationParameters.Parameters, sk);
+
+            return new AsymmetricCipherKeyPair(publicKey, privateKey);
+        }
+
+       
+
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/HqcKeyParameters.cs b/crypto/src/pqc/crypto/hqc/HqcKeyParameters.cs
new file mode 100644
index 000000000..8fc900a64
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/HqcKeyParameters.cs
@@ -0,0 +1,19 @@
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    public class HqcKeyParameters : AsymmetricKeyParameter
+    {
+        private HqcParameters param;
+
+        public HqcKeyParameters(
+            bool isPrivate,
+            HqcParameters param) : base(isPrivate)
+        {
+            this.param = param;
+        }
+
+        public HqcParameters Parameters => param;
+       
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/HqcParameters.cs b/crypto/src/pqc/crypto/hqc/HqcParameters.cs
new file mode 100644
index 000000000..da5948296
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/HqcParameters.cs
@@ -0,0 +1,71 @@
+using Org.BouncyCastle.Crypto;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+
+{
+    public class HqcParameters : ICipherParameters
+    {
+        // 128 bits security
+        public static HqcParameters hqc128 = new HqcParameters("hqc128", 17669, 46, 384, 16, 31, 15, 66, 75, 75, 16767881, 4, new int[] { 89, 69, 153, 116, 176, 117, 111, 75, 73, 233, 242, 233, 65, 210, 21, 139, 103, 173, 67, 118, 105, 210, 174, 110, 74, 69, 228, 82, 255, 181, 1 }, 128);
+
+        // 192 bits security
+        public static HqcParameters hqc192 = new HqcParameters("hqc192", 35851, 56, 640, 24, 33, 16, 100, 114, 114, 16742417, 5, new int[] { 45, 216, 239, 24, 253, 104, 27, 40, 107, 50, 163, 210, 227, 134, 224, 158, 119, 13, 158, 1, 238, 164, 82, 43, 15, 232, 246, 142, 50, 189, 29, 232, 1 }, 192);
+
+        // 256 bits security
+        public static HqcParameters hqc256 = new HqcParameters("hqc256", 57637, 90, 640, 32, 59, 29, 131, 149, 149, 16772367, 5, new int[] { 49, 167, 49, 39, 200, 121, 124, 91, 240, 63, 148, 71, 150, 123, 87, 101, 32, 215, 159, 71, 201, 115, 97, 210, 186, 183, 141, 217, 123, 12, 31, 243, 180, 219, 152, 239, 99, 141, 4, 246, 191, 144, 8, 232, 47, 27, 141, 178, 130, 64, 124, 47, 39, 188, 216, 48, 199, 187, 1 }, 256);
+
+        private string name;
+        private int n;
+        private int n1;
+        private int n2;
+        private int k;
+        private int g;
+        private int delta;
+        private int w;
+        private int wr;
+        private int we;
+        private int utilRejectionThreshold;
+        private int fft;
+
+        private int[] generatorPoly;
+        private int defaultKeySize;
+
+        internal const int PARAM_M = 8;
+        internal const int GF_MUL_ORDER = 255;
+
+        private HqcEngine hqcEngine;
+
+        private HqcParameters(string name, int n, int n1, int n2, int k, int g, int delta, int w, int wr, int we, int utilRejectionThreshold, int fft, int[] generatorPoly, int defaultKeySize)
+        {
+            this.name = name;
+            this.n = n;
+            this.n1 = n1;
+            this.n2 = n2;
+            this.k = k;
+            this.delta = delta;
+            this.w = w;
+            this.wr = wr;
+            this.we = we;
+            this.generatorPoly = generatorPoly;
+            this.g = g;
+            this.utilRejectionThreshold = utilRejectionThreshold;
+            this.fft = fft;
+            this.defaultKeySize = defaultKeySize;
+            hqcEngine = new HqcEngine(n, n1, n2, k, g, delta, w, wr, we, utilRejectionThreshold, fft, generatorPoly);
+        }
+
+        public int N => n;
+        public int K => k;
+        public int Delta => delta;
+        public int W => w;
+        public int Wr => wr;
+        public  int We => we;
+        public int N1 => n1;
+        public int N2 => n2;
+        public int Sha512Bytes => 512 / 8;
+        public int NBytes => (n + 7) / 8;
+        public int N1n2Bytes => (n1 * n2 + 7) / 8;
+        public int DefaultKeySize => defaultKeySize;
+        internal HqcEngine Engine => hqcEngine;
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/HqcPrivateKeyParameters.cs b/crypto/src/pqc/crypto/hqc/HqcPrivateKeyParameters.cs
new file mode 100644
index 000000000..96963e53c
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/HqcPrivateKeyParameters.cs
@@ -0,0 +1,20 @@
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    public class HqcPrivateKeyParameters : HqcKeyParameters
+    {
+        private byte[] sk;
+
+        public HqcPrivateKeyParameters(HqcParameters param, byte[] sk) : base(true, param)
+        {
+            this.sk = Arrays.Clone(sk);
+        }
+
+        public byte[] PrivateKey => Arrays.Clone(sk);
+        public byte[] GetEncoded()
+        {
+            return PrivateKey;
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/HqcPublicKeyParameters.cs b/crypto/src/pqc/crypto/hqc/HqcPublicKeyParameters.cs
new file mode 100644
index 000000000..a87d24704
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/HqcPublicKeyParameters.cs
@@ -0,0 +1,21 @@
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    public class HqcPublicKeyParameters : HqcKeyParameters
+    {
+        private byte[] pk;
+
+        public HqcPublicKeyParameters(HqcParameters param, byte[] pk) : base(false, param)
+        {
+            this.pk = Arrays.Clone(pk);
+        }
+
+        public byte[] PublicKey => Arrays.Clone(pk);
+
+        public byte[] GetEncoded()
+        {
+            return PublicKey;
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/ReedMuller.cs b/crypto/src/pqc/crypto/hqc/ReedMuller.cs
new file mode 100644
index 000000000..5f1f8e2bf
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/ReedMuller.cs
@@ -0,0 +1,196 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    internal class ReedMuller
+    {
+        internal class Codeword
+        {
+            internal int[] type32;
+            internal int[] type8;
+
+            public Codeword()
+            {
+                this.type32 = new int[4];
+                this.type8 = new int[16];
+            }
+        }
+
+        static void EncodeSub(Codeword codeword, int m)
+        {
+
+            int word1;
+            word1 = Bit0Mask(m >> 7);
+
+            word1 ^= (int) (Bit0Mask(m >> 0) & 0xaaaaaaaa);
+            word1 ^= (int) (Bit0Mask(m >> 1) & 0xcccccccc);
+            word1 ^= (int) (Bit0Mask(m >> 2) & 0xf0f0f0f0);
+            word1 ^= (int) (Bit0Mask(m >> 3) & 0xff00ff00);
+            word1 ^= (int) (Bit0Mask(m >> 4) & 0xffff0000);
+
+            codeword.type32[0] = word1;
+
+            word1 ^= Bit0Mask(m >> 5);
+            codeword.type32[1] = word1;
+
+            word1 ^= Bit0Mask(m >> 6);
+            codeword.type32[3] = word1;
+
+            word1 ^= Bit0Mask(m >> 5);
+            codeword.type32[2] = word1;
+        }
+
+        private static void HadamardTransform(int[] srcCode, int[] desCode)
+        {
+            int[] srcCodeCopy = Arrays.Clone(srcCode);
+            int[] desCodeCopy = Arrays.Clone(desCode);
+
+            for (int i = 0; i < 7; i++)
+            {
+                for (int j = 0; j < 64; j++)
+                {
+                    desCodeCopy[j] = srcCodeCopy[2 * j] + srcCodeCopy[2 * j + 1];
+                    desCodeCopy[j + 64] = srcCodeCopy[2 * j] - srcCodeCopy[2 * j + 1];
+                }
+
+                //swap srcCode and desCode
+                int[] tmp = srcCodeCopy; srcCodeCopy = desCodeCopy; desCodeCopy = tmp;
+            }
+
+            // swap
+            Array.Copy(desCodeCopy, 0, srcCode, 0, srcCode.Length);
+            Array.Copy(srcCodeCopy, 0, desCode, 0, desCode.Length);
+        }
+
+
+        private static void ExpandThenSum(int[] desCode, Codeword[] srcCode, int off, int mulParam)
+        {
+            for (int i = 0; i < 4; i++)
+            {
+                for (int j = 0; j < 32; j++)
+                {
+                    long ii = srcCode[0 + off].type32[i] >> j & 1;
+                    desCode[i * 32 + j] = srcCode[0 + off].type32[i] >> j & 1;
+                }
+            }
+
+            for (int i = 1; i < mulParam; i++)
+            {
+                for (int j = 0; j < 4; j++)
+                {
+                    for (int k = 0; k < 32; k++)
+                    {
+                        desCode[j * 32 + k] += srcCode[i + off].type32[j] >> k & 1;
+
+                    }
+                }
+            }
+
+        }
+
+        private static int FindPeaks(int[] input)
+        {
+            int peakAbsVal = 0;
+            int peakVal = 0;
+            int peakPos = 0;
+
+            for (int i = 0; i < 128; i++)
+            {
+                int t = input[i];
+                int posMask = t > 0 ? -1 : 0;
+                int abs = (posMask & t) | (~posMask & -t);
+
+                peakVal = abs > peakAbsVal ? t : peakVal;
+                peakPos = abs > peakAbsVal ? i : peakPos;
+                peakAbsVal = abs > peakAbsVal ? abs : peakAbsVal;
+            }
+            int tmp = peakVal > 0 ? 1 : 0;
+            peakPos |= 128 * tmp;
+            return peakPos;
+        }
+
+
+        private static int Bit0Mask(int b)
+        {
+            return (int) ((-(b & 1)) & 0xffffffff);
+        }
+
+        public static void Encode(ulong[] codeword, byte[] m, int n1, int mulParam)
+        {
+            byte[] mBytes = Arrays.Clone(m);
+
+            Codeword[] codewordCopy = new Codeword[n1 * mulParam];
+            for (int i = 0; i < codewordCopy.Length; i++)
+            {
+                codewordCopy[i] = new Codeword();
+            }
+
+            for (int i = 0; i < n1; i++)
+            {
+                int pos = i * mulParam;
+                EncodeSub(codewordCopy[pos], mBytes[i]);
+
+                for (int j = 1; j < mulParam; j++)
+                {
+                    codewordCopy[pos + j] = codewordCopy[pos];
+                }
+            }
+
+
+            int[] cwd64 = new int[codewordCopy.Length * 4];
+            int off = 0;
+            for (int i = 0; i < codewordCopy.Length; i++)
+            {
+                Array.Copy(codewordCopy[i].type32, 0, cwd64, off, codewordCopy[i].type32.Length);
+                off += 4;
+            }
+
+            Utils.FromByte32ArrayToULongArray(codeword, cwd64);
+        }
+
+        public static void Decode(byte[] m, ulong[] codeword, int n1, int mulParam)
+        {
+            byte[] mBytes = Arrays.Clone(m);
+
+            Codeword[] codewordCopy = new Codeword[codeword.Length / 2]; // because each codewordCopy has a 32 bit array size 4
+            int[] byteCodeWords = new int[codeword.Length * 2];
+            Utils.FromULongArrayToByte32Array(byteCodeWords, codeword);
+
+            for (int i = 0; i < codewordCopy.Length; i++)
+            {
+                codewordCopy[i] = new Codeword();
+                for (int j = 0; j < 4; j++)
+                {
+                    codewordCopy[i].type32[j] = byteCodeWords[i * 4 + j];
+                }
+            }
+
+            int[] expandedCodeword = new int[128];
+
+
+            for (int i = 0; i < n1; i++)
+            {
+                ExpandThenSum(expandedCodeword, codewordCopy, i * mulParam, mulParam);
+
+
+                int[] tmp = new int[128];
+                HadamardTransform(expandedCodeword, tmp);
+
+                tmp[0] -= 64 * mulParam;
+                mBytes[i] = (byte)FindPeaks(tmp);
+            }
+
+            int[] cwd64 = new int[codewordCopy.Length * 4];
+            int off = 0;
+            for (int i = 0; i < codewordCopy.Length; i++)
+            {
+                Array.Copy(codewordCopy[i].type32, 0, cwd64, off, codewordCopy[i].type32.Length);
+                off += 4;
+            }
+            Utils.FromByte32ArrayToULongArray(codeword, cwd64);
+            Array.Copy(mBytes, 0, m, 0, m.Length);
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/ReedSolomon.cs b/crypto/src/pqc/crypto/hqc/ReedSolomon.cs
new file mode 100644
index 000000000..8e7fc664d
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/ReedSolomon.cs
@@ -0,0 +1,264 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    internal class ReedSolomon
+    {
+        static int[,] alpha128 = new int[30,45] { { 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193 }, { 4, 16, 64, 29, 116, 205, 19, 76, 45, 180, 234, 143, 6, 24, 96, 157, 78, 37, 148, 106, 181, 238, 159, 70, 5, 20, 80, 93, 105, 185, 222, 95, 97, 153, 94, 101, 137, 30, 120, 253, 211, 107, 177, 254, 223 }, { 8, 64, 58, 205, 38, 45, 117, 143, 12, 96, 39, 37, 53, 181, 193, 70, 10, 80, 186, 185, 161, 97, 47, 101, 15, 120, 231, 107, 127, 223, 182, 217, 134, 68, 26, 208, 206, 62, 237, 59, 197, 102, 23, 184, 169 }, { 16, 29, 205, 76, 180, 143, 24, 157, 37, 106, 238, 70, 20, 93, 185, 95, 153, 101, 30, 253, 107, 254, 91, 217, 17, 13, 208, 129, 248, 59, 151, 133, 184, 79, 132, 168, 82, 73, 228, 230, 198, 252, 123, 227, 150 }, { 32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, 17, 26, 103, 124, 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174, 100, 28, 167, 89, 239, 172, 36 }, { 64, 205, 45, 143, 96, 37, 181, 70, 80, 185, 97, 101, 120, 107, 223, 217, 68, 208, 62, 59, 102, 184, 33, 168, 85, 228, 191, 252, 241, 150, 110, 130, 7, 221, 89, 195, 138, 61, 251, 44, 207, 173, 8, 58, 38 }, { 128, 19, 117, 24, 156, 181, 140, 93, 161, 94, 60, 107, 163, 67, 26, 129, 147, 102, 109, 132, 41, 57, 209, 252, 255, 98, 87, 200, 224, 89, 155, 18, 245, 11, 233, 173, 16, 232, 45, 3, 157, 53, 159, 40, 185 }, { 29, 76, 143, 157, 106, 70, 93, 95, 101, 253, 254, 217, 13, 129, 59, 133, 79, 168, 73, 230, 252, 227, 149, 130, 28, 81, 195, 18, 247, 44, 27, 2, 58, 152, 3, 39, 212, 140, 186, 190, 202, 231, 225, 175, 26 }, { 58, 45, 12, 37, 193, 80, 161, 101, 231, 223, 134, 208, 237, 102, 169, 168, 146, 191, 179, 150, 87, 7, 166, 195, 36, 251, 125, 173, 64, 38, 143, 39, 181, 10, 185, 47, 120, 127, 217, 26, 62, 197, 184, 21, 85 }, { 116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, 28, 89, 172, 244, 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51, 169, 77, 114, 145, 255, 55, 100 }, { 232, 234, 39, 238, 160, 97, 60, 254, 134, 103, 118, 184, 84, 57, 145, 227, 220, 7, 162, 172, 245, 176, 71, 58, 180, 192, 181, 40, 95, 15, 177, 175, 208, 147, 46, 21, 73, 99, 241, 55, 200, 166, 43, 122, 44 }, { 205, 143, 37, 70, 185, 101, 107, 217, 208, 59, 184, 168, 228, 252, 150, 130, 221, 195, 61, 44, 173, 58, 117, 39, 193, 186, 47, 231, 182, 26, 237, 23, 21, 146, 145, 219, 87, 56, 242, 36, 139, 54, 64, 45, 96 }, { 135, 6, 53, 20, 190, 120, 163, 13, 237, 46, 84, 228, 229, 98, 100, 81, 69, 251, 131, 32, 45, 192, 238, 186, 94, 187, 217, 189, 236, 169, 82, 209, 241, 220, 28, 242, 72, 22, 173, 116, 201, 37, 140, 222, 15 }, { 19, 24, 181, 93, 94, 107, 67, 129, 102, 132, 57, 252, 98, 200, 89, 18, 11, 173, 232, 3, 53, 40, 194, 231, 226, 189, 197, 158, 170, 145, 75, 25, 166, 69, 235, 54, 29, 234, 37, 5, 95, 120, 91, 52, 59 }, { 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145 }, { 76, 157, 70, 95, 253, 217, 129, 133, 168, 230, 227, 130, 81, 18, 44, 2, 152, 39, 140, 190, 231, 175, 31, 23, 77, 209, 219, 25, 162, 36, 88, 4, 45, 78, 5, 97, 211, 67, 62, 46, 154, 191, 171, 50, 89 }, { 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1 }, { 45, 37, 80, 101, 223, 208, 102, 168, 191, 150, 7, 195, 251, 173, 38, 39, 10, 47, 127, 26, 197, 21, 115, 219, 100, 242, 245, 54, 205, 96, 70, 97, 107, 68, 59, 33, 228, 241, 130, 89, 61, 207, 58, 12, 193 }, { 90, 148, 186, 30, 226, 62, 109, 73, 179, 174, 162, 61, 131, 232, 96, 140, 153, 127, 52, 51, 168, 99, 98, 56, 172, 22, 8, 234, 212, 185, 240, 67, 237, 79, 114, 241, 25, 121, 245, 108, 19, 39, 20, 188, 223 }, { 180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, 77, 145, 55, 167, 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108, 38, 156, 160, 15, 226, 124, 169 }, { 117, 181, 161, 107, 26, 102, 41, 252, 87, 89, 245, 173, 45, 53, 185, 231, 68, 197, 168, 145, 110, 166, 61, 54, 38, 37, 186, 120, 134, 59, 21, 191, 196, 221, 36, 207, 205, 39, 80, 15, 217, 237, 33, 115, 150 }, { 234, 238, 97, 254, 103, 184, 57, 227, 7, 172, 176, 58, 192, 40, 15, 175, 147, 21, 99, 55, 166, 122, 216, 45, 106, 222, 107, 52, 133, 85, 123, 50, 195, 11, 32, 12, 140, 188, 182, 124, 158, 115, 49, 224, 36 }, { 201, 159, 47, 91, 124, 33, 209, 149, 166, 244, 71, 117, 238, 194, 223, 31, 79, 115, 98, 167, 61, 216, 90, 181, 190, 254, 206, 218, 213, 150, 224, 72, 54, 152, 106, 161, 177, 189, 184, 114, 171, 56, 18, 131, 38 }, { 143, 70, 101, 217, 59, 168, 252, 130, 195, 44, 58, 39, 186, 231, 26, 23, 146, 219, 56, 36, 54, 45, 181, 97, 223, 62, 33, 191, 110, 89, 251, 8, 12, 10, 15, 134, 197, 41, 179, 100, 86, 125, 205, 37, 185 }, { 3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, 233, 38, 106, 190, 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55, 89, 235, 32, 96, 160, 253, 26 }, { 6, 20, 120, 13, 46, 228, 98, 81, 251, 32, 192, 186, 187, 189, 169, 209, 220, 242, 22, 116, 37, 222, 254, 62, 132, 63, 130, 43, 250, 38, 212, 194, 182, 147, 77, 179, 141, 9, 54, 180, 159, 101, 67, 151, 85 }, { 12, 80, 231, 208, 169, 191, 87, 195, 125, 38, 181, 47, 217, 197, 85, 219, 221, 245, 8, 96, 186, 107, 206, 33, 145, 130, 86, 207, 45, 193, 101, 134, 102, 146, 150, 166, 251, 64, 39, 185, 127, 62, 21, 252, 100 }, { 24, 93, 107, 129, 132, 252, 200, 18, 173, 3, 40, 231, 189, 158, 145, 25, 69, 54, 234, 5, 120, 52, 218, 191, 174, 43, 207, 90, 35, 15, 136, 92, 115, 220, 239, 125, 76, 238, 101, 17, 133, 228, 149, 121, 44 }, { 48, 105, 127, 248, 77, 241, 224, 247, 64, 156, 95, 182, 236, 170, 150, 162, 11, 205, 212, 94, 134, 133, 213, 110, 239, 250, 45, 35, 30, 26, 218, 99, 130, 69, 108, 143, 40, 211, 206, 132, 229, 7, 144, 2, 96 }, { 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15 } };
+        static int[,] alpha192 = new int[32,55]  { { 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160 }, { 4, 16, 64, 29, 116, 205, 19, 76, 45, 180, 234, 143, 6, 24, 96, 157, 78, 37, 148, 106, 181, 238, 159, 70, 5, 20, 80, 93, 105, 185, 222, 95, 97, 153, 94, 101, 137, 30, 120, 253, 211, 107, 177, 254, 223, 91, 113, 217, 67, 17, 68, 13, 52, 208, 103 }, { 8, 64, 58, 205, 38, 45, 117, 143, 12, 96, 39, 37, 53, 181, 193, 70, 10, 80, 186, 185, 161, 97, 47, 101, 15, 120, 231, 107, 127, 223, 182, 217, 134, 68, 26, 208, 206, 62, 237, 59, 197, 102, 23, 184, 169, 33, 21, 168, 41, 85, 146, 228, 115, 191, 145 }, { 16, 29, 205, 76, 180, 143, 24, 157, 37, 106, 238, 70, 20, 93, 185, 95, 153, 101, 30, 253, 107, 254, 91, 217, 17, 13, 208, 129, 248, 59, 151, 133, 184, 79, 132, 168, 82, 73, 228, 230, 198, 252, 123, 227, 150, 149, 165, 130, 200, 28, 221, 81, 121, 195, 172 }, { 32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, 17, 26, 103, 124, 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174, 100, 28, 167, 89, 239, 172, 36, 244, 235, 44, 233, 108, 1, 32, 116, 38, 180 }, { 64, 205, 45, 143, 96, 37, 181, 70, 80, 185, 97, 101, 120, 107, 223, 217, 68, 208, 62, 59, 102, 184, 33, 168, 85, 228, 191, 252, 241, 150, 110, 130, 7, 221, 89, 195, 138, 61, 251, 44, 207, 173, 8, 58, 38, 117, 12, 39, 53, 193, 10, 186, 161, 47, 15 }, { 128, 19, 117, 24, 156, 181, 140, 93, 161, 94, 60, 107, 163, 67, 26, 129, 147, 102, 109, 132, 41, 57, 209, 252, 255, 98, 87, 200, 224, 89, 155, 18, 245, 11, 233, 173, 16, 232, 45, 3, 157, 53, 159, 40, 185, 194, 137, 231, 254, 226, 68, 189, 248, 197, 46 }, { 29, 76, 143, 157, 106, 70, 93, 95, 101, 253, 254, 217, 13, 129, 59, 133, 79, 168, 73, 230, 252, 227, 149, 130, 28, 81, 195, 18, 247, 44, 27, 2, 58, 152, 3, 39, 212, 140, 186, 190, 202, 231, 225, 175, 26, 31, 118, 23, 158, 77, 146, 209, 229, 219, 55 }, { 58, 45, 12, 37, 193, 80, 161, 101, 231, 223, 134, 208, 237, 102, 169, 168, 146, 191, 179, 150, 87, 7, 166, 195, 36, 251, 125, 173, 64, 38, 143, 39, 181, 10, 185, 47, 120, 127, 217, 26, 62, 197, 184, 21, 85, 115, 252, 219, 110, 100, 221, 242, 138, 245, 44 }, { 116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, 28, 89, 172, 244, 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51, 169, 77, 114, 145, 255, 55, 100, 167, 239, 36, 235, 233, 1, 116, 180, 96, 106 }, { 232, 234, 39, 238, 160, 97, 60, 254, 134, 103, 118, 184, 84, 57, 145, 227, 220, 7, 162, 172, 245, 176, 71, 58, 180, 192, 181, 40, 95, 15, 177, 175, 208, 147, 46, 21, 73, 99, 241, 55, 200, 166, 43, 122, 44, 216, 128, 45, 48, 106, 10, 222, 202, 107, 226 }, { 205, 143, 37, 70, 185, 101, 107, 217, 208, 59, 184, 168, 228, 252, 150, 130, 221, 195, 61, 44, 173, 58, 117, 39, 193, 186, 47, 231, 182, 26, 237, 23, 21, 146, 145, 219, 87, 56, 242, 36, 139, 54, 64, 45, 96, 181, 80, 97, 120, 223, 68, 62, 102, 33, 85 }, { 135, 6, 53, 20, 190, 120, 163, 13, 237, 46, 84, 228, 229, 98, 100, 81, 69, 251, 131, 32, 45, 192, 238, 186, 94, 187, 217, 189, 236, 169, 82, 209, 241, 220, 28, 242, 72, 22, 173, 116, 201, 37, 140, 222, 15, 254, 34, 62, 204, 132, 146, 63, 75, 130, 167 }, { 19, 24, 181, 93, 94, 107, 67, 129, 102, 132, 57, 252, 98, 200, 89, 18, 11, 173, 232, 3, 53, 40, 194, 231, 226, 189, 197, 158, 170, 145, 75, 25, 166, 69, 235, 54, 29, 234, 37, 5, 95, 120, 91, 52, 59, 218, 82, 191, 227, 174, 221, 43, 247, 207, 32 }, { 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185 }, { 76, 157, 70, 95, 253, 217, 129, 133, 168, 230, 227, 130, 81, 18, 44, 2, 152, 39, 140, 190, 231, 175, 31, 23, 77, 209, 219, 25, 162, 36, 88, 4, 45, 78, 5, 97, 211, 67, 62, 46, 154, 191, 171, 50, 89, 72, 176, 8, 90, 156, 10, 194, 187, 134, 124 }, { 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215 }, { 45, 37, 80, 101, 223, 208, 102, 168, 191, 150, 7, 195, 251, 173, 38, 39, 10, 47, 127, 26, 197, 21, 115, 219, 100, 242, 245, 54, 205, 96, 70, 97, 107, 68, 59, 33, 228, 241, 130, 89, 61, 207, 58, 12, 193, 161, 231, 134, 237, 169, 146, 179, 87, 166, 36 }, { 90, 148, 186, 30, 226, 62, 109, 73, 179, 174, 162, 61, 131, 232, 96, 140, 153, 127, 52, 51, 168, 99, 98, 56, 172, 22, 8, 234, 212, 185, 240, 67, 237, 79, 114, 241, 25, 121, 245, 108, 19, 39, 20, 188, 223, 189, 133, 41, 63, 55, 221, 9, 176, 64, 3 }, { 180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, 77, 145, 55, 167, 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108, 38, 156, 160, 15, 226, 124, 169, 114, 255, 100, 239, 235, 1, 180, 106, 185, 253 }, { 117, 181, 161, 107, 26, 102, 41, 252, 87, 89, 245, 173, 45, 53, 185, 231, 68, 197, 168, 145, 110, 166, 61, 54, 38, 37, 186, 120, 134, 59, 21, 191, 196, 221, 36, 207, 205, 39, 80, 15, 217, 237, 33, 115, 150, 56, 138, 125, 58, 96, 10, 101, 182, 62, 169 }, { 234, 238, 97, 254, 103, 184, 57, 227, 7, 172, 176, 58, 192, 40, 15, 175, 147, 21, 99, 55, 166, 122, 216, 45, 106, 222, 107, 52, 133, 85, 123, 50, 195, 11, 32, 12, 140, 188, 182, 124, 158, 115, 49, 224, 36, 131, 19, 37, 105, 253, 68, 151, 154, 252, 174 }, { 201, 159, 47, 91, 124, 33, 209, 149, 166, 244, 71, 117, 238, 194, 223, 31, 79, 115, 98, 167, 61, 216, 90, 181, 190, 254, 206, 218, 213, 150, 224, 72, 54, 152, 106, 161, 177, 189, 184, 114, 171, 56, 18, 131, 38, 148, 111, 107, 104, 46, 146, 227, 14, 138, 233 }, { 143, 70, 101, 217, 59, 168, 252, 130, 195, 44, 58, 39, 186, 231, 26, 23, 146, 219, 56, 36, 54, 45, 181, 97, 223, 62, 33, 191, 110, 89, 251, 8, 12, 10, 15, 134, 197, 41, 179, 100, 86, 125, 205, 37, 185, 107, 208, 184, 228, 150, 221, 61, 173, 117, 193 }, { 3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, 233, 38, 106, 190, 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55, 89, 235, 32, 96, 160, 253, 26, 46, 114, 150, 167, 244, 1, 3, 5, 15, 17 }, { 6, 20, 120, 13, 46, 228, 98, 81, 251, 32, 192, 186, 187, 189, 169, 209, 220, 242, 22, 116, 37, 222, 254, 62, 132, 63, 130, 43, 250, 38, 212, 194, 182, 147, 77, 179, 141, 9, 54, 180, 159, 101, 67, 151, 85, 227, 112, 61, 142, 3, 10, 60, 136, 23, 114 }, { 12, 80, 231, 208, 169, 191, 87, 195, 125, 38, 181, 47, 217, 197, 85, 219, 221, 245, 8, 96, 186, 107, 206, 33, 145, 130, 86, 207, 45, 193, 101, 134, 102, 146, 150, 166, 251, 64, 39, 185, 127, 62, 21, 252, 100, 138, 54, 117, 70, 15, 68, 23, 228, 196, 89 }, { 24, 93, 107, 129, 132, 252, 200, 18, 173, 3, 40, 231, 189, 158, 145, 25, 69, 54, 234, 5, 120, 52, 218, 191, 174, 43, 207, 90, 35, 15, 136, 92, 115, 220, 239, 125, 76, 238, 101, 17, 133, 228, 149, 121, 44, 135, 212, 47, 175, 51, 146, 49, 162, 139, 116 }, { 48, 105, 127, 248, 77, 241, 224, 247, 64, 156, 95, 182, 236, 170, 150, 162, 11, 205, 212, 94, 134, 133, 213, 110, 239, 250, 45, 35, 30, 26, 218, 99, 130, 69, 108, 143, 40, 211, 206, 132, 229, 7, 144, 2, 96, 210, 254, 237, 154, 255, 221, 243, 128, 37, 190 }, { 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59 }, { 192, 222, 182, 151, 114, 110, 155, 27, 143, 160, 177, 237, 82, 75, 89, 88, 152, 70, 240, 103, 21, 123, 224, 251, 116, 212, 101, 136, 218, 145, 200, 144, 8, 78, 190, 217, 204, 183, 87, 172, 216, 12, 105, 225, 59, 170, 98, 242, 250, 180, 10, 211, 31, 168, 255 }, { 157, 95, 217, 133, 230, 130, 18, 2, 39, 190, 175, 23, 209, 25, 36, 4, 78, 97, 67, 46, 191, 50, 72, 8, 156, 194, 134, 92, 99, 100, 144, 16, 37, 153, 17, 184, 198, 200, 61, 32, 74, 47, 34, 109, 145, 141, 122, 64, 148, 94, 68, 218, 63, 7, 244 } };
+        static int[,] alpha256 = new int[58,89]  { { 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225 }, { 4, 16, 64, 29, 116, 205, 19, 76, 45, 180, 234, 143, 6, 24, 96, 157, 78, 37, 148, 106, 181, 238, 159, 70, 5, 20, 80, 93, 105, 185, 222, 95, 97, 153, 94, 101, 137, 30, 120, 253, 211, 107, 177, 254, 223, 91, 113, 217, 67, 17, 68, 13, 52, 208, 103, 129, 62, 248, 199, 59, 236, 151, 102, 133, 46, 184, 218, 79, 33, 132, 42, 168, 154, 82, 85, 73, 57, 228, 183, 230, 191, 198, 63, 252, 215, 123, 241, 227, 171 }, { 8, 64, 58, 205, 38, 45, 117, 143, 12, 96, 39, 37, 53, 181, 193, 70, 10, 80, 186, 185, 161, 97, 47, 101, 15, 120, 231, 107, 127, 223, 182, 217, 134, 68, 26, 208, 206, 62, 237, 59, 197, 102, 23, 184, 169, 33, 21, 168, 41, 85, 146, 228, 115, 191, 145, 252, 179, 241, 219, 150, 196, 110, 87, 130, 100, 7, 56, 221, 166, 89, 242, 195, 86, 138, 36, 61, 245, 251, 139, 44, 125, 207, 54, 173, 1, 8, 64, 58, 205 }, { 16, 29, 205, 76, 180, 143, 24, 157, 37, 106, 238, 70, 20, 93, 185, 95, 153, 101, 30, 253, 107, 254, 91, 217, 17, 13, 208, 129, 248, 59, 151, 133, 184, 79, 132, 168, 82, 73, 228, 230, 198, 252, 123, 227, 150, 149, 165, 130, 200, 28, 221, 81, 121, 195, 172, 18, 61, 247, 203, 44, 250, 27, 173, 2, 32, 58, 135, 152, 117, 3, 48, 39, 74, 212, 193, 140, 40, 186, 111, 190, 47, 202, 60, 231, 214, 225, 182, 175, 34 }, { 32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, 17, 26, 103, 124, 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174, 100, 28, 167, 89, 239, 172, 36, 244, 235, 44, 233, 108, 1, 32, 116, 38, 180, 3, 96, 156, 106, 193, 5, 160, 185, 190, 94, 15, 253, 214, 223, 226, 17, 26, 103, 124, 59, 51, 46, 169, 132, 77, 85, 114, 230, 145, 215, 255, 150, 55, 174 }, { 64, 205, 45, 143, 96, 37, 181, 70, 80, 185, 97, 101, 120, 107, 223, 217, 68, 208, 62, 59, 102, 184, 33, 168, 85, 228, 191, 252, 241, 150, 110, 130, 7, 221, 89, 195, 138, 61, 251, 44, 207, 173, 8, 58, 38, 117, 12, 39, 53, 193, 10, 186, 161, 47, 15, 231, 127, 182, 134, 26, 206, 237, 197, 23, 169, 21, 41, 146, 115, 145, 179, 219, 196, 87, 100, 56, 166, 242, 86, 36, 245, 139, 125, 54, 1, 64, 205, 45, 143 }, { 128, 19, 117, 24, 156, 181, 140, 93, 161, 94, 60, 107, 163, 67, 26, 129, 147, 102, 109, 132, 41, 57, 209, 252, 255, 98, 87, 200, 224, 89, 155, 18, 245, 11, 233, 173, 16, 232, 45, 3, 157, 53, 159, 40, 185, 194, 137, 231, 254, 226, 68, 189, 248, 197, 46, 158, 168, 170, 183, 145, 123, 75, 110, 25, 28, 166, 249, 69, 61, 235, 176, 54, 2, 29, 38, 234, 48, 37, 119, 5, 186, 95, 188, 120, 214, 91, 134, 52, 31 }, { 29, 76, 143, 157, 106, 70, 93, 95, 101, 253, 254, 217, 13, 129, 59, 133, 79, 168, 73, 230, 252, 227, 149, 130, 28, 81, 195, 18, 247, 44, 27, 2, 58, 152, 3, 39, 212, 140, 186, 190, 202, 231, 225, 175, 26, 31, 118, 23, 158, 77, 146, 209, 229, 219, 55, 25, 56, 162, 155, 36, 243, 88, 54, 4, 116, 45, 6, 78, 181, 5, 105, 97, 137, 211, 223, 67, 52, 62, 236, 46, 33, 154, 57, 191, 215, 171, 110, 50, 112 }, { 58, 45, 12, 37, 193, 80, 161, 101, 231, 223, 134, 208, 237, 102, 169, 168, 146, 191, 179, 150, 87, 7, 166, 195, 36, 251, 125, 173, 64, 38, 143, 39, 181, 10, 185, 47, 120, 127, 217, 26, 62, 197, 184, 21, 85, 115, 252, 219, 110, 100, 221, 242, 138, 245, 44, 54, 8, 205, 117, 96, 53, 70, 186, 97, 15, 107, 182, 68, 206, 59, 23, 33, 41, 228, 145, 241, 196, 130, 56, 89, 86, 61, 139, 207, 1, 58, 45, 12, 37 }, { 116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, 28, 89, 172, 244, 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51, 169, 77, 114, 145, 255, 55, 100, 167, 239, 36, 235, 233, 1, 116, 180, 96, 106, 5, 185, 94, 253, 223, 17, 103, 59, 46, 132, 85, 230, 215, 150, 174, 28, 89, 172, 244, 44, 108, 32, 38, 3, 156, 193, 160, 190, 15, 214, 226, 26, 124, 51 }, { 232, 234, 39, 238, 160, 97, 60, 254, 134, 103, 118, 184, 84, 57, 145, 227, 220, 7, 162, 172, 245, 176, 71, 58, 180, 192, 181, 40, 95, 15, 177, 175, 208, 147, 46, 21, 73, 99, 241, 55, 200, 166, 43, 122, 44, 216, 128, 45, 48, 106, 10, 222, 202, 107, 226, 52, 237, 133, 66, 85, 209, 123, 196, 50, 167, 195, 144, 11, 54, 32, 76, 12, 148, 140, 185, 188, 211, 182, 13, 124, 102, 158, 82, 115, 215, 49, 130, 224, 249 }, { 205, 143, 37, 70, 185, 101, 107, 217, 208, 59, 184, 168, 228, 252, 150, 130, 221, 195, 61, 44, 173, 58, 117, 39, 193, 186, 47, 231, 182, 26, 237, 23, 21, 146, 145, 219, 87, 56, 242, 36, 139, 54, 64, 45, 96, 181, 80, 97, 120, 223, 68, 62, 102, 33, 85, 191, 241, 110, 7, 89, 138, 251, 207, 8, 38, 12, 53, 10, 161, 15, 127, 134, 206, 197, 169, 41, 115, 179, 196, 100, 166, 86, 245, 125, 1, 205, 143, 37, 70 }, { 135, 6, 53, 20, 190, 120, 163, 13, 237, 46, 84, 228, 229, 98, 100, 81, 69, 251, 131, 32, 45, 192, 238, 186, 94, 187, 217, 189, 236, 169, 82, 209, 241, 220, 28, 242, 72, 22, 173, 116, 201, 37, 140, 222, 15, 254, 34, 62, 204, 132, 146, 63, 75, 130, 167, 43, 245, 250, 4, 38, 24, 212, 80, 194, 253, 182, 52, 147, 184, 77, 183, 179, 149, 141, 89, 9, 203, 54, 128, 180, 39, 159, 210, 101, 214, 67, 206, 151, 158 }, { 19, 24, 181, 93, 94, 107, 67, 129, 102, 132, 57, 252, 98, 200, 89, 18, 11, 173, 232, 3, 53, 40, 194, 231, 226, 189, 197, 158, 170, 145, 75, 25, 166, 69, 235, 54, 29, 234, 37, 5, 95, 120, 91, 52, 59, 218, 82, 191, 227, 174, 221, 43, 247, 207, 32, 90, 39, 35, 111, 15, 225, 136, 237, 92, 77, 115, 246, 220, 56, 239, 122, 125, 4, 76, 96, 238, 105, 101, 177, 17, 62, 133, 42, 228, 215, 149, 7, 121, 72 }, { 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185, 15, 223, 26, 59, 169, 85, 145, 150, 100, 89, 36, 44, 1, 38, 96, 193, 185 }, { 76, 157, 70, 95, 253, 217, 129, 133, 168, 230, 227, 130, 81, 18, 44, 2, 152, 39, 140, 190, 231, 175, 31, 23, 77, 209, 219, 25, 162, 36, 88, 4, 45, 78, 5, 97, 211, 67, 62, 46, 154, 191, 171, 50, 89, 72, 176, 8, 90, 156, 10, 194, 187, 134, 124, 92, 41, 99, 75, 100, 178, 144, 125, 16, 180, 37, 20, 153, 107, 17, 248, 184, 82, 198, 150, 200, 121, 61, 250, 32, 117, 74, 40, 47, 214, 34, 237, 109, 164 }, { 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11, 1, 152, 78, 10, 153, 214, 68, 147, 79, 146, 215, 220, 221, 69, 11 }, { 45, 37, 80, 101, 223, 208, 102, 168, 191, 150, 7, 195, 251, 173, 38, 39, 10, 47, 127, 26, 197, 21, 115, 219, 100, 242, 245, 54, 205, 96, 70, 97, 107, 68, 59, 33, 228, 241, 130, 89, 61, 207, 58, 12, 193, 161, 231, 134, 237, 169, 146, 179, 87, 166, 36, 125, 64, 143, 181, 185, 120, 217, 62, 184, 85, 252, 110, 221, 138, 44, 8, 117, 53, 186, 15, 182, 206, 23, 41, 145, 196, 56, 86, 139, 1, 45, 37, 80, 101 }, { 90, 148, 186, 30, 226, 62, 109, 73, 179, 174, 162, 61, 131, 232, 96, 140, 153, 127, 52, 51, 168, 99, 98, 56, 172, 22, 8, 234, 212, 185, 240, 67, 237, 79, 114, 241, 25, 121, 245, 108, 19, 39, 20, 188, 223, 189, 133, 41, 63, 55, 221, 9, 176, 64, 3, 238, 161, 211, 34, 59, 66, 183, 219, 200, 239, 251, 71, 152, 37, 160, 137, 182, 129, 92, 85, 229, 165, 166, 72, 233, 58, 24, 35, 97, 214, 13, 197, 42, 209 }, { 180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, 77, 145, 55, 167, 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108, 38, 156, 160, 15, 226, 124, 169, 114, 255, 100, 239, 235, 1, 180, 106, 185, 253, 17, 59, 132, 230, 150, 28, 172, 44, 32, 3, 193, 190, 214, 26, 51, 77, 145, 55, 167, 36, 233, 116, 96, 5, 94, 223, 103, 46, 85, 215, 174, 89, 244, 108 }, { 117, 181, 161, 107, 26, 102, 41, 252, 87, 89, 245, 173, 45, 53, 185, 231, 68, 197, 168, 145, 110, 166, 61, 54, 38, 37, 186, 120, 134, 59, 21, 191, 196, 221, 36, 207, 205, 39, 80, 15, 217, 237, 33, 115, 150, 56, 138, 125, 58, 96, 10, 101, 182, 62, 169, 228, 219, 7, 86, 44, 64, 12, 70, 47, 223, 206, 184, 146, 241, 100, 195, 139, 8, 143, 193, 97, 127, 208, 23, 85, 179, 130, 242, 251, 1, 117, 181, 161, 107 }, { 234, 238, 97, 254, 103, 184, 57, 227, 7, 172, 176, 58, 192, 40, 15, 175, 147, 21, 99, 55, 166, 122, 216, 45, 106, 222, 107, 52, 133, 85, 123, 50, 195, 11, 32, 12, 140, 188, 182, 124, 158, 115, 49, 224, 36, 131, 19, 37, 105, 253, 68, 151, 154, 252, 174, 121, 251, 2, 201, 193, 194, 225, 206, 109, 114, 219, 14, 69, 125, 116, 157, 80, 30, 67, 59, 42, 198, 110, 81, 244, 173, 90, 212, 161, 214, 104, 23, 170, 246 }, { 201, 159, 47, 91, 124, 33, 209, 149, 166, 244, 71, 117, 238, 194, 223, 31, 79, 115, 98, 167, 61, 216, 90, 181, 190, 254, 206, 218, 213, 150, 224, 72, 54, 152, 106, 161, 177, 189, 184, 114, 171, 56, 18, 131, 38, 148, 111, 107, 104, 46, 146, 227, 14, 138, 233, 135, 37, 210, 211, 26, 133, 170, 241, 141, 172, 125, 232, 78, 186, 253, 136, 102, 164, 123, 100, 43, 88, 58, 157, 160, 120, 34, 151, 41, 215, 25, 195, 22, 128 }, { 143, 70, 101, 217, 59, 168, 252, 130, 195, 44, 58, 39, 186, 231, 26, 23, 146, 219, 56, 36, 54, 45, 181, 97, 223, 62, 33, 191, 110, 89, 251, 8, 12, 10, 15, 134, 197, 41, 179, 100, 86, 125, 205, 37, 185, 107, 208, 184, 228, 150, 221, 61, 173, 117, 193, 47, 182, 237, 21, 145, 87, 242, 139, 64, 96, 80, 120, 68, 102, 85, 241, 7, 138, 207, 38, 53, 161, 127, 206, 169, 115, 196, 166, 245, 1, 143, 70, 101, 217 }, { 3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, 233, 38, 106, 190, 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55, 89, 235, 32, 96, 160, 253, 26, 46, 114, 150, 167, 244, 1, 3, 5, 15, 17, 51, 85, 255, 28, 36, 108, 180, 193, 94, 226, 59, 77, 215, 100, 172, 233, 38, 106, 190, 223, 124, 132, 145, 174, 239, 44, 116, 156, 185, 214, 103, 169, 230, 55 }, { 6, 20, 120, 13, 46, 228, 98, 81, 251, 32, 192, 186, 187, 189, 169, 209, 220, 242, 22, 116, 37, 222, 254, 62, 132, 63, 130, 43, 250, 38, 212, 194, 182, 147, 77, 179, 141, 9, 54, 180, 159, 101, 67, 151, 85, 227, 112, 61, 142, 3, 10, 60, 136, 23, 114, 49, 166, 243, 16, 96, 93, 211, 208, 218, 230, 110, 121, 11, 58, 156, 111, 127, 31, 66, 145, 65, 155, 125, 19, 106, 97, 91, 199, 168, 215, 200, 138, 27, 90 }, { 12, 80, 231, 208, 169, 191, 87, 195, 125, 38, 181, 47, 217, 197, 85, 219, 221, 245, 8, 96, 186, 107, 206, 33, 145, 130, 86, 207, 45, 193, 101, 134, 102, 146, 150, 166, 251, 64, 39, 185, 127, 62, 21, 252, 100, 138, 54, 117, 70, 15, 68, 23, 228, 196, 89, 139, 58, 37, 161, 223, 237, 168, 179, 7, 36, 173, 143, 10, 120, 26, 184, 115, 110, 242, 44, 205, 53, 97, 182, 59, 41, 241, 56, 61, 1, 12, 80, 231, 208 }, { 24, 93, 107, 129, 132, 252, 200, 18, 173, 3, 40, 231, 189, 158, 145, 25, 69, 54, 234, 5, 120, 52, 218, 191, 174, 43, 207, 90, 35, 15, 136, 92, 115, 220, 239, 125, 76, 238, 101, 17, 133, 228, 149, 121, 44, 135, 212, 47, 175, 51, 146, 49, 162, 139, 116, 148, 97, 113, 236, 85, 171, 83, 251, 128, 156, 161, 163, 147, 41, 255, 224, 245, 16, 157, 185, 254, 248, 168, 123, 28, 61, 2, 48, 186, 214, 31, 21, 229, 141 }, { 48, 105, 127, 248, 77, 241, 224, 247, 64, 156, 95, 182, 236, 170, 150, 162, 11, 205, 212, 94, 134, 133, 213, 110, 239, 250, 45, 35, 30, 26, 218, 99, 130, 69, 108, 143, 40, 211, 206, 132, 229, 7, 144, 2, 96, 210, 254, 237, 154, 255, 221, 243, 128, 37, 190, 113, 197, 73, 49, 89, 22, 135, 181, 188, 17, 23, 183, 220, 195, 233, 90, 70, 60, 52, 169, 198, 25, 138, 216, 3, 80, 187, 129, 21, 215, 14, 61, 4, 192 }, { 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59, 85, 150, 89, 44, 38, 193, 15, 26, 169, 145, 100, 36, 1, 96, 185, 223, 59 }, { 192, 222, 182, 151, 114, 110, 155, 27, 143, 160, 177, 237, 82, 75, 89, 88, 152, 70, 240, 103, 21, 123, 224, 251, 116, 212, 101, 136, 218, 145, 200, 144, 8, 78, 190, 217, 204, 183, 87, 172, 216, 12, 105, 225, 59, 170, 98, 242, 250, 180, 10, 211, 31, 168, 255, 83, 139, 135, 238, 15, 52, 158, 252, 14, 244, 64, 74, 153, 134, 46, 209, 130, 9, 142, 96, 111, 91, 197, 57, 55, 195, 131, 201, 80, 214, 248, 41, 171, 162 }, { 157, 95, 217, 133, 230, 130, 18, 2, 39, 190, 175, 23, 209, 25, 36, 4, 78, 97, 67, 46, 191, 50, 72, 8, 156, 194, 134, 92, 99, 100, 144, 16, 37, 153, 17, 184, 198, 200, 61, 32, 74, 47, 34, 109, 145, 141, 122, 64, 148, 94, 68, 218, 63, 7, 244, 128, 53, 188, 136, 169, 126, 14, 245, 29, 106, 101, 13, 79, 252, 28, 247, 58, 212, 202, 26, 158, 229, 56, 243, 116, 181, 137, 52, 33, 215, 112, 251, 232, 119 }, { 39, 97, 134, 184, 145, 7, 245, 58, 181, 15, 208, 21, 241, 166, 44, 45, 10, 107, 237, 85, 196, 195, 54, 12, 185, 182, 102, 115, 130, 36, 8, 37, 47, 68, 169, 252, 56, 251, 205, 193, 120, 206, 168, 219, 89, 125, 117, 80, 127, 59, 146, 110, 86, 173, 96, 161, 217, 23, 191, 100, 61, 64, 53, 101, 26, 33, 179, 221, 139, 38, 70, 231, 62, 41, 150, 242, 207, 143, 186, 223, 197, 228, 87, 138, 1, 39, 97, 134, 184 }, { 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69, 1, 78, 153, 68, 79, 215, 221, 11, 152, 10, 214, 147, 146, 220, 69 }, { 156, 94, 26, 132, 255, 89, 233, 3, 185, 226, 46, 145, 28, 235, 38, 5, 214, 59, 114, 174, 36, 32, 106, 15, 103, 77, 150, 239, 108, 96, 190, 17, 169, 215, 167, 44, 180, 160, 223, 51, 230, 100, 244, 116, 193, 253, 124, 85, 55, 172, 1, 156, 94, 26, 132, 255, 89, 233, 3, 185, 226, 46, 145, 28, 235, 38, 5, 214, 59, 114, 174, 36, 32, 106, 15, 103, 77, 150, 239, 108, 96, 190, 17, 169, 215, 167, 44, 180, 160 }, { 37, 101, 208, 168, 150, 195, 173, 39, 47, 26, 21, 219, 242, 54, 96, 97, 68, 33, 241, 89, 207, 12, 161, 134, 169, 179, 166, 125, 143, 185, 217, 184, 252, 221, 44, 117, 186, 182, 23, 145, 56, 139, 45, 80, 223, 102, 191, 7, 251, 38, 10, 127, 197, 115, 100, 245, 205, 70, 107, 59, 228, 130, 61, 58, 193, 231, 237, 146, 87, 36, 64, 181, 120, 62, 85, 110, 138, 8, 53, 15, 206, 41, 196, 86, 1, 37, 101, 208, 168 }, { 74, 137, 206, 82, 55, 138, 16, 212, 120, 124, 73, 87, 72, 29, 193, 211, 147, 228, 25, 244, 205, 140, 177, 197, 230, 141, 251, 76, 40, 223, 204, 198, 56, 11, 180, 186, 113, 92, 252, 167, 176, 143, 111, 67, 169, 123, 162, 207, 24, 190, 68, 66, 227, 242, 108, 157, 47, 52, 84, 150, 155, 142, 37, 202, 103, 41, 149, 69, 8, 106, 60, 62, 170, 165, 36, 128, 238, 231, 199, 114, 130, 122, 232, 70, 214, 236, 115, 200, 243 }, { 148, 30, 62, 73, 174, 61, 232, 140, 127, 51, 99, 56, 22, 234, 185, 67, 79, 241, 121, 108, 39, 188, 189, 41, 55, 9, 64, 238, 211, 59, 183, 200, 251, 152, 160, 182, 92, 229, 166, 233, 24, 97, 13, 42, 150, 43, 2, 53, 60, 124, 146, 65, 122, 205, 5, 254, 102, 198, 112, 44, 201, 111, 134, 158, 255, 242, 216, 78, 101, 103, 82, 110, 18, 128, 193, 187, 118, 115, 141, 235, 45, 93, 113, 184, 215, 81, 207, 48, 194 }, { 53, 120, 237, 228, 100, 251, 45, 186, 217, 169, 241, 242, 173, 37, 15, 62, 146, 130, 245, 38, 80, 182, 184, 179, 89, 54, 39, 101, 206, 85, 87, 61, 205, 10, 223, 23, 252, 166, 207, 96, 47, 208, 41, 110, 36, 58, 70, 127, 102, 145, 221, 125, 12, 97, 26, 168, 196, 138, 64, 193, 107, 197, 191, 56, 44, 143, 161, 68, 21, 150, 86, 8, 181, 231, 59, 115, 7, 139, 117, 185, 134, 33, 219, 195, 1, 53, 120, 237, 228 }, { 106, 253, 59, 230, 28, 44, 3, 190, 26, 77, 55, 36, 116, 5, 223, 46, 215, 89, 108, 156, 15, 124, 114, 100, 235, 180, 185, 17, 132, 150, 172, 32, 193, 214, 51, 145, 167, 233, 96, 94, 103, 85, 174, 244, 38, 160, 226, 169, 255, 239, 1, 106, 253, 59, 230, 28, 44, 3, 190, 26, 77, 55, 36, 116, 5, 223, 46, 215, 89, 108, 156, 15, 124, 114, 100, 235, 180, 185, 17, 132, 150, 172, 32, 193, 214, 51, 145, 167, 233 }, { 212, 211, 197, 198, 167, 207, 157, 202, 62, 114, 200, 139, 201, 95, 26, 154, 220, 61, 19, 160, 217, 158, 171, 86, 32, 159, 127, 133, 229, 89, 216, 74, 120, 147, 230, 56, 176, 24, 47, 103, 170, 130, 243, 90, 185, 34, 42, 196, 18, 116, 10, 91, 109, 241, 239, 2, 181, 187, 151, 145, 83, 131, 39, 137, 124, 228, 141, 11, 143, 190, 52, 41, 165, 122, 38, 93, 175, 33, 75, 172, 64, 35, 254, 23, 215, 178, 173, 148, 240 }, { 181, 107, 102, 252, 89, 173, 53, 231, 197, 145, 166, 54, 37, 120, 59, 191, 221, 207, 39, 15, 237, 115, 56, 125, 96, 101, 62, 228, 7, 44, 12, 47, 206, 146, 100, 139, 143, 97, 208, 85, 130, 251, 117, 161, 26, 41, 87, 245, 45, 185, 68, 168, 110, 61, 38, 186, 134, 21, 196, 36, 205, 80, 217, 33, 150, 138, 58, 10, 182, 169, 219, 86, 64, 70, 223, 184, 241, 195, 8, 193, 127, 23, 179, 242, 1, 181, 107, 102, 252 }, { 119, 177, 23, 123, 239, 8, 159, 225, 184, 255, 43, 64, 140, 91, 169, 171, 69, 58, 20, 226, 33, 49, 18, 205, 160, 67, 21, 149, 144, 38, 105, 34, 168, 220, 244, 45, 111, 13, 41, 174, 243, 117, 95, 104, 85, 25, 203, 143, 194, 103, 146, 200, 22, 12, 94, 31, 228, 14, 176, 96, 202, 248, 115, 112, 233, 39, 30, 147, 191, 167, 27, 37, 240, 236, 145, 81, 216, 53, 211, 51, 252, 178, 142, 181, 214, 133, 179, 249, 4 }, { 238, 254, 184, 227, 172, 58, 40, 175, 21, 55, 122, 45, 222, 52, 85, 50, 11, 12, 188, 124, 115, 224, 131, 37, 253, 151, 252, 121, 2, 193, 225, 109, 219, 69, 116, 80, 67, 42, 110, 244, 90, 161, 104, 170, 100, 22, 24, 101, 248, 230, 221, 27, 74, 231, 51, 229, 242, 4, 159, 223, 218, 171, 138, 232, 160, 134, 84, 220, 245, 180, 95, 208, 73, 200, 44, 48, 202, 237, 209, 167, 54, 148, 211, 102, 215, 249, 8, 35, 163 }, { 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150, 36, 38, 185, 26, 85, 100, 44, 96, 15, 59, 145, 89, 1, 193, 223, 169, 150 }, { 159, 91, 33, 149, 244, 117, 194, 31, 115, 167, 216, 181, 254, 218, 150, 72, 152, 161, 189, 114, 56, 131, 148, 107, 46, 227, 138, 135, 210, 26, 170, 141, 125, 78, 253, 102, 123, 43, 58, 160, 34, 41, 25, 22, 96, 30, 236, 252, 249, 32, 10, 175, 84, 87, 235, 6, 101, 199, 198, 89, 2, 35, 182, 66, 55, 245, 234, 153, 62, 230, 83, 173, 119, 225, 169, 49, 144, 45, 95, 103, 228, 112, 27, 53, 214, 92, 219, 9, 19 }, { 35, 113, 21, 165, 235, 12, 137, 118, 252, 239, 128, 80, 34, 82, 100, 176, 78, 231, 133, 255, 138, 19, 111, 208, 114, 112, 54, 212, 254, 169, 98, 122, 117, 153, 124, 191, 162, 2, 70, 226, 42, 87, 203, 24, 15, 236, 229, 195, 29, 160, 68, 164, 200, 125, 156, 211, 23, 227, 9, 38, 222, 189, 228, 224, 108, 181, 225, 79, 196, 244, 234, 47, 248, 99, 89, 4, 140, 217, 84, 174, 139, 48, 30, 197, 215, 155, 58, 93, 136 }, { 70, 217, 168, 130, 44, 39, 231, 23, 219, 36, 45, 97, 62, 191, 89, 8, 10, 134, 41, 100, 125, 37, 107, 184, 150, 61, 117, 47, 237, 145, 242, 64, 80, 68, 85, 7, 207, 53, 127, 169, 196, 245, 143, 101, 59, 252, 195, 58, 186, 26, 146, 56, 54, 181, 223, 33, 110, 251, 12, 15, 197, 179, 86, 205, 185, 208, 228, 221, 173, 193, 182, 21, 87, 139, 96, 120, 102, 241, 138, 38, 161, 206, 115, 166, 1, 70, 217, 168, 130 }, { 140, 67, 41, 200, 233, 53, 254, 158, 110, 235, 48, 120, 204, 227, 36, 90, 153, 237, 63, 239, 58, 105, 104, 228, 167, 142, 70, 175, 154, 100, 250, 148, 127, 79, 55, 251, 24, 60, 102, 255, 18, 45, 194, 248, 145, 249, 29, 186, 52, 114, 221, 71, 35, 217, 77, 50, 125, 74, 177, 169, 149, 243, 12, 30, 51, 241, 9, 152, 97, 124, 198, 242, 128, 93, 26, 57, 224, 173, 159, 226, 168, 25, 176, 37, 214, 218, 196, 247, 6 }, { 5, 17, 85, 28, 108, 193, 226, 77, 100, 233, 106, 223, 132, 174, 44, 156, 214, 169, 55, 235, 96, 253, 46, 150, 244, 3, 15, 51, 255, 36, 180, 94, 59, 215, 172, 38, 190, 124, 145, 239, 116, 185, 103, 230, 89, 32, 160, 26, 114, 167, 1, 5, 17, 85, 28, 108, 193, 226, 77, 100, 233, 106, 223, 132, 174, 44, 156, 214, 169, 55, 235, 96, 253, 46, 150, 244, 3, 15, 51, 255, 36, 180, 94, 59, 215, 172, 38, 190, 124 }, { 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221, 1, 10, 68, 146, 221 }, { 20, 13, 228, 81, 32, 186, 189, 209, 242, 116, 222, 62, 63, 43, 38, 194, 147, 179, 9, 180, 101, 151, 227, 61, 3, 60, 23, 49, 243, 96, 211, 218, 110, 11, 156, 127, 66, 65, 125, 106, 91, 168, 200, 27, 193, 175, 164, 56, 71, 5, 68, 57, 83, 8, 160, 104, 115, 178, 29, 185, 129, 198, 195, 135, 190, 237, 229, 69, 45, 94, 236, 241, 72, 201, 15, 204, 75, 245, 24, 253, 184, 149, 203, 39, 214, 158, 87, 88, 148 }, { 40, 52, 115, 121, 116, 161, 248, 229, 138, 180, 202, 102, 75, 247, 96, 187, 79, 87, 176, 106, 182, 154, 14, 173, 5, 136, 228, 162, 128, 185, 31, 63, 86, 152, 94, 197, 227, 122, 12, 253, 109, 110, 22, 74, 223, 84, 200, 54, 35, 17, 146, 83, 16, 186, 103, 99, 195, 19, 194, 59, 246, 72, 143, 60, 46, 196, 203, 78, 127, 132, 25, 207, 238, 175, 85, 224, 2, 80, 104, 230, 242, 232, 95, 237, 215, 9, 117, 137, 204 }, { 80, 208, 191, 195, 38, 47, 197, 219, 245, 96, 107, 33, 130, 207, 193, 134, 146, 166, 64, 185, 62, 252, 138, 117, 15, 23, 196, 139, 37, 223, 168, 7, 173, 10, 26, 115, 242, 205, 97, 59, 241, 61, 12, 231, 169, 87, 125, 181, 217, 85, 221, 8, 186, 206, 145, 86, 45, 101, 102, 150, 251, 39, 127, 21, 100, 54, 70, 68, 228, 89, 58, 161, 237, 179, 36, 143, 120, 184, 110, 44, 53, 182, 41, 56, 1, 80, 208, 191, 195 }, { 160, 103, 145, 172, 180, 15, 46, 55, 44, 106, 226, 85, 167, 32, 185, 124, 215, 36, 3, 253, 169, 174, 233, 193, 17, 114, 89, 116, 190, 59, 255, 244, 96, 214, 132, 100, 108, 5, 26, 230, 239, 38, 94, 51, 150, 235, 156, 223, 77, 28, 1, 160, 103, 145, 172, 180, 15, 46, 55, 44, 106, 226, 85, 167, 32, 185, 124, 215, 36, 3, 253, 169, 174, 233, 193, 17, 114, 89, 116, 190, 59, 255, 244, 96, 214, 132, 100, 108, 5 }, { 93, 129, 252, 18, 3, 231, 158, 25, 54, 5, 52, 191, 43, 90, 15, 92, 220, 125, 238, 17, 228, 121, 135, 47, 51, 49, 139, 148, 113, 85, 83, 128, 161, 147, 255, 245, 157, 254, 168, 28, 2, 186, 31, 229, 36, 6, 211, 33, 50, 108, 10, 104, 99, 86, 180, 30, 184, 165, 250, 193, 34, 213, 242, 19, 94, 102, 98, 11, 53, 226, 170, 166, 29, 95, 59, 227, 247, 39, 225, 77, 56, 4, 105, 62, 215, 72, 12, 187, 66 }, { 186, 62, 179, 61, 96, 127, 168, 56, 8, 185, 237, 241, 245, 39, 223, 41, 221, 64, 161, 59, 219, 251, 37, 182, 85, 166, 58, 97, 197, 150, 139, 53, 217, 146, 89, 205, 47, 102, 196, 44, 181, 134, 228, 242, 38, 101, 23, 110, 125, 193, 68, 115, 195, 45, 15, 184, 87, 207, 70, 26, 191, 86, 117, 120, 169, 130, 54, 10, 208, 145, 138, 143, 231, 33, 100, 173, 80, 206, 252, 36, 12, 107, 21, 7, 1, 186, 62, 179, 61 }, { 105, 248, 241, 247, 156, 182, 170, 162, 205, 94, 133, 110, 250, 35, 26, 99, 69, 143, 211, 132, 7, 2, 210, 237, 255, 243, 37, 113, 73, 89, 135, 188, 23, 220, 233, 70, 52, 198, 138, 3, 187, 21, 14, 4, 185, 199, 227, 251, 74, 226, 146, 178, 19, 101, 46, 165, 207, 140, 104, 145, 9, 6, 107, 42, 28, 8, 111, 147, 219, 235, 148, 217, 57, 121, 38, 202, 92, 87, 131, 5, 208, 63, 18, 12, 214, 84, 56, 16, 222 } };
+        static int[] logArrays = { 256, 0, 1, 25, 2, 50, 26, 198, 3, 223, 51, 238, 27, 104, 199, 75, 4, 100, 224, 14, 52, 141, 239, 129, 28, 193, 105, 248, 200, 8, 76, 113, 5, 138, 101, 47, 225, 36, 15, 33, 53, 147, 142, 218, 240, 18, 130, 69, 29, 181, 194, 125, 106, 39, 249, 185, 201, 154, 9, 120, 77, 228, 114, 166, 6, 191, 139, 98, 102, 221, 48, 253, 226, 152, 37, 179, 16, 145, 34, 136, 54, 208, 148, 206, 143, 150, 219, 189, 241, 210, 19, 92, 131, 56, 70, 64, 30, 66, 182, 163, 195, 72, 126, 110, 107, 58, 40, 84, 250, 133, 186, 61, 202, 94, 155, 159, 10, 21, 121, 43, 78, 212, 229, 172, 115, 243, 167, 87, 7, 112, 192, 247, 140, 128, 99, 13, 103, 74, 222, 237, 49, 197, 254, 24, 227, 165, 153, 119, 38, 184, 180, 124, 17, 68, 146, 217, 35, 32, 137, 46, 55, 63, 209, 91, 149, 188, 207, 205, 144, 135, 151, 178, 220, 252, 190, 97, 242, 86, 211, 171, 20, 42, 93, 158, 132, 60, 57, 83, 71, 109, 65, 162, 31, 45, 67, 216, 183, 123, 164, 118, 196, 23, 73, 236, 127, 12, 111, 246, 108, 161, 59, 82, 41, 157, 85, 170, 251, 96, 134, 177, 187, 204, 62, 90, 203, 89, 95, 176, 156, 169, 160, 81, 11, 245, 22, 235, 122, 117, 44, 215, 79, 174, 213, 233, 230, 231, 173, 232, 116, 214, 244, 234, 168, 80, 88, 175 };
+        static int[] expArrays = { 1, 2, 4, 8, 16, 32, 64, 128, 29, 58, 116, 232, 205, 135, 19, 38, 76, 152, 45, 90, 180, 117, 234, 201, 143, 3, 6, 12, 24, 48, 96, 192, 157, 39, 78, 156, 37, 74, 148, 53, 106, 212, 181, 119, 238, 193, 159, 35, 70, 140, 5, 10, 20, 40, 80, 160, 93, 186, 105, 210, 185, 111, 222, 161, 95, 190, 97, 194, 153, 47, 94, 188, 101, 202, 137, 15, 30, 60, 120, 240, 253, 231, 211, 187, 107, 214, 177, 127, 254, 225, 223, 163, 91, 182, 113, 226, 217, 175, 67, 134, 17, 34, 68, 136, 13, 26, 52, 104, 208, 189, 103, 206, 129, 31, 62, 124, 248, 237, 199, 147, 59, 118, 236, 197, 151, 51, 102, 204, 133, 23, 46, 92, 184, 109, 218, 169, 79, 158, 33, 66, 132, 21, 42, 84, 168, 77, 154, 41, 82, 164, 85, 170, 73, 146, 57, 114, 228, 213, 183, 115, 230, 209, 191, 99, 198, 145, 63, 126, 252, 229, 215, 179, 123, 246, 241, 255, 227, 219, 171, 75, 150, 49, 98, 196, 149, 55, 110, 220, 165, 87, 174, 65, 130, 25, 50, 100, 200, 141, 7, 14, 28, 56, 112, 224, 221, 167, 83, 166, 81, 162, 89, 178, 121, 242, 249, 239, 195, 155, 43, 86, 172, 69, 138, 9, 18, 36, 72, 144, 61, 122, 244, 245, 247, 243, 251, 235, 203, 139, 11, 22, 44, 88, 176, 125, 250, 233, 207, 131, 27, 54, 108, 216, 173, 71, 142, 1, 2, 4 };
+
+        // Encode
+        internal static void Encode(byte[] codeWord, byte[] message, int mBitSize, int n1, int paramK, int paramG, int[] rsPoly)
+        {
+            int gateValue = 0;
+            byte[] encodedBytes = new byte[n1];
+            int[] tmp = new int[paramG];
+
+            byte[] msgByte = Arrays.Clone(message);
+
+            for (int i = 0; i < paramK; i++)
+            {
+                gateValue = Utils.ToUnsigned8bits(msgByte[paramK - 1 - i] ^ encodedBytes[n1 - paramK - 1]);
+
+                for (int j = 0; j < paramG; j++)
+                {
+                    tmp[j] = GFCalculator.mult(gateValue, rsPoly[j]);
+                    int n = 1;
+                }
+
+                for (int j = n1 - paramK - 1; j > 0; j--)
+                {
+                    encodedBytes[j] = (byte)(encodedBytes[j - 1] ^ tmp[j]);
+                }
+                encodedBytes[0] = (byte)(tmp[0]);
+            }
+
+            Array.Copy(msgByte, 0, encodedBytes, n1 - paramK, paramK);
+            Array.Copy(encodedBytes, 0, codeWord, 0, codeWord.Length);
+        }
+
+        // Decode
+        internal static void Decode(byte[] message, byte[] codeWord, int n1, int fft, int delta, int paramK, int paramG)
+        {
+            int fftSize = 1 << fft;
+            int mSize = 1 << (HqcParameters.PARAM_M - 1);
+
+            byte[] codeWordByte = Arrays.Clone(codeWord);
+
+            int[] syndromes = new int[2 * delta];
+            // Step 1: Compute syndromes
+            ComputeSyndromes(syndromes, codeWordByte, delta, n1);
+
+            // Step 2: Compute the error locator polynomial sigma
+            int[] sigma = new int[fftSize];
+            int degSigma = ComputeELP(sigma, syndromes, delta);
+
+            // Step 3: Compute roots using FFT
+            int[] fftRes = new int[1 << HqcParameters.PARAM_M];
+            byte[] errorSet = new byte[1 << HqcParameters.PARAM_M];
+            FastFourierTransform.FFT(fftRes, sigma, delta + 1, fft);
+            FastFourierTransform.FastFourierTransformGetError(errorSet, fftRes, mSize, logArrays);
+
+            // Step 4: Compute z(x)
+            int[] zx = new int[n1];
+            ComputeZx(zx, sigma, degSigma, syndromes, delta);
+
+            // Step 5: Compute errors
+            int[] errors = new int[n1];
+            ComputeErrors(errors, zx, errorSet, delta, n1);
+
+            // Step 6: Correct errors
+            for (int i = 0; i < n1; i++)
+            {
+                codeWordByte[i] ^= (byte) errors[i];
+            }
+            byte[] mTmp = new byte[paramK];
+            Array.Copy(codeWordByte, paramG - 1, mTmp, 0, paramK);
+            Array.Copy(mTmp, 0, message, 0, message.Length);
+        }
+
+        private static void ComputeSyndromes(int[] syndromes, byte[] codeWord, int delta, int n1)
+        {
+            if (n1 == 46)
+            {
+                for (int i = 0; i < 2 * delta; i++)
+                {
+                    for (int j = 1; j < n1; j++)
+                    {
+                        syndromes[i] ^= GFCalculator.mult(Utils.ToUnsigned8bits(codeWord[j]), alpha128[i, j - 1]);
+                    }
+                    syndromes[i] ^= Utils.ToUnsigned8bits(codeWord[0]);
+                }
+            }
+            else if (n1 == 56)
+            {
+                for (int i = 0; i < 2 * delta; i++)
+                {
+                    for (int j = 1; j < n1; j++)
+                    {
+                        syndromes[i] ^= GFCalculator.mult(Utils.ToUnsigned8bits(codeWord[j]), alpha192[i, j - 1]);
+                    }
+                    syndromes[i] ^= Utils.ToUnsigned8bits(codeWord[0]);
+                }
+            }
+            else if (n1 == 90)
+            {
+                for (int i = 0; i < 2 * delta; i++)
+                {
+                    for (int j = 1; j < n1; j++)
+                    {
+                        syndromes[i] ^= GFCalculator.mult(Utils.ToUnsigned8bits(codeWord[j]), alpha256[i, j - 1]);
+                    }
+                    syndromes[i] ^= Utils.ToUnsigned8bits(codeWord[0]);
+                }
+            }
+        }
+
+        private static int ComputeELP(int[] sigma, int[] syndromes, int delta)
+        {
+            sigma[0] = 1;
+            int degSigma = 0;
+            int degSigmaP = 0;
+            int[] sigmaDup = new int[delta + 1];
+            int[] sigmaP = new int[delta + 1];
+            int degSigmaDup = 0;
+            int pp = Utils.ToUnsigned16Bits(-1);
+            int dp = 1;
+            int d = syndromes[0];
+
+            sigmaP[1] = 1;
+
+            for (int i = 0; i < 2 * delta; i++)
+            {
+                Array.Copy(sigma, 0, sigmaDup, 0, delta + 1);
+                degSigmaDup = degSigma;
+                int dd = GFCalculator.mult(d, GFCalculator.inverse(dp));
+
+                for (int j = 1; j <= i + 1 && j <= delta; j++)
+                {
+                    sigma[j] ^= GFCalculator.mult(dd, sigmaP[j]);
+                }
+
+                int degX = Utils.ToUnsigned16Bits(i - pp);
+                int degXSigmaP = Utils.ToUnsigned16Bits(degX + degSigmaP);
+
+                int firstMask = d != 0 ? 0xffff : 0;
+                int secondMask = degXSigmaP > degSigma ? 0xffff : 0;
+
+                int mask = firstMask & secondMask;
+                degSigma ^= mask & (degXSigmaP ^ degSigma);
+
+                if (i == (2 * delta - 1))
+                {
+                    break;
+                }
+
+                pp ^= mask & (i ^ pp);
+                dp ^= mask & (d ^ dp);
+
+                for (int k = delta; k > 0; k--)
+                {
+                    sigmaP[k] = (mask & sigmaDup[k - 1]) ^ (~mask & sigmaP[k - 1]);
+                }
+
+                degSigmaP ^= mask & (degSigmaDup ^ degSigmaP);
+                d = syndromes[i + 1];
+
+                for (int k = 1; k <= i + 1 && k <= delta; k++)
+                {
+                    d ^= GFCalculator.mult(sigma[k], syndromes[i + 1 - k]);
+                }
+            }
+            return degSigma;
+        }
+
+        private static void ComputeZx(int[] output, int[] sigma, int deg, int[] syndromes, int delta)
+        {
+            output[0] = 1;
+
+            for (int i = 1; i < delta + 1; i++)
+            {
+                int mask = i - deg < 1 ? 0xffff : 0;
+                output[i] = mask & sigma[i];
+            }
+
+            output[1] ^= syndromes[0];
+
+            for (int i = 2; i <= delta; i++)
+            {
+                int mask = i - deg < 1 ? 0xffff : 0;
+                output[i] = mask & sigma[i - 1];
+
+                for (int j = 1; j < i; j++)
+                {
+                    output[i] ^= (mask) & GFCalculator.mult(sigma[j], syndromes[i - j - 1]);
+                }
+            }
+        }
+
+        private static void ComputeErrors(int[] res, int[] zx, byte[] errorCompactSet, int delta, int n1)
+        {
+            int[] betaSet = new int[delta];
+            int[] eSet = new int[delta];
+
+            int deltaCount = 0;
+            int deltaVal = 0;
+            int mask1 = 0;
+            for (int i = 0; i < n1; i++)
+            {
+                int mark = 0;
+                int mask = errorCompactSet[i] != 0 ? 0xffff : 0;
+                for (int j = 0; j < delta; j++)
+                {
+                    int iMask = j == deltaCount ? 0xffff : 0;
+                    betaSet[j] += iMask & mask & expArrays[i];
+                    mark += iMask & mask & 1;
+                }
+                deltaCount += mark;
+            }
+            deltaVal = deltaCount;
+
+            for (int i = 0; i < delta; i++)
+            {
+                int temp1 = 1;
+                int temp2 = 1;
+                int inv = GFCalculator.inverse(betaSet[i]);
+                int invPow = 1;
+
+                for (int j = 1; j <= delta; j++)
+                {
+                    invPow = GFCalculator.mult(invPow, inv);
+                    temp1 ^= GFCalculator.mult(invPow, zx[j]);
+                }
+
+                for (int j = 1; j < delta; j++)
+                {
+                    temp2 = GFCalculator.mult(temp2, (1 ^ GFCalculator.mult(inv, betaSet[(i + j) % delta])));
+                }
+
+                mask1 = i < deltaVal ? 0xffff : 0;
+                eSet[i] = mask1 & GFCalculator.mult(temp1, GFCalculator.inverse(temp2));
+            }
+
+            deltaCount = 0;
+            for (int i = 0; i < n1; i++)
+            {
+                int mark = 0;
+                int mask = errorCompactSet[i] != 0 ? 0xffff : 0;
+
+                for (int j = 0; j < delta; j++)
+                {
+                    int iMask = j == deltaCount ? 0xffff : 0;
+                    res[i] += iMask & mask & eSet[j];
+                    mark += iMask & mask & 1;
+                }
+                deltaCount += mark;
+            }
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/hqc/Utils.cs b/crypto/src/pqc/crypto/hqc/Utils.cs
new file mode 100644
index 000000000..4d44db07c
--- /dev/null
+++ b/crypto/src/pqc/crypto/hqc/Utils.cs
@@ -0,0 +1,155 @@
+using System;
+
+using Org.BouncyCastle.Crypto.Utilities;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Hqc
+{
+    internal class Utils
+    {
+        internal static void ResizeArray(ulong[] output, int sizeOutBits, ulong[] input, int sizeInBits,
+            int n1n2ByteSize, int n1n2Byte64Size)
+        {
+            ulong mask = 0x7FFFFFFFFFFFFFFFUL;
+            int val = 0;
+            if (sizeOutBits < sizeInBits)
+            {
+                if (sizeOutBits % 64 != 0)
+                {
+                    val = 64 - (sizeOutBits % 64);
+                }
+
+                Array.Copy(input, 0, output, 0, n1n2ByteSize);
+
+                for (int i = 0; i < val; ++i)
+                {
+                    output[n1n2Byte64Size - 1] &= mask >> i;
+                }
+            }
+            else
+            {
+                Array.Copy(input, 0, output, 0, (sizeInBits + 7) / 8);
+            }
+        }
+
+        internal static void FromULongArrayToByteArray(byte[] output, ulong[] input)
+        {
+            int max = output.Length / 8;
+            for (int i = 0; i != max; i++)
+            {
+                Pack.UInt64_To_LE(input[i], output, i * 8);
+            }
+
+            if (output.Length % 8 != 0)
+            {
+                int off = max * 8;
+                int count = 0;
+                while (off < output.Length)
+                {
+                    output[off++] = (byte)(input[max] >> (count++ * 8));
+                }
+            }
+        }
+
+        internal static ulong BitMask(ulong a, ulong b)
+        {
+            uint tmp = (uint)(a % b);
+            return ((1UL << (int)tmp) - 1);
+        }
+
+        internal static void FromByteArrayToULongArray(ulong[] output, byte[] input)
+        {
+            byte[] tmp = input;
+            if (input.Length % 8 != 0)
+            {
+                tmp = new byte[((input.Length + 7) / 8) * 8];
+                Array.Copy(input, 0, tmp, 0, input.Length);
+            }
+
+            int off = 0;
+            for (int i = 0; i < output.Length; i++)
+            {
+                output[i] = Pack.LE_To_UInt64(tmp, off);
+                off += 8;
+            }
+        }
+
+        internal static void FromByteArrayToByte16Array(int[] output, byte[] input)
+        {
+            byte[] tmp = input;
+            if (input.Length % 2 != 0)
+            {
+                tmp = new byte[((input.Length + 1) / 2) * 2];
+                Array.Copy(input, 0, tmp, 0, input.Length);
+            }
+
+            int off = 0;
+            for (int i = 0; i < output.Length; i++)
+            {
+                output[i] = (int)Pack.LE_To_UInt16(tmp, off);
+                off += 2;
+            }
+        }
+
+        internal static void FromByte32ArrayToULongArray(ulong[] output, int[] input)
+        {
+            for (int i = 0; i != input.Length; i += 2)
+            {
+                output[i / 2] = (uint)input[i];
+                output[i / 2] |= (ulong)input[i + 1] << 32;
+            }
+        }
+
+        internal static void FromByte16ArrayToULongArray(ulong[] output, ushort[] input)
+        {
+            for (int i = 0; i != input.Length; i += 4)
+            {
+                output[i / 4] = input[i];
+                output[i / 4] |= (ulong)input[i + 1] << 16;
+                output[i / 4] |= (ulong)input[i + 2] << 32;
+                output[i / 4] |= (ulong)input[i + 3] << 48;
+            }
+        }
+
+        internal static void FromULongArrayToByte32Array(int[] output, ulong[] input)
+        {
+            for (int i = 0; i != input.Length; i++)
+            {
+                output[2 * i] = (int)input[i];
+                output[2 * i + 1] = (int)(input[i] >> 32);
+            }
+        }
+
+        internal static void CopyBytes(int[] src, int offsetSrc, int[] dst, int offsetDst, int lengthBytes)
+        {
+            Array.Copy(src, offsetSrc, dst, offsetDst, lengthBytes / 2);
+        }
+
+        internal static int GetByteSizeFromBitSize(int size)
+        {
+            return (size + 7) / 8;
+        }
+
+        internal  static int GetByte64SizeFromBitSize(int size)
+        {
+            return (size + 63) / 64;
+        }
+
+        internal static int ToUnsigned8bits(int a)
+        {
+            return a & 0xff;
+        }
+
+        internal static int ToUnsigned16Bits(int a)
+        {
+            return a & 0xffff;
+        }
+
+        internal static void XorULongToByte16Array(ushort[] output, int outOff, ulong input)
+        {
+            output[outOff + 0] ^= (ushort)input;
+            output[outOff + 1] ^= (ushort)(input >> 16);
+            output[outOff + 2] ^= (ushort)(input >> 32);
+            output[outOff + 3] ^= (ushort)(input >> 48);
+        }
+    }
+}
diff --git a/crypto/src/pqc/crypto/lms/HSS.cs b/crypto/src/pqc/crypto/lms/HSS.cs
index 77c5fdab0..9c21198e4 100644
--- a/crypto/src/pqc/crypto/lms/HSS.cs
+++ b/crypto/src/pqc/crypto/lms/HSS.cs
@@ -3,15 +3,15 @@ using System.Collections.Generic;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class HSS
+    public static class Hss
     {
-        public static HSSPrivateKeyParameters GenerateHssKeyPair(HSSKeyGenerationParameters parameters)
+        public static HssPrivateKeyParameters GenerateHssKeyPair(HssKeyGenerationParameters parameters)
         {
             //
             // LmsPrivateKey can derive and hold the public key so we just use an array of those.
             //
-            LMSPrivateKeyParameters[] keys = new LMSPrivateKeyParameters[parameters.Depth];
-            LMSSignature[] sig = new LMSSignature[parameters.Depth - 1];
+            LmsPrivateKeyParameters[] keys = new LmsPrivateKeyParameters[parameters.Depth];
+            LmsSignature[] sig = new LmsSignature[parameters.Depth - 1];
 
             byte[] rootSeed = new byte[32];
             parameters.Random.NextBytes(rootSeed);
@@ -33,7 +33,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 var lms = parameters.GetLmsParameters(t);
                 if (t == 0)
                 {
-                    keys[t] = new LMSPrivateKeyParameters(
+                    keys[t] = new LmsPrivateKeyParameters(
                         lms.LMSigParameters,
                         lms.LMOtsParameters,
                         0,
@@ -61,10 +61,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 hssKeyMaxIndex = long.MaxValue;
             }
 
-            return new HSSPrivateKeyParameters(
+            return new HssPrivateKeyParameters(
                 parameters.Depth,
-                new List<LMSPrivateKeyParameters>(keys),
-                new List<LMSSignature>(sig),
+                new List<LmsPrivateKeyParameters>(keys),
+                new List<LmsSignature>(sig),
                 0, hssKeyMaxIndex);
         }
 
@@ -77,7 +77,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
          *
          * @param keyPair
          */
-        public static void IncrementIndex(HSSPrivateKeyParameters keyPair)
+        public static void IncrementIndex(HssPrivateKeyParameters keyPair)
         {
             lock (keyPair)
             {
@@ -87,7 +87,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             }
         }
 
-        public static void RangeTestKeys(HSSPrivateKeyParameters keyPair)
+        public static void RangeTestKeys(HssPrivateKeyParameters keyPair)
         {
             lock (keyPair)
             {
@@ -117,10 +117,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         }
 
 
-        public static HSSSignature GenerateSignature(HSSPrivateKeyParameters keyPair, byte[] message)
+        public static HssSignature GenerateSignature(HssPrivateKeyParameters keyPair, byte[] message)
         {
-            LMSSignedPubKey[] signed_pub_key;
-            LMSPrivateKeyParameters nextKey;
+            LmsSignedPubKey[] signed_pub_key;
+            LmsPrivateKeyParameters nextKey;
             int L = keyPair.L;
 
             lock (keyPair)
@@ -134,10 +134,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
                 // Step 2. Stand in for sig[L-1]
                 int i = 0;
-                signed_pub_key = new LMSSignedPubKey[L - 1];
+                signed_pub_key = new LmsSignedPubKey[L - 1];
                 while (i < L - 1)
                 {
-                    signed_pub_key[i] = new LMSSignedPubKey(sig[i], keys[i + 1].GetPublicKey());
+                    signed_pub_key[i] = new LmsSignedPubKey(sig[i], keys[i + 1].GetPublicKey());
                     ++i;
                 }
 
@@ -147,26 +147,26 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 keyPair.IncIndex();
             }
 
-            LMSContext context = nextKey.GenerateLmsContext().WithSignedPublicKeys(signed_pub_key);
+            LmsContext context = nextKey.GenerateLmsContext().WithSignedPublicKeys(signed_pub_key);
 
             context.BlockUpdate(message, 0, message.Length);
 
             return GenerateSignature(L, context);
         }
 
-        public static HSSSignature GenerateSignature(int L, LMSContext context)
+        public static HssSignature GenerateSignature(int L, LmsContext context)
         {
-            return new HSSSignature(L - 1, context.SignedPubKeys, LMS.GenerateSign(context));
+            return new HssSignature(L - 1, context.SignedPubKeys, Lms.GenerateSign(context));
         }
 
-        public static bool VerifySignature(HSSPublicKeyParameters publicKey, HSSSignature signature, byte[] message)
+        public static bool VerifySignature(HssPublicKeyParameters publicKey, HssSignature signature, byte[] message)
         {
             int Nspk = signature.GetlMinus1();
             if (Nspk + 1 != publicKey.L)
                 return false;
 
-            LMSSignature[] sigList = new LMSSignature[Nspk + 1];
-            LMSPublicKeyParameters[] pubList = new LMSPublicKeyParameters[Nspk];
+            LmsSignature[] sigList = new LmsSignature[Nspk + 1];
+            LmsPublicKeyParameters[] pubList = new LmsPublicKeyParameters[Nspk];
 
             for (int i = 0; i < Nspk; i++)
             {
@@ -175,13 +175,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             }
             sigList[Nspk] = signature.Signature;
 
-            LMSPublicKeyParameters key = publicKey.LmsPublicKey;
+            LmsPublicKeyParameters key = publicKey.LmsPublicKey;
 
             for (int i = 0; i < Nspk; i++)
             {
-                LMSSignature sig = sigList[i];
+                LmsSignature sig = sigList[i];
                 byte[] msg = pubList[i].ToByteArray();
-                if (!LMS.VerifySignature(key, sig, msg))
+                if (!Lms.VerifySignature(key, sig, msg))
                 {
                     return false;
                 }
@@ -194,11 +194,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                     throw new Exception(ex.Message, ex);
                 }
             }
-            return LMS.VerifySignature(key, sigList[Nspk], message);
+            return Lms.VerifySignature(key, sigList[Nspk], message);
         }
 
         private class PlaceholderLMSPrivateKey
-            : LMSPrivateKeyParameters
+            : LmsPrivateKeyParameters
         {
             internal PlaceholderLMSPrivateKey(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q,
                 byte[] I, int maxQ, byte[] masterSecret)
@@ -211,7 +211,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 throw new Exception("placeholder only");
             }
 
-            public override LMSPublicKeyParameters GetPublicKey()
+            public override LmsPublicKeyParameters GetPublicKey()
             {
                 throw new Exception("placeholder only");
             }
diff --git a/crypto/src/pqc/crypto/lms/HSSKeyGenerationParameters.cs b/crypto/src/pqc/crypto/lms/HSSKeyGenerationParameters.cs
index 5baaa7aa2..61ea51368 100644
--- a/crypto/src/pqc/crypto/lms/HSSKeyGenerationParameters.cs
+++ b/crypto/src/pqc/crypto/lms/HSSKeyGenerationParameters.cs
@@ -5,10 +5,10 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public sealed class HSSKeyGenerationParameters
+    public sealed class HssKeyGenerationParameters
         : KeyGenerationParameters
     {
-        private static LMSParameters[] ValidateLmsParameters(LMSParameters[] lmsParameters)
+        private static LmsParameters[] ValidateLmsParameters(LmsParameters[] lmsParameters)
         {
             if (lmsParameters == null)
                 throw new ArgumentNullException(nameof(lmsParameters));
@@ -17,7 +17,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             return lmsParameters;
         }
 
-        private readonly LMSParameters[] m_lmsParameters;
+        private readonly LmsParameters[] m_lmsParameters;
 
         /**
          * Base constructor - parameters and a source of randomness.
@@ -25,15 +25,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
          * @param lmsParameters array of LMS parameters, one per level in the hierarchy (up to 8 levels).
          * @param random   the random byte source.
          */
-        public HSSKeyGenerationParameters(LMSParameters[] lmsParameters, SecureRandom random)
-            :base(random, LmsUtils.CalculateStrength(ValidateLmsParameters(lmsParameters)[0]))
+        public HssKeyGenerationParameters(LmsParameters[] lmsParameters, SecureRandom random)
+            :base(random, LmsUtilities.CalculateStrength(ValidateLmsParameters(lmsParameters)[0]))
         {
             m_lmsParameters = lmsParameters;
         }
 
         public int Depth => m_lmsParameters.Length;
 
-        public LMSParameters GetLmsParameters(int index)
+        public LmsParameters GetLmsParameters(int index)
         {
             if (index < 0 || index >= m_lmsParameters.Length)
                 throw new ArgumentOutOfRangeException(nameof(index));
diff --git a/crypto/src/pqc/crypto/lms/HSSKeyPairGenerator.cs b/crypto/src/pqc/crypto/lms/HSSKeyPairGenerator.cs
index 137275a9a..273e18904 100644
--- a/crypto/src/pqc/crypto/lms/HSSKeyPairGenerator.cs
+++ b/crypto/src/pqc/crypto/lms/HSSKeyPairGenerator.cs
@@ -2,19 +2,19 @@ using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public sealed class HSSKeyPairGenerator
+    public sealed class HssKeyPairGenerator
         : IAsymmetricCipherKeyPairGenerator
     {
-        private HSSKeyGenerationParameters m_parameters;
+        private HssKeyGenerationParameters m_parameters;
 
         public void Init(KeyGenerationParameters parameters)
         {
-            m_parameters = (HSSKeyGenerationParameters)parameters;
+            m_parameters = (HssKeyGenerationParameters)parameters;
         }
 
         public AsymmetricCipherKeyPair GenerateKeyPair()
         {
-            HSSPrivateKeyParameters privKey = HSS.GenerateHssKeyPair(m_parameters);
+            HssPrivateKeyParameters privKey = Hss.GenerateHssKeyPair(m_parameters);
 
             return new AsymmetricCipherKeyPair(privKey.GetPublicKey(), privKey);
         }
diff --git a/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs b/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs
index bcbccef1a..447dbad27 100644
--- a/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/HSSPrivateKeyParameters.cs
@@ -8,25 +8,25 @@ using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class HSSPrivateKeyParameters
-        : LMSKeyParameters, ILMSContextBasedSigner
+    public class HssPrivateKeyParameters
+        : LmsKeyParameters, ILmsContextBasedSigner
     {
         private int l;
         private bool isShard;
-        private IList<LMSPrivateKeyParameters> keys;
-        private IList<LMSSignature> sig;
+        private IList<LmsPrivateKeyParameters> keys;
+        private IList<LmsSignature> sig;
         private long indexLimit;
         private long index = 0;
 
-        private HSSPublicKeyParameters publicKey;
+        private HssPublicKeyParameters publicKey;
 
-        public HSSPrivateKeyParameters(int l, IList<LMSPrivateKeyParameters> keys, IList<LMSSignature> sig, long index,
+        public HssPrivateKeyParameters(int l, IList<LmsPrivateKeyParameters> keys, IList<LmsSignature> sig, long index,
             long indexLimit)
     	    :base(true)
         {
             this.l = l;
-            this.keys = new List<LMSPrivateKeyParameters>(keys);
-            this.sig = new List<LMSSignature>(sig);
+            this.keys = new List<LmsPrivateKeyParameters>(keys);
+            this.sig = new List<LmsSignature>(sig);
             this.index = index;
             this.indexLimit = indexLimit;
             this.isShard = false;
@@ -37,7 +37,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             ResetKeyToIndex();
         }
 
-        private HSSPrivateKeyParameters(int l, IList<LMSPrivateKeyParameters> keys, IList<LMSSignature> sig, long index,
+        private HssPrivateKeyParameters(int l, IList<LmsPrivateKeyParameters> keys, IList<LmsSignature> sig, long index,
             long indexLimit, bool isShard)
     	    :base(true)
         {
@@ -45,67 +45,56 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             this.l = l;
             // this.keys =  new UnmodifiableListProxy(keys);
             // this.sig =  new UnmodifiableListProxy(sig);
-            this.keys = new List<LMSPrivateKeyParameters>(keys);
-            this.sig = new List<LMSSignature>(sig);
+            this.keys = new List<LmsPrivateKeyParameters>(keys);
+            this.sig = new List<LmsSignature>(sig);
             this.index = index;
             this.indexLimit = indexLimit;
             this.isShard = isShard;
         }
 
-        public static HSSPrivateKeyParameters GetInstance(byte[] privEnc, byte[] pubEnc)
+        public static HssPrivateKeyParameters GetInstance(byte[] privEnc, byte[] pubEnc)
         {
-            HSSPrivateKeyParameters pKey = GetInstance(privEnc);
+            HssPrivateKeyParameters pKey = GetInstance(privEnc);
 
-            pKey.publicKey = HSSPublicKeyParameters.GetInstance(pubEnc);
+            pKey.publicKey = HssPublicKeyParameters.GetInstance(pubEnc);
 
             return pKey;
         }
 
-        public static HSSPrivateKeyParameters GetInstance(Object src)
+        public static HssPrivateKeyParameters GetInstance(object src)
         {
-            if (src is HSSPrivateKeyParameters hssPrivateKeyParameters)
+            if (src is HssPrivateKeyParameters hssPrivateKeyParameters)
             {
                 return hssPrivateKeyParameters;
             }
             else if (src is BinaryReader binaryReader)
             {
-                byte[] data = binaryReader.ReadBytes(4);
-                Array.Reverse(data);
-                int version = BitConverter.ToInt32(data, 0);
+                int version = BinaryReaders.ReadInt32BigEndian(binaryReader);
                 if (version != 0)
-                {
-                    throw new Exception("unknown version for hss private key");
-                }
-                data = binaryReader.ReadBytes(4);
-                Array.Reverse(data);
-                int d = BitConverter.ToInt32(data, 0);
-                
-                data = binaryReader.ReadBytes(8);
-                Array.Reverse(data);
-                long index = BitConverter.ToInt64(data, 0);
-                
-                data = binaryReader.ReadBytes(8);
-                Array.Reverse(data);
-                long maxIndex = BitConverter.ToInt64(data, 0);;
-                
-                data = binaryReader.ReadBytes(1);
-                Array.Reverse(data);
-                bool limited = BitConverter.ToBoolean(data, 0);
-
-                var keys = new List<LMSPrivateKeyParameters>();
-                var signatures = new List<LMSSignature>();
+                    throw new Exception("unknown version for HSS private key");
+
+                int d = BinaryReaders.ReadInt32BigEndian(binaryReader);
+
+                long index = BinaryReaders.ReadInt64BigEndian(binaryReader);
+
+                long maxIndex = BinaryReaders.ReadInt64BigEndian(binaryReader);
+
+                bool limited = binaryReader.ReadBoolean();
+
+                var keys = new List<LmsPrivateKeyParameters>();
+                var signatures = new List<LmsSignature>();
 
                 for (int t = 0; t < d; t++)
                 {
-                    keys.Add(LMSPrivateKeyParameters.GetInstance(src));
+                    keys.Add(LmsPrivateKeyParameters.GetInstance(src));
                 }
 
                 for (int t = 0; t < d - 1; t++)
                 {
-                    signatures.Add(LMSSignature.GetInstance(src));
+                    signatures.Add(LmsSignature.GetInstance(src));
                 }
 
-                return new HSSPrivateKeyParameters(d, keys, signatures, index, maxIndex, limited);
+                return new HssPrivateKeyParameters(d, keys, signatures, index, maxIndex, limited);
             }
             else if (src is byte[] bytes)
             {
@@ -133,25 +122,25 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
         public int L => l;
 
-        public  long GetIndex()
+        public long GetIndex()
         {
             lock (this)
                 return index;
         }
 
-        public LMSParameters[] GetLmsParameters()
+        public LmsParameters[] GetLmsParameters()
         {
             lock (this)
             {
                 int len = keys.Count;
 
-                LMSParameters[] parms = new LMSParameters[len];
+                LmsParameters[] parms = new LmsParameters[len];
 
                 for (int i = 0; i < len; i++)
                 {
-                    LMSPrivateKeyParameters lmsPrivateKey = keys[i];
+                    LmsPrivateKeyParameters lmsPrivateKey = keys[i];
 
-                    parms[i] = new LMSParameters(lmsPrivateKey.GetSigParameters(), lmsPrivateKey.GetOtsParameters());
+                    parms[i] = new LmsParameters(lmsPrivateKey.GetSigParameters(), lmsPrivateKey.GetOtsParameters());
                 }
 
                 return parms;
@@ -166,17 +155,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             }
         }
 
-        private static HSSPrivateKeyParameters MakeCopy(HSSPrivateKeyParameters privateKeyParameters)
+        private static HssPrivateKeyParameters MakeCopy(HssPrivateKeyParameters privateKeyParameters)
         {
             return GetInstance(privateKeyParameters.GetEncoded());
         }
 
-        protected void UpdateHierarchy(IList<LMSPrivateKeyParameters> newKeys, IList<LMSSignature> newSig)
+        protected void UpdateHierarchy(IList<LmsPrivateKeyParameters> newKeys, IList<LmsSignature> newSig)
         {
             lock (this)
             {
-                keys = new List<LMSPrivateKeyParameters>(newKeys);
-                sig = new List<LMSSignature>(newSig);
+                keys = new List<LmsPrivateKeyParameters>(newKeys);
+                sig = new List<LmsSignature>(newSig);
             }
         }
 
@@ -192,7 +181,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             return indexLimit - index;
         }
 
-        LMSPrivateKeyParameters GetRootKey()
+        LmsPrivateKeyParameters GetRootKey()
         {
             return keys[0];
         }
@@ -206,7 +195,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
          * @param usageCount the number of usages the key should have.
          * @return a key based on the current key that can be used usageCount times.
          */
-        public HSSPrivateKeyParameters ExtractKeyShard(int usageCount)
+        public HssPrivateKeyParameters ExtractKeyShard(int usageCount)
         {
             lock (this)
             {
@@ -221,11 +210,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 //
                 index += usageCount;
 
-                var keys = new List<LMSPrivateKeyParameters>(this.GetKeys());
-                var sig = new List<LMSSignature>(this.GetSig());
+                var keys = new List<LmsPrivateKeyParameters>(this.GetKeys());
+                var sig = new List<LmsSignature>(this.GetSig());
 
-                HSSPrivateKeyParameters shard = MakeCopy(
-                    new HSSPrivateKeyParameters(l, keys, sig, shardStartIndex, maxIndexForShard, true));
+                HssPrivateKeyParameters shard = MakeCopy(
+                    new HssPrivateKeyParameters(l, keys, sig, shardStartIndex, maxIndexForShard, true));
 
                 ResetKeyToIndex();
 
@@ -233,12 +222,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             }
         }
 
-        public IList<LMSPrivateKeyParameters> GetKeys()
+        public IList<LmsPrivateKeyParameters> GetKeys()
         {
             lock (this) return keys;
         }
 
-        internal IList<LMSSignature> GetSig()
+        internal IList<LmsSignature> GetSig()
         {
             lock (this) return sig;
         }
@@ -271,14 +260,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             // LMSSignature[] sig = this.sig.toArray(new LMSSignature[this.sig.Count]);//   new LMSSignature[originalKeys.Size() - 1];
             //
 
-            LMSPrivateKeyParameters originalRootKey = this.GetRootKey();
+            LmsPrivateKeyParameters originalRootKey = this.GetRootKey();
 
             //
             // We need to replace the root key to a new q value.
             //
             if (keys[0].GetIndex() - 1 != qTreePath[0])
             {
-                keys[0] = LMS.GenerateKeys(
+                keys[0] = Lms.GenerateKeys(
                     originalRootKey.GetSigParameters(),
                     originalRootKey.GetOtsParameters(),
                     (int)qTreePath[0], originalRootKey.GetI(), originalRootKey.GetMasterSecret());
@@ -287,7 +276,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
             for (int i = 1; i < qTreePath.Length; i++)
             {
-                LMSPrivateKeyParameters intermediateKey = keys[i - 1];
+                LmsPrivateKeyParameters intermediateKey = keys[i - 1];
 
                 byte[] childI = new byte[16];
                 byte[] childSeed = new byte[32];
@@ -326,7 +315,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                     //
                     // This means the parent has changed.
                     //
-                    keys[i] = LMS.GenerateKeys(
+                    keys[i] = Lms.GenerateKeys(
                         originalKeys[i].GetSigParameters(),
                         originalKeys[i].GetOtsParameters(),
                         (int)qTreePath[i], childI, childSeed);
@@ -334,7 +323,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                     //
                     // Ensure post increment occurs on parent and the new public key is signed.
                     //
-                    sig[i - 1] = LMS.GenerateSign((LMSPrivateKeyParameters)keys[i - 1], ((LMSPrivateKeyParameters)keys[i]).GetPublicKey().ToByteArray());
+                    sig[i - 1] = Lms.GenerateSign((LmsPrivateKeyParameters)keys[i - 1], ((LmsPrivateKeyParameters)keys[i]).GetPublicKey().ToByteArray());
                     changed = true;
                 }
                 else if (!lmsQMatch)
@@ -343,7 +332,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                     // Q is different so we can generate a new private key but it will have the same public
                     // key so we do not need to sign it again.
                     //
-                    keys[i] = LMS.GenerateKeys(
+                    keys[i] = Lms.GenerateKeys(
                         originalKeys[i].GetSigParameters(),
                         originalKeys[i].GetOtsParameters(),
                         (int)qTreePath[i], childI, childSeed);
@@ -358,10 +347,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             }
         }
 
-        public HSSPublicKeyParameters GetPublicKey()
+        public HssPublicKeyParameters GetPublicKey()
         {
             lock (this)
-                return new HSSPublicKeyParameters(l, GetRootKey().GetPublicKey());
+                return new HssPublicKeyParameters(l, GetRootKey().GetPublicKey());
         }
 
         internal void ReplaceConsumedKey(int d)
@@ -375,21 +364,21 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             byte[] childI = new byte[16];
             Array.Copy(postImage, 0, childI, 0, childI.Length);
 
-            var newKeys = new List<LMSPrivateKeyParameters>(keys);
+            var newKeys = new List<LmsPrivateKeyParameters>(keys);
 
             //
             // We need the parameters from the LMS key we are replacing.
             //
-            LMSPrivateKeyParameters oldPk = keys[d];
+            LmsPrivateKeyParameters oldPk = keys[d];
 
-            newKeys[d] = LMS.GenerateKeys(oldPk.GetSigParameters(), oldPk.GetOtsParameters(), 0, childI, childRootSeed);
+            newKeys[d] = Lms.GenerateKeys(oldPk.GetSigParameters(), oldPk.GetOtsParameters(), 0, childI, childRootSeed);
 
-            var newSig = new List<LMSSignature>(sig);
+            var newSig = new List<LmsSignature>(sig);
 
-            newSig[d - 1] = LMS.GenerateSign(newKeys[d - 1], newKeys[d].GetPublicKey().ToByteArray());
+            newSig[d - 1] = Lms.GenerateSign(newKeys[d - 1], newKeys[d].GetPublicKey().ToByteArray());
 
-            this.keys = new List<LMSPrivateKeyParameters>(newKeys);
-            this.sig = new List<LMSSignature>(newSig);
+            this.keys = new List<LmsPrivateKeyParameters>(newKeys);
+            this.sig = new List<LmsSignature>(newSig);
         }
 
         public override bool Equals(Object o)
@@ -403,7 +392,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 return false;
             }
 
-            HSSPrivateKeyParameters that = (HSSPrivateKeyParameters)o;
+            HssPrivateKeyParameters that = (HssPrivateKeyParameters)o;
 
             if (l != that.l)
             {
@@ -456,12 +445,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                     .U64Str(indexLimit)
                     .Boolean(isShard); // Depth
 
-                foreach (LMSPrivateKeyParameters key in keys)
+                foreach (LmsPrivateKeyParameters key in keys)
                 {
                     composer.Bytes(key);
                 }
 
-                foreach (LMSSignature s in sig)
+                foreach (LmsSignature s in sig)
                 {
                     composer.Bytes(s);
                 }
@@ -486,15 +475,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             return MakeCopy(this);
         }
 
-        public LMSContext GenerateLmsContext()
+        public LmsContext GenerateLmsContext()
         {
-            LMSSignedPubKey[] signed_pub_key;
-            LMSPrivateKeyParameters nextKey;
+            LmsSignedPubKey[] signed_pub_key;
+            LmsPrivateKeyParameters nextKey;
             int L = this.L;
 
             lock (this)
             {
-                HSS.RangeTestKeys(this);
+                Hss.RangeTestKeys(this);
 
                 var keys = this.GetKeys();
                 var sig = this.GetSig();
@@ -503,10 +492,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
                 // Step 2. Stand in for sig[L-1]
                 int i = 0;
-                signed_pub_key = new LMSSignedPubKey[L - 1];
+                signed_pub_key = new LmsSignedPubKey[L - 1];
                 while (i < L - 1)
                 {
-                    signed_pub_key[i] = new LMSSignedPubKey(sig[i], keys[i + 1].GetPublicKey());
+                    signed_pub_key[i] = new LmsSignedPubKey(sig[i], keys[i + 1].GetPublicKey());
                     ++i;
                 }
 
@@ -519,11 +508,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             return nextKey.GenerateLmsContext().WithSignedPublicKeys(signed_pub_key);
         }
 
-        public byte[] GenerateSignature(LMSContext context)
+        public byte[] GenerateSignature(LmsContext context)
         {
             try
             {
-                return HSS.GenerateSignature(L, context).GetEncoded();
+                return Hss.GenerateSignature(L, context).GetEncoded();
             }
             catch (IOException e)
             {
diff --git a/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs b/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs
index f6641d9c1..85b781228 100644
--- a/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/HSSPublicKeyParameters.cs
@@ -5,32 +5,31 @@ using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public sealed class HSSPublicKeyParameters
-        : LMSKeyParameters, ILMSContextBasedVerifier
+    public sealed class HssPublicKeyParameters
+        : LmsKeyParameters, ILmsContextBasedVerifier
     {
         private readonly int m_l;
-        private readonly LMSPublicKeyParameters m_lmsPublicKey;
+        private readonly LmsPublicKeyParameters m_lmsPublicKey;
 
-        public HSSPublicKeyParameters(int l, LMSPublicKeyParameters lmsPublicKey)
+        public HssPublicKeyParameters(int l, LmsPublicKeyParameters lmsPublicKey)
     	    :base(false)
         {
             m_l = l;
             m_lmsPublicKey = lmsPublicKey;
         }
 
-        public static HSSPublicKeyParameters GetInstance(object src)
+        public static HssPublicKeyParameters GetInstance(object src)
         {
-            if (src is HSSPublicKeyParameters hssPublicKeyParameters)
+            if (src is HssPublicKeyParameters hssPublicKeyParameters)
             {
                 return hssPublicKeyParameters;
             }
             else if (src is BinaryReader binaryReader)
             {
-                byte[] data = binaryReader.ReadBytes(4);
-                Array.Reverse(data);
-                int L = BitConverter.ToInt32(data, 0);
-                LMSPublicKeyParameters lmsPublicKey = LMSPublicKeyParameters.GetInstance(src);// todo check endianness
-                return new HSSPublicKeyParameters(L, lmsPublicKey);
+                int L = BinaryReaders.ReadInt32BigEndian(binaryReader);
+
+                LmsPublicKeyParameters lmsPublicKey = LmsPublicKeyParameters.GetInstance(src);
+                return new HssPublicKeyParameters(L, lmsPublicKey);
             }
             else if (src is byte[] bytes)
             {
@@ -55,7 +54,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
         public int L => m_l;
 
-        public LMSPublicKeyParameters LmsPublicKey => m_lmsPublicKey;
+        public LmsPublicKeyParameters LmsPublicKey => m_lmsPublicKey;
 
         public override bool Equals(Object o)
         {
@@ -64,7 +63,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             if (o == null || GetType() != o.GetType())
                 return false;
 
-            HSSPublicKeyParameters publicKey = (HSSPublicKeyParameters)o;
+            HssPublicKeyParameters publicKey = (HssPublicKeyParameters)o;
 
             return m_l == publicKey.m_l
                 && m_lmsPublicKey.Equals(publicKey.m_lmsPublicKey);
@@ -84,39 +83,39 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 .Build();
         }
 
-        public LMSContext GenerateLmsContext(byte[] sigEnc)
+        public LmsContext GenerateLmsContext(byte[] sigEnc)
         {
-            HSSSignature signature;
+            HssSignature signature;
             try
             {
-                signature = HSSSignature.GetInstance(sigEnc, L);
+                signature = HssSignature.GetInstance(sigEnc, L);
             }
             catch (IOException e)
             {
                 throw new Exception($"cannot parse signature: {e.Message}");
             }
 
-            LMSSignedPubKey[] signedPubKeys = signature.GetSignedPubKeys();
-            LMSPublicKeyParameters key = signedPubKeys[signedPubKeys.Length - 1].GetPublicKey();
+            LmsSignedPubKey[] signedPubKeys = signature.GetSignedPubKeys();
+            LmsPublicKeyParameters key = signedPubKeys[signedPubKeys.Length - 1].GetPublicKey();
 
             return key.GenerateOtsContext(signature.Signature).WithSignedPublicKeys(signedPubKeys);
         }
 
-        public bool Verify(LMSContext context)
+        public bool Verify(LmsContext context)
         {
-            LMSSignedPubKey[] sigKeys = context.SignedPubKeys;
+            LmsSignedPubKey[] sigKeys = context.SignedPubKeys;
 
             if (sigKeys.Length != L - 1)
                 return false;
 
-            LMSPublicKeyParameters key = LmsPublicKey;
+            LmsPublicKeyParameters key = LmsPublicKey;
             bool failed = false;
 
             for (int i = 0; i < sigKeys.Length; i++)
             {
-                LMSSignature sig = sigKeys[i].GetSignature();
+                LmsSignature sig = sigKeys[i].GetSignature();
                 byte[] msg = sigKeys[i].GetPublicKey().ToByteArray();
-                if (!LMS.VerifySignature(key, sig, msg))
+                if (!Lms.VerifySignature(key, sig, msg))
                 {
                     failed = true;
                 }
diff --git a/crypto/src/pqc/crypto/lms/HSSSignature.cs b/crypto/src/pqc/crypto/lms/HSSSignature.cs
index 793beda66..7c4599835 100644
--- a/crypto/src/pqc/crypto/lms/HSSSignature.cs
+++ b/crypto/src/pqc/crypto/lms/HSSSignature.cs
@@ -6,54 +6,51 @@ using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class HSSSignature
+    public sealed class HssSignature
         : IEncodable
     {
         private int lMinus1;
-        private LMSSignedPubKey[] signedPubKey;
-        private LMSSignature signature;
+        private LmsSignedPubKey[] signedPubKey;
+        private LmsSignature signature;
 
-        public HSSSignature(int lMinus1, LMSSignedPubKey[] signedPubKey, LMSSignature signature)
+        public HssSignature(int lMinus1, LmsSignedPubKey[] signedPubKey, LmsSignature signature)
         {
             this.lMinus1 = lMinus1;
             this.signedPubKey = signedPubKey;
             this.signature = signature;
         }
 
-
         /**
-     * @param src byte[], InputStream or HSSSignature
-     * @param L   The HSS depth, available from public key.
-     * @return An HSSSignature instance.
-     * @throws IOException
-     */
-        public static HSSSignature GetInstance(Object src, int L)
+         * @param src byte[], InputStream or HSSSignature
+         * @param L   The HSS depth, available from public key.
+         * @return An HSSSignature instance.
+         * @throws IOException
+         */
+        public static HssSignature GetInstance(object src, int L)
         {
-            if (src is HSSSignature hssSignature)
+            if (src is HssSignature hssSignature)
             {
                 return hssSignature;
             }
             else if (src is BinaryReader binaryReader)
             {
-                byte[] data = binaryReader.ReadBytes(4);
-                Array.Reverse(data);
-                int lminus = BitConverter.ToInt32(data, 0);
+                int lminus = BinaryReaders.ReadInt32BigEndian(binaryReader);
                 if (lminus != L - 1)
                     throw new Exception("nspk exceeded maxNspk");
 
-                LMSSignedPubKey[] signedPubKeys = new LMSSignedPubKey[lminus];
+                LmsSignedPubKey[] signedPubKeys = new LmsSignedPubKey[lminus];
                 if (lminus != 0)
                 {
                     for (int t = 0; t < signedPubKeys.Length; t++)
                     {
-                        signedPubKeys[t] = new LMSSignedPubKey(LMSSignature.GetInstance(src),
-                            LMSPublicKeyParameters.GetInstance(src));
+                        signedPubKeys[t] = new LmsSignedPubKey(LmsSignature.GetInstance(src),
+                            LmsPublicKeyParameters.GetInstance(src));
                     }
                 }
 
-                LMSSignature sig = LMSSignature.GetInstance(src);
+                LmsSignature sig = LmsSignature.GetInstance(src);
 
-                return new HSSSignature(lminus, signedPubKeys, sig);
+                return new HssSignature(lminus, signedPubKeys, sig);
             }
             else if (src is byte[] bytes)
             {
@@ -82,12 +79,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             return lMinus1;
         }
 
-        public LMSSignedPubKey[] GetSignedPubKeys()
+        public LmsSignedPubKey[] GetSignedPubKeys()
         {
             return signedPubKey;
         }
 
-        public LMSSignature Signature => signature;
+        public LmsSignature Signature => signature;
 
         public override bool Equals(Object o)
         {
@@ -101,7 +98,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 return false;
             }
 
-            HSSSignature signature1 = (HSSSignature) o;
+            HssSignature signature1 = (HssSignature) o;
 
             if (lMinus1 != signature1.lMinus1)
             {
@@ -141,7 +138,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             composer.U32Str(lMinus1);
             if (signedPubKey != null)
             {
-                foreach (LMSSignedPubKey sigPub in signedPubKey)
+                foreach (LmsSignedPubKey sigPub in signedPubKey)
                 {
                     composer.Bytes(sigPub);
                 }
diff --git a/crypto/src/pqc/crypto/lms/HSSSigner.cs b/crypto/src/pqc/crypto/lms/HSSSigner.cs
index 4bbdff848..9ef7b57ae 100644
--- a/crypto/src/pqc/crypto/lms/HSSSigner.cs
+++ b/crypto/src/pqc/crypto/lms/HSSSigner.cs
@@ -5,21 +5,21 @@ using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class HSSSigner 
+    public sealed class HssSigner 
         : IMessageSigner
     {
-        private HSSPrivateKeyParameters privKey;
-        private HSSPublicKeyParameters pubKey;
+        private HssPrivateKeyParameters privKey;
+        private HssPublicKeyParameters pubKey;
 
         public void Init(bool forSigning, ICipherParameters param)
         {
             if (forSigning)
             {
-                this.privKey = (HSSPrivateKeyParameters) param;
+                this.privKey = (HssPrivateKeyParameters) param;
             }
             else
             {
-                this.pubKey = (HSSPublicKeyParameters) param;
+                this.pubKey = (HssPublicKeyParameters) param;
             }
         }
 
@@ -27,7 +27,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         {
             try
             {
-                return HSS.GenerateSignature(privKey, message).GetEncoded();
+                return Hss.GenerateSignature(privKey, message).GetEncoded();
             }
             catch (IOException e)
             {
@@ -39,7 +39,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         {
             try
             {
-                return HSS.VerifySignature(pubKey, HSSSignature.GetInstance(signature, pubKey.L), message);
+                return Hss.VerifySignature(pubKey, HssSignature.GetInstance(signature, pubKey.L), message);
             }
             catch (IOException e)
             {
diff --git a/crypto/src/pqc/crypto/lms/ILMSContextBasedSigner.cs b/crypto/src/pqc/crypto/lms/ILMSContextBasedSigner.cs
index 86144b8e8..94864b471 100644
--- a/crypto/src/pqc/crypto/lms/ILMSContextBasedSigner.cs
+++ b/crypto/src/pqc/crypto/lms/ILMSContextBasedSigner.cs
@@ -1,10 +1,10 @@
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public interface ILMSContextBasedSigner
+    public interface ILmsContextBasedSigner
     {
-        LMSContext GenerateLmsContext();
+        LmsContext GenerateLmsContext();
 
-        byte[] GenerateSignature(LMSContext context);
+        byte[] GenerateSignature(LmsContext context);
 
         long GetUsagesRemaining();
     }
diff --git a/crypto/src/pqc/crypto/lms/ILMSContextBasedVerifier.cs b/crypto/src/pqc/crypto/lms/ILMSContextBasedVerifier.cs
index 76538d052..ffba83ad2 100644
--- a/crypto/src/pqc/crypto/lms/ILMSContextBasedVerifier.cs
+++ b/crypto/src/pqc/crypto/lms/ILMSContextBasedVerifier.cs
@@ -1,9 +1,9 @@
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public interface ILMSContextBasedVerifier
+    public interface ILmsContextBasedVerifier
     {
-        LMSContext GenerateLmsContext(byte[] signature);
+        LmsContext GenerateLmsContext(byte[] signature);
 
-        bool Verify(LMSContext context);
+        bool Verify(LmsContext context);
     }
 }
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs b/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs
index 8482c1a53..e9df6fbfd 100644
--- a/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs
+++ b/crypto/src/pqc/crypto/lms/LMOtsPrivateKey.cs
@@ -18,22 +18,22 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             m_masterSecret = masterSecret;
         }
 
-        public LMSContext GetSignatureContext(LMSigParameters sigParams, byte[][] path)
+        public LmsContext GetSignatureContext(LMSigParameters sigParams, byte[][] path)
         {
-            byte[] C = new byte[LM_OTS.SEED_LEN];
+            byte[] C = new byte[LMOts.SEED_LEN];
 
             SeedDerive derive = GetDerivationFunction();
-            derive.J = LM_OTS.SEED_RANDOMISER_INDEX; // This value from reference impl.
+            derive.J = LMOts.SEED_RANDOMISER_INDEX; // This value from reference impl.
             derive.DeriveSeed(false, C, 0);
 
             IDigest ctx = DigestUtilities.GetDigest(m_parameters.DigestOid);
 
-            LmsUtils.ByteArray(m_I, ctx);
-            LmsUtils.U32Str(m_q, ctx);
-            LmsUtils.U16Str(LM_OTS.D_MESG, ctx);
-            LmsUtils.ByteArray(C, ctx);
+            LmsUtilities.ByteArray(m_I, ctx);
+            LmsUtilities.U32Str(m_q, ctx);
+            LmsUtilities.U16Str(LMOts.D_MESG, ctx);
+            LmsUtilities.ByteArray(C, ctx);
 
-            return new LMSContext(this, sigParams, ctx, C, path);
+            return new LmsContext(this, sigParams, ctx, C, path);
         }
 
         internal SeedDerive GetDerivationFunction()
diff --git a/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs b/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs
index 49c0871f5..09e8b2951 100644
--- a/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs
+++ b/crypto/src/pqc/crypto/lms/LMOtsPublicKey.cs
@@ -32,22 +32,16 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             }
             else if (src is BinaryReader binaryReader)
             {
-                byte[] data = binaryReader.ReadBytes(4);
-                Array.Reverse(data);
-                int index = BitConverter.ToInt32(data, 0);
-                
+                int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
                 LMOtsParameters parameter = LMOtsParameters.GetParametersByID(index);
-                byte[] I = new byte[16];
-                binaryReader.Read(I, 0, I.Length);
-                
-                Array.Reverse(data);
-                int q = BitConverter.ToInt32(data, 0);
 
-                byte[] K = new byte[parameter.N];
-                binaryReader.Read(K, 0, K.Length);
+                byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16);
 
-                return new LMOtsPublicKey(parameter, I, q, K);
+                int q = BinaryReaders.ReadInt32BigEndian(binaryReader);
+
+                byte[] K = BinaryReaders.ReadBytesFully(binaryReader, parameter.N);
 
+                return new LMOtsPublicKey(parameter, I, q, K);
             }
             else if (src is byte[] bytes)
             {
@@ -109,28 +103,28 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 .Build();
         }
 
-        internal LMSContext CreateOtsContext(LMOtsSignature signature)
+        internal LmsContext CreateOtsContext(LMOtsSignature signature)
         {
             IDigest ctx = DigestUtilities.GetDigest(m_parameters.DigestOid);
 
-            LmsUtils.ByteArray(m_I, ctx);
-            LmsUtils.U32Str(m_q, ctx);
-            LmsUtils.U16Str(LM_OTS.D_MESG, ctx);
-            LmsUtils.ByteArray(signature.C, ctx);
+            LmsUtilities.ByteArray(m_I, ctx);
+            LmsUtilities.U32Str(m_q, ctx);
+            LmsUtilities.U16Str(LMOts.D_MESG, ctx);
+            LmsUtilities.ByteArray(signature.C, ctx);
 
-            return new LMSContext(this, signature, ctx);
+            return new LmsContext(this, signature, ctx);
         }
 
-        internal LMSContext CreateOtsContext(LMSSignature signature)
+        internal LmsContext CreateOtsContext(LmsSignature signature)
         {
             IDigest ctx = DigestUtilities.GetDigest(m_parameters.DigestOid);
 
-            LmsUtils.ByteArray(m_I, ctx);
-            LmsUtils.U32Str(m_q, ctx);
-            LmsUtils.U16Str(LM_OTS.D_MESG, ctx);
-            LmsUtils.ByteArray(signature.OtsSignature.C, ctx);
+            LmsUtilities.ByteArray(m_I, ctx);
+            LmsUtilities.U32Str(m_q, ctx);
+            LmsUtilities.U16Str(LMOts.D_MESG, ctx);
+            LmsUtilities.ByteArray(signature.OtsSignature.C, ctx);
 
-            return new LMSContext(this, signature, ctx);
+            return new LmsContext(this, signature, ctx);
         }
     }
 }
diff --git a/crypto/src/pqc/crypto/lms/LMOtsSignature.cs b/crypto/src/pqc/crypto/lms/LMOtsSignature.cs
index db4b25641..c55866661 100644
--- a/crypto/src/pqc/crypto/lms/LMOtsSignature.cs
+++ b/crypto/src/pqc/crypto/lms/LMOtsSignature.cs
@@ -13,9 +13,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         private readonly byte[] m_C;
         private readonly byte[] m_y;
 
-        public LMOtsSignature(LMOtsParameters ParamType, byte[] c, byte[] y)
+        public LMOtsSignature(LMOtsParameters paramType, byte[] c, byte[] y)
         {
-            m_paramType = ParamType;
+            m_paramType = paramType;
             m_C = c;
             m_y = y;
         }
@@ -26,22 +26,16 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             {
                 return lmOtsSignature;
             }
-            //TODO replace inputstreams with something
-            
             else if (src is BinaryReader binaryReader)
             {
-                byte[] data = binaryReader.ReadBytes(4);
-                Array.Reverse(data);
-                int index = BitConverter.ToInt32(data, 0);
-                LMOtsParameters type = LMOtsParameters.GetParametersByID(index);
-                byte[] C = new byte[type.N];
+                int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
+                LMOtsParameters parameter = LMOtsParameters.GetParametersByID(index);
 
-                binaryReader.Read(C, 0, C.Length);
-            
-                byte[] sig = new byte[type.P * type.N];
-                binaryReader.Read(sig, 0, sig.Length);
+                byte[] C = BinaryReaders.ReadBytesFully(binaryReader, parameter.N);
 
-                return new LMOtsSignature(type, C, sig);
+                byte[] sig = BinaryReaders.ReadBytesFully(binaryReader, parameter.P * parameter.N);
+
+                return new LMOtsSignature(parameter, C, sig);
             }
             else if (src is byte[] bytes)
             {
diff --git a/crypto/src/pqc/crypto/lms/LMS.cs b/crypto/src/pqc/crypto/lms/LMS.cs
index c2401bd35..3c17b0a1e 100644
--- a/crypto/src/pqc/crypto/lms/LMS.cs
+++ b/crypto/src/pqc/crypto/lms/LMS.cs
@@ -5,12 +5,12 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public static class LMS
+    public static class Lms
     {
         internal static ushort D_LEAF = 0x8282;
         internal static ushort D_INTR = 0x8383;
 
-        public static LMSPrivateKeyParameters GenerateKeys(LMSigParameters parameterSet,
+        public static LmsPrivateKeyParameters GenerateKeys(LMSigParameters parameterSet,
             LMOtsParameters lmOtsParameters, int q, byte[] I, byte[] rootSeed)
         {
             //
@@ -30,10 +30,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
             int twoToH = 1 << parameterSet.H;
 
-            return new LMSPrivateKeyParameters(parameterSet, lmOtsParameters, q, I, twoToH, rootSeed);
+            return new LmsPrivateKeyParameters(parameterSet, lmOtsParameters, q, I, twoToH, rootSeed);
         }
 
-        public static LMSSignature GenerateSign(LMSPrivateKeyParameters privateKey, byte[] message)
+        public static LmsSignature GenerateSign(LmsPrivateKeyParameters privateKey, byte[] message)
         {
             //
             // Get T from the public key.
@@ -42,14 +42,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             // byte[][] T = new byte[privateKey.getMaxQ()][];
 
             // Step 2
-            LMSContext context = privateKey.GenerateLmsContext();
+            LmsContext context = privateKey.GenerateLmsContext();
 
             context.BlockUpdate(message, 0, message.Length);
 
             return GenerateSign(context);
         }
 
-        public static LMSSignature GenerateSign(LMSContext context)
+        public static LmsSignature GenerateSign(LmsContext context)
         {
             //
             // Get T from the public key.
@@ -59,36 +59,36 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
             // Step 1.
             LMOtsSignature ots_signature =
-                LM_OTS.LMOtsGenerateSignature(context.PrivateKey, context.GetQ(), context.C);
+                LMOts.LMOtsGenerateSignature(context.PrivateKey, context.GetQ(), context.C);
 
-            return new LMSSignature(context.PrivateKey.Q, ots_signature, context.SigParams, context.Path);
+            return new LmsSignature(context.PrivateKey.Q, ots_signature, context.SigParams, context.Path);
         }
 
-        public static bool VerifySignature(LMSPublicKeyParameters publicKey, LMSSignature S, byte[] message)
+        public static bool VerifySignature(LmsPublicKeyParameters publicKey, LmsSignature S, byte[] message)
         {
-            LMSContext context = publicKey.GenerateOtsContext(S);
+            LmsContext context = publicKey.GenerateOtsContext(S);
 
-            LmsUtils.ByteArray(message, context);
+            LmsUtilities.ByteArray(message, context);
 
             return VerifySignature(publicKey, context);
         }
 
-        public static bool VerifySignature(LMSPublicKeyParameters publicKey, byte[] S, byte[] message)
+        public static bool VerifySignature(LmsPublicKeyParameters publicKey, byte[] S, byte[] message)
         {
-            LMSContext context = publicKey.GenerateLmsContext(S);
+            LmsContext context = publicKey.GenerateLmsContext(S);
 
-            LmsUtils.ByteArray(message, context);
+            LmsUtilities.ByteArray(message, context);
 
             return VerifySignature(publicKey, context);
         }
 
-        public static bool VerifySignature(LMSPublicKeyParameters publicKey, LMSContext context)
+        public static bool VerifySignature(LmsPublicKeyParameters publicKey, LmsContext context)
         {
-            LMSSignature S = (LMSSignature)context.Signature;
+            LmsSignature S = (LmsSignature)context.Signature;
             LMSigParameters lmsParameter = S.SigParameters;
             int h = lmsParameter.H;
             byte[][] path = S.Y;
-            byte[] Kc = LM_OTS.LMOtsValidateSignatureCalculate(context);
+            byte[] Kc = LMOts.LMOtsValidateSignatureCalculate(context);
             // Step 4
             // node_num = 2^h + q
             int node_num = (1 << h) + S.Q;
@@ -99,8 +99,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             byte[] tmp = new byte[H.GetDigestSize()];
 
             H.BlockUpdate(I, 0, I.Length);
-            LmsUtils.U32Str(node_num, H);
-            LmsUtils.U16Str(D_LEAF, H);
+            LmsUtilities.U32Str(node_num, H);
+            LmsUtilities.U16Str(D_LEAF, H);
             H.BlockUpdate(Kc, 0, Kc.Length);
             H.DoFinal(tmp, 0);
 
@@ -112,8 +112,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 {
                     // is odd
                     H.BlockUpdate(I, 0, I.Length);
-                    LmsUtils.U32Str(node_num / 2, H);
-                    LmsUtils.U16Str(D_INTR, H);
+                    LmsUtilities.U32Str(node_num / 2, H);
+                    LmsUtilities.U16Str(D_INTR, H);
                     H.BlockUpdate(path[i], 0, path[i].Length);
                     H.BlockUpdate(tmp, 0, tmp.Length);
                     H.DoFinal(tmp, 0);
@@ -121,8 +121,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 else
                 {
                     H.BlockUpdate(I, 0, I.Length);
-                    LmsUtils.U32Str(node_num / 2, H);
-                    LmsUtils.U16Str(D_INTR, H);
+                    LmsUtilities.U32Str(node_num / 2, H);
+                    LmsUtilities.U16Str(D_INTR, H);
                     H.BlockUpdate(tmp, 0, tmp.Length);
                     H.BlockUpdate(path[i], 0, path[i].Length);
                     H.DoFinal(tmp, 0);
diff --git a/crypto/src/pqc/crypto/lms/LMSContext.cs b/crypto/src/pqc/crypto/lms/LMSContext.cs
index 12975b637..6fcbd9413 100644
--- a/crypto/src/pqc/crypto/lms/LMSContext.cs
+++ b/crypto/src/pqc/crypto/lms/LMSContext.cs
@@ -4,7 +4,7 @@ using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public sealed class LMSContext
+    public sealed class LmsContext
         : IDigest
     {
         private readonly byte[] m_c;
@@ -14,10 +14,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
         private readonly LMOtsPublicKey m_publicKey;
         private readonly object m_signature;
-        private LMSSignedPubKey[] m_signedPubKeys;
+        private LmsSignedPubKey[] m_signedPubKeys;
         private volatile IDigest m_digest;
 
-        public LMSContext(LMOtsPrivateKey privateKey, LMSigParameters sigParams, IDigest digest, byte[] C,
+        public LmsContext(LMOtsPrivateKey privateKey, LMSigParameters sigParams, IDigest digest, byte[] C,
             byte[][] path)
         {
             m_privateKey = privateKey;
@@ -29,7 +29,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             m_signature = null;
         }
 
-        public LMSContext(LMOtsPublicKey publicKey, object signature, IDigest digest)
+        public LmsContext(LMOtsPublicKey publicKey, object signature, IDigest digest)
         {
             m_publicKey = publicKey;
             m_signature = signature;
@@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
         public byte[] GetQ()
         {
-            byte[] Q = new byte[LM_OTS.MAX_HASH + 2];
+            byte[] Q = new byte[LMOts.MAX_HASH + 2];
             m_digest.DoFinal(Q, 0);
             m_digest = null;
             return Q;
@@ -60,9 +60,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
         public object Signature => m_signature;
 
-        internal LMSSignedPubKey[] SignedPubKeys => m_signedPubKeys;
+        internal LmsSignedPubKey[] SignedPubKeys => m_signedPubKeys;
 
-        internal LMSContext WithSignedPublicKeys(LMSSignedPubKey[] signedPubKeys)
+        internal LmsContext WithSignedPublicKeys(LmsSignedPubKey[] signedPubKeys)
         {
             m_signedPubKeys = signedPubKeys;
             return this;
diff --git a/crypto/src/pqc/crypto/lms/LMSException.cs b/crypto/src/pqc/crypto/lms/LMSException.cs
index c9c286b7f..694a370ed 100644
--- a/crypto/src/pqc/crypto/lms/LMSException.cs
+++ b/crypto/src/pqc/crypto/lms/LMSException.cs
@@ -4,25 +4,25 @@ using System.Runtime.Serialization;
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
     [Serializable]
-    public class LMSException
+    public class LmsException
         : Exception
     {
-		public LMSException()
+		public LmsException()
 			: base()
 		{
 		}
 
-		public LMSException(string message)
+		public LmsException(string message)
 			: base(message)
 		{
 		}
 
-		public LMSException(string message, Exception innerException)
+		public LmsException(string message, Exception innerException)
 			: base(message, innerException)
 		{
 		}
 
-		protected LMSException(SerializationInfo info, StreamingContext context)
+		protected LmsException(SerializationInfo info, StreamingContext context)
 			: base(info, context)
 		{
 		}
diff --git a/crypto/src/pqc/crypto/lms/LMSKeyGenerationParameters.cs b/crypto/src/pqc/crypto/lms/LMSKeyGenerationParameters.cs
index dd932c17d..ed2cb8957 100644
--- a/crypto/src/pqc/crypto/lms/LMSKeyGenerationParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMSKeyGenerationParameters.cs
@@ -3,10 +3,10 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class LMSKeyGenerationParameters
+    public class LmsKeyGenerationParameters
         : KeyGenerationParameters
     {
-        private readonly LMSParameters m_lmsParameters;
+        private readonly LmsParameters m_lmsParameters;
 
         /**
          * Base constructor - parameters and a source of randomness.
@@ -14,12 +14,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
          * @param lmsParameters LMS parameter set to use.
          * @param random   the random byte source.
          */
-        public LMSKeyGenerationParameters(LMSParameters lmsParameters, SecureRandom random)
-            : base(random, LmsUtils.CalculateStrength(lmsParameters)) // TODO: need something for "strength"
+        public LmsKeyGenerationParameters(LmsParameters lmsParameters, SecureRandom random)
+            : base(random, LmsUtilities.CalculateStrength(lmsParameters)) // TODO: need something for "strength"
         {
             m_lmsParameters = lmsParameters;
         }
 
-        public LMSParameters LmsParameters => m_lmsParameters;
+        public LmsParameters LmsParameters => m_lmsParameters;
     }
 }
diff --git a/crypto/src/pqc/crypto/lms/LMSKeyPairGenerator.cs b/crypto/src/pqc/crypto/lms/LMSKeyPairGenerator.cs
index 9147c3fdf..e1afb00d9 100644
--- a/crypto/src/pqc/crypto/lms/LMSKeyPairGenerator.cs
+++ b/crypto/src/pqc/crypto/lms/LMSKeyPairGenerator.cs
@@ -3,14 +3,14 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public sealed class LMSKeyPairGenerator
+    public sealed class LmsKeyPairGenerator
         : IAsymmetricCipherKeyPairGenerator
     {
-        private LMSKeyGenerationParameters m_parameters;
+        private LmsKeyGenerationParameters m_parameters;
 
         public void Init(KeyGenerationParameters parameters)
         {
-            m_parameters = (LMSKeyGenerationParameters)parameters;
+            m_parameters = (LmsKeyGenerationParameters)parameters;
         }
 
         public AsymmetricCipherKeyPair GenerateKeyPair()
@@ -23,7 +23,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             byte[] rootSecret = new byte[32];
             source.NextBytes(rootSecret);
 
-            LMSPrivateKeyParameters privKey = LMS.GenerateKeys(m_parameters.LmsParameters.LMSigParameters,
+            LmsPrivateKeyParameters privKey = Lms.GenerateKeys(m_parameters.LmsParameters.LMSigParameters,
                 m_parameters.LmsParameters.LMOtsParameters, 0, I, rootSecret);
 
             return new AsymmetricCipherKeyPair(privKey.GetPublicKey(), privKey);
diff --git a/crypto/src/pqc/crypto/lms/LMSKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSKeyParameters.cs
index e4b2df66d..b35ba36c4 100644
--- a/crypto/src/pqc/crypto/lms/LMSKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMSKeyParameters.cs
@@ -3,10 +3,10 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public abstract class LMSKeyParameters
+    public abstract class LmsKeyParameters
         : AsymmetricKeyParameter, IEncodable
     {
-        protected LMSKeyParameters(bool isPrivateKey)
+        protected LmsKeyParameters(bool isPrivateKey)
             : base(isPrivateKey)
         {
         }
diff --git a/crypto/src/pqc/crypto/lms/LMSParameters.cs b/crypto/src/pqc/crypto/lms/LMSParameters.cs
index adffad2da..49ce2f71a 100644
--- a/crypto/src/pqc/crypto/lms/LMSParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMSParameters.cs
@@ -1,11 +1,11 @@
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public sealed class LMSParameters
+    public sealed class LmsParameters
     {
         private readonly LMSigParameters m_lmSigParameters;
         private readonly LMOtsParameters m_lmOtsParameters;
 
-        public LMSParameters(LMSigParameters lmSigParameters, LMOtsParameters lmOtsParameters)
+        public LmsParameters(LMSigParameters lmSigParameters, LMOtsParameters lmOtsParameters)
         {
             m_lmSigParameters = lmSigParameters;
             m_lmOtsParameters = lmOtsParameters;
diff --git a/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs
index f83cdc5f4..25ca81938 100644
--- a/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMSPrivateKeyParameters.cs
@@ -9,13 +9,13 @@ using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class LMSPrivateKeyParameters
-        : LMSKeyParameters, ILMSContextBasedSigner
+    public class LmsPrivateKeyParameters
+        : LmsKeyParameters, ILmsContextBasedSigner
     {
         private static CacheKey T1 = new CacheKey(1);
         private static CacheKey[] internedKeys = new CacheKey[129];
 
-        static LMSPrivateKeyParameters()
+        static LmsPrivateKeyParameters()
         {
             internedKeys[1] = T1;
             for (int i = 2; i < internedKeys.Length; i++)
@@ -39,10 +39,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         // These are not final because they can be generated.
         // They also do not need to be persisted.
         //
-        private LMSPublicKeyParameters publicKey;
+        private LmsPublicKeyParameters publicKey;
 
 
-        public LMSPrivateKeyParameters(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q, byte[] I, int maxQ, byte[] masterSecret)
+        public LmsPrivateKeyParameters(LMSigParameters lmsParameter, LMOtsParameters otsParameters, int q, byte[] I,
+            int maxQ, byte[] masterSecret)
             : base(true)
         {
             this.parameters = lmsParameter;
@@ -56,7 +57,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             this.tDigest = DigestUtilities.GetDigest(lmsParameter.DigestOid);
         }
 
-        private LMSPrivateKeyParameters(LMSPrivateKeyParameters parent, int q, int maxQ)
+        private LmsPrivateKeyParameters(LmsPrivateKeyParameters parent, int q, int maxQ)
             : base(true)
         {
             this.parameters = parent.parameters;
@@ -71,92 +72,53 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             this.publicKey = parent.publicKey;
         }
 
-        public static LMSPrivateKeyParameters GetInstance(byte[] privEnc, byte[] pubEnc)
+        public static LmsPrivateKeyParameters GetInstance(byte[] privEnc, byte[] pubEnc)
         {
-            LMSPrivateKeyParameters pKey = GetInstance(privEnc);
+            LmsPrivateKeyParameters pKey = GetInstance(privEnc);
         
-            pKey.publicKey = LMSPublicKeyParameters.GetInstance(pubEnc);
+            pKey.publicKey = LmsPublicKeyParameters.GetInstance(pubEnc);
 
             return pKey;
         }
 
-        public static LMSPrivateKeyParameters GetInstance(Object src)
+        public static LmsPrivateKeyParameters GetInstance(object src)
         {
-            if (src is LMSPrivateKeyParameters)
+            if (src is LmsPrivateKeyParameters lmsPrivateKeyParameters)
             {
-                return (LMSPrivateKeyParameters)src;
+                return lmsPrivateKeyParameters;
             }
-            //TODO
-            else if (src is BinaryReader)
+            else if (src is BinaryReader binaryReader)
             {
-                BinaryReader dIn = (BinaryReader)src;
-            
-                /*
-                .u32str(0) // version
-                .u32str(parameters.getType()) // type
-                .u32str(otsParameters.getType()) // ots type
-                .bytes(I) // I at 16 bytes
-                .u32str(q) // q
-                .u32str(maxQ) // maximum q
-                .u32str(masterSecret.length) // length of master secret.
-                .bytes(masterSecret) // the master secret
-                .build();
-                 */
-            
-            
-                if (dIn.ReadInt32() != 0) // todo check endienness
-                {
-                    throw new Exception("expected version 0 lms private key");
-                }
-                
-                // todo check endienness
-                byte[] data = ((BinaryReader) src).ReadBytes(4);
-                Array.Reverse(data);
-                int paramType = BitConverter.ToInt32(data, 0);
-                LMSigParameters parameter = LMSigParameters.GetParametersByID(paramType);
-
-                data = ((BinaryReader) src).ReadBytes(4);
-                Array.Reverse(data);
-                paramType = BitConverter.ToInt32(data, 0);
-                
-                LMOtsParameters otsParameter = LMOtsParameters.GetParametersByID(paramType);
-                byte[] I = new byte[16];
-                dIn.Read(I, 0, I.Length);
-            
-                
-                data = ((BinaryReader) src).ReadBytes(4);
-                Array.Reverse(data);
-                int q =  BitConverter.ToInt32(data, 0);
-                
-                data = ((BinaryReader) src).ReadBytes(4);
-                Array.Reverse(data);
-                int maxQ = BitConverter.ToInt32(data, 0);
-                
-                data = ((BinaryReader) src).ReadBytes(4);
-                Array.Reverse(data);
-                int l = BitConverter.ToInt32(data, 0);
-                
-                
+                int version = BinaryReaders.ReadInt32BigEndian(binaryReader);
+                if (version != 0)
+                    throw new Exception("unknown version for LMS private key");
+
+                int sigParamType = BinaryReaders.ReadInt32BigEndian(binaryReader);
+                LMSigParameters sigParameter = LMSigParameters.GetParametersByID(sigParamType);
+
+                int otsParamType = BinaryReaders.ReadInt32BigEndian(binaryReader);
+                LMOtsParameters otsParameter = LMOtsParameters.GetParametersByID(otsParamType);
+
+                byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16);
+
+                int q = BinaryReaders.ReadInt32BigEndian(binaryReader);
+
+                int maxQ = BinaryReaders.ReadInt32BigEndian(binaryReader);
+
+                int l = BinaryReaders.ReadInt32BigEndian(binaryReader);
                 if (l < 0)
-                {
                     throw new Exception("secret length less than zero");
-                }
-                if (l > dIn.BaseStream.Length)
-                {
-                    throw new IOException("secret length exceeded " + dIn.BaseStream.Length);
-                }
-                byte[] masterSecret = new byte[l];
-                dIn.Read(masterSecret, 0, masterSecret.Length);
-            
-                return new LMSPrivateKeyParameters(parameter, otsParameter, q, I, maxQ, masterSecret);
-            
+
+                byte[] masterSecret = BinaryReaders.ReadBytesFully(binaryReader, l);
+
+                return new LmsPrivateKeyParameters(sigParameter, otsParameter, q, I, maxQ, masterSecret);
             }
-            else if (src is byte[])
+            else if (src is byte[] bytes)
             {
                 BinaryReader input = null;
                 try // 1.5 / 1.6 compatibility
                 {
-                    input = new BinaryReader(new MemoryStream((byte[])src, false));
+                    input = new BinaryReader(new MemoryStream(bytes, false));
                     return GetInstance(input);
                 }
                 finally
@@ -167,9 +129,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                     }
                 }
             }
-            else if (src is MemoryStream)
+            else if (src is MemoryStream memoryStream)
             {
-                return GetInstance(Streams.ReadAll((Stream)src));
+                return GetInstance(Streams.ReadAll(memoryStream));
             }
 
             throw new ArgumentException($"cannot parse {src}");
@@ -181,9 +143,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             lock (this)
             {
                 if (q >= maxQ)
-                {
                     throw new Exception("ots private keys expired");
-                }
+
                 return new LMOtsPrivateKey(otsParameters, I, q, masterSecret);
             }
         }
@@ -205,7 +166,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 q++;
         }
 
-        public LMSContext GenerateLmsContext()
+        public LmsContext GenerateLmsContext()
         {
             // Step 1.
             LMSigParameters lmsParameter = this.GetSigParameters();
@@ -230,11 +191,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             return otsPk.GetSignatureContext(this.GetSigParameters(), path);
         }
 
-        public byte[] GenerateSignature(LMSContext context)
+        public byte[] GenerateSignature(LmsContext context)
         {
             try
             {
-                return LMS.GenerateSign(context).GetEncoded();
+                return Lms.GenerateSign(context).GetEncoded();
             }
             catch (IOException e)
             {
@@ -247,9 +208,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             lock (this)
             {
                 if (q >= maxQ)
-                {
                     throw new Exception("ots private key exhausted");
-                }
+
                 LMOtsPrivateKey otsPrivateKey = new LMOtsPrivateKey(otsParameters, I, q, masterSecret);
                 IncIndex();
                 return otsPrivateKey;
@@ -265,15 +225,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
          * @param usageCount the number of usages the key should have.
          * @return a key based on the current key that can be used usageCount times.
          */
-        public LMSPrivateKeyParameters ExtractKeyShard(int usageCount)
+        public LmsPrivateKeyParameters ExtractKeyShard(int usageCount)
         {
             lock (this)
             {
                 if (q + usageCount >= maxQ)
-                {
                     throw new ArgumentException("usageCount exceeds usages remaining");
-                }
-                LMSPrivateKeyParameters keyParameters = new LMSPrivateKeyParameters(this, q, q + usageCount);
+
+                LmsPrivateKeyParameters keyParameters = new LmsPrivateKeyParameters(this, q, q + usageCount);
                 q += usageCount;
 
                 return keyParameters;
@@ -305,13 +264,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             return maxQ - q;
         }
 
-        public virtual LMSPublicKeyParameters GetPublicKey()
+        public virtual LmsPublicKeyParameters GetPublicKey()
         {
             lock (this)
             {
                 if (publicKey == null)
                 {
-                    publicKey = new LMSPublicKeyParameters(parameters, otsParameters, this.FindT(T1), I);
+                    publicKey = new LmsPublicKeyParameters(parameters, otsParameters, this.FindT(T1), I);
                 }
                 return publicKey;
             }
@@ -354,17 +313,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
             if (r >= twoToh)
             {
-                LmsUtils.ByteArray(this.GetI(), tDigest);
-                LmsUtils.U32Str(r, tDigest);
-                LmsUtils.U16Str(LMS.D_LEAF, tDigest);
+                LmsUtilities.ByteArray(this.GetI(), tDigest);
+                LmsUtilities.U32Str(r, tDigest);
+                LmsUtilities.U16Str(Lms.D_LEAF, tDigest);
                 //
                 // These can be pre generated at the time of key generation and held within the private key.
                 // However it will cost memory to have them stick around.
                 //
-                byte[] K = LM_OTS.LmsOtsGeneratePublicKey(this.GetOtsParameters(), this.GetI(), (r - twoToh),
+                byte[] K = LMOts.LmsOtsGeneratePublicKey(this.GetOtsParameters(), this.GetI(), (r - twoToh),
                     this.GetMasterSecret());
 
-                LmsUtils.ByteArray(K, tDigest);
+                LmsUtilities.ByteArray(K, tDigest);
                 T = new byte[tDigest.GetDigestSize()];
                 tDigest.DoFinal(T, 0);
                 return T;
@@ -373,11 +332,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             byte[] t2r = FindT(2 * r);
             byte[] t2rPlus1 = FindT((2 * r + 1));
 
-            LmsUtils.ByteArray(this.GetI(), tDigest);
-            LmsUtils.U32Str(r, tDigest);
-            LmsUtils.U16Str(LMS.D_INTR, tDigest);
-            LmsUtils.ByteArray(t2r, tDigest);
-            LmsUtils.ByteArray(t2rPlus1, tDigest);
+            LmsUtilities.ByteArray(this.GetI(), tDigest);
+            LmsUtilities.U32Str(r, tDigest);
+            LmsUtilities.U16Str(Lms.D_INTR, tDigest);
+            LmsUtilities.ByteArray(t2r, tDigest);
+            LmsUtilities.ByteArray(t2rPlus1, tDigest);
             T = new byte[tDigest.GetDigestSize()];
             tDigest.DoFinal(T, 0);
 
@@ -395,7 +354,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 return false;
             }
 
-            LMSPrivateKeyParameters that = (LMSPrivateKeyParameters)o;
+            LmsPrivateKeyParameters that = (LmsPrivateKeyParameters)o;
 
             if (q != that.q)
             {
diff --git a/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs b/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs
index 1bf857f60..fa12b47c3 100644
--- a/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/lms/LMSPublicKeyParameters.cs
@@ -6,15 +6,15 @@ using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class LMSPublicKeyParameters
-        : LMSKeyParameters, ILMSContextBasedVerifier
+    public class LmsPublicKeyParameters
+        : LmsKeyParameters, ILmsContextBasedVerifier
     {
         private LMSigParameters parameterSet;
         private LMOtsParameters lmOtsType;
         private byte[] I;
         private byte[] T1;
 
-        public LMSPublicKeyParameters(LMSigParameters parameterSet, LMOtsParameters lmOtsType, byte[] T1, byte[] I)
+        public LmsPublicKeyParameters(LMSigParameters parameterSet, LMOtsParameters lmOtsType, byte[] T1, byte[] I)
             : base(false)
         {
             this.parameterSet = parameterSet;
@@ -23,33 +23,27 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             this.T1 = Arrays.Clone(T1);
         }
 
-        public static LMSPublicKeyParameters GetInstance(Object src)
+        public static LmsPublicKeyParameters GetInstance(object src)
         {
-            if (src is LMSPublicKeyParameters lmsPublicKeyParameters)
+            if (src is LmsPublicKeyParameters lmsPublicKeyParameters)
             {
                 return lmsPublicKeyParameters;
             }
-            // todo
-             else if (src is BinaryReader binaryReader)
-             {
-                 byte[] data = binaryReader.ReadBytes(4);
-                 Array.Reverse(data);
-                 int pubType = BitConverter.ToInt32(data, 0);
-                 LMSigParameters lmsParameter = LMSigParameters.GetParametersByID(pubType);
-                 
-                 data = binaryReader.ReadBytes(4);
-                 Array.Reverse(data);
-                 int index = BitConverter.ToInt32(data, 0);
-                 LMOtsParameters ostTypeCode = LMOtsParameters.GetParametersByID(index);
-            
-                 byte[] I = new byte[16];
-                binaryReader.Read(I, 0, I.Length);//change to readbytes?
-            
-                 byte[] T1 = new byte[lmsParameter.M];
-                binaryReader.Read(T1, 0, T1.Length);
-                 return new LMSPublicKeyParameters(lmsParameter, ostTypeCode, T1, I);
-             }
-             else if (src is byte[] bytes)
+            else if (src is BinaryReader binaryReader)
+            {
+                int pubType = BinaryReaders.ReadInt32BigEndian(binaryReader);
+                LMSigParameters lmsParameter = LMSigParameters.GetParametersByID(pubType);
+
+                int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
+                LMOtsParameters ostTypeCode = LMOtsParameters.GetParametersByID(index);
+
+                byte[] I = BinaryReaders.ReadBytesFully(binaryReader, 16);
+
+                byte[] T1 = BinaryReaders.ReadBytesFully(binaryReader, lmsParameter.M);
+
+                return new LmsPublicKeyParameters(lmsParameter, ostTypeCode, T1, I);
+            }
+            else if (src is byte[] bytes)
              {
                  BinaryReader input = null;
                  try // 1.5 / 1.6 compatibility
@@ -87,9 +81,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             return lmOtsType;
         }
 
-        public LMSParameters GetLmsParameters()
+        public LmsParameters GetLmsParameters()
         {
-            return new LMSParameters(this.GetSigParameters(), this.GetOtsParameters());
+            return new LmsParameters(this.GetSigParameters(), this.GetOtsParameters());
         }
 
         public byte[] GetT1()
@@ -123,7 +117,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 return false;
             }
 
-            LMSPublicKeyParameters publicKey = (LMSPublicKeyParameters)o;
+            LmsPublicKeyParameters publicKey = (LmsPublicKeyParameters)o;
 
             if (!parameterSet.Equals(publicKey.parameterSet))
             {
@@ -159,11 +153,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 .Build();
         }
 
-        public LMSContext GenerateLmsContext(byte[] signature)
+        public LmsContext GenerateLmsContext(byte[] signature)
         {
             try
             {
-                return GenerateOtsContext(LMSSignature.GetInstance(signature));
+                return GenerateOtsContext(LmsSignature.GetInstance(signature));
             }
             catch (IOException e)
             {
@@ -171,7 +165,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             }
         }
 
-        internal LMSContext GenerateOtsContext(LMSSignature S)
+        internal LmsContext GenerateOtsContext(LmsSignature S)
         {
             int ots_typecode = GetOtsParameters().ID;
             if (S.OtsSignature.ParamType.ID != ots_typecode)
@@ -184,9 +178,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 .CreateOtsContext(S);
         }
 
-        public bool Verify(LMSContext context)
+        public bool Verify(LmsContext context)
         {
-            return LMS.VerifySignature(this, context);
+            return Lms.VerifySignature(this, context);
         }
     }
 }
diff --git a/crypto/src/pqc/crypto/lms/LMSSignature.cs b/crypto/src/pqc/crypto/lms/LMSSignature.cs
index 48026e2f6..f5d355297 100644
--- a/crypto/src/pqc/crypto/lms/LMSSignature.cs
+++ b/crypto/src/pqc/crypto/lms/LMSSignature.cs
@@ -6,7 +6,7 @@ using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class LMSSignature
+    public class LmsSignature
         : IEncodable
     {
         private int q;
@@ -14,7 +14,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         private LMSigParameters parameter;
         private byte[][] y;
 
-        public LMSSignature(int q, LMOtsSignature otsSignature, LMSigParameters parameter, byte[][] y)
+        public LmsSignature(int q, LMOtsSignature otsSignature, LMSigParameters parameter, byte[][] y)
         {
             this.q = q;
             this.otsSignature = otsSignature;
@@ -22,23 +22,19 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             this.y = y;
         }
 
-        public static LMSSignature GetInstance(object src)
+        public static LmsSignature GetInstance(object src)
         {
-            if (src is LMSSignature lmsSignature)
+            if (src is LmsSignature lmsSignature)
             {
                 return lmsSignature;
             }
             else if (src is BinaryReader binaryReader)
             {
-                byte[] data = binaryReader.ReadBytes(4);
-                Array.Reverse(data);
-                int q = BitConverter.ToInt32(data, 0);
-                
+                int q = BinaryReaders.ReadInt32BigEndian(binaryReader);
+
                 LMOtsSignature otsSignature = LMOtsSignature.GetInstance(src);
 
-                data = binaryReader.ReadBytes(4);
-                Array.Reverse(data);
-                int index = BitConverter.ToInt32(data, 0);
+                int index = BinaryReaders.ReadInt32BigEndian(binaryReader);
                 LMSigParameters type = LMSigParameters.GetParametersByID(index);
 
                 byte[][] path = new byte[type.H][];
@@ -47,8 +43,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                     path[h] = new byte[type.M];
                     binaryReader.Read(path[h], 0, path[h].Length);
                 }
-            
-                return new LMSSignature(q, otsSignature, type, path);
+
+                return new LmsSignature(q, otsSignature, type, path);
             }
             else if (src is byte[] bytes)
             {
@@ -81,7 +77,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 return false;
             }
 
-            LMSSignature that = (LMSSignature)o;
+            LmsSignature that = (LmsSignature)o;
 
             if (q != that.q)
             {
diff --git a/crypto/src/pqc/crypto/lms/LMSSignedPubKey.cs b/crypto/src/pqc/crypto/lms/LMSSignedPubKey.cs
index 024ee5f4c..5e07c9c93 100644
--- a/crypto/src/pqc/crypto/lms/LMSSignedPubKey.cs
+++ b/crypto/src/pqc/crypto/lms/LMSSignedPubKey.cs
@@ -4,25 +4,25 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class LMSSignedPubKey
+    public class LmsSignedPubKey
         : IEncodable
     {
-        private LMSSignature signature;
-        private LMSPublicKeyParameters publicKey;
+        private LmsSignature signature;
+        private LmsPublicKeyParameters publicKey;
 
-        public LMSSignedPubKey(LMSSignature signature, LMSPublicKeyParameters publicKey)
+        public LmsSignedPubKey(LmsSignature signature, LmsPublicKeyParameters publicKey)
         {
             this.signature = signature;
             this.publicKey = publicKey;
         }
 
 
-        public LMSSignature GetSignature()
+        public LmsSignature GetSignature()
         {
             return signature;
         }
 
-        public LMSPublicKeyParameters GetPublicKey()
+        public LmsPublicKeyParameters GetPublicKey()
         {
             return publicKey;
         }
@@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
                 return false;
             }
 
-            LMSSignedPubKey that = (LMSSignedPubKey)o;
+            LmsSignedPubKey that = (LmsSignedPubKey)o;
 
             if (signature != null ? !signature.Equals(that.signature) : that.signature != null)
             {
diff --git a/crypto/src/pqc/crypto/lms/LMSSigner.cs b/crypto/src/pqc/crypto/lms/LMSSigner.cs
index 05824307a..edbfd7330 100644
--- a/crypto/src/pqc/crypto/lms/LMSSigner.cs
+++ b/crypto/src/pqc/crypto/lms/LMSSigner.cs
@@ -5,21 +5,21 @@ using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public sealed class LMSSigner
+    public sealed class LmsSigner
         : IMessageSigner
     {
-        private LMSPrivateKeyParameters m_privateKey;
-        private LMSPublicKeyParameters m_publicKey;
+        private LmsPrivateKeyParameters m_privateKey;
+        private LmsPublicKeyParameters m_publicKey;
 
         public void Init(bool forSigning, ICipherParameters param)
         {
             if (forSigning)
             {
-                m_privateKey = (LMSPrivateKeyParameters)param;
+                m_privateKey = (LmsPrivateKeyParameters)param;
             }
             else
             {
-                m_publicKey = (LMSPublicKeyParameters)param;
+                m_publicKey = (LmsPublicKeyParameters)param;
             }
         }
 
@@ -27,7 +27,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         {
             try
             {
-                return LMS.GenerateSign(m_privateKey, message).GetEncoded();
+                return Lms.GenerateSign(m_privateKey, message).GetEncoded();
             }
             catch (IOException e)
             {
@@ -39,7 +39,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         {
             try
             {
-                return LMS.VerifySignature(m_publicKey, LMSSignature.GetInstance(signature), message);
+                return Lms.VerifySignature(m_publicKey, LmsSignature.GetInstance(signature), message);
             }
             catch (IOException e)
             {
diff --git a/crypto/src/pqc/crypto/lms/LM_OTS.cs b/crypto/src/pqc/crypto/lms/LM_OTS.cs
index b9634c652..c3cd3da90 100644
--- a/crypto/src/pqc/crypto/lms/LM_OTS.cs
+++ b/crypto/src/pqc/crypto/lms/LM_OTS.cs
@@ -7,7 +7,7 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class LM_OTS
+    public static class LMOts
     {
         private static ushort D_PBLC = 0x8080;
         private static int ITER_K = 20;
@@ -113,9 +113,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
 
             if (!preHashed)
             {
-                LMSContext qCtx = privateKey.GetSignatureContext(sigParams, path);
+                LmsContext qCtx = privateKey.GetSignatureContext(sigParams, path);
 
-                LmsUtils.ByteArray(message, 0, message.Length, qCtx);
+                LmsUtilities.ByteArray(message, 0, message.Length, qCtx);
 
                 C = qCtx.C;
                 Q = qCtx.GetQ();
@@ -175,7 +175,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             bool prehashed)
         {
             if (!signature.ParamType.Equals(publicKey.Parameters)) // todo check
-                throw new LMSException("public key and signature ots types do not match");
+                throw new LmsException("public key and signature ots types do not match");
 
             return Arrays.AreEqual(LMOtsValidateSignatureCalculate(publicKey, signature, message), publicKey.K);
         }
@@ -183,22 +183,22 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
         public static byte[] LMOtsValidateSignatureCalculate(LMOtsPublicKey publicKey, LMOtsSignature signature, 
             byte[] message)
         {
-            LMSContext ctx = publicKey.CreateOtsContext(signature);
+            LmsContext ctx = publicKey.CreateOtsContext(signature);
 
-            LmsUtils.ByteArray(message, ctx);
+            LmsUtilities.ByteArray(message, ctx);
 
             return LMOtsValidateSignatureCalculate(ctx);
         }
 
-        public static byte[] LMOtsValidateSignatureCalculate(LMSContext context)
+        public static byte[] LMOtsValidateSignatureCalculate(LmsContext context)
         {
             LMOtsPublicKey publicKey = context.PublicKey;
             LMOtsParameters parameter = publicKey.Parameters;
             object sig = context.Signature;
             LMOtsSignature signature;
-            if (sig is LMSSignature)
+            if (sig is LmsSignature)
             {
-                signature = ((LMSSignature)sig).OtsSignature;
+                signature = ((LmsSignature)sig).OtsSignature;
             }
             else
             {
@@ -218,9 +218,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             int q = publicKey.Q;
 
             IDigest finalContext = DigestUtilities.GetDigest(parameter.DigestOid);
-            LmsUtils.ByteArray(I, finalContext);
-            LmsUtils.U32Str(q, finalContext);
-            LmsUtils.U16Str(D_PBLC, finalContext);
+            LmsUtilities.ByteArray(I, finalContext);
+            LmsUtilities.U32Str(q, finalContext);
+            LmsUtilities.U16Str(D_PBLC, finalContext);
 
             byte[] tmp = Composer.Compose()
                 .Bytes(I)
diff --git a/crypto/src/pqc/crypto/lms/LmsUtils.cs b/crypto/src/pqc/crypto/lms/LmsUtils.cs
index 3b08b009d..da3f457d2 100644
--- a/crypto/src/pqc/crypto/lms/LmsUtils.cs
+++ b/crypto/src/pqc/crypto/lms/LmsUtils.cs
@@ -4,7 +4,7 @@ using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Lms
 {
-    public class LmsUtils
+    public static class LmsUtilities
     {
         public static void U32Str(int n, IDigest d)
         {
@@ -30,7 +30,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Lms
             digest.BlockUpdate(array, start, len);
         }
 
-        public static int CalculateStrength(LMSParameters lmsParameters)
+        public static int CalculateStrength(LmsParameters lmsParameters)
         {
             if (lmsParameters == null)
                 throw new ArgumentNullException(nameof(lmsParameters));
diff --git a/crypto/src/pqc/crypto/saber/Poly.cs b/crypto/src/pqc/crypto/saber/Poly.cs
index 021f1d0e3..1a7312201 100644
--- a/crypto/src/pqc/crypto/saber/Poly.cs
+++ b/crypto/src/pqc/crypto/saber/Poly.cs
@@ -1,65 +1,70 @@
-
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Digests;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Saber
 {
-
-    class Poly
+    internal class Poly
     {
-        private static int KARATSUBA_N = 64;
-
-        private static int SCHB_N = 16;
-
-        private int N_RES;
-        private int N_SB;
-        private int N_SB_RES;
-        private int SABER_N;
-        private int SABER_L;
+        private const int KARATSUBA_N = 64;
 
-        private SABEREngine engine;
-        private Utils utils;
+        //private readonly int N_RES;
+        private readonly int N_SB;
+        private readonly int N_SB_RES;
+        private readonly int SABER_N;
+        private readonly int SABER_L;
 
+        private readonly SaberEngine engine;
+        private readonly SaberUtilities utils;
 
-        public Poly(SABEREngine engine)
+        public Poly(SaberEngine engine)
         {
             this.engine = engine;
-            this.SABER_L = engine.getSABER_L();
-            this.SABER_N = engine.getSABER_N();
-            this.N_RES = (SABER_N << 1);
-            this.N_SB = (SABER_N >> 2);
-            this.N_SB_RES = (2 * N_SB - 1);
-            this.utils = engine.GetUtils();
+            this.SABER_L = engine.L;
+            this.SABER_N = engine.N;
+            //this.N_RES = SABER_N << 1;
+            this.N_SB = SABER_N >> 2;
+            this.N_SB_RES = 2 * N_SB - 1;
+            this.utils = engine.Utilities;
         }
 
         public void GenMatrix(short[][][] A, byte[] seed)
         {
-            byte[] buf = new byte[SABER_L * engine.getSABER_POLYVECBYTES()];
+            byte[] buf = new byte[SABER_L * engine.PolyVecBytes];
             int i;
 
-            IXof digest = new ShakeDigest(128);
-            digest.BlockUpdate(seed, 0, engine.getSABER_SEEDBYTES());
-            digest.OutputFinal(buf, 0, buf.Length);
+            engine.Symmetric.Prf(buf, seed, engine.SeedBytes, buf.Length);
+
 
             for (i = 0; i < SABER_L; i++)
             {
-                utils.BS2POLVECq(buf, i * engine.getSABER_POLYVECBYTES(), A[i]);
+                utils.BS2POLVECq(buf, i * engine.PolyVecBytes, A[i]);
             }
         }
 
         public void GenSecret(short[][] s, byte[] seed)
         {
-            byte[] buf = new byte[SABER_L * engine.getSABER_POLYCOINBYTES()];
-            int i;
-            IXof digest = new ShakeDigest(128);
-            digest.BlockUpdate(seed, 0, engine.getSABER_NOISE_SEEDBYTES());
-            digest.OutputFinal(buf, 0, buf.Length);
+            byte[] buf = new byte[SABER_L * engine.PolyCoinBytes];
 
-            for (i = 0; i < SABER_L; i++)
+            engine.Symmetric.Prf(buf, seed, engine.NoiseSeedBytes, buf.Length);
+
+
+            for (int i = 0; i < SABER_L; i++)
             {
-                Cbd(s[i], buf, i * engine.getSABER_POLYCOINBYTES());
+                if (!engine.UsingEffectiveMasking)
+                {
+                    Cbd(s[i], buf, i * engine.PolyCoinBytes);
+                }
+                else
+                {
+                    for(int j = 0; j<SABER_N/4; j++)
+                    {
+                        s[i][4*j] = (short) ((((buf[j + i * engine.PolyCoinBytes]) & 0x03) ^ 2) - 2);
+                        s[i][4*j+1] = (short) ((((buf[j + i * engine.PolyCoinBytes] >> 2) & 0x03)  ^ 2) - 2);
+                        s[i][4*j+2] = (short) ((((buf[j + i * engine.PolyCoinBytes] >> 4) & 0x03)  ^ 2) - 2);
+                        s[i][4*j+3] = (short) ((((buf[j + i * engine.PolyCoinBytes] >> 6) & 0x03)  ^ 2) - 2);
+                    }
+                }
             }
-
         }
 
         private long LoadLittleEndian(byte[] x, int offset, int bytes)
@@ -78,7 +83,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
         {
             int[] a = new int[4], b = new int[4];
             int i, j;
-            if (engine.getSABER_MU() == 6)
+            if (engine.MU == 6)
             {
                 int t, d;
                 for (i = 0; i < SABER_N / 4; i++)
@@ -103,7 +108,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
                     s[4 * i + 3] = (short) (a[3] - b[3]);
                 }
             }
-            else if (engine.getSABER_MU() == 8)
+            else if (engine.MU == 8)
             {
                 int t, d;
                 for (i = 0; i < SABER_N / 4; i++)
@@ -129,7 +134,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
                     s[4 * i + 3] = (short) (a[3] - b[3]);
                 }
             }
-            else if (engine.getSABER_MU() == 10)
+            else if (engine.MU == 10)
             {
                 long t, d;
                 for (i = 0; i < SABER_N / 4; i++)
@@ -435,4 +440,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
 
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/saber/SABEREngine.cs b/crypto/src/pqc/crypto/saber/SABEREngine.cs
index a7c8d3ff9..e57c0a23f 100644
--- a/crypto/src/pqc/crypto/saber/SABEREngine.cs
+++ b/crypto/src/pqc/crypto/saber/SABEREngine.cs
@@ -1,5 +1,5 @@
-
 using System;
+
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Digests;
 using Org.BouncyCastle.Security;
@@ -7,103 +7,75 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Saber
 {
-    internal class SABEREngine
+    internal sealed class SaberEngine
     {
         // constant parameters
-        public static int SABER_EQ = 13;
-        public static int SABER_EP = 10;
-        public static int SABER_N = 256;
-
-        private static int SABER_SEEDBYTES = 32;
-        private static int SABER_NOISE_SEEDBYTES = 32;
-        private static int SABER_KEYBYTES = 32;
-        private static int SABER_HASHBYTES = 32;
+        internal const int SABER_EP = 10;
+        internal const int SABER_N = 256;
 
+        private const int SABER_SEEDBYTES = 32;
+        private const int SABER_NOISE_SEEDBYTES = 32;
+        private const int SABER_KEYBYTES = 32;
+        private const int SABER_HASHBYTES = 32;
 
         // parameters for SABER{n}
-        private int SABER_L;
-        private int SABER_MU;
-        private int SABER_ET;
-
-        private int SABER_POLYCOINBYTES;
-        private int SABER_POLYBYTES;
-        private int SABER_POLYVECBYTES;
-        private int SABER_POLYCOMPRESSEDBYTES;
-        private int SABER_POLYVECCOMPRESSEDBYTES;
-        private int SABER_SCALEBYTES_KEM;
-        private int SABER_INDCPA_PUBLICKEYBYTES;
-        private int SABER_INDCPA_SECRETKEYBYTES;
-        private int SABER_PUBLICKEYBYTES;
-        private int SABER_SECRETKEYBYTES;
-        private int SABER_BYTES_CCA_DEC;
-        private int defaultKeySize;
+        private readonly int SABER_L;
+        private readonly int SABER_MU;
+        private readonly int SABER_ET;
+
+        private readonly int SABER_POLYCOINBYTES;
+        private readonly int SABER_EQ;
+        private readonly int SABER_POLYBYTES;
+        private readonly int SABER_POLYVECBYTES;
+        private readonly int SABER_POLYCOMPRESSEDBYTES;
+        private readonly int SABER_POLYVECCOMPRESSEDBYTES;
+        private readonly int SABER_SCALEBYTES_KEM;
+        private readonly int SABER_INDCPA_PUBLICKEYBYTES;
+        private readonly int SABER_INDCPA_SECRETKEYBYTES;
+        private readonly int SABER_PUBLICKEYBYTES;
+        private readonly int SABER_SECRETKEYBYTES;
+        private readonly int SABER_BYTES_CCA_DEC;
+        private readonly int defaultKeySize;
 
         //
         private int h1;
         private int h2;
 
-        private Utils utils;
+        private Symmetric symmetric;
+        private SaberUtilities utils;
         private Poly poly;
 
-        public int getSABER_N()
-        {
-            return SABER_N;
-        }
+        private readonly bool usingAes;
+        private readonly bool usingEffectiveMasking;
 
-        public int getSABER_EP()
-        {
-            return SABER_EP;
-        }
+        public bool UsingAes => usingAes;
+        public bool UsingEffectiveMasking => usingEffectiveMasking;
+        public Symmetric Symmetric => symmetric;
+        
+        public int EQ => SABER_EQ;
+        public int N => SABER_N;
 
-        public int getSABER_KEYBYTES()
-        {
-            return SABER_KEYBYTES;
-        }
+        public int EP => SABER_EP;
 
-        public int getSABER_L()
-        {
-            return SABER_L;
-        }
+        public int KeyBytes => SABER_KEYBYTES;
 
-        public int getSABER_ET()
-        {
-            return SABER_ET;
-        }
+        public int L => SABER_L;
 
-        public int getSABER_POLYBYTES()
-        {
-            return SABER_POLYBYTES;
-        }
+        public int ET => SABER_ET;
 
-        public int getSABER_POLYVECBYTES()
-        {
-            return SABER_POLYVECBYTES;
-        }
+        public int PolyBytes => SABER_POLYBYTES;
 
-        public int getSABER_SEEDBYTES()
-        {
-            return SABER_SEEDBYTES;
-        }
+        public int PolyVecBytes => SABER_POLYVECBYTES;
 
-        public int getSABER_POLYCOINBYTES()
-        {
-            return SABER_POLYCOINBYTES;
-        }
+        public int SeedBytes => SABER_SEEDBYTES;
 
-        public int getSABER_NOISE_SEEDBYTES()
-        {
-            return SABER_NOISE_SEEDBYTES;
-        }
+        public int PolyCoinBytes => SABER_POLYCOINBYTES;
 
-        public int getSABER_MU()
-        {
-            return SABER_MU;
-        }
+        public int NoiseSeedBytes => SABER_NOISE_SEEDBYTES;
 
-        public Utils GetUtils()
-        {
-            return utils;
-        }
+        public int MU => SABER_MU;
+
+        public SaberUtilities Utilities => utils;
 
         public int GetSessionKeySize()
         {
@@ -126,10 +98,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             return SABER_SECRETKEYBYTES;
         }
 
-        public SABEREngine(int l, int defaultKeySize)
+        internal SaberEngine(int l, int defaultKeySize, bool usingAes, bool usingEffectiveMasking)
         {
             this.defaultKeySize = defaultKeySize;
-
+            this.usingAes = usingAes;
+            this.usingEffectiveMasking = usingEffectiveMasking;
             this.SABER_L = l;
             if (l == 2)
             {
@@ -146,8 +119,25 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
                 this.SABER_MU = 6;
                 this.SABER_ET = 6;
             }
+            if(usingAes)
+            {
+                symmetric = new Symmetric.AesSymmetric();
+            }
+            else
+            {
+                symmetric = new Symmetric.ShakeSymmetric();
+            }
 
-            this.SABER_POLYCOINBYTES = (SABER_MU * SABER_N / 8);
+            if(usingEffectiveMasking)
+            {
+                this.SABER_EQ = 12;
+                this.SABER_POLYCOINBYTES = (2 * SABER_N / 8);
+            }
+            else
+            {
+                this.SABER_EQ = 13;
+                this.SABER_POLYCOINBYTES = (SABER_MU * SABER_N / 8);
+            }
             this.SABER_POLYBYTES = (SABER_EQ * SABER_N / 8);
             this.SABER_POLYVECBYTES = (SABER_L * SABER_POLYBYTES);
             this.SABER_POLYCOMPRESSEDBYTES = (SABER_EP * SABER_N / 8);
@@ -162,7 +152,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
             this.h1 = (1 << (SABER_EQ - SABER_EP - 1));
             this.h2 = ((1 << (SABER_EP - 2)) - (1 << (SABER_EP - SABER_ET - 1)) + (1 << (SABER_EQ - SABER_EP - 1)));
-            utils = new Utils(this);
+            utils = new SaberUtilities(this);
             poly = new Poly(this);
         }
 
@@ -202,9 +192,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
             random.NextBytes(seed_A);
 
-            IXof digest = new ShakeDigest(128);
-            digest.BlockUpdate(seed_A, 0, SABER_SEEDBYTES);
-            digest.OutputFinal(seed_A, 0, SABER_SEEDBYTES);
+            symmetric.Prf(seed_A, seed_A, SABER_SEEDBYTES, SABER_SEEDBYTES);
 
             random.NextBytes(seed_s);
 
@@ -233,13 +221,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             int i;
             indcpa_kem_keypair(pk, sk, random); // sk[0:SABER_INDCPA_SECRETKEYBYTES-1] <-- sk
             for (i = 0; i < SABER_INDCPA_PUBLICKEYBYTES; i++)
+            {
                 sk[i + SABER_INDCPA_SECRETKEYBYTES] =
                     pk[i]; // sk[SABER_INDCPA_SECRETKEYBYTES:SABER_INDCPA_SECRETKEYBYTES+SABER_INDCPA_SECRETKEYBYTES-1] <-- pk
-
+            }
             // Then hash(pk) is appended.
-            Sha3Digest digest = new Sha3Digest(256);
-            digest.BlockUpdate(pk, 0, SABER_INDCPA_PUBLICKEYBYTES);
-            digest.DoFinal(sk, SABER_SECRETKEYBYTES - 64);
+            symmetric.Hash_h(sk, pk, SABER_SECRETKEYBYTES - 64);
 
             // Remaining part of sk contains a pseudo-random number.
             byte[] nonce = new byte[SABER_KEYBYTES];
@@ -289,7 +276,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             }
 
             short[] mp = new short[SABER_N];
-            ;
             short[] vp = new short[SABER_N];
             byte[] seed_A = Arrays.CopyOfRange(pk, SABER_POLYVECCOMPRESSEDBYTES, pk.Length);
 
@@ -327,35 +313,30 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             byte[] nonce = new byte[32];
             random.NextBytes(nonce);
 
-            Sha3Digest digest_256 = new Sha3Digest(256);
-            Sha3Digest digest_512 = new Sha3Digest(512);
+           
 
             // BUF[0:31] <-- random message (will be used as the key for client) Note: hash doesnot release system RNG output
-            digest_256.BlockUpdate(nonce, 0, 32);
-            digest_256.DoFinal(nonce, 0);
+            symmetric.Hash_h(nonce, nonce, 0);
+
             Array.Copy(nonce, 0, buf, 0, 32);
 
             // BUF[32:63] <-- Hash(public key);  Multitarget countermeasure for coins + contributory KEM
-            digest_256.BlockUpdate(pk, 0, SABER_INDCPA_PUBLICKEYBYTES);
-            digest_256.DoFinal(buf, 32);
+            symmetric.Hash_h(buf, pk, 32);
 
             // kr[0:63] <-- Hash(buf[0:63]);
-            digest_512.BlockUpdate(buf, 0, 64);
-            digest_512.DoFinal(kr, 0);
+            symmetric.Hash_g(kr, buf);
 
             // K^ <-- kr[0:31]
             // noiseseed (r) <-- kr[32:63];
             // buf[0:31] contains message; kr[32:63] contains randomness r;
             indcpa_kem_enc(buf, Arrays.CopyOfRange(kr, 32, kr.Length), pk, c);
 
-            digest_256.BlockUpdate(c, 0, SABER_BYTES_CCA_DEC);
-            digest_256.DoFinal(kr, 32);
+            symmetric.Hash_h(kr, c, 32);
 
             // hash concatenation of pre-k and h(c) to k
             //todo support 128 and 192 bit keys
             byte[] temp_k = new byte[32];
-            digest_256.BlockUpdate(kr, 0, 64);
-            digest_256.DoFinal(temp_k, 0);
+            symmetric.Hash_h(temp_k, kr, 0);
 
             Array.Copy(temp_k, 0, k, 0, defaultKeySize / 8);
 
@@ -407,14 +388,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
             // Multitarget countermeasure for coins + contributory KEM
             for (i = 0; i < 32; i++) // Save hash by storing h(pk) in sk
+            {
                 buf[32 + i] = sk[SABER_SECRETKEYBYTES - 64 + i];
+            }
 
 
-            Sha3Digest digest_256 = new Sha3Digest(256);
-            Sha3Digest digest_512 = new Sha3Digest(512);
-
-            digest_512.BlockUpdate(buf, 0, 64);
-            digest_512.DoFinal(kr, 0);
+            symmetric.Hash_g(kr, buf);
 
             indcpa_kem_enc(buf, Arrays.CopyOfRange(kr, 32, kr.Length), pk, cmp);
 
@@ -422,16 +401,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
             // overwrite coins in kr with h(c)
 
-            digest_256.BlockUpdate(c, 0, SABER_BYTES_CCA_DEC);
-            digest_256.DoFinal(kr, 32);
-
+            symmetric.Hash_h(kr, c, 32);
+            
             cmov(kr, sk, SABER_SECRETKEYBYTES - SABER_KEYBYTES, SABER_KEYBYTES, (byte) fail);
 
             // hash concatenation of pre-k and h(c) to k
             //todo support 128 and 192 bit keys
             byte[] temp_k = new byte[32];
-            digest_256.BlockUpdate(kr, 0, 64);
-            digest_256.DoFinal(temp_k, 0);
+            symmetric.Hash_h(temp_k, kr, 0);
 
             Array.Copy(temp_k, 0, k, 0, defaultKeySize / 8);
             return 0;
@@ -461,4 +438,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
 
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/saber/SABERKEMExtractor.cs b/crypto/src/pqc/crypto/saber/SABERKEMExtractor.cs
index 7199b9dab..ce0b374f3 100644
--- a/crypto/src/pqc/crypto/saber/SABERKEMExtractor.cs
+++ b/crypto/src/pqc/crypto/saber/SABERKEMExtractor.cs
@@ -1,24 +1,23 @@
-
 using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Saber
 {
-    public class SaberKemExtractor
+    public sealed class SaberKemExtractor
         : IEncapsulatedSecretExtractor
     {
-        private SABEREngine engine;
+        private readonly SaberKeyParameters key;
 
-        private SaberKeyParameters key;
+        private SaberEngine engine;
 
         public SaberKemExtractor(SaberKeyParameters privParams)
         {
             this.key = privParams;
-            InitCipher(key.GetParameters());
+            InitCipher(key.Parameters);
         }
 
         private void InitCipher(SaberParameters param)
         {
-            engine = param.GetEngine();
+            engine = param.Engine;
         }
 
         public byte[] ExtractSecret(byte[] encapsulation)
@@ -30,4 +29,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
         public int EncapsulationLength => engine.GetCipherTextSize();
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/saber/SABERKEMGenerator.cs b/crypto/src/pqc/crypto/saber/SABERKEMGenerator.cs
index 0919b4dea..f948717b1 100644
--- a/crypto/src/pqc/crypto/saber/SABERKEMGenerator.cs
+++ b/crypto/src/pqc/crypto/saber/SABERKEMGenerator.cs
@@ -1,13 +1,10 @@
-
-using System;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Pqc.Crypto.Utilities;
 using Org.BouncyCastle.Security;
-using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Saber
 {
-    public class SaberKemGenerator
+    public sealed class SaberKemGenerator
         : IEncapsulatedSecretGenerator
     {
         // the source of randomness
@@ -15,18 +12,17 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
         public SaberKemGenerator(SecureRandom random)
         {
-            this.sr = random;
+            this.sr = CryptoServicesRegistrar.GetSecureRandom(random);
         }
 
         public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey)
         {
-            SaberPublicKeyParameters key = (SaberPublicKeyParameters) recipientKey;
-            SABEREngine engine = key.GetParameters().GetEngine();
+            SaberPublicKeyParameters key = (SaberPublicKeyParameters)recipientKey;
+            SaberEngine engine = key.Parameters.Engine;
             byte[] cipher_text = new byte[engine.GetCipherTextSize()];
             byte[] sessionKey = new byte[engine.GetSessionKeySize()];
-            engine.crypto_kem_enc(cipher_text, sessionKey, key.PublicKey, sr);
+            engine.crypto_kem_enc(cipher_text, sessionKey, key.GetPublicKey(), sr);
             return new SecretWithEncapsulationImpl(sessionKey, cipher_text);
         }
-        
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/saber/SABERKeyGenerationParameters.cs b/crypto/src/pqc/crypto/saber/SABERKeyGenerationParameters.cs
index 038c191ef..c76ec6234 100644
--- a/crypto/src/pqc/crypto/saber/SABERKeyGenerationParameters.cs
+++ b/crypto/src/pqc/crypto/saber/SABERKeyGenerationParameters.cs
@@ -1,17 +1,14 @@
-
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Saber
 {
-    public class SaberKeyGenerationParameters
+    public sealed class SaberKeyGenerationParameters
         : KeyGenerationParameters
     {
         private SaberParameters parameters;
 
-        public SaberKeyGenerationParameters(
-            SecureRandom random,
-            SaberParameters saberParameters)
+        public SaberKeyGenerationParameters(SecureRandom random, SaberParameters saberParameters)
             : base(random, 256)
         {
             this.parameters = saberParameters;
@@ -19,4 +16,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
         public SaberParameters Parameters => parameters;
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/saber/SABERKeyPairGenerator.cs b/crypto/src/pqc/crypto/saber/SABERKeyPairGenerator.cs
index 73209b18b..1407f74a3 100644
--- a/crypto/src/pqc/crypto/saber/SABERKeyPairGenerator.cs
+++ b/crypto/src/pqc/crypto/saber/SABERKeyPairGenerator.cs
@@ -1,4 +1,3 @@
-
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Security;
 
@@ -16,7 +15,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
         private void Initialize(
             KeyGenerationParameters param)
         {
-            this.saberParams = (SaberKeyGenerationParameters) param;
+            this.saberParams = (SaberKeyGenerationParameters)param;
             this.random = param.Random;
 
             this.l = this.saberParams.Parameters.L;
@@ -24,7 +23,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
         private AsymmetricCipherKeyPair GenKeyPair()
         {
-            SABEREngine engine = saberParams.Parameters.GetEngine();
+            SaberEngine engine = saberParams.Parameters.Engine;
             byte[] sk = new byte[engine.GetPrivateKeySize()];
             byte[] pk = new byte[engine.GetPublicKeySize()];
             engine.crypto_kem_keypair(pk, sk, random);
@@ -44,4 +43,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             return GenKeyPair();
         }
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/saber/SABERKeyParameters.cs b/crypto/src/pqc/crypto/saber/SABERKeyParameters.cs
index e5a9e767e..d83d2e3ea 100644
--- a/crypto/src/pqc/crypto/saber/SABERKeyParameters.cs
+++ b/crypto/src/pqc/crypto/saber/SABERKeyParameters.cs
@@ -1,24 +1,18 @@
-
 using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Saber
 {
-    public class SaberKeyParameters
+    public abstract class SaberKeyParameters
         : AsymmetricKeyParameter
     {
-        private SaberParameters parameters;
+        private readonly SaberParameters parameters;
 
-        public SaberKeyParameters(
-            bool isPrivate,
-            SaberParameters parameters)
+        public SaberKeyParameters(bool isPrivate, SaberParameters parameters)
             : base(isPrivate)
         {
             this.parameters = parameters;
         }
 
-        public SaberParameters GetParameters()
-        {
-            return parameters;
-        }
+        public SaberParameters Parameters => parameters;
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/saber/SABERParameters.cs b/crypto/src/pqc/crypto/saber/SABERParameters.cs
index 357430d50..e2992d4c4 100644
--- a/crypto/src/pqc/crypto/saber/SABERParameters.cs
+++ b/crypto/src/pqc/crypto/saber/SABERParameters.cs
@@ -1,5 +1,3 @@
-
-using System;
 using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Saber
@@ -7,29 +5,42 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
     public sealed class SaberParameters
         : ICipherParameters
     {
-        public static SaberParameters lightsaberkem128r3 = new SaberParameters("lightsaberkem128r3", 2, 128);
-        public static SaberParameters saberkem128r3 = new SaberParameters("saberkem128r3", 3, 128);
-        public static SaberParameters firesaberkem128r3 = new SaberParameters("firesaberkem128r3", 4, 128);
+        public static SaberParameters lightsaberkem128r3 = new SaberParameters("lightsaberkem128r3", 2, 128, false, false);
+        public static SaberParameters saberkem128r3 = new SaberParameters("saberkem128r3", 3, 128, false, false);
+        public static SaberParameters firesaberkem128r3 = new SaberParameters("firesaberkem128r3", 4, 128, false, false);
+
+        public static SaberParameters lightsaberkem192r3 = new SaberParameters("lightsaberkem192r3", 2, 192, false, false);
+        public static SaberParameters saberkem192r3 = new SaberParameters("saberkem192r3", 3, 192, false, false);
+        public static SaberParameters firesaberkem192r3 = new SaberParameters("firesaberkem192r3", 4, 192, false, false);
+
+        public static SaberParameters lightsaberkem256r3 = new SaberParameters("lightsaberkem256r3", 2, 256, false, false);
+        public static SaberParameters saberkem256r3 = new SaberParameters("saberkem256r3", 3, 256, false, false);
+        public static SaberParameters firesaberkem256r3 = new SaberParameters("firesaberkem256r3", 4, 256, false, false);
+        
+        public static SaberParameters lightsaberkem90sr3 = new SaberParameters("lightsaberkem90sr3", 2, 256, true, false);
+        public static SaberParameters saberkem90sr3 = new SaberParameters("saberkem90sr3", 3, 256, true, false);
+        public static SaberParameters firesaberkem90sr3 = new SaberParameters("firesaberkem90sr3", 4, 256, true, false);
 
-        public static SaberParameters lightsaberkem192r3 = new SaberParameters("lightsaberkem192r3", 2, 192);
-        public static SaberParameters saberkem192r3 = new SaberParameters("saberkem192r3", 3, 192);
-        public static SaberParameters firesaberkem192r3 = new SaberParameters("firesaberkem192r3", 4, 192);
+        public static SaberParameters ulightsaberkemr3 = new SaberParameters("ulightsaberkemr3", 2, 256, false, true);
+        public static SaberParameters usaberkemr3 = new SaberParameters("usaberkemr3", 3, 256, false, true);
+        public static SaberParameters ufiresaberkemr3 = new SaberParameters("ufiresaberkemr3", 4, 256, false, true);
 
-        public static SaberParameters lightsaberkem256r3 = new SaberParameters("lightsaberkem256r3", 2, 256);
-        public static SaberParameters saberkem256r3 = new SaberParameters("saberkem256r3", 3, 256);
-        public static SaberParameters firesaberkem256r3 = new SaberParameters("firesaberkem256r3", 4, 256);
+        public static SaberParameters ulightsaberkem90sr3 = new SaberParameters("ulightsaberkem90sr3", 2, 256, true, true);
+        public static SaberParameters usaberkem90sr3 = new SaberParameters("usaberkem90sr3", 3, 256, true, true);
+        public static SaberParameters ufiresaberkem90sr3 = new SaberParameters("ufiresaberkem90sr3", 4, 256, true, true);
 
-        private string name;
-        private int l;
-        private int defaultKeySize;
-        private SABEREngine engine;
 
-        public SaberParameters(string name, int l, int defaultKeySize)
+        private readonly string name;
+        private readonly int l;
+        private readonly int defaultKeySize;
+        private readonly SaberEngine engine;
+
+        private SaberParameters(string name, int l, int defaultKeySize, bool usingAes, bool usingEffectiveMasking)
         {
             this.name = name;
             this.l = l;
             this.defaultKeySize = defaultKeySize;
-            this.engine = new SABEREngine(l, defaultKeySize);
+            this.engine = new SaberEngine(l, defaultKeySize, usingAes, usingEffectiveMasking);
         }
 
         public string Name => name;
@@ -38,9 +49,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
 
         public int DefaultKeySize => defaultKeySize;
 
-        internal SABEREngine GetEngine()
-        {
-            return engine;
-        }
+        internal SaberEngine Engine => engine;
     }
 }
diff --git a/crypto/src/pqc/crypto/saber/SABERPrivateKeyParameters.cs b/crypto/src/pqc/crypto/saber/SABERPrivateKeyParameters.cs
index ec4add8b5..6b708af73 100644
--- a/crypto/src/pqc/crypto/saber/SABERPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/saber/SABERPrivateKeyParameters.cs
@@ -2,15 +2,10 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Saber
 {
-    public class SaberPrivateKeyParameters
+    public sealed class SaberPrivateKeyParameters
         : SaberKeyParameters
     {
-        private byte[] privateKey;
-
-        public byte[] GetPrivateKey()
-        {
-            return Arrays.Clone(privateKey);
-        }
+        private readonly byte[] privateKey;
 
         public SaberPrivateKeyParameters(SaberParameters parameters, byte[] privateKey)
             : base(true, parameters)
@@ -22,5 +17,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
         {
             return Arrays.Clone(privateKey);
         }
+
+        public byte[] GetPrivateKey()
+        {
+            return Arrays.Clone(privateKey);
+        }
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/saber/SABERPublicKeyParameters.cs b/crypto/src/pqc/crypto/saber/SABERPublicKeyParameters.cs
index dcac1ec3c..573ca2661 100644
--- a/crypto/src/pqc/crypto/saber/SABERPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/saber/SABERPublicKeyParameters.cs
@@ -2,22 +2,25 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Saber
 {
-    public class SaberPublicKeyParameters
+    public sealed class SaberPublicKeyParameters
         : SaberKeyParameters
     {
-        public byte[] publicKey;
+        public readonly byte[] publicKey;
 
-        public byte[] PublicKey => Arrays.Clone(publicKey);
+        public SaberPublicKeyParameters(SaberParameters parameters, byte[] publicKey)
+            : base(false, parameters)
+        {
+            this.publicKey = Arrays.Clone(publicKey);
+        }
 
         public byte[] GetEncoded()
         {
-            return PublicKey;
+            return Arrays.Clone(publicKey);
         }
 
-        public SaberPublicKeyParameters(SaberParameters parameters, byte[] publicKey)
-            : base(false, parameters)
+        public byte[] GetPublicKey()
         {
-            this.publicKey = Arrays.Clone(publicKey);
+            return Arrays.Clone(publicKey);
         }
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/saber/Utils.cs b/crypto/src/pqc/crypto/saber/SaberUtilities.cs
index ff74ef1cb..90c2b4ea4 100644
--- a/crypto/src/pqc/crypto/saber/Utils.cs
+++ b/crypto/src/pqc/crypto/saber/SaberUtilities.cs
@@ -1,23 +1,23 @@
 namespace Org.BouncyCastle.Pqc.Crypto.Saber
 {
-    internal class Utils
+    internal class SaberUtilities
     {
-
-        private int SABER_N;
-        private int SABER_L;
-        private int SABER_ET;
-        private int SABER_POLYBYTES;
-        private int SABER_EP;
-        private int SABER_KEYBYTES;
-
-        internal Utils(SABEREngine engine)
+        private readonly int SABER_N;
+        private readonly int SABER_L;
+        private readonly int SABER_ET;
+        private readonly int SABER_POLYBYTES;
+        private readonly int SABER_EP;
+        private readonly int SABER_KEYBYTES;
+        private readonly bool usingEffectiveMasking;
+        internal SaberUtilities(SaberEngine engine)
         {
-            this.SABER_N = engine.getSABER_N();
-            this.SABER_L = engine.getSABER_L();
-            this.SABER_ET = engine.getSABER_ET();
-            this.SABER_POLYBYTES = engine.getSABER_POLYBYTES();
-            this.SABER_EP = engine.getSABER_EP();
-            this.SABER_KEYBYTES = engine.getSABER_KEYBYTES();
+            this.SABER_N = engine.N;
+            this.SABER_L = engine.L;
+            this.SABER_ET = engine.ET;
+            this.SABER_POLYBYTES = engine.PolyBytes;
+            this.SABER_EP = engine.EP;
+            this.SABER_KEYBYTES = engine.KeyBytes;
+            this.usingEffectiveMasking = engine.UsingEffectiveMasking;
         }
 
         public void POLT2BS(byte[] bytes, int byteIndex, short[] data)
@@ -118,60 +118,87 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
         private void POLq2BS(byte[] bytes, int byteIndex, short[] data)
         {
             short j, offset_byte, offset_data;
-            for (j = 0; j < SABER_N / 8; j++)
+            if (!usingEffectiveMasking)
             {
-                offset_byte = (short) (13 * j);
-                offset_data = (short) (8 * j);
-                bytes[byteIndex + offset_byte + 0] = (byte) (data[offset_data + 0] & (0xff));
-                bytes[byteIndex + offset_byte + 1] =
-                    (byte) (((data[offset_data + 0] >> 8) & 0x1f) | ((data[offset_data + 1] & 0x07) << 5));
-                bytes[byteIndex + offset_byte + 2] = (byte) ((data[offset_data + 1] >> 3) & 0xff);
-                bytes[byteIndex + offset_byte + 3] =
-                    (byte) (((data[offset_data + 1] >> 11) & 0x03) | ((data[offset_data + 2] & 0x3f) << 2));
-                bytes[byteIndex + offset_byte + 4] =
-                    (byte) (((data[offset_data + 2] >> 6) & 0x7f) | ((data[offset_data + 3] & 0x01) << 7));
-                bytes[byteIndex + offset_byte + 5] = (byte) ((data[offset_data + 3] >> 1) & 0xff);
-                bytes[byteIndex + offset_byte + 6] =
-                    (byte) (((data[offset_data + 3] >> 9) & 0x0f) | ((data[offset_data + 4] & 0x0f) << 4));
-                bytes[byteIndex + offset_byte + 7] = (byte) ((data[offset_data + 4] >> 4) & 0xff);
-                bytes[byteIndex + offset_byte + 8] =
-                    (byte) (((data[offset_data + 4] >> 12) & 0x01) | ((data[offset_data + 5] & 0x7f) << 1));
-                bytes[byteIndex + offset_byte + 9] =
-                    (byte) (((data[offset_data + 5] >> 7) & 0x3f) | ((data[offset_data + 6] & 0x03) << 6));
-                bytes[byteIndex + offset_byte + 10] = (byte) ((data[offset_data + 6] >> 2) & 0xff);
-                bytes[byteIndex + offset_byte + 11] =
-                    (byte) (((data[offset_data + 6] >> 10) & 0x07) | ((data[offset_data + 7] & 0x1f) << 3));
-                bytes[byteIndex + offset_byte + 12] = (byte) ((data[offset_data + 7] >> 5) & 0xff);
+                for (j = 0; j < SABER_N / 8; j++)
+                {
+                    offset_byte = (short)(13 * j);
+                    offset_data = (short)(8 * j);
+                    bytes[byteIndex + offset_byte + 0] = (byte)(data[offset_data + 0] & (0xff));
+                    bytes[byteIndex + offset_byte + 1] =
+                        (byte)(((data[offset_data + 0] >> 8) & 0x1f) | ((data[offset_data + 1] & 0x07) << 5));
+                    bytes[byteIndex + offset_byte + 2] = (byte)((data[offset_data + 1] >> 3) & 0xff);
+                    bytes[byteIndex + offset_byte + 3] =
+                        (byte)(((data[offset_data + 1] >> 11) & 0x03) | ((data[offset_data + 2] & 0x3f) << 2));
+                    bytes[byteIndex + offset_byte + 4] =
+                        (byte)(((data[offset_data + 2] >> 6) & 0x7f) | ((data[offset_data + 3] & 0x01) << 7));
+                    bytes[byteIndex + offset_byte + 5] = (byte)((data[offset_data + 3] >> 1) & 0xff);
+                    bytes[byteIndex + offset_byte + 6] =
+                        (byte)(((data[offset_data + 3] >> 9) & 0x0f) | ((data[offset_data + 4] & 0x0f) << 4));
+                    bytes[byteIndex + offset_byte + 7] = (byte)((data[offset_data + 4] >> 4) & 0xff);
+                    bytes[byteIndex + offset_byte + 8] =
+                        (byte)(((data[offset_data + 4] >> 12) & 0x01) | ((data[offset_data + 5] & 0x7f) << 1));
+                    bytes[byteIndex + offset_byte + 9] =
+                        (byte)(((data[offset_data + 5] >> 7) & 0x3f) | ((data[offset_data + 6] & 0x03) << 6));
+                    bytes[byteIndex + offset_byte + 10] = (byte)((data[offset_data + 6] >> 2) & 0xff);
+                    bytes[byteIndex + offset_byte + 11] =
+                        (byte)(((data[offset_data + 6] >> 10) & 0x07) | ((data[offset_data + 7] & 0x1f) << 3));
+                    bytes[byteIndex + offset_byte + 12] = (byte)((data[offset_data + 7] >> 5) & 0xff);
+                }
+            }
+            else
+            {
+                for (j = 0; j < SABER_N / 2; j++)
+                {
+                    offset_byte = (short) (3 * j);
+                    offset_data = (short) (2 * j);
+                    bytes[byteIndex + offset_byte + 0] = (byte) (data[offset_data + 0] & (0xff));
+                    bytes[byteIndex + offset_byte + 1] = (byte) (((data[offset_data + 0] >> 8) & 0xf) | ((data[offset_data + 1] & 0xf) << 4));
+                    bytes[byteIndex + offset_byte + 2] = (byte) ((data[offset_data + 1] >> 4) & 0xff);
+                }
             }
         }
 
         private void BS2POLq(byte[] bytes, int byteIndex, short[] data)
         {
             short j, offset_byte, offset_data;
-            for (j = 0; j < SABER_N / 8; j++)
+            if (!usingEffectiveMasking)
             {
-                offset_byte = (short) (13 * j);
-                offset_data = (short) (8 * j);
-                data[offset_data + 0] = (short) ((bytes[byteIndex + offset_byte + 0] & (0xff)) |
-                                                 ((bytes[byteIndex + offset_byte + 1] & 0x1f) << 8));
-                data[offset_data + 1] = (short) ((bytes[byteIndex + offset_byte + 1] >> 5 & (0x07)) |
-                                                 ((bytes[byteIndex + offset_byte + 2] & 0xff) << 3) |
-                                                 ((bytes[byteIndex + offset_byte + 3] & 0x03) << 11));
-                data[offset_data + 2] = (short) ((bytes[byteIndex + offset_byte + 3] >> 2 & (0x3f)) |
-                                                 ((bytes[byteIndex + offset_byte + 4] & 0x7f) << 6));
-                data[offset_data + 3] = (short) ((bytes[byteIndex + offset_byte + 4] >> 7 & (0x01)) |
-                                                 ((bytes[byteIndex + offset_byte + 5] & 0xff) << 1) |
-                                                 ((bytes[byteIndex + offset_byte + 6] & 0x0f) << 9));
-                data[offset_data + 4] = (short) ((bytes[byteIndex + offset_byte + 6] >> 4 & (0x0f)) |
-                                                 ((bytes[byteIndex + offset_byte + 7] & 0xff) << 4) |
-                                                 ((bytes[byteIndex + offset_byte + 8] & 0x01) << 12));
-                data[offset_data + 5] = (short) ((bytes[byteIndex + offset_byte + 8] >> 1 & (0x7f)) |
-                                                 ((bytes[byteIndex + offset_byte + 9] & 0x3f) << 7));
-                data[offset_data + 6] = (short) ((bytes[byteIndex + offset_byte + 9] >> 6 & (0x03)) |
-                                                 ((bytes[byteIndex + offset_byte + 10] & 0xff) << 2) |
-                                                 ((bytes[byteIndex + offset_byte + 11] & 0x07) << 10));
-                data[offset_data + 7] = (short) ((bytes[byteIndex + offset_byte + 11] >> 3 & (0x1f)) |
-                                                 ((bytes[byteIndex + offset_byte + 12] & 0xff) << 5));
+                for (j = 0; j < SABER_N / 8; j++)
+                {
+                    offset_byte = (short)(13 * j);
+                    offset_data = (short)(8 * j);
+                    data[offset_data + 0] = (short)((bytes[byteIndex + offset_byte + 0] & (0xff)) |
+                                                    ((bytes[byteIndex + offset_byte + 1] & 0x1f) << 8));
+                    data[offset_data + 1] = (short)((bytes[byteIndex + offset_byte + 1] >> 5 & (0x07)) |
+                                                    ((bytes[byteIndex + offset_byte + 2] & 0xff) << 3) |
+                                                    ((bytes[byteIndex + offset_byte + 3] & 0x03) << 11));
+                    data[offset_data + 2] = (short)((bytes[byteIndex + offset_byte + 3] >> 2 & (0x3f)) |
+                                                    ((bytes[byteIndex + offset_byte + 4] & 0x7f) << 6));
+                    data[offset_data + 3] = (short)((bytes[byteIndex + offset_byte + 4] >> 7 & (0x01)) |
+                                                    ((bytes[byteIndex + offset_byte + 5] & 0xff) << 1) |
+                                                    ((bytes[byteIndex + offset_byte + 6] & 0x0f) << 9));
+                    data[offset_data + 4] = (short)((bytes[byteIndex + offset_byte + 6] >> 4 & (0x0f)) |
+                                                    ((bytes[byteIndex + offset_byte + 7] & 0xff) << 4) |
+                                                    ((bytes[byteIndex + offset_byte + 8] & 0x01) << 12));
+                    data[offset_data + 5] = (short)((bytes[byteIndex + offset_byte + 8] >> 1 & (0x7f)) |
+                                                    ((bytes[byteIndex + offset_byte + 9] & 0x3f) << 7));
+                    data[offset_data + 6] = (short)((bytes[byteIndex + offset_byte + 9] >> 6 & (0x03)) |
+                                                    ((bytes[byteIndex + offset_byte + 10] & 0xff) << 2) |
+                                                    ((bytes[byteIndex + offset_byte + 11] & 0x07) << 10));
+                    data[offset_data + 7] = (short)((bytes[byteIndex + offset_byte + 11] >> 3 & (0x1f)) |
+                                                    ((bytes[byteIndex + offset_byte + 12] & 0xff) << 5));
+                }
+            }
+            else
+            {
+                for (j = 0; j < SABER_N / 2; j++)
+                {
+                    offset_byte = (short) (3 * j);
+                    offset_data = (short) (2 * j);
+                    data[offset_data + 0] = (short) ((bytes[byteIndex + offset_byte + 0] & (0xff)) | ((bytes[byteIndex + offset_byte + 1] & 0xf) << 8));
+                    data[offset_data + 1] = (short) ((bytes[byteIndex + offset_byte + 1] >> 4 & (0xf)) | ((bytes[byteIndex + offset_byte + 2] & 0xff) << 4));
+                }
             }
         }
 
@@ -271,4 +298,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Saber
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/saber/Symmetric.cs b/crypto/src/pqc/crypto/saber/Symmetric.cs
new file mode 100644
index 000000000..bcbe8a9a3
--- /dev/null
+++ b/crypto/src/pqc/crypto/saber/Symmetric.cs
@@ -0,0 +1,99 @@
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Crypto.Modes;
+using Org.BouncyCastle.Crypto.Parameters;
+
+namespace Org.BouncyCastle.Pqc.Crypto.Saber
+{
+
+    public abstract class Symmetric
+    {
+
+        internal abstract void Hash_h(byte[] output, byte[] input, int outputOffset);
+
+        internal abstract void Hash_g(byte[] output, byte[] input);
+
+        internal abstract void Prf(byte[] output, byte[] input, int inLen, int outputLen);
+
+        protected internal class ShakeSymmetric
+            : Symmetric
+        {
+
+            private readonly Sha3Digest sha3Digest256;
+            private readonly Sha3Digest sha3Digest512;
+            private readonly IXof shakeDigest;
+
+            internal ShakeSymmetric()
+            {
+                shakeDigest = new ShakeDigest(128);
+                sha3Digest256 = new Sha3Digest(256);
+                sha3Digest512 = new Sha3Digest(512);
+            }
+
+            internal override void Hash_h(byte[] output, byte[] input, int outputOffset)
+            {
+                sha3Digest256.BlockUpdate(input, 0, input.Length);
+                sha3Digest256.DoFinal(output, outputOffset);
+            }
+
+            internal override void Hash_g(byte[] output, byte[] input)
+            {
+                sha3Digest512.BlockUpdate(input, 0, input.Length);
+                sha3Digest512.DoFinal(output, 0);
+            }
+
+            internal override void Prf(byte[] output, byte[] input, int inLen, int outputLen)
+            {
+                shakeDigest.Reset();
+                shakeDigest.BlockUpdate(input, 0, inLen);
+                shakeDigest.OutputFinal(output, 0, outputLen);
+            }
+
+
+        }
+
+        internal class AesSymmetric
+            : Symmetric
+        {
+
+            private readonly Sha256Digest sha256Digest;
+            private readonly Sha512Digest sha512Digest;
+
+            private readonly SicBlockCipher cipher;
+
+
+            protected internal AesSymmetric()
+            {
+                sha256Digest = new Sha256Digest();
+                sha512Digest = new Sha512Digest();
+                cipher = new SicBlockCipher(AesUtilities.CreateEngine());
+            }
+
+            internal override void Hash_h(byte[] output, byte[] input, int outputOffset)
+            {
+                sha256Digest.BlockUpdate(input, 0, input.Length);
+                sha256Digest.DoFinal(output, outputOffset);
+            }
+
+            internal override void Hash_g(byte[] output, byte[] input)
+            {
+                sha512Digest.BlockUpdate(input, 0, input.Length);
+                sha512Digest.DoFinal(output, 0);
+            }
+
+            internal override void Prf(byte[] output, byte[] input, int inLen, int outputLen)
+            {
+                ParametersWithIV kp = new ParametersWithIV(new KeyParameter(input, 0, inLen), new byte[16]);
+                cipher.Init(true, kp);
+                byte[] buf = new byte[outputLen]; // TODO: there might be a more efficient way of doing this...
+                for (int i = 0; i < outputLen; i += 16)
+                {
+                    cipher.ProcessBlock(buf, i, output, i);
+                }
+            }
+
+
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/sike/Fpx.cs b/crypto/src/pqc/crypto/sike/Fpx.cs
index 2ba6ab2f5..9ba332753 100644
--- a/crypto/src/pqc/crypto/sike/Fpx.cs
+++ b/crypto/src/pqc/crypto/sike/Fpx.cs
@@ -1,4 +1,3 @@
-using System;
 using System.Diagnostics;
 #if NETSTANDARD1_0_OR_GREATER || NETCOREAPP1_0_OR_GREATER
 using System.Runtime.CompilerServices;
@@ -8,11 +7,11 @@ using Org.BouncyCastle.Crypto.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-    internal class Fpx
+    internal sealed class Fpx
     {
-        private SIKEEngine engine;
+        private readonly SikeEngine engine;
 
-        internal Fpx(SIKEEngine engine)
+        internal Fpx(SikeEngine engine)
         {
             this.engine = engine;
         }
@@ -47,7 +46,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
         // Also, vec and out CANNOT be the same variable!
         protected internal void mont_n_way_inv(ulong[][][] vec, uint n, ulong[][][] output)
         {
-            ulong[][] t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+            ulong[][] t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
             int i;
 
             fp2copy(vec[0], output[0]);                      // output[0] = vec[0]
@@ -368,7 +367,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
         // This uses the binary GCD for inversion in fp and is NOT constant time!!!
         protected internal void fp2inv_mont_bingcd(ulong[][] a)
         {
-            ulong[][] t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+            ulong[][] t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
             fpsqr_mont(a[0], t1[0]);             // t10 = a0^2
             fpsqr_mont(a[1], t1[1]);             // t11 = a1^2
@@ -892,7 +891,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
         // Conversion of GF(p^2) element from Montgomery to standard representation, and encoding by removing leading 0 bytes
         protected internal void fp2_encode(ulong[][] x, byte[] enc, uint encOffset)
         {
-            ulong[][] t = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+            ulong[][] t = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
             from_fp2mont(x, t);
             encode_to_bytes(t[0], enc, encOffset,engine.param.FP2_ENCODED_BYTES / 2);
@@ -1280,8 +1279,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
         protected internal byte cmp_f2elm(ulong[][] x, ulong[][] y)
         { // Comparison of two GF(p^2) elements in constant time. 
             // Is x != y? return -1 if condition is true, 0 otherwise.
-            ulong[][] a = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-                b = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+            ulong[][] a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+                b = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
             byte r = 0;
 
             fp2copy(x, a);
@@ -1661,7 +1660,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
         // GF(p^2) inversion using Montgomery arithmetic, a = (a0-i*a1)/(a0^2+a1^2).
         protected internal void fp2inv_mont(ulong[][] a)
         {
-            ulong[][] t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+            ulong[][] t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
             fpsqr_mont(a[0], t1[0]);                 // t10 = a0^2
             fpsqr_mont(a[1], t1[1]);                 // t11 = a1^2
@@ -1808,7 +1807,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
             if (engine.param.NBITS_FIELD == 434)
             {
                 ulong[] tt = new ulong[engine.param.NWORDS_FIELD];
-                ulong[][] t =  Utils.InitArray(31, engine.param.NWORDS_FIELD);
+                ulong[][] t =  SikeUtilities.InitArray(31, engine.param.NWORDS_FIELD);
 
                 // Precomputed table
                 fpsqr_mont(a, tt);
@@ -1888,7 +1887,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
 
             if (engine.param.NBITS_FIELD == 503)
             {
-                ulong[][] t = Utils.InitArray(15, engine.param.NWORDS_FIELD);
+                ulong[][] t = SikeUtilities.InitArray(15, engine.param.NWORDS_FIELD);
                 ulong[] tt = new ulong[engine.param.NWORDS_FIELD];
 
                 // Precomputed table
@@ -1991,7 +1990,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
 
             if (engine.param.NBITS_FIELD == 610)
             {   
-                ulong[][] t = Utils.InitArray(31, engine.param.NWORDS_FIELD); 
+                ulong[][] t = SikeUtilities.InitArray(31, engine.param.NWORDS_FIELD); 
                 ulong[] tt = new ulong[engine.param.NWORDS_FIELD];
 
                 // Precomputed table
@@ -2096,7 +2095,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
 
             if (engine.param.NBITS_FIELD == 751)
             {
-                ulong[][] t = Utils.InitArray(27, engine.param.NWORDS_FIELD);
+                ulong[][] t = SikeUtilities.InitArray(27, engine.param.NWORDS_FIELD);
                 ulong[] tt = new ulong[engine.param.NWORDS_FIELD];
 
                 // Precomputed table
diff --git a/crypto/src/pqc/crypto/sike/Internal.cs b/crypto/src/pqc/crypto/sike/Internal.cs
index 06df0a202..35b1a46e8 100644
--- a/crypto/src/pqc/crypto/sike/Internal.cs
+++ b/crypto/src/pqc/crypto/sike/Internal.cs
@@ -1,217 +1,214 @@
 using System;
 using System.Collections.Generic;
+
 using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Utilities.Encoders;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-
     internal abstract class Internal
-        {
-                protected static Dictionary<string, string> _props;
+    {
+        protected static Dictionary<string, string> _props;
                 
-                protected internal static uint RADIX = 64;
-                protected internal static uint LOG2RADIX = 6;
-
-                protected internal uint CRYPTO_PUBLICKEYBYTES;
-                protected internal int CRYPTO_CIPHERTEXTBYTES;
-                protected internal uint CRYPTO_BYTES;
-                protected internal uint CRYPTO_SECRETKEYBYTES;
-
-
-
-                protected internal uint NWORDS_FIELD;     // Number of words of a n-bit field element
-                protected internal uint PRIME_ZERO_WORDS;  // Number of "0" digits in the least significant part of PRIME + 1
-                protected internal uint NBITS_FIELD;
-                protected internal uint MAXBITS_FIELD;
-                protected uint MAXWORDS_FIELD;   // Max. number of words to represent field elements
-                protected uint NWORDS64_FIELD;   // Number of 64-bit words of a 434-bit field element
-                protected internal uint NBITS_ORDER;
-                protected internal uint NWORDS_ORDER;     // Number of words of oA and oB, where oA and oB are the subgroup orders of Alice and Bob, resp.
-                protected uint NWORDS64_ORDER;   // Number of 64-bit words of a x-bit element
-                protected internal uint MAXBITS_ORDER;
-                protected internal uint ALICE;
-                protected internal uint BOB;
-                protected internal uint OALICE_BITS;
-                protected internal uint OBOB_BITS;
-                protected internal uint OBOB_EXPON;
-                protected internal uint MASK_ALICE;
-                protected internal uint MASK_BOB;
-                protected uint PARAM_A;
-                protected uint PARAM_C;
-
-                // Fixed parameters for isogeny tree computation
-                protected internal uint MAX_INT_POINTS_ALICE;
-                protected internal uint MAX_INT_POINTS_BOB;
-                protected internal uint MAX_Alice;
-                protected internal uint MAX_Bob;
-                protected internal uint MSG_BYTES;
-                protected internal uint SECRETKEY_A_BYTES;
-                protected internal uint SECRETKEY_B_BYTES;
-                protected internal uint FP2_ENCODED_BYTES;
-
-                protected bool COMPRESS;
-
-                // Compressed Parameters
-                protected internal uint MASK2_BOB;
-                protected internal uint MASK3_BOB;
-                protected internal uint ORDER_A_ENCODED_BYTES;
-                protected internal uint ORDER_B_ENCODED_BYTES;
-                protected internal uint PARTIALLY_COMPRESSED_CHUNK_CT;
-                protected uint COMPRESSED_CHUNK_CT;
-                protected uint UNCOMPRESSEDPK_BYTES;
-                // Table sizes used by the Entangled basis generation
-                protected uint TABLE_R_LEN;
-                protected internal uint TABLE_V_LEN;
-                protected uint TABLE_V3_LEN;
-                // Parameters for discrete log computations
-                // Binary Pohlig-Hellman reduced to smaller logs of order ell^W
-                protected internal uint W_2;
-                protected internal uint W_3;
-                // ell^w    
-                protected internal uint ELL2_W;
-                protected internal uint ELL3_W;
-                // ell^(e mod w)
-                protected internal uint ELL2_EMODW;
-                protected internal uint ELL3_EMODW;
-                // # of digits in the discrete log
-                protected internal uint DLEN_2; // ceil(eA/W_2)
-                protected internal uint DLEN_3; // ceil(eB/W_3)
-                // Use compressed tables: FULL_SIGNED
-
-
-                // Encoding of field elements
-                protected internal uint PLEN_2;
-                protected internal uint PLEN_3;
-
-                protected internal ulong[] PRIME;
-                protected internal ulong[] PRIMEx2;
-                protected internal ulong[] PRIMEx4;
-                protected internal ulong[] PRIMEp1;
-                protected ulong[] PRIMEx16p;
-                protected ulong[] PRIMEp1x64;
-                protected internal ulong[] Alice_order;        // Order of Alice's subgroup
-                protected internal ulong[] Bob_order;     // Order of Bob's subgroup
-                protected internal ulong[] A_gen;    // Alice's generator values {XPA0 + XPA1*iL, XQA0 + xQA1*iL, XRA0 + XRA1*i} in GF(p^2)L, expressed in Montgomery representation
-                protected internal ulong[] B_gen;    // Bob's generator values {XPB0L, XQB0L, XRB0 + XRB1*i} in GF(p^2)L, expressed in Montgomery representation
-                protected internal ulong[] Montgomery_R2;    // Montgomery constant Montgomery_R2 = (2^448)^2 mod p434
-                protected internal ulong[] Montgomery_one;    // Value one in Montgomery representation
-
-                // Fixed parameters for isogeny tree computation
-                protected internal uint[] strat_Alice;
-                protected internal uint[] strat_Bob;
-
-                //Compressed Encodings
-                //todo: abstract this more?
-                protected internal ulong[] XQB3;
-                protected internal ulong[] A_basis_zero;
-                protected ulong[] B_basis_zero;
-                protected internal ulong[] B_gen_3_tors;
-                protected internal ulong[] g_R_S_im;
-                protected ulong[] g_phiR_phiS_re;
-                protected ulong[] g_phiR_phiS_im;
-                protected ulong[] Montgomery_R;
-                protected internal ulong[] Montgomery_RB1;
-                protected internal ulong[] Montgomery_RB2;
-                protected ulong[] threeinv;
-                protected internal uint[] ph2_path;
-                protected internal uint[] ph3_path;
-                protected ulong[] u_entang;
-                protected ulong[] u0_entang;
-                protected internal ulong[][] table_r_qr;
-                protected internal ulong[][] table_r_qnr;
-                protected internal ulong[][] table_v_qr;
-                protected internal ulong[][] table_v_qnr;
-                protected internal ulong[][][] v_3_torsion;
-
-                protected internal ulong[] T_tate3;
-                protected internal ulong[] T_tate2_firststep_P;
-                protected internal ulong[] T_tate2_P;
-                protected internal ulong[] T_tate2_firststep_Q;
-                protected internal ulong[] T_tate2_Q;
-
-                ///Compressed Dlogs
-                protected internal ulong[] ph2_T;
-                protected internal ulong[] ph2_T1;
-                protected internal ulong[] ph2_T2;
-                protected internal ulong[] ph3_T;
-                protected internal ulong[] ph3_T1;
-                protected internal ulong[] ph3_T2;
-
-
-                static protected uint[] ReadIntsFromProperty(string key, uint intSize)
-                {
-                        uint[] ints = new uint[intSize];
-                        string s = _props[key];
-                        uint i = 0;
-                        foreach (string number in s.Split(','))
-                        {
-                                ints[i] = UInt32.Parse(number);
-                                i++;
-                        }
-                        return ints;
-                }
+        protected internal static uint RADIX = 64;
+        protected internal static uint LOG2RADIX = 6;
+
+        protected internal uint CRYPTO_PUBLICKEYBYTES;
+        protected internal int CRYPTO_CIPHERTEXTBYTES;
+        protected internal uint CRYPTO_BYTES;
+        protected internal uint CRYPTO_SECRETKEYBYTES;
+
+
+
+        protected internal uint NWORDS_FIELD;     // Number of words of a n-bit field element
+        protected internal uint PRIME_ZERO_WORDS;  // Number of "0" digits in the least significant part of PRIME + 1
+        protected internal uint NBITS_FIELD;
+        protected internal uint MAXBITS_FIELD;
+        protected uint MAXWORDS_FIELD;   // Max. number of words to represent field elements
+        protected uint NWORDS64_FIELD;   // Number of 64-bit words of a 434-bit field element
+        protected internal uint NBITS_ORDER;
+        protected internal uint NWORDS_ORDER;     // Number of words of oA and oB, where oA and oB are the subgroup orders of Alice and Bob, resp.
+        protected uint NWORDS64_ORDER;   // Number of 64-bit words of a x-bit element
+        protected internal uint MAXBITS_ORDER;
+        protected internal uint ALICE;
+        protected internal uint BOB;
+        protected internal uint OALICE_BITS;
+        protected internal uint OBOB_BITS;
+        protected internal uint OBOB_EXPON;
+        protected internal uint MASK_ALICE;
+        protected internal uint MASK_BOB;
+        protected uint PARAM_A;
+        protected uint PARAM_C;
+
+        // Fixed parameters for isogeny tree computation
+        protected internal uint MAX_INT_POINTS_ALICE;
+        protected internal uint MAX_INT_POINTS_BOB;
+        protected internal uint MAX_Alice;
+        protected internal uint MAX_Bob;
+        protected internal uint MSG_BYTES;
+        protected internal uint SECRETKEY_A_BYTES;
+        protected internal uint SECRETKEY_B_BYTES;
+        protected internal uint FP2_ENCODED_BYTES;
+
+        protected bool COMPRESS;
+
+        // Compressed Parameters
+        protected internal uint MASK2_BOB;
+        protected internal uint MASK3_BOB;
+        protected internal uint ORDER_A_ENCODED_BYTES;
+        protected internal uint ORDER_B_ENCODED_BYTES;
+        protected internal uint PARTIALLY_COMPRESSED_CHUNK_CT;
+        protected uint COMPRESSED_CHUNK_CT;
+        protected uint UNCOMPRESSEDPK_BYTES;
+        // Table sizes used by the Entangled basis generation
+        protected uint TABLE_R_LEN;
+        protected internal uint TABLE_V_LEN;
+        protected uint TABLE_V3_LEN;
+        // Parameters for discrete log computations
+        // Binary Pohlig-Hellman reduced to smaller logs of order ell^W
+        protected internal uint W_2;
+        protected internal uint W_3;
+        // ell^w    
+        protected internal uint ELL2_W;
+        protected internal uint ELL3_W;
+        // ell^(e mod w)
+        protected internal uint ELL2_EMODW;
+        protected internal uint ELL3_EMODW;
+        // # of digits in the discrete log
+        protected internal uint DLEN_2; // ceil(eA/W_2)
+        protected internal uint DLEN_3; // ceil(eB/W_3)
+        // Use compressed tables: FULL_SIGNED
+
+
+        // Encoding of field elements
+        protected internal uint PLEN_2;
+        protected internal uint PLEN_3;
+
+        protected internal ulong[] PRIME;
+        protected internal ulong[] PRIMEx2;
+        protected internal ulong[] PRIMEx4;
+        protected internal ulong[] PRIMEp1;
+        protected ulong[] PRIMEx16p;
+        protected ulong[] PRIMEp1x64;
+        protected internal ulong[] Alice_order;        // Order of Alice's subgroup
+        protected internal ulong[] Bob_order;     // Order of Bob's subgroup
+        protected internal ulong[] A_gen;    // Alice's generator values {XPA0 + XPA1*iL, XQA0 + xQA1*iL, XRA0 + XRA1*i} in GF(p^2)L, expressed in Montgomery representation
+        protected internal ulong[] B_gen;    // Bob's generator values {XPB0L, XQB0L, XRB0 + XRB1*i} in GF(p^2)L, expressed in Montgomery representation
+        protected internal ulong[] Montgomery_R2;    // Montgomery constant Montgomery_R2 = (2^448)^2 mod p434
+        protected internal ulong[] Montgomery_one;    // Value one in Montgomery representation
+
+        // Fixed parameters for isogeny tree computation
+        protected internal uint[] strat_Alice;
+        protected internal uint[] strat_Bob;
+
+        //Compressed Encodings
+        //todo: abstract this more?
+        protected internal ulong[] XQB3;
+        protected internal ulong[] A_basis_zero;
+        protected ulong[] B_basis_zero;
+        protected internal ulong[] B_gen_3_tors;
+        protected internal ulong[] g_R_S_im;
+        protected ulong[] g_phiR_phiS_re;
+        protected ulong[] g_phiR_phiS_im;
+        protected ulong[] Montgomery_R;
+        protected internal ulong[] Montgomery_RB1;
+        protected internal ulong[] Montgomery_RB2;
+        protected ulong[] threeinv;
+        protected internal uint[] ph2_path;
+        protected internal uint[] ph3_path;
+        protected ulong[] u_entang;
+        protected ulong[] u0_entang;
+        protected internal ulong[][] table_r_qr;
+        protected internal ulong[][] table_r_qnr;
+        protected internal ulong[][] table_v_qr;
+        protected internal ulong[][] table_v_qnr;
+        protected internal ulong[][][] v_3_torsion;
+
+        protected internal ulong[] T_tate3;
+        protected internal ulong[] T_tate2_firststep_P;
+        protected internal ulong[] T_tate2_P;
+        protected internal ulong[] T_tate2_firststep_Q;
+        protected internal ulong[] T_tate2_Q;
+
+        ///Compressed Dlogs
+        protected internal ulong[] ph2_T;
+        protected internal ulong[] ph2_T1;
+        protected internal ulong[] ph2_T2;
+        protected internal ulong[] ph3_T;
+        protected internal ulong[] ph3_T1;
+        protected internal ulong[] ph3_T2;
+
+
+        static protected uint[] ReadIntsFromProperty(string key, uint intSize)
+        {
+            uint[] ints = new uint[intSize];
+            string s = _props[key];
+            uint i = 0;
+            foreach (string number in s.Split(','))
+            {
+                ints[i] = UInt32.Parse(number);
+                i++;
+            }
+            return ints;
+        }
 
-                static protected ulong[] ReadFromProperty(string key, uint ulongSize)
-                {
-                        string s = _props[key];
-                        s = s.Replace(",", "");
-                        byte[] bytes = Hex.Decode(s);
-                        ulong[] ulongs = new ulong[ulongSize];
-                        for (int i = 0; i < bytes.Length / 8; i++)
-                        {
-                                ulongs[i] = Pack.BE_To_UInt64(bytes, i * 8);
-                        }
-                        return ulongs;
-                }
+        static protected ulong[] ReadFromProperty(string key, uint ulongSize)
+        {
+            string s = _props[key];
+            s = s.Replace(",", "");
+            byte[] bytes = Hex.Decode(s);
+            ulong[] ulongs = new ulong[ulongSize];
+            for (int i = 0; i < bytes.Length / 8; i++)
+            {
+                ulongs[i] = Pack.BE_To_UInt64(bytes, i * 8);
+            }
+            return ulongs;
+        }
 
-                static protected ulong[][] ReadFromProperty(string key, uint d1Size, uint d2Size)
-                {
-                        string s = _props[key];
-                        s = s.Replace(",", "");
-                        byte[] bytes = Hex.Decode(s);
-                        ulong[][] ulongs = new ulong[d1Size][]; //[d2Size];
-                        for (int k = 0; k < d1Size; k++)
-                        {
-                                ulongs[k] = new ulong[d2Size];
-                        }
-                        uint i, j;
-                        for (uint x = 0; x < bytes.Length / 8; x++)
-                        {
-                                i = x/d2Size;
-                                j = x%d2Size;
-                                ulongs[i][j] = Pack.BE_To_UInt64(bytes, (int)x * 8);
-                        }
-                        return ulongs;
-                }
+        static protected ulong[][] ReadFromProperty(string key, uint d1Size, uint d2Size)
+        {
+            string s = _props[key];
+            s = s.Replace(",", "");
+            byte[] bytes = Hex.Decode(s);
+            ulong[][] ulongs = new ulong[d1Size][]; //[d2Size];
+            for (int k = 0; k < d1Size; k++)
+            {
+                ulongs[k] = new ulong[d2Size];
+            }
+            uint i, j;
+            for (uint x = 0; x < bytes.Length / 8; x++)
+            {
+                i = x/d2Size;
+                j = x%d2Size;
+                ulongs[i][j] = Pack.BE_To_UInt64(bytes, (int)x * 8);
+            }
+            return ulongs;
+        }
 
-                static protected ulong[][][] ReadFromProperty(string key, uint d1Size, uint d2Size, uint d3Size)
+        static protected ulong[][][] ReadFromProperty(string key, uint d1Size, uint d2Size, uint d3Size)
+        {
+            string s = _props[key];
+            s = s.Replace(",", "");
+            byte[] bytes = Hex.Decode(s);
+            ulong[][][] ulongs = new ulong[d1Size][][]; //[d2Size][d3Size];
+            for (int l = 0; l < d1Size; l++)
+            {
+                ulongs[l] = new ulong[d2Size][];
+                for (int m = 0; m < d2Size; m++)
                 {
-                        string s = _props[key];
-                        s = s.Replace(",", "");
-                        byte[] bytes = Hex.Decode(s);
-                        ulong[][][] ulongs = new ulong[d1Size][][]; //[d2Size][d3Size];
-                        for (int l = 0; l < d1Size; l++)
-                        {
-                                ulongs[l] = new ulong[d2Size][];
-                                for (int m = 0; m < d2Size; m++)
-                                {
-                                        ulongs[l][m] = new ulong[d3Size];
-                                }
-                        }
-                        
-                        uint i, j, k;
-                        for (uint x = 0; x < bytes.Length / 8; x++)
-                        {
-                                i = x/(d2Size * d3Size);
-                                j = x%(d2Size * d3Size)/d3Size;
-                                k = x % d3Size;
-                                ulongs[i][j][k] = Pack.BE_To_UInt64(bytes, (int)x * 8);
-                        }
-                        return ulongs;
+                    ulongs[l][m] = new ulong[d3Size];
                 }
-
-
+            }
+                        
+            uint i, j, k;
+            for (uint x = 0; x < bytes.Length / 8; x++)
+            {
+                i = x/(d2Size * d3Size);
+                j = x%(d2Size * d3Size)/d3Size;
+                k = x % d3Size;
+                ulongs[i][j][k] = Pack.BE_To_UInt64(bytes, (int)x * 8);
+            }
+            return ulongs;
         }
-
-}
\ No newline at end of file
+    }
+}
diff --git a/crypto/src/pqc/crypto/sike/Isogeny.cs b/crypto/src/pqc/crypto/sike/Isogeny.cs
index fc2b3e5ca..2d0ef1473 100644
--- a/crypto/src/pqc/crypto/sike/Isogeny.cs
+++ b/crypto/src/pqc/crypto/sike/Isogeny.cs
@@ -1,25 +1,25 @@
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-    internal class Isogeny
+internal sealed class Isogeny
 {
-     SIKEEngine engine;
+    private readonly SikeEngine engine;
 
-     internal Isogeny(SIKEEngine engine)
+    internal Isogeny(SikeEngine engine)
     {
         this.engine = engine;
     }
-    
+
     // Doubling of a Montgomery point in projective coordinates (X:Z) over affine curve coefficient A. 
     // Input: projective Montgomery x-coordinates P = (X1:Z1), where x1=X1/Z1 and Montgomery curve constants (A+2)/4.
     // Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2). 
     protected internal void Double(PointProj P, PointProj Q, ulong[][] A24, uint k)
     {
-        ulong[][] temp = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            a = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            b = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            c = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            aa = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            bb = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] temp = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            b = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            c = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            aa = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            bb = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         engine.fpx.fp2copy(P.X, Q.X);
         engine.fpx.fp2copy(P.Z, Q.Z);
 
@@ -39,15 +39,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
 
     protected internal void CompleteMPoint(ulong[][] A, PointProj P, PointProjFull R)
     { // Given an xz-only representation on a montgomery curve, compute its affine representation
-        ulong[][] zero = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            one = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            xz = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            yz = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            s2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            r2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            invz = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            temp0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            temp1 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] zero = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            one = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            xz = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            yz = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            s2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            r2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            invz = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            temp0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            temp1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
 
             engine.fpx.fpcopy(engine.param.Montgomery_one,0, one[0]);
@@ -83,7 +83,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     {
         PointProj R0 = new PointProj(engine.param.NWORDS_FIELD),
                   R1 = new PointProj(engine.param.NWORDS_FIELD);
-        ulong[][] A24 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] A24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         uint bit = 0;
         ulong mask;
         int j, swap, prevbit = 0;
@@ -132,9 +132,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: projective Montgomery points P <- 2*P = (X2P:Z2P) such that x(2P)=X2P/Z2P, and Q <- P+Q = (XQP:ZQP) such that = x(Q+P)=XQP/ZQP.
     private void xDBLADD_proj(PointProj P, PointProj Q, ulong[][] XPQ, ulong[][] ZPQ, ulong[][] A24)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
 
         engine.fpx.fp2add(P.X, P.Z, t0);                         // t0 = XP+ZP
@@ -164,12 +164,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2).
     private void xDBL_e(PointProj P, PointProj Q, ulong[][] A24, int e)
     {
-        ulong[][] temp = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            a = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            b = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            c = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            aa = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            bb = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] temp = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            a = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            b = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            c = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            aa = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            bb = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
 
         engine.fpx.fp2copy(P.X,Q.X);
@@ -209,10 +209,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: projective Montgomery x-coordinates Q = 3*P = (X3:Z3).
     private void xTPL_fast(PointProj P, PointProj Q, ulong[][] A2)
     {
-        ulong[][] t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t3 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t4 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
 
         engine.fpx.fp2sqr_mont(P.X, t1);        // t1 = x^2
@@ -242,7 +242,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     {
         PointProj R0 = new PointProj(engine.param.NWORDS_FIELD),
                   R2 = new PointProj(engine.param.NWORDS_FIELD);
-        ulong[][] A24 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] A24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         ulong mask;
         uint i, nbits, bit, swap, prevbit = 0;
 
@@ -289,14 +289,14 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Complete point on A = 0 curve
     protected internal void CompletePoint(PointProj P, PointProjFull R)
     {
-        ulong[][] xz = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            s2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            r2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            yz = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            invz = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            one = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] xz = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            s2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            r2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            yz = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            invz = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            one = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.fpcopy(engine.param.Montgomery_one, 0, one[0]);
         engine.fpx.fp2mul_mont(P.X, P.Z, xz);
@@ -346,9 +346,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: projective Montgomery points P <- 2*P = (X2P:Z2P) such that x(2P)=X2P/Z2P, and Q <- P+Q = (XQP:ZQP) such that = x(Q+P)=XQP/ZQP.
     protected internal void xDBLADD(PointProj P, PointProj Q, ulong[][] xPQ, ulong[][] A24)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.mp2_add(P.X, P.Z, t0);                  // t0 = XP+ZP
         engine.fpx.mp2_sub_p2(P.X, P.Z, t1);               // t1 = XP-ZP
@@ -389,8 +389,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: projective Montgomery x-coordinates Q = 2*P = (X2:Z2).
     protected void xDBL(PointProj P, PointProj Q, ulong[][] A24plus, ulong[][] C24)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.mp2_sub_p2(P.X, P.Z, t0);                // t0 = X1-Z1
         engine.fpx.mp2_add(P.X, P.Z, t1);                   // t1 = X1+Z1
@@ -409,13 +409,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: projective Montgomery x-coordinates Q = 3*P = (X3:Z3).
     private void xTPL(PointProj P, PointProj Q, ulong[][] A24minus, ulong[][] A24plus)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t3 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t4 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t5 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t6 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t5 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t6 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.mp2_sub_p2(P.X, P.Z, t0);               // t0 = X-Z
         engine.fpx.fp2sqr_mont(t0, t2);                    // t2 = (X-Z)^2
@@ -459,9 +459,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: the coefficient A corresponding to the curve E_A: y^2=x^3+A*x^2+x.
     protected internal void get_A(ulong[][] xP, ulong[][] xQ, ulong[][] xR, ulong[][] A)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            one = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            one = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.fpcopy(engine.param.Montgomery_one, 0, one[0]);
         engine.fpx.fp2add(xP, xQ, t1);                     // t1 = xP+xQ
@@ -484,8 +484,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: j=256*(A^2-3*C^2)^3/(C^4*(A^2-4*C^2)), which is the j-invariant of the Montgomery curve B*y^2=x^3+(A/C)*x^2+x or (equivalently) j-invariant of B'*y^2=C*x^3+A*x^2+C*x.
     protected internal void j_inv(ulong[][] A, ulong[][] C, ulong[][] jinv)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         
         engine.fpx.fp2sqr_mont(A, jinv);                   // jinv = A^2
         engine.fpx.fp2sqr_mont(C, t1);                     // t1 = C^2
@@ -512,11 +512,11 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: the 3-isogenous Montgomery curve with projective coefficient A/C.
     protected internal void get_3_isog(PointProj P, ulong[][] A24minus, ulong[][] A24plus, ulong[][][] coeff)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t3 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t4 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.mp2_sub_p2(P.X, P.Z, coeff[0]);         // coeff0 = X-Z
         engine.fpx.fp2sqr_mont(coeff[0], t0);              // t0 = (X-Z)^2
@@ -542,9 +542,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: the projective point Q <- phi(Q) = (X3:Z3).
     protected internal void eval_3_isog(PointProj Q, ulong[][][] coeff)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.mp2_add(Q.X, Q.Z, t0);                  // t0 = X+Z
         engine.fpx.mp2_sub_p2(Q.X, Q.Z, t1);               // t1 = X-Z
@@ -563,10 +563,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: 1/z1,1/z2,1/z3 (override inputs).
     protected internal void inv_3_way(ulong[][] z1, ulong[][] z2, ulong[][] z3)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t3 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.fp2mul_mont(z1, z2, t0);                // t0 = z1*z2
         engine.fpx.fp2mul_mont(z3, t0, t1);                // t1 = z1*z2*z3
@@ -593,10 +593,10 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: the projective point P = phi(P) = (X:Z) in the codomain. 
     protected internal void eval_2_isog(PointProj P, PointProj Q)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t3 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.mp2_add(Q.X, Q.Z, t0);                  // t0 = X2+Z2
         engine.fpx.mp2_sub_p2(Q.X, Q.Z, t1);               // t1 = X2-Z2
@@ -633,8 +633,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
     // Output: the projective point P = phi(P) = (X:Z) in the codomain.
     protected internal void eval_4_isog(PointProj P, ulong[][][] coeff)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.mp2_add(P.X, P.Z, t0);                  // t0 = X+Z
         engine.fpx.mp2_sub_p2(P.X, P.Z, t1);               // t1 = X-Z
diff --git a/crypto/src/pqc/crypto/sike/PointProj.cs b/crypto/src/pqc/crypto/sike/PointProj.cs
index 4f6e8b882..a9c82c249 100644
--- a/crypto/src/pqc/crypto/sike/PointProj.cs
+++ b/crypto/src/pqc/crypto/sike/PointProj.cs
@@ -1,14 +1,13 @@
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-internal class PointProj
-{
-    internal PointProj(uint nwords_field)
+    internal sealed class PointProj
     {
-        X = Utils.InitArray(2, nwords_field);
-        Z = Utils.InitArray(2, nwords_field);
+        internal PointProj(uint nwords_field)
+        {
+            X = SikeUtilities.InitArray(2, nwords_field);
+            Z = SikeUtilities.InitArray(2, nwords_field);
+        }
+        internal ulong[][] X;
+        internal ulong[][] Z;
     }
-    public ulong[][] X;
-    public ulong[][] Z;
 }
-
-}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/sike/PointProjFull.cs b/crypto/src/pqc/crypto/sike/PointProjFull.cs
index 4e717f31a..8153d9c38 100644
--- a/crypto/src/pqc/crypto/sike/PointProjFull.cs
+++ b/crypto/src/pqc/crypto/sike/PointProjFull.cs
@@ -1,15 +1,15 @@
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-internal class PointProjFull
-{
-    internal PointProjFull(uint nwords_field)
+    internal sealed class PointProjFull
     {
-        X = Utils.InitArray(2, nwords_field);
-        Y = Utils.InitArray(2, nwords_field);
-        Z = Utils.InitArray(2, nwords_field);
+        internal PointProjFull(uint nwords_field)
+        {
+            X = SikeUtilities.InitArray(2, nwords_field);
+            Y = SikeUtilities.InitArray(2, nwords_field);
+            Z = SikeUtilities.InitArray(2, nwords_field);
+        }
+        internal ulong[][] X;
+        internal ulong[][] Y;
+        internal ulong[][] Z;
     }
-    public ulong[][] X;
-    public ulong[][] Y;
-    public ulong[][] Z;
-}
 }
diff --git a/crypto/src/pqc/crypto/sike/SIDH.cs b/crypto/src/pqc/crypto/sike/SIDH.cs
index d5a86d6b1..c1d1714f6 100644
--- a/crypto/src/pqc/crypto/sike/SIDH.cs
+++ b/crypto/src/pqc/crypto/sike/SIDH.cs
@@ -1,10 +1,10 @@
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-internal class SIDH
+internal sealed class Sidh
 {
-    private SIKEEngine engine;
+    private readonly SikeEngine engine;
 
-    public SIDH(SIKEEngine engine)
+    public Sidh(SikeEngine engine)
     {
         this.engine = engine;
     }
@@ -32,14 +32,14 @@ internal class SIDH
 
         PointProj[] pts = new PointProj[engine.param.MAX_INT_POINTS_BOB];
 
-        ulong[][] XPB = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            XQB = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            XRB = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24plus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24minus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] XPB = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            XQB = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            XRB = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24plus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24minus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
-        ulong[][][] coeff = Utils.InitArray(3, 2, engine.param.NWORDS_FIELD);
+        ulong[][][] coeff = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD);
         uint i, row, m, index = 0, npts = 0, ii = 0;
         uint[] pts_index = new uint[engine.param.MAX_INT_POINTS_BOB];
         ulong[] SecretKeyB = new ulong[engine.param.NWORDS_ORDER];
@@ -116,14 +116,14 @@ internal class SIDH
                 phiR = new PointProj(engine.param.NWORDS_FIELD);
 
         PointProj[] pts = new PointProj[engine.param.MAX_INT_POINTS_ALICE];
-        ulong[][] XPA = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            XQA = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            XRA = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24plus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            C24 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A = Utils.InitArray(2, engine.param.NWORDS_FIELD);
-
-        ulong[][][] coeff = Utils.InitArray(3, 2, engine.param.NWORDS_FIELD);
+        ulong[][] XPA = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            XQA = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            XRA = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24plus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            C24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
+
+        ulong[][][] coeff = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD);
         uint index = 0, npts = 0, ii = 0, m, i, row;
         uint[] pts_index = new uint[engine.param.MAX_INT_POINTS_ALICE];
         ulong[] SecretKeyA = new ulong[engine.param.NWORDS_ORDER];
@@ -213,12 +213,12 @@ internal class SIDH
     {
         PointProj R = new PointProj(engine.param.NWORDS_FIELD);
         PointProj[] pts = new PointProj[engine.param.MAX_INT_POINTS_ALICE];
-        ulong[][][] PKB = Utils.InitArray(3, 2, engine.param.NWORDS_FIELD),
-            coeff = Utils.InitArray(3, 2, engine.param.NWORDS_FIELD);
-        ulong[][] jinv = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24plus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            C24 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][][] PKB = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD),
+            coeff = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD);
+        ulong[][] jinv = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24plus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            C24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         uint i = 0, row = 0, m = 0, index = 0, npts = 0, ii = 0;
         uint[] pts_index = new uint[engine.param.MAX_INT_POINTS_ALICE];
@@ -292,13 +292,13 @@ internal class SIDH
     {
         PointProj R = new PointProj(engine.param.NWORDS_FIELD);
         PointProj[] pts = new PointProj[engine.param.MAX_INT_POINTS_BOB];
-        ulong[][][] coeff = Utils.InitArray(3, 2, engine.param.NWORDS_FIELD),
-            PKB = Utils.InitArray(3, 2, engine.param.NWORDS_FIELD);
+        ulong[][][] coeff = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD),
+            PKB = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD);
 
-        ulong[][] jinv = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24plus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24minus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] jinv = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24plus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24minus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         uint i, row, m, index = 0, npts = 0, ii = 0;
         uint[] pts_index = new uint[engine.param.MAX_INT_POINTS_BOB];
         ulong[] SecretKeyB = new ulong[engine.param.NWORDS_ORDER];
diff --git a/crypto/src/pqc/crypto/sike/SIDH_Compressed.cs b/crypto/src/pqc/crypto/sike/SIDH_Compressed.cs
index 46a289c97..ca140aa50 100644
--- a/crypto/src/pqc/crypto/sike/SIDH_Compressed.cs
+++ b/crypto/src/pqc/crypto/sike/SIDH_Compressed.cs
@@ -1,17 +1,19 @@
 using System;
+
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-internal class SIDH_Compressed
+internal sealed class SidhCompressed
 {
-    private SIKEEngine engine;
+    private readonly SikeEngine engine;
 
-    public SIDH_Compressed(SIKEEngine engine)
+    public SidhCompressed(SikeEngine engine)
     {
         this.engine = engine;
     }
+
     protected void init_basis(ulong[] gen, ulong[][] XP, ulong[][] XQ, ulong[][] XR)
     { // Initialization of basis points
 
@@ -104,8 +106,8 @@ internal class SIDH_Compressed
                 N = new ulong[engine.param.NWORDS_FIELD],
                 temp0 = new ulong[engine.param.NWORDS_FIELD],
                 temp1 = new ulong[engine.param.NWORDS_FIELD];
-        ulong[][] A = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            y2 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            y2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         uint t_ptr = 0;
 
 //        System.out.print("a24: ");
@@ -214,12 +216,12 @@ internal class SIDH_Compressed
 
     protected void BiQuad_affine(ulong[][] a24, ulong[][] x0, ulong[][] x1, PointProj R)
     {
-        ulong[][] Ap2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            aa = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            bb = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            cc = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] Ap2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            aa = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            bb = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            cc = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.fp2add(a24, a24, Ap2);
         engine.fpx.fp2add(Ap2, Ap2, Ap2);    // Ap2 = a+2 = 4*a24
@@ -275,7 +277,7 @@ internal class SIDH_Compressed
 
     protected void eval_dual_2_isog(ulong[][] X2, ulong[][] Z2, PointProj P)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.fp2add(P.X, P.Z, t0);
         engine.fpx.fp2sub(P.X, P.Z, P.Z);
@@ -288,8 +290,8 @@ internal class SIDH_Compressed
 
     protected void eval_final_dual_2_isog(PointProj P)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         ulong[] t2 = new ulong[engine.param.NWORDS_FIELD];
 
         engine.fpx.fp2add(P.X, P.Z, t0);
@@ -341,10 +343,10 @@ internal class SIDH_Compressed
 
     protected void eval_dual_4_isog(ulong[][] A24, ulong[][] C24, ulong[][][] coeff, uint coeffOffset, PointProj P)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t3 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.fp2add(P.X, P.Z, t0);
         engine.fpx.fp2sub(P.X, P.Z, t1);
@@ -395,8 +397,8 @@ internal class SIDH_Compressed
 
     protected void Tate3_proj(PointProjFull P, PointProjFull Q, ulong[][] gX, ulong[][] gZ)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            l1x = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            l1x = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         TripleAndParabola_proj(P, l1x, gZ);
         engine.fpx.fp2sub(Q.X, P.X, gX);
@@ -411,7 +413,7 @@ internal class SIDH_Compressed
     {
         uint i;
 
-        ulong[][] f_ = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] f_ = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.fp2copy(gZ, f_);
         engine.fpx.fpnegPRIME(f_[1]);
@@ -435,8 +437,8 @@ internal class SIDH_Compressed
     {
         uint i, j;
 
-        ulong[][][] f_ = Utils.InitArray(2, 2, engine.param.NWORDS_FIELD),
-            finv = Utils.InitArray(2, 2, engine.param.NWORDS_FIELD);
+        ulong[][][] f_ = SikeUtilities.InitArray(2, 2, engine.param.NWORDS_FIELD),
+            finv = SikeUtilities.InitArray(2, 2, engine.param.NWORDS_FIELD);
 
         for(i = 0; i < 2; i++)
         {
@@ -467,8 +469,8 @@ internal class SIDH_Compressed
         PointProjFull R3 = new PointProjFull(engine.param.NWORDS_FIELD),
                       S3 = new PointProjFull(engine.param.NWORDS_FIELD);
 
-        ulong[][][] gX = Utils.InitArray(2, 2, engine.param.NWORDS_FIELD),
-            gZ = Utils.InitArray(2, 2, engine.param.NWORDS_FIELD);
+        ulong[][][] gX = SikeUtilities.InitArray(2, 2, engine.param.NWORDS_FIELD),
+            gZ = SikeUtilities.InitArray(2, 2, engine.param.NWORDS_FIELD);
         ulong[] zero = new ulong[engine.param.NWORDS_FIELD];
         uint nbytes = engine.param.NWORDS_FIELD;// (((engine.param.NBITS_FIELD)+7)/8);
         uint alpha,beta;
@@ -583,8 +585,8 @@ internal class SIDH_Compressed
     {
         PointProjFull RS3 = new PointProjFull(engine.param.NWORDS_FIELD);
 
-        ulong[][] gX = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            gZ = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] gX = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            gZ = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         ulong[] zero = new ulong[engine.param.NWORDS_FIELD];
         uint nbytes = engine.param.NWORDS_FIELD;
@@ -725,9 +727,9 @@ internal class SIDH_Compressed
 
     protected void makeDiff(PointProjFull R, PointProjFull S, PointProj D)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         uint nbytes = engine.param.NWORDS_FIELD;
 
         engine.fpx.fp2sub(R.X, S.X, t0);
@@ -752,7 +754,7 @@ internal class SIDH_Compressed
     {
         PointProj D = new PointProj(engine.param.NWORDS_FIELD);
 
-        ulong[][][] xs = Utils.InitArray(2, 2, engine.param.NWORDS_FIELD);
+        ulong[][][] xs = SikeUtilities.InitArray(2, 2, engine.param.NWORDS_FIELD);
         byte[] ind = new byte[1],
                bit = new byte[1];
 
@@ -815,14 +817,14 @@ internal class SIDH_Compressed
         PointProj R = new PointProj(engine.param.NWORDS_FIELD);
         PointProj[] pts = new PointProj[engine.param.MAX_INT_POINTS_ALICE];
 
-        ulong[][] XPA = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            XQA = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            XRA = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            C24 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] XPA = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            XQA = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            XRA = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            C24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
-        ulong[][][] coeff = Utils.InitArray(5, 2, engine.param.NWORDS_FIELD);
+        ulong[][][] coeff = SikeUtilities.InitArray(5, 2, engine.param.NWORDS_FIELD);
 
         uint i, row, m, index = 0, npts = 0, ii = 0;
         uint[] pts_index = new uint[engine.param.MAX_INT_POINTS_ALICE];
@@ -1074,7 +1076,7 @@ internal class SIDH_Compressed
     {
         byte bit;
         uint[] rs = new uint[3];
-        ulong[][] A24 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] A24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         PointProj[] Rs = new PointProj[3];
         Rs[0] = new PointProj(engine.param.NWORDS_FIELD);
         Rs[1] = new PointProj(engine.param.NWORDS_FIELD);
@@ -1159,7 +1161,7 @@ internal class SIDH_Compressed
         uint bit;
         ulong[] temp = new ulong[engine.param.NWORDS_ORDER],
                inv = new ulong[engine.param.NWORDS_ORDER];
-        ulong[][] A = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.fp2add(a24,a24,A);
         engine.fpx.fp2add(A,A,A);
@@ -1233,10 +1235,10 @@ internal class SIDH_Compressed
     {
         uint[] rs = new uint[3];
         int[] D = new int[engine.param.DLEN_3];
-        ulong[][] a24 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] a24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         
-        ulong[][][][] As = Utils.InitArray(engine.param.MAX_Alice + 1, 5, 2, engine.param.NWORDS_FIELD);
-        ulong[][][] f = Utils.InitArray(4, 2, engine.param.NWORDS_FIELD);
+        ulong[][][][] As = SikeUtilities.InitArray(engine.param.MAX_Alice + 1, 5, 2, engine.param.NWORDS_FIELD);
+        ulong[][][] f = SikeUtilities.InitArray(4, 2, engine.param.NWORDS_FIELD);
         ulong[] c0 = new ulong[engine.param.NWORDS_ORDER],
                d0 = new ulong[engine.param.NWORDS_ORDER],
                c1 = new ulong[engine.param.NWORDS_ORDER],
@@ -1309,9 +1311,9 @@ internal class SIDH_Compressed
                d0 = new ulong[engine.param.NWORDS_ORDER],
                c1 = new ulong[engine.param.NWORDS_ORDER],
                d1 = new ulong[engine.param.NWORDS_ORDER];
-        ulong[][] a24 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
-        ulong[][][] f = Utils.InitArray(4, 2, engine.param.NWORDS_FIELD);
-        ulong[][][][] As = Utils.InitArray(engine.param.MAX_Alice + 1, 5, 2, engine.param.NWORDS_FIELD);
+        ulong[][] a24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][][] f = SikeUtilities.InitArray(4, 2, engine.param.NWORDS_FIELD);
+        ulong[][][][] As = SikeUtilities.InitArray(engine.param.MAX_Alice + 1, 5, 2, engine.param.NWORDS_FIELD);
         PointProjFull[] Rs = new PointProjFull[2];
 
         FullIsogeny_A_dual(PrivateKeyA, As, a24, 0);
@@ -1331,14 +1333,14 @@ internal class SIDH_Compressed
     {
         uint i, ii = 0, row, m, index = 0, npts = 0;
         uint[] pts_index = new uint[engine.param.MAX_INT_POINTS_BOB];
-        ulong[][] A24plus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24minus = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] A24plus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24minus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         PointProj R = new PointProj(engine.param.NWORDS_FIELD);
         PointProj[] pts = new PointProj[engine.param.MAX_INT_POINTS_BOB];
-        ulong[][] jinv = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A = Utils.InitArray(2, engine.param.NWORDS_FIELD);
-        ulong[][][] coeff = Utils.InitArray(3, 2, engine.param.NWORDS_FIELD);
-        ulong[][] param_A = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] jinv = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][][] coeff = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD);
+        ulong[][] param_A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         PKADecompression_dual(PrivateKeyB, PKA, R, param_A);
         engine.fpx.fp2copy(param_A, A);
@@ -1392,8 +1394,8 @@ internal class SIDH_Compressed
     {
         ulong[] s = new ulong[engine.param.NWORDS_FIELD];
         ulong[][] t_ptr,
-            r = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+            r = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         uint t_ptrOffset = 0;
 
         // Select the correct table
@@ -1457,11 +1459,11 @@ internal class SIDH_Compressed
 
     protected void RecoverY(ulong[][] A, PointProj[] xs, PointProjFull[] Rs)
     {
-        ulong[][] t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t3 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t4 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         engine.fpx.fp2mul_mont(xs[2].X, xs[1].Z, t0);
         engine.fpx.fp2mul_mont(xs[1].X, xs[2].Z, t1);
@@ -1500,7 +1502,7 @@ internal class SIDH_Compressed
     {
         uint i;
         ulong[] t0 = new ulong[engine.param.NWORDS_FIELD];
-        ulong[][] A6 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] A6 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         PointProj[] xs = new PointProj[3];
         xs[0] = new PointProj(engine.param.NWORDS_FIELD);
         xs[1] = new PointProj(engine.param.NWORDS_FIELD);
@@ -1566,12 +1568,12 @@ internal class SIDH_Compressed
         PointProj R = new PointProj(engine.param.NWORDS_FIELD),
         Q3 = new PointProj(engine.param.NWORDS_FIELD);
         PointProj[] pts = new PointProj[engine.param.MAX_INT_POINTS_BOB];
-        ulong[][] XPB = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            XQB = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            XRB = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24plus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24minus = Utils.InitArray(2, engine.param.NWORDS_FIELD);
-        ulong[][][] coeff = Utils.InitArray(3, 2, engine.param.NWORDS_FIELD);
+        ulong[][] XPB = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            XQB = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            XRB = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24plus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24minus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][][] coeff = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD);
         uint i, row, m, index = 0, npts = 0, ii = 0;
         uint[] pts_index = new uint[engine.param.MAX_INT_POINTS_BOB];
         ulong[] SecretKeyB = new ulong[engine.param.NWORDS_ORDER];
@@ -1663,8 +1665,8 @@ internal class SIDH_Compressed
     protected void BuildEntangledXonly_Decomp(ulong[][] A, PointProj[] R, uint qnr, uint ind)
     {
         ulong[][] t_ptr,
-            r = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+            r = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         // Select the correct table
         if ( qnr == 1 )
@@ -1716,8 +1718,8 @@ internal class SIDH_Compressed
     { 
         ulong mask = unchecked((ulong) -1L);
         uint qnr, ind;
-        ulong[][] A24 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            Adiv2 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] A24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            Adiv2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         
         ulong[] tmp1 = new ulong[2*engine.param.NWORDS_ORDER],
                 tmp2 = new ulong[2*engine.param.NWORDS_ORDER],
@@ -1879,7 +1881,7 @@ internal class SIDH_Compressed
         ulong mask = unchecked((ulong) -1L);
         uint bit,qnr,ind;
 
-        ulong[][] A24 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] A24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         ulong[] tmp1 = new ulong[2*engine.param.NWORDS_ORDER],
                tmp2 = new ulong[2*engine.param.NWORDS_ORDER],
                vone = new ulong[2*engine.param.NWORDS_ORDER],
@@ -1996,9 +1998,9 @@ internal class SIDH_Compressed
                d0 = new ulong[engine.param.NWORDS_ORDER],
                c1 = new ulong[engine.param.NWORDS_ORDER],
                d1 = new ulong[engine.param.NWORDS_ORDER];
-        ulong[][][][] Ds = Utils.InitArray(engine.param.MAX_Bob, 2, 2, engine.param.NWORDS_FIELD);
-        ulong[][][] f = Utils.InitArray(4, 2, engine.param.NWORDS_FIELD);
-        ulong[][] A = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][][][] Ds = SikeUtilities.InitArray(engine.param.MAX_Bob, 2, 2, engine.param.NWORDS_FIELD);
+        ulong[][][] f = SikeUtilities.InitArray(4, 2, engine.param.NWORDS_FIELD);
+        ulong[][] A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         PointProjFull[] Rs = new PointProjFull[2];
         Rs[0] = new PointProjFull(engine.param.NWORDS_FIELD);
@@ -2122,15 +2124,15 @@ internal class SIDH_Compressed
     {
         uint i, ii = 0, row, m, index = 0, npts = 0;
         uint[] pts_index = new uint[engine.param.MAX_INT_POINTS_ALICE];
-        ulong[][] A24plus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            C24 = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] A24plus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            C24 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         
         PointProj R = new PointProj(engine.param.NWORDS_FIELD);
         PointProj[] pts = new PointProj[engine.param.MAX_INT_POINTS_ALICE];
-        ulong[][] jinv = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            param_A = Utils.InitArray(2, engine.param.NWORDS_FIELD);
-        ulong[][][] coeff = Utils.InitArray(5, 2, engine.param.NWORDS_FIELD);
+        ulong[][] jinv = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            param_A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][][] coeff = SikeUtilities.InitArray(5, 2, engine.param.NWORDS_FIELD);
 
 
         if (sike == 1)
@@ -2216,16 +2218,16 @@ internal class SIDH_Compressed
         PointProj R = new PointProj(engine.param.NWORDS_FIELD),
                   S = new PointProj(engine.param.NWORDS_FIELD);
 
-        ulong[][] XPB = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            XQB = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            XRB = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24plus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A24minus = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            A = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            comp1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            comp2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            one = Utils.InitArray(2, engine.param.NWORDS_FIELD);
-        ulong[][][] coeff = Utils.InitArray(3, 2, engine.param.NWORDS_FIELD);;
+        ulong[][] XPB = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            XQB = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            XRB = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24plus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A24minus = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            A = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            comp1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            comp2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            one = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][][] coeff = SikeUtilities.InitArray(3, 2, engine.param.NWORDS_FIELD);;
 
         uint i, row, m, index = 0, npts = 0, ii = 0;
         uint[] pts_index = new uint[engine.param.MAX_INT_POINTS_BOB];
@@ -2455,8 +2457,8 @@ internal class SIDH_Compressed
     void Traverse_w_notdiv_e_fullsigned(ulong[][] r, uint j, uint k, uint z, uint[] P, ulong[] CT1, ulong[] CT2,
                                         int[] D, uint Dlen, uint ell, uint ellw, uint ell_emodw, uint w, uint e)
     {
-        ulong[][] rp = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            alpha = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] rp = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            alpha = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
 
         if (z > 1)
@@ -2633,8 +2635,8 @@ internal class SIDH_Compressed
     // Assume the integer w divides the exponent e
     void Traverse_w_div_e_fullsigned(ulong[][] r, uint j, uint k, uint z, uint[] P, ulong[] CT, int[] D, uint Dlen, uint ellw, uint w)
     {
-        ulong[][] rp = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            alpha = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] rp = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            alpha = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         if (z > 1)
         {
@@ -2729,18 +2731,18 @@ internal class SIDH_Compressed
                 x23 = new ulong[engine.param.NWORDS_FIELD],
                 x2p3 = new ulong[engine.param.NWORDS_FIELD];
 
-        ulong[][][] xQ2s = Utils.InitArray(t_points, 2, engine.param.NWORDS_FIELD),
-            finv = Utils.InitArray(2*t_points, 2, engine.param.NWORDS_FIELD);
-        ulong[][] one = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t2 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t3 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t4 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t5 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            g = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            h = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            tf = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][][] xQ2s = SikeUtilities.InitArray(t_points, 2, engine.param.NWORDS_FIELD),
+            finv = SikeUtilities.InitArray(2*t_points, 2, engine.param.NWORDS_FIELD);
+        ulong[][] one = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t2 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t3 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t4 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t5 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            g = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            h = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            tf = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
 
         engine.fpx.fpcopy(engine.param.Montgomery_one, 0, one[0]);
@@ -2919,7 +2921,7 @@ internal class SIDH_Compressed
     private void final_exponentiation_3_torsion(ulong[][] f, ulong[][] finv, ulong[][] fout)
     {
         ulong[] one = new ulong[engine.param.NWORDS_FIELD];
-        ulong[][] temp = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] temp = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         uint i;
 
         engine.fpx.fpcopy(engine.param.Montgomery_one, 0, one);
@@ -2938,16 +2940,16 @@ internal class SIDH_Compressed
     private void Tate2_pairings(PointProj P, PointProj Q, PointProjFull[] Qj, ulong[][][] f)
     {
         ulong[] x, y, x_, y_, l1;
-        ulong[][][] finv = Utils.InitArray(2 * t_points, 2, engine.param.NWORDS_FIELD);
+        ulong[][][] finv = SikeUtilities.InitArray(2 * t_points, 2, engine.param.NWORDS_FIELD);
 
         ulong[][] x_first,
             y_first,
-            one = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            l1_first = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t0 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            t1 = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            g = Utils.InitArray(2, engine.param.NWORDS_FIELD),
-            h = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+            one = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            l1_first = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t0 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            t1 = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            g = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD),
+            h = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
 
         uint x_Offset, y_Offset, l1Offset, xOffset, yOffset;
 
@@ -3141,7 +3143,7 @@ internal class SIDH_Compressed
     private void final_exponentiation_2_torsion(ulong[][] f, ulong[][] finv, ulong[][] fout)
     {
         ulong[] one = new ulong[engine.param.NWORDS_FIELD];
-        ulong[][] temp = Utils.InitArray(2, engine.param.NWORDS_FIELD);
+        ulong[][] temp = SikeUtilities.InitArray(2, engine.param.NWORDS_FIELD);
         uint i;
 
         engine.fpx.fpcopy(engine.param.Montgomery_one, 0, one);
diff --git a/crypto/src/pqc/crypto/sike/SIKEEngine.cs b/crypto/src/pqc/crypto/sike/SIKEEngine.cs
index e7b218589..6a825fe44 100644
--- a/crypto/src/pqc/crypto/sike/SIKEEngine.cs
+++ b/crypto/src/pqc/crypto/sike/SIKEEngine.cs
@@ -4,16 +4,15 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-    
-internal class SIKEEngine
+internal sealed class SikeEngine
 {
-    private SecureRandom random;
-    
+    //private readonly SecureRandom random;
+
     protected internal Internal param;
     protected internal Isogeny isogeny;
     protected internal Fpx fpx;
-    private SIDH sidh;
-    private SIDH_Compressed sidhCompressed;
+    private Sidh sidh;
+    private SidhCompressed sidhCompressed;
     private bool isCompressed;
 
     public uint GetDefaultSessionKeySize()
@@ -35,9 +34,9 @@ internal class SIKEEngine
     {
         return param.CRYPTO_PUBLICKEYBYTES;
     }
-    public SIKEEngine(int ver, bool isCompressed, SecureRandom random)
+    public SikeEngine(int ver, bool isCompressed, SecureRandom random)
     {
-        this.random = random;
+        //this.random = random;
         this.isCompressed = isCompressed;
         //todo switch for different parameters
         switch(ver)
@@ -62,9 +61,9 @@ internal class SIKEEngine
         isogeny = new Isogeny(this);
         if(isCompressed)
         {
-            sidhCompressed = new SIDH_Compressed(this);
+            sidhCompressed = new SidhCompressed(this);
         }
-        sidh = new SIDH(this);
+        sidh = new Sidh(this);
     }
 
     // SIKE's key generation
diff --git a/crypto/src/pqc/crypto/sike/SIKEKEMExtractor.cs b/crypto/src/pqc/crypto/sike/SIKEKEMExtractor.cs
index 144b4649f..3c523ba8c 100644
--- a/crypto/src/pqc/crypto/sike/SIKEKEMExtractor.cs
+++ b/crypto/src/pqc/crypto/sike/SIKEKEMExtractor.cs
@@ -1,43 +1,42 @@
-using Org.BouncyCastle.Crypto;
 using System;
 
+using Org.BouncyCastle.Crypto;
+
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-    public class SIKEKEMExtractor
+    public sealed class SikeKemExtractor
         : IEncapsulatedSecretExtractor
     {
-    private SIKEEngine engine;
-
-    private SIKEKeyParameters key;
-
-    public SIKEKEMExtractor(SIKEPrivateKeyParameters privParams)
-    {
-        this.key = privParams;
-        InitCipher(key.GetParameters());
-    }
-
-    private void InitCipher(SIKEParameters param)
-    {
-        engine = param.GetEngine();
-        SIKEPrivateKeyParameters privateParams = (SIKEPrivateKeyParameters)key;
-        //todo: add compression check
-    }
-
-    public byte[] ExtractSecret(byte[] encapsulation)
-    {
-        return ExtractSecret(encapsulation, engine.GetDefaultSessionKeySize());
-    }
-
-    public byte[] ExtractSecret(byte[] encapsulation, uint sessionKeySizeInBits)
-    {
+        private readonly SikeKeyParameters key;
+
+        private SikeEngine engine;
+
+        public SikeKemExtractor(SikePrivateKeyParameters privParams)
+        {
+            this.key = privParams;
+            InitCipher(key.Parameters);
+        }
+
+        private void InitCipher(SikeParameters param)
+        {
+            engine = param.Engine;
+            SikePrivateKeyParameters privateParams = (SikePrivateKeyParameters)key;
+            //todo: add compression check
+        }
+
+        public byte[] ExtractSecret(byte[] encapsulation)
+        {
+            return ExtractSecret(encapsulation, engine.GetDefaultSessionKeySize());
+        }
+
+        public byte[] ExtractSecret(byte[] encapsulation, uint sessionKeySizeInBits)
+        {
             Console.Error.WriteLine("WARNING: the SIKE algorithm is only for research purposes, insecure");
-        byte[] session_key = new byte[sessionKeySizeInBits / 8];
-        engine.crypto_kem_dec(session_key, encapsulation, ((SIKEPrivateKeyParameters)key).GetPrivateKey());
-        return session_key;
-    }
+            byte[] session_key = new byte[sessionKeySizeInBits / 8];
+            engine.crypto_kem_dec(session_key, encapsulation, ((SikePrivateKeyParameters)key).GetPrivateKey());
+            return session_key;
+        }
 
         public int EncapsulationLength => (int)engine.GetCipherTextSize();
-
     }
-
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/sike/SIKEKEMGenerator.cs b/crypto/src/pqc/crypto/sike/SIKEKEMGenerator.cs
index cf98a0696..76689496f 100644
--- a/crypto/src/pqc/crypto/sike/SIKEKEMGenerator.cs
+++ b/crypto/src/pqc/crypto/sike/SIKEKEMGenerator.cs
@@ -1,40 +1,39 @@
+using System;
+
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Pqc.Crypto.Utilities;
 using Org.BouncyCastle.Security;
-using System;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-public class SIKEKEMGenerator
-    : IEncapsulatedSecretGenerator
-{
-    // the source of randomness
-    private SecureRandom sr;
-
-
-    public SIKEKEMGenerator(SecureRandom random)
+    public sealed class SikeKemGenerator
+        : IEncapsulatedSecretGenerator
     {
-        this.sr = random;
-    }
+        // the source of randomness
+        private readonly SecureRandom sr;
 
-    public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey)
-    {
-        SIKEPublicKeyParameters key = (SIKEPublicKeyParameters)recipientKey;
-        SIKEEngine engine = key.GetParameters().GetEngine();
+        public SikeKemGenerator(SecureRandom random)
+        {
+            this.sr = CryptoServicesRegistrar.GetSecureRandom(random);
+        }
 
-        return GenerateEncapsulated(recipientKey, engine.GetDefaultSessionKeySize());
-    }
+        public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey)
+        {
+            SikePublicKeyParameters key = (SikePublicKeyParameters)recipientKey;
+            SikeEngine engine = key.Parameters.Engine;
 
-    public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey, uint sessionKeySizeInBits)
-    {
+            return GenerateEncapsulated(recipientKey, engine.GetDefaultSessionKeySize());
+        }
+
+        public ISecretWithEncapsulation GenerateEncapsulated(AsymmetricKeyParameter recipientKey, uint sessionKeySizeInBits)
+        {
             Console.Error.WriteLine("WARNING: the SIKE algorithm is only for research purposes, insecure");
-        SIKEPublicKeyParameters key = (SIKEPublicKeyParameters)recipientKey;
-        SIKEEngine engine = key.GetParameters().GetEngine();
-        byte[] cipher_text = new byte[engine.GetCipherTextSize()];
-        byte[] sessionKey = new byte[sessionKeySizeInBits / 8];
-        engine.crypto_kem_enc(cipher_text, sessionKey, key.GetPublicKey(), sr);
-        return new SecretWithEncapsulationImpl(sessionKey, cipher_text);
+            SikePublicKeyParameters key = (SikePublicKeyParameters)recipientKey;
+            SikeEngine engine = key.Parameters.Engine;
+            byte[] cipher_text = new byte[engine.GetCipherTextSize()];
+            byte[] sessionKey = new byte[sessionKeySizeInBits / 8];
+            engine.crypto_kem_enc(cipher_text, sessionKey, key.GetPublicKey(), sr);
+            return new SecretWithEncapsulationImpl(sessionKey, cipher_text);
+        }
     }
 }
-
-}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/sike/SIKEKeyGenerationParameters.cs b/crypto/src/pqc/crypto/sike/SIKEKeyGenerationParameters.cs
index 669a417b2..353587637 100644
--- a/crypto/src/pqc/crypto/sike/SIKEKeyGenerationParameters.cs
+++ b/crypto/src/pqc/crypto/sike/SIKEKeyGenerationParameters.cs
@@ -3,23 +3,17 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-public class SIKEKeyGenerationParameters
-    : KeyGenerationParameters
-{
-    private SIKEParameters param;
-
-    public SIKEKeyGenerationParameters(
-            SecureRandom random,
-            SIKEParameters sikeParameters
-    )
-    	: base(random, 256)
-    {
-        this.param = sikeParameters;
-    }
-    public SIKEParameters GetParameters()
+    public sealed class SikeKeyGenerationParameters
+        : KeyGenerationParameters
     {
-        return param;
+        private readonly SikeParameters m_parameters;
+
+        public SikeKeyGenerationParameters(SecureRandom random, SikeParameters sikeParameters)
+            : base(random, 256)
+        {
+            m_parameters = sikeParameters;
+        }
+
+        public SikeParameters Parameters => m_parameters;
     }
 }
-
-}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/sike/SIKEKeyPairGenerator.cs b/crypto/src/pqc/crypto/sike/SIKEKeyPairGenerator.cs
index 3945fe8c8..3ba67faa9 100644
--- a/crypto/src/pqc/crypto/sike/SIKEKeyPairGenerator.cs
+++ b/crypto/src/pqc/crypto/sike/SIKEKeyPairGenerator.cs
@@ -3,30 +3,29 @@ using Org.BouncyCastle.Security;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-    public class SIKEKeyPairGenerator
+    public sealed class SikeKeyPairGenerator
         : IAsymmetricCipherKeyPairGenerator
     {
-        private SIKEKeyGenerationParameters sikeParams;
+        private SikeKeyGenerationParameters sikeParams;
 
         private SecureRandom random;
 
         private void Initialize(KeyGenerationParameters param)
         {
-            this.sikeParams = (SIKEKeyGenerationParameters) param;
+            this.sikeParams = (SikeKeyGenerationParameters) param;
             this.random = param.Random;
         }
 
         private AsymmetricCipherKeyPair GenKeyPair()
         {
-            SIKEEngine engine = sikeParams.GetParameters().GetEngine();
+            SikeEngine engine = sikeParams.Parameters.Engine;
             byte[] sk = new byte[engine.GetPrivateKeySize()];
             byte[] pk = new byte[engine.GetPublicKeySize()];
 
             engine.crypto_kem_keypair(pk, sk, random);
 
-
-            SIKEPublicKeyParameters pubKey = new SIKEPublicKeyParameters(sikeParams.GetParameters(), pk);
-            SIKEPrivateKeyParameters privKey = new SIKEPrivateKeyParameters(sikeParams.GetParameters(), sk);
+            SikePublicKeyParameters pubKey = new SikePublicKeyParameters(sikeParams.Parameters, pk);
+            SikePrivateKeyParameters privKey = new SikePrivateKeyParameters(sikeParams.Parameters, sk);
             return new AsymmetricCipherKeyPair(pubKey, privKey);
         }
 
@@ -40,5 +39,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
             return GenKeyPair();
         }
     }
-
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/sike/SIKEKeyParameters.cs b/crypto/src/pqc/crypto/sike/SIKEKeyParameters.cs
index 29ef6114d..5d515eb1d 100644
--- a/crypto/src/pqc/crypto/sike/SIKEKeyParameters.cs
+++ b/crypto/src/pqc/crypto/sike/SIKEKeyParameters.cs
@@ -2,24 +2,17 @@ using Org.BouncyCastle.Crypto;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-public class SIKEKeyParameters
-    : AsymmetricKeyParameter
-{
-    private SIKEParameters param;
-
-    public SIKEKeyParameters(
-            bool isPrivate,
-            SIKEParameters param
-    )
-    	:base(isPrivate)
+    public abstract class SikeKeyParameters
+        : AsymmetricKeyParameter
     {
-        this.param = param;
-    }
+        private readonly SikeParameters m_parameters;
 
-    public SIKEParameters GetParameters()
-    {
-        return param;
+        public SikeKeyParameters(bool isPrivate, SikeParameters param)
+            : base(isPrivate)
+        {
+            this.m_parameters = param;
+        }
+
+        public SikeParameters Parameters => m_parameters;
     }
 }
-
-}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/sike/SIKEParameters.cs b/crypto/src/pqc/crypto/sike/SIKEParameters.cs
index d687871ec..3aa332341 100644
--- a/crypto/src/pqc/crypto/sike/SIKEParameters.cs
+++ b/crypto/src/pqc/crypto/sike/SIKEParameters.cs
@@ -1,33 +1,30 @@
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-public class SIKEParameters
-{
+    public sealed class SikeParameters
+    {
+        public static readonly SikeParameters sikep434 = new SikeParameters(434, false, "sikep434");
+        public static readonly SikeParameters sikep503 = new SikeParameters(503, false, "sikep503");
+        public static readonly SikeParameters sikep610 = new SikeParameters(610, false, "sikep610");
+        public static readonly SikeParameters sikep751 = new SikeParameters(751, false, "sikep751");
 
-    public static SIKEParameters sikep434 = new SIKEParameters(434, false,"sikep434");
-    public static SIKEParameters sikep503 = new SIKEParameters(503, false,"sikep503");
-    public static SIKEParameters sikep610 = new SIKEParameters(610, false,"sikep610");
-    public static SIKEParameters sikep751 = new SIKEParameters(751, false,"sikep751");
+        public static readonly SikeParameters sikep434_compressed = new SikeParameters(434, true, "sikep434_compressed");
+        public static readonly SikeParameters sikep503_compressed = new SikeParameters(503, true, "sikep503_compressed");
+        public static readonly SikeParameters sikep610_compressed = new SikeParameters(610, true, "sikep610_compressed");
+        public static readonly SikeParameters sikep751_compressed = new SikeParameters(751, true, "sikep751_compressed");
 
-    public static SIKEParameters sikep434_compressed = new SIKEParameters(434, true,"sikep434_compressed");
-    public static SIKEParameters sikep503_compressed = new SIKEParameters(503, true,"sikep503_compressed");
-    public static SIKEParameters sikep610_compressed = new SIKEParameters(610, true,"sikep610_compressed");
-    public static SIKEParameters sikep751_compressed = new SIKEParameters(751, true,"sikep751_compressed");
+        private readonly string name;
+        private readonly SikeEngine engine;
 
-    private string name;
-    private SIKEEngine engine;
-    public SIKEParameters(int ver, bool isCompressed, string name)
-    {
-        this.name = name;
-        this.engine = new SIKEEngine(ver, isCompressed, null);
-    }
+        public SikeParameters(int ver, bool isCompressed, string name)
+        {
+            this.name = name;
+            this.engine = new SikeEngine(ver, isCompressed, null);
+        }
 
-    internal SIKEEngine GetEngine()
-    {
-        return engine;
-    }
+        internal SikeEngine Engine => engine;
 
         public string Name => name;
+
         public int DefaultKeySize => (int)this.engine.GetDefaultSessionKeySize();
     }
-
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/sike/SIKEPrivateKeyParameters.cs b/crypto/src/pqc/crypto/sike/SIKEPrivateKeyParameters.cs
index e3e791e71..0666ffb72 100644
--- a/crypto/src/pqc/crypto/sike/SIKEPrivateKeyParameters.cs
+++ b/crypto/src/pqc/crypto/sike/SIKEPrivateKeyParameters.cs
@@ -2,26 +2,25 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-public class SIKEPrivateKeyParameters
-    : SIKEKeyParameters
-{
-    private byte[] privateKey;
-
-    public byte[] GetPrivateKey()
+    public sealed class SikePrivateKeyParameters
+        : SikeKeyParameters
     {
-        return Arrays.Clone(privateKey);
-    }
+        private readonly byte[] privateKey;
 
-    public SIKEPrivateKeyParameters(SIKEParameters param, byte[] privateKey)
-    	:base(true, param)
-    {
-        this.privateKey = Arrays.Clone(privateKey);
-    }
+        public SikePrivateKeyParameters(SikeParameters param, byte[] privateKey)
+            : base(true, param)
+        {
+            this.privateKey = Arrays.Clone(privateKey);
+        }
 
-    public byte[] GetEncoded()
-    {
-        return Arrays.Clone(privateKey);
+        public byte[] GetEncoded()
+        {
+            return Arrays.Clone(privateKey);
+        }
+
+        public byte[] GetPrivateKey()
+        {
+            return Arrays.Clone(privateKey);
+        }
     }
 }
-
-}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/sike/SIKEPublicKeyParameters.cs b/crypto/src/pqc/crypto/sike/SIKEPublicKeyParameters.cs
index a777d7896..b567e979c 100644
--- a/crypto/src/pqc/crypto/sike/SIKEPublicKeyParameters.cs
+++ b/crypto/src/pqc/crypto/sike/SIKEPublicKeyParameters.cs
@@ -2,26 +2,25 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-public class SIKEPublicKeyParameters
-    : SIKEKeyParameters
-{
-    public byte[] publicKey;
-
-    public byte[] GetPublicKey()
+    public sealed class SikePublicKeyParameters
+        : SikeKeyParameters
     {
-        return Arrays.Clone(publicKey);
-    }
+        public readonly byte[] publicKey;
 
-    public byte[] GetEncoded()
-    {
-        return GetPublicKey();
-    }
+        public SikePublicKeyParameters(SikeParameters param, byte[] publicKey)
+            : base(false, param)
+        {
+            this.publicKey = Arrays.Clone(publicKey);
+        }
 
-    public SIKEPublicKeyParameters(SIKEParameters param, byte[] publicKey)
-    	: base(false, param)
-    {
-        this.publicKey = Arrays.Clone(publicKey);
+        public byte[] GetEncoded()
+        {
+            return Arrays.Clone(publicKey);
+        }
+
+        public byte[] GetPublicKey()
+        {
+            return Arrays.Clone(publicKey);
+        }
     }
 }
-
-}
\ No newline at end of file
diff --git a/crypto/src/pqc/crypto/sike/Utils.cs b/crypto/src/pqc/crypto/sike/SikeUtilities.cs
index 013e39316..ca5ee67a0 100644
--- a/crypto/src/pqc/crypto/sike/Utils.cs
+++ b/crypto/src/pqc/crypto/sike/SikeUtilities.cs
@@ -1,8 +1,8 @@
 namespace Org.BouncyCastle.Pqc.Crypto.Sike
 {
-    internal class Utils
+    internal static class SikeUtilities
     {
-        public static ulong[][] InitArray(uint size1, uint size2)
+        internal static ulong[][] InitArray(uint size1, uint size2)
         {
             ulong[][] res = new ulong[size1][];
             for (int i = 0; i < size1; i++)
@@ -12,8 +12,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
 
             return res;
         }
-        
-        public static ulong[][][] InitArray(uint size1, uint size2, uint size3)
+
+        internal static ulong[][][] InitArray(uint size1, uint size2, uint size3)
         {
             ulong[][][] res = new ulong[size1][][];
             for (int i = 0; i < size1; i++)
@@ -27,8 +27,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
 
             return res;
         }
-        
-        public static ulong[][][][] InitArray(uint size1, uint size2, uint size3, uint size4)
+
+        internal static ulong[][][][] InitArray(uint size1, uint size2, uint size3, uint size4)
         {
             ulong[][][][] res = new ulong[size1][][][];
             for (int i = 0; i < size1; i++)
@@ -47,4 +47,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Sike
             return res;
         }
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/sphincsplus/HarakaSBase.cs b/crypto/src/pqc/crypto/sphincsplus/HarakaSBase.cs
index 5efafc1db..2134c5c73 100644
--- a/crypto/src/pqc/crypto/sphincsplus/HarakaSBase.cs
+++ b/crypto/src/pqc/crypto/sphincsplus/HarakaSBase.cs
@@ -3,6 +3,7 @@
 using Org.BouncyCastle.Crypto.Utilities;
 using Org.BouncyCastle.Math.Raw;
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
 
 namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus
 {
@@ -14,6 +15,61 @@ namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus
      */
     internal abstract class HarakaSBase
     {
+        private static readonly byte[] RC0  = Hex.DecodeStrict("0684704ce620c00ab2c5fef075817b9d");
+        private static readonly byte[] RC1  = Hex.DecodeStrict("8b66b4e188f3a06b640f6ba42f08f717");
+        private static readonly byte[] RC2  = Hex.DecodeStrict("3402de2d53f28498cf029d609f029114");
+        private static readonly byte[] RC3  = Hex.DecodeStrict("0ed6eae62e7b4f08bbf3bcaffd5b4f79");
+        private static readonly byte[] RC4  = Hex.DecodeStrict("cbcfb0cb4872448b79eecd1cbe397044");
+        private static readonly byte[] RC5  = Hex.DecodeStrict("7eeacdee6e9032b78d5335ed2b8a057b");
+        private static readonly byte[] RC6  = Hex.DecodeStrict("67c28f435e2e7cd0e2412761da4fef1b");
+        private static readonly byte[] RC7  = Hex.DecodeStrict("2924d9b0afcacc07675ffde21fc70b3b");
+        private static readonly byte[] RC8  = Hex.DecodeStrict("ab4d63f1e6867fe9ecdb8fcab9d465ee");
+        private static readonly byte[] RC9  = Hex.DecodeStrict("1c30bf84d4b7cd645b2a404fad037e33");
+        private static readonly byte[] RC10 = Hex.DecodeStrict("b2cc0bb9941723bf69028b2e8df69800");
+        private static readonly byte[] RC11 = Hex.DecodeStrict("fa0478a6de6f55724aaa9ec85c9d2d8a");
+        private static readonly byte[] RC12 = Hex.DecodeStrict("dfb49f2b6b772a120efa4f2e29129fd4");
+        private static readonly byte[] RC13 = Hex.DecodeStrict("1ea10344f449a23632d611aebb6a12ee");
+        private static readonly byte[] RC14 = Hex.DecodeStrict("af0449884b0500845f9600c99ca8eca6");
+        private static readonly byte[] RC15 = Hex.DecodeStrict("21025ed89d199c4f78a2c7e327e593ec");
+        private static readonly byte[] RC16 = Hex.DecodeStrict("bf3aaaf8a759c9b7b9282ecd82d40173");
+        private static readonly byte[] RC17 = Hex.DecodeStrict("6260700d6186b01737f2efd910307d6b");
+        private static readonly byte[] RC18 = Hex.DecodeStrict("5aca45c22130044381c29153f6fc9ac6");
+        private static readonly byte[] RC19 = Hex.DecodeStrict("9223973c226b68bb2caf92e836d1943a");
+        private static readonly byte[] RC20 = Hex.DecodeStrict("d3bf9238225886eb6cbab958e51071b4");
+        private static readonly byte[] RC21 = Hex.DecodeStrict("db863ce5aef0c677933dfddd24e1128d");
+        private static readonly byte[] RC22 = Hex.DecodeStrict("bb606268ffeba09c83e48de3cb2212b1");
+        private static readonly byte[] RC23 = Hex.DecodeStrict("734bd3dce2e4d19c2db91a4ec72bf77d");
+        private static readonly byte[] RC24 = Hex.DecodeStrict("43bb47c361301b434b1415c42cb3924e");
+        private static readonly byte[] RC25 = Hex.DecodeStrict("dba775a8e707eff603b231dd16eb6899");
+        private static readonly byte[] RC26 = Hex.DecodeStrict("6df3614b3c7559778e5e23027eca472c");
+        private static readonly byte[] RC27 = Hex.DecodeStrict("cda75a17d6de7d776d1be5b9b88617f9");
+        private static readonly byte[] RC28 = Hex.DecodeStrict("ec6b43f06ba8e9aa9d6c069da946ee5d");
+        private static readonly byte[] RC29 = Hex.DecodeStrict("cb1e6950f957332ba25311593bf327c1");
+        private static readonly byte[] RC30 = Hex.DecodeStrict("2cee0c7500da619ce4ed0353600ed0d9");
+        private static readonly byte[] RC31 = Hex.DecodeStrict("f0b1a5a196e90cab80bbbabc63a4a350");
+        private static readonly byte[] RC32 = Hex.DecodeStrict("ae3db1025e962988ab0dde30938dca39");
+        private static readonly byte[] RC33 = Hex.DecodeStrict("17bb8f38d554a40b8814f3a82e75b442");
+        private static readonly byte[] RC34 = Hex.DecodeStrict("34bb8a5b5f427fd7aeb6b779360a16f6");
+        private static readonly byte[] RC35 = Hex.DecodeStrict("26f65241cbe5543843ce5918ffbaafde");
+        private static readonly byte[] RC36 = Hex.DecodeStrict("4ce99a54b9f3026aa2ca9cf7839ec978");
+        private static readonly byte[] RC37 = Hex.DecodeStrict("ae51a51a1bdff7be40c06e2822901235");
+        private static readonly byte[] RC38 = Hex.DecodeStrict("a0c1613cba7ed22bc173bc0f48a659cf");
+        private static readonly byte[] RC39 = Hex.DecodeStrict("756acc03022882884ad6bdfde9c59da1");
+
+        private static readonly byte[][] RoundConstants =
+        {
+            RC0 , RC1 , RC2 , RC3 ,
+            RC4 , RC5 , RC6 , RC7 ,
+            RC8 , RC9 , RC10, RC11,
+            RC12, RC13, RC14, RC15,
+            RC16, RC17, RC18, RC19,
+            RC20, RC21, RC22, RC23,
+            RC24, RC25, RC26, RC27,
+            RC28, RC29, RC30, RC31,
+            RC32, RC33, RC34, RC35,
+            RC36, RC37, RC38, RC39,
+        };
+
         internal ulong[][] haraka512_rc = new ulong[][]{
             new ulong[]{0x24cf0ab9086f628bL, 0xbdd6eeecc83b8382L, 0xd96fb0306cdad0a7L, 0xaace082ac8f95f89L, 0x449d8e8870d7041fL, 0x49bb2f80b2b3e2f8L, 0x0569ae98d93bb258L, 0x23dc9691e7d6a4b1L},
             new ulong[]{0xd8ba10ede0fe5b6eL, 0x7ecf7dbe424c7b8eL, 0x6ea9949c6df62a31L, 0xbf3f3c97ec9c313eL, 0x241d03a196a1861eL, 0xead3a51116e5a2eaL, 0x77d479fcad9574e3L, 0x18657a1af894b7a0L},
@@ -36,6 +92,23 @@ namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus
         {
             this.buffer = new byte[64];
             off = 0;
+
+            byte[] buf = new byte[640];
+            byte[] tmp = new byte[16];
+            for (int rc = 0; rc < 40; ++rc)
+            {
+                Arrays.Reverse(RoundConstants[rc]).CopyTo(buf, rc << 4);
+            }
+            for (int round = 0; round < 10; ++round)
+            {
+                InterleaveConstant(haraka512_rc[round], buf, round << 6);
+                //for (int j = 0; j < 8; ++j)
+                //{
+                //    Console.Write(haraka512_rc[round][j].ToString("X") + ", ");
+                //}
+                //Console.WriteLine();
+            }
+            //Console.WriteLine("-----");
         }
 
         protected void Reset()
diff --git a/crypto/src/pqc/crypto/sphincsplus/HarakaS_X86.cs b/crypto/src/pqc/crypto/sphincsplus/HarakaS_X86.cs
index 3975f02ff..87681c484 100644
--- a/crypto/src/pqc/crypto/sphincsplus/HarakaS_X86.cs
+++ b/crypto/src/pqc/crypto/sphincsplus/HarakaS_X86.cs
@@ -1,7 +1,9 @@
 #if NETCOREAPP3_0_OR_GREATER
 using System;
+using System.Buffers.Binary;
 using System.Diagnostics;
 using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
 using System.Runtime.Intrinsics;
 
 using Org.BouncyCastle.Crypto;
@@ -185,15 +187,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.SphincsPlus
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
         private static Vector128<byte> Load128(ReadOnlySpan<byte> t)
         {
-#if NET7_0_OR_GREATER
-            return Vector128.Create<byte>(t);
-#else
             if (BitConverter.IsLittleEndian && Unsafe.SizeOf<Vector128<byte>>() == 16)
-                return Unsafe.ReadUnaligned<Vector128<byte>>(ref Unsafe.AsRef(t[0]));
+                return MemoryMarshal.Read<Vector128<byte>>(t);
 
-            return Vector128.Create(t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7], t[8], t[9], t[10], t[11], t[12],
-                t[13], t[14], t[15]);
-#endif
+            return Vector128.Create(
+                BinaryPrimitives.ReadUInt64LittleEndian(t[..8]),
+                BinaryPrimitives.ReadUInt64LittleEndian(t[8..])
+            ).AsByte();
         }
 
         [MethodImpl(MethodImplOptions.AggressiveInlining)]
diff --git a/crypto/src/pqc/crypto/utils/PqcUtilities.cs b/crypto/src/pqc/crypto/utils/PqcUtilities.cs
index 8d73333c9..1f1da5e74 100644
--- a/crypto/src/pqc/crypto/utils/PqcUtilities.cs
+++ b/crypto/src/pqc/crypto/utils/PqcUtilities.cs
@@ -1,4 +1,3 @@
-using System;
 using System.Collections.Generic;
 
 using Org.BouncyCastle.Asn1;
@@ -27,8 +26,8 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
         private readonly static Dictionary<PicnicParameters, DerObjectIdentifier> picnicOids = new Dictionary<PicnicParameters, DerObjectIdentifier>();
         private readonly static Dictionary<DerObjectIdentifier, PicnicParameters> picnicParams = new Dictionary<DerObjectIdentifier, PicnicParameters>();
         
-        private readonly static Dictionary<SIKEParameters, DerObjectIdentifier> sikeOids = new Dictionary<SIKEParameters, DerObjectIdentifier>();
-        private readonly static Dictionary<DerObjectIdentifier, SIKEParameters> sikeParams = new Dictionary<DerObjectIdentifier, SIKEParameters>();
+        private readonly static Dictionary<SikeParameters, DerObjectIdentifier> sikeOids = new Dictionary<SikeParameters, DerObjectIdentifier>();
+        private readonly static Dictionary<DerObjectIdentifier, SikeParameters> sikeParams = new Dictionary<DerObjectIdentifier, SikeParameters>();
      
         private readonly static Dictionary<KyberParameters, DerObjectIdentifier> kyberOids = new Dictionary<KyberParameters, DerObjectIdentifier>();
         private readonly static Dictionary<DerObjectIdentifier, KyberParameters> kyberParams = new Dictionary<DerObjectIdentifier, KyberParameters>();
@@ -79,7 +78,16 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             saberOids[SaberParameters.lightsaberkem256r3] = BCObjectIdentifiers.lightsaberkem256r3;
             saberOids[SaberParameters.saberkem256r3] = BCObjectIdentifiers.saberkem256r3;
             saberOids[SaberParameters.firesaberkem256r3] = BCObjectIdentifiers.firesaberkem256r3;
-            
+            saberOids[SaberParameters.ulightsaberkemr3] = BCObjectIdentifiers.ulightsaberkemr3;
+            saberOids[SaberParameters.usaberkemr3] = BCObjectIdentifiers.usaberkemr3;
+            saberOids[SaberParameters.ufiresaberkemr3] = BCObjectIdentifiers.ufiresaberkemr3;
+            saberOids[SaberParameters.lightsaberkem90sr3] = BCObjectIdentifiers.lightsaberkem90sr3;
+            saberOids[SaberParameters.saberkem90sr3] = BCObjectIdentifiers.saberkem90sr3;
+            saberOids[SaberParameters.firesaberkem90sr3] = BCObjectIdentifiers.firesaberkem90sr3;
+            saberOids[SaberParameters.ulightsaberkem90sr3] = BCObjectIdentifiers.ulightsaberkem90sr3;
+            saberOids[SaberParameters.usaberkem90sr3] = BCObjectIdentifiers.usaberkem90sr3;
+            saberOids[SaberParameters.ufiresaberkem90sr3] = BCObjectIdentifiers.ufiresaberkem90sr3;
+
             saberParams[BCObjectIdentifiers.lightsaberkem128r3] = SaberParameters.lightsaberkem128r3;
             saberParams[BCObjectIdentifiers.saberkem128r3] = SaberParameters.saberkem128r3;
             saberParams[BCObjectIdentifiers.firesaberkem128r3] = SaberParameters.firesaberkem128r3;
@@ -89,7 +97,15 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             saberParams[BCObjectIdentifiers.lightsaberkem256r3] = SaberParameters.lightsaberkem256r3;
             saberParams[BCObjectIdentifiers.saberkem256r3] = SaberParameters.saberkem256r3;
             saberParams[BCObjectIdentifiers.firesaberkem256r3] = SaberParameters.firesaberkem256r3;
-
+            saberParams[BCObjectIdentifiers.ulightsaberkemr3] = SaberParameters.ulightsaberkemr3;
+            saberParams[BCObjectIdentifiers.usaberkemr3] = SaberParameters.usaberkemr3;
+            saberParams[BCObjectIdentifiers.ufiresaberkemr3] = SaberParameters.ufiresaberkemr3;
+            saberParams[BCObjectIdentifiers.lightsaberkem90sr3] = SaberParameters.lightsaberkem90sr3;
+            saberParams[BCObjectIdentifiers.saberkem90sr3] = SaberParameters.saberkem90sr3;
+            saberParams[BCObjectIdentifiers.firesaberkem90sr3] = SaberParameters.firesaberkem90sr3;
+            saberParams[BCObjectIdentifiers.ulightsaberkem90sr3] = SaberParameters.ulightsaberkem90sr3;
+            saberParams[BCObjectIdentifiers.usaberkem90sr3] = SaberParameters.usaberkem90sr3;
+            saberParams[BCObjectIdentifiers.ufiresaberkem90sr3] = SaberParameters.ufiresaberkem90sr3;
             
             picnicOids[PicnicParameters.picnicl1fs] = BCObjectIdentifiers.picnicl1fs;
             picnicOids[PicnicParameters.picnicl1ur] = BCObjectIdentifiers.picnicl1ur;
@@ -117,23 +133,23 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             picnicParams[BCObjectIdentifiers.picnicl3full] = PicnicParameters.picnicl3full;
             picnicParams[BCObjectIdentifiers.picnicl5full] = PicnicParameters.picnicl5full;
             
-            sikeParams[BCObjectIdentifiers.sikep434] = SIKEParameters.sikep434;
-            sikeParams[BCObjectIdentifiers.sikep503] = SIKEParameters.sikep503;
-            sikeParams[BCObjectIdentifiers.sikep610] = SIKEParameters.sikep610;
-            sikeParams[BCObjectIdentifiers.sikep751] = SIKEParameters.sikep751;
-            sikeParams[BCObjectIdentifiers.sikep434_compressed] = SIKEParameters.sikep434_compressed;
-            sikeParams[BCObjectIdentifiers.sikep503_compressed] = SIKEParameters.sikep503_compressed;
-            sikeParams[BCObjectIdentifiers.sikep610_compressed] = SIKEParameters.sikep610_compressed;
-            sikeParams[BCObjectIdentifiers.sikep751_compressed] = SIKEParameters.sikep751_compressed;
+            sikeParams[BCObjectIdentifiers.sikep434] = SikeParameters.sikep434;
+            sikeParams[BCObjectIdentifiers.sikep503] = SikeParameters.sikep503;
+            sikeParams[BCObjectIdentifiers.sikep610] = SikeParameters.sikep610;
+            sikeParams[BCObjectIdentifiers.sikep751] = SikeParameters.sikep751;
+            sikeParams[BCObjectIdentifiers.sikep434_compressed] = SikeParameters.sikep434_compressed;
+            sikeParams[BCObjectIdentifiers.sikep503_compressed] = SikeParameters.sikep503_compressed;
+            sikeParams[BCObjectIdentifiers.sikep610_compressed] = SikeParameters.sikep610_compressed;
+            sikeParams[BCObjectIdentifiers.sikep751_compressed] = SikeParameters.sikep751_compressed;
             
-            sikeOids[SIKEParameters.sikep434] = BCObjectIdentifiers.sikep434;
-            sikeOids[SIKEParameters.sikep503] = BCObjectIdentifiers.sikep503;
-            sikeOids[SIKEParameters.sikep610] = BCObjectIdentifiers.sikep610;
-            sikeOids[SIKEParameters.sikep751] = BCObjectIdentifiers.sikep751;
-            sikeOids[SIKEParameters.sikep434_compressed] = BCObjectIdentifiers.sikep434_compressed;
-            sikeOids[SIKEParameters.sikep503_compressed] = BCObjectIdentifiers.sikep503_compressed;
-            sikeOids[SIKEParameters.sikep610_compressed] = BCObjectIdentifiers.sikep610_compressed;
-            sikeOids[SIKEParameters.sikep751_compressed] = BCObjectIdentifiers.sikep751_compressed;
+            sikeOids[SikeParameters.sikep434] = BCObjectIdentifiers.sikep434;
+            sikeOids[SikeParameters.sikep503] = BCObjectIdentifiers.sikep503;
+            sikeOids[SikeParameters.sikep610] = BCObjectIdentifiers.sikep610;
+            sikeOids[SikeParameters.sikep751] = BCObjectIdentifiers.sikep751;
+            sikeOids[SikeParameters.sikep434_compressed] = BCObjectIdentifiers.sikep434_compressed;
+            sikeOids[SikeParameters.sikep503_compressed] = BCObjectIdentifiers.sikep503_compressed;
+            sikeOids[SikeParameters.sikep610_compressed] = BCObjectIdentifiers.sikep610_compressed;
+            sikeOids[SikeParameters.sikep751_compressed] = BCObjectIdentifiers.sikep751_compressed;
             
             kyberOids[KyberParameters.kyber512] = BCObjectIdentifiers.kyber512;
             kyberOids[KyberParameters.kyber768] = BCObjectIdentifiers.kyber768;
@@ -170,21 +186,21 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             dilithiumParams[BCObjectIdentifiers.dilithium3_aes] = DilithiumParameters.Dilithium3Aes;
             dilithiumParams[BCObjectIdentifiers.dilithium5_aes] = DilithiumParameters.Dilithium5Aes;
 
-            bikeOids[BikeParameters.bike128] = BCObjectIdentifiers.bike128;
-            bikeOids[BikeParameters.bike192] = BCObjectIdentifiers.bike192;
-            bikeOids[BikeParameters.bike256] = BCObjectIdentifiers.bike256;
-
             bikeParams[BCObjectIdentifiers.bike128] = BikeParameters.bike128;
             bikeParams[BCObjectIdentifiers.bike192] = BikeParameters.bike192;
             bikeParams[BCObjectIdentifiers.bike256] = BikeParameters.bike256;
 
-            hqcOids[HqcParameters.hqc128] = BCObjectIdentifiers.hqc128;
-            hqcOids[HqcParameters.hqc192] = BCObjectIdentifiers.hqc192;
-            hqcOids[HqcParameters.hqc256] = BCObjectIdentifiers.hqc256;
+            bikeOids[BikeParameters.bike128] = BCObjectIdentifiers.bike128;
+            bikeOids[BikeParameters.bike192] = BCObjectIdentifiers.bike192;
+            bikeOids[BikeParameters.bike256] = BCObjectIdentifiers.bike256;
 
             hqcParams[BCObjectIdentifiers.hqc128] = HqcParameters.hqc128;
             hqcParams[BCObjectIdentifiers.hqc192] = HqcParameters.hqc192;
             hqcParams[BCObjectIdentifiers.hqc256] = HqcParameters.hqc256;
+
+            hqcOids[HqcParameters.hqc128] = BCObjectIdentifiers.hqc128;
+            hqcOids[HqcParameters.hqc192] = BCObjectIdentifiers.hqc192;
+            hqcOids[HqcParameters.hqc256] = BCObjectIdentifiers.hqc256;
         }
 
         public static DerObjectIdentifier McElieceOidLookup(CmceParameters parameters)
@@ -256,12 +272,12 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
         {
             return picnicParams[oid];
         }
-        internal static DerObjectIdentifier SikeOidLookup(SIKEParameters parameters)
+        internal static DerObjectIdentifier SikeOidLookup(SikeParameters parameters)
         {
             return sikeOids[parameters];
         }
 
-        internal static SIKEParameters SikeParamsLookup(DerObjectIdentifier oid)
+        internal static SikeParameters SikeParamsLookup(DerObjectIdentifier oid)
         {
             return sikeParams[oid];
         }
diff --git a/crypto/src/pqc/crypto/utils/PrivateKeyFactory.cs b/crypto/src/pqc/crypto/utils/PrivateKeyFactory.cs
index 7b0039d63..7db65dbfb 100644
--- a/crypto/src/pqc/crypto/utils/PrivateKeyFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PrivateKeyFactory.cs
@@ -24,9 +24,8 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 {
-    public class PrivateKeyFactory
+    public static class PrivateKeyFactory
     {
-
         /// <summary> Create a private key parameter from a PKCS8 PrivateKeyInfo encoding.</summary>
         /// <param name="privateKeyInfoData"> the PrivateKeyInfo encoding</param>
         /// <returns> a suitable private key parameter</returns>
@@ -45,7 +44,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             return CreateKey(PrivateKeyInfo.GetInstance(new Asn1InputStream(inStr).ReadObject()));
         }
 
-
         /// <summary> Create a private key parameter from the passed in PKCS8 PrivateKeyInfo object.</summary>
         /// <param name="keyInfo"> the PrivateKeyInfo object containing the key material</param>
         /// <returns> a suitable private key parameter</returns>
@@ -66,14 +64,13 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
                     {
                         byte[] pubEnc = pubKey.GetOctets();
 
-                        return LMSPrivateKeyParameters.GetInstance(Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length),
+                        return LmsPrivateKeyParameters.GetInstance(Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length),
                             Arrays.CopyOfRange(pubEnc, 4, pubEnc.Length));
                     }
 
-                    return LMSPrivateKeyParameters.GetInstance(Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length));
+                    return LmsPrivateKeyParameters.GetInstance(Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length));
                 }
             }
-
             if (algOID.On(BCObjectIdentifiers.pqc_kem_mceliece))
             {
                 CmcePrivateKey cmceKey = CmcePrivateKey.GetInstance(keyInfo.ParsePrivateKey());
@@ -81,7 +78,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 
                 return new CmcePrivateKeyParameters(spParams, cmceKey.Delta, cmceKey.C, cmceKey.G, cmceKey.Alpha, cmceKey.S);
             }
-            
             if (algOID.On(BCObjectIdentifiers.sphincsPlus))
             {
                 byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
@@ -106,9 +102,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             if (algOID.On(BCObjectIdentifiers.pqc_kem_sike))
             {
                 byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePrivateKey()).GetOctets();
-                SIKEParameters sikeParams = PqcUtilities.SikeParamsLookup(keyInfo.PrivateKeyAlgorithm.Algorithm);
+                SikeParameters sikeParams = PqcUtilities.SikeParamsLookup(keyInfo.PrivateKeyAlgorithm.Algorithm);
 
-                return new SIKEPrivateKeyParameters(sikeParams, keyEnc);
+                return new SikePrivateKeyParameters(sikeParams, keyEnc);
             }
             if (algOID.On(BCObjectIdentifiers.pqc_kem_bike))
             {
@@ -119,7 +115,6 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
                 byte[] h1 = Arrays.CopyOfRange(keyEnc, bikeParams.RByte, 2 * bikeParams.RByte);
                 byte[] sigma = Arrays.CopyOfRange(keyEnc, 2 * bikeParams.RByte, keyEnc.Length);
 
-
                 return new BikePrivateKeyParameters(bikeParams, h0, h1, sigma);
             }
             if (algOID.On(BCObjectIdentifiers.pqc_kem_hqc))
@@ -179,9 +174,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 
                 int version = DerInteger.GetInstance(keyEnc[0]).Value.IntValue;
                 if (version != 0)
-                {
                     throw new IOException("unknown private key version: " + version);
-                }
 
                 if (keyInfo.PublicKeyData != null)
                 {
@@ -208,39 +201,35 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
                 }
             }
             if (algOID.Equals(BCObjectIdentifiers.falcon_512) || algOID.Equals(BCObjectIdentifiers.falcon_1024))
-                {
-                    Asn1Sequence keyEnc = Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey());
-                    FalconParameters spParams = PqcUtilities.FalconParamsLookup(keyInfo.PrivateKeyAlgorithm.Algorithm);
+            {
+                Asn1Sequence keyEnc = Asn1Sequence.GetInstance(keyInfo.ParsePrivateKey());
+                FalconParameters spParams = PqcUtilities.FalconParamsLookup(keyInfo.PrivateKeyAlgorithm.Algorithm);
                     
-                    DerBitString publicKeyData = keyInfo.PublicKeyData;
-                    int version = DerInteger.GetInstance(keyEnc[0]).Value.IntValue;
-                    if (version != 1)
-                    {
-                        throw new IOException("unknown private key version: " + version);
-                    }
+                DerBitString publicKeyData = keyInfo.PublicKeyData;
+                int version = DerInteger.GetInstance(keyEnc[0]).Value.IntValue;
+                if (version != 1)
+                    throw new IOException("unknown private key version: " + version);
 
-                    if (keyInfo.PublicKeyData != null)
-                    {
-                        //ASN1Sequence pubKey = ASN1Sequence.getInstance(keyInfo.getPublicKeyData().getOctets());
-                        return new FalconPrivateKeyParameters(spParams,
-                            Asn1OctetString.GetInstance(keyEnc[1]).GetOctets(),
-                            Asn1OctetString.GetInstance(keyEnc[2]).GetOctets(),
-                            Asn1OctetString.GetInstance(keyEnc[3]).GetOctets(),
-                            publicKeyData.GetOctets()); // encT1
-                    }
-                    else
-                    {
-                        return new FalconPrivateKeyParameters(spParams,
-                            Asn1OctetString.GetInstance(keyEnc[1]).GetOctets(),
-                            Asn1OctetString.GetInstance(keyEnc[2]).GetOctets(),
-                            Asn1OctetString.GetInstance(keyEnc[3]).GetOctets(),
-                            null);
-                    }
+                if (keyInfo.PublicKeyData != null)
+                {
+                    //ASN1Sequence pubKey = ASN1Sequence.getInstance(keyInfo.getPublicKeyData().getOctets());
+                    return new FalconPrivateKeyParameters(spParams,
+                        Asn1OctetString.GetInstance(keyEnc[1]).GetOctets(),
+                        Asn1OctetString.GetInstance(keyEnc[2]).GetOctets(),
+                        Asn1OctetString.GetInstance(keyEnc[3]).GetOctets(),
+                        publicKeyData.GetOctets()); // encT1
                 }
-            
-            
-            throw new Exception("algorithm identifier in private key not recognised");
+                else
+                {
+                    return new FalconPrivateKeyParameters(spParams,
+                        Asn1OctetString.GetInstance(keyEnc[1]).GetOctets(),
+                        Asn1OctetString.GetInstance(keyEnc[2]).GetOctets(),
+                        Asn1OctetString.GetInstance(keyEnc[3]).GetOctets(),
+                        null);
+                }
+            }
 
+            throw new Exception("algorithm identifier in private key not recognised");
         }
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/utils/PrivateKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/PrivateKeyInfoFactory.cs
index e4ae51361..806eae8b7 100644
--- a/crypto/src/pqc/crypto/utils/PrivateKeyInfoFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PrivateKeyInfoFactory.cs
@@ -5,28 +5,23 @@ using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Pqc.Asn1;
+using Org.BouncyCastle.Pqc.Crypto.Bike;
 using Org.BouncyCastle.Pqc.Crypto.Cmce;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
 using Org.BouncyCastle.Pqc.Crypto.Falcon;
+using Org.BouncyCastle.Pqc.Crypto.Hqc;
 using Org.BouncyCastle.Pqc.Crypto.Lms;
 using Org.BouncyCastle.Pqc.Crypto.Picnic;
 using Org.BouncyCastle.Pqc.Crypto.Saber;
 using Org.BouncyCastle.Pqc.Crypto.Sike;
-using Org.BouncyCastle.Pqc.Crypto.Bike;
-using Org.BouncyCastle.Pqc.Crypto.Hqc;
 using Org.BouncyCastle.Pqc.Crypto.SphincsPlus;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 {
-    public class PrivateKeyInfoFactory
+    public static class PrivateKeyInfoFactory
     {
-        private PrivateKeyInfoFactory()
-        {
-
-        }
-
         /// <summary> Create a PrivateKeyInfo representation of a private key.</summary>
         /// <param name="privateKey"> the key to be encoded into the info object.</param>
         /// <returns> the appropriate PrivateKeyInfo</returns>
@@ -43,154 +38,142 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
         /// <exception cref="ArgumentException"> on an error encoding the key</exception>
         public static PrivateKeyInfo CreatePrivateKeyInfo(AsymmetricKeyParameter privateKey, Asn1Set attributes)
         {
-            if (privateKey is LMSPrivateKeyParameters)
+            if (privateKey is LmsPrivateKeyParameters lmsPrivateKeyParameters)
             {
-                LMSPrivateKeyParameters parameters = (LMSPrivateKeyParameters)privateKey;
-
-                byte[] encoding = Composer.Compose().U32Str(1).Bytes(parameters).Build();
-                byte[] pubEncoding = Composer.Compose().U32Str(1).Bytes(parameters.GetPublicKey()).Build();
+                byte[] encoding = Composer.Compose().U32Str(1).Bytes(lmsPrivateKeyParameters).Build();
+                byte[] pubEncoding = Composer.Compose().U32Str(1).Bytes(lmsPrivateKeyParameters.GetPublicKey()).Build();
 
                 AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdAlgHssLmsHashsig);
                 return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes, pubEncoding);
             }
-            if (privateKey is HSSPrivateKeyParameters)
+            if (privateKey is HssPrivateKeyParameters hssPrivateKeyParameters)
             {
-                HSSPrivateKeyParameters parameters = (HSSPrivateKeyParameters)privateKey;
-
-                byte[] encoding = Composer.Compose().U32Str(parameters.L).Bytes(parameters).Build();
-                byte[] pubEncoding = Composer.Compose().U32Str(parameters.L).Bytes(parameters.GetPublicKey().LmsPublicKey).Build();
+                int L = hssPrivateKeyParameters.L;
+                byte[] encoding = Composer.Compose().U32Str(L).Bytes(hssPrivateKeyParameters).Build();
+                byte[] pubEncoding = Composer.Compose().U32Str(L).Bytes(hssPrivateKeyParameters.GetPublicKey().LmsPublicKey).Build();
 
                 AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdAlgHssLmsHashsig);
                 return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes, pubEncoding);
             }
-            if (privateKey is SphincsPlusPrivateKeyParameters)
+            if (privateKey is SphincsPlusPrivateKeyParameters sphincsPlusPrivateKeyParameters)
             {
-                SphincsPlusPrivateKeyParameters parameters = (SphincsPlusPrivateKeyParameters)privateKey;
-
-                byte[] encoding = parameters.GetEncoded();
-                byte[] pubEncoding = parameters.GetEncodedPublicKey();
+                byte[] encoding = sphincsPlusPrivateKeyParameters.GetEncoded();
+                byte[] pubEncoding = sphincsPlusPrivateKeyParameters.GetEncodedPublicKey();
 
                 AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
-                    PqcUtilities.SphincsPlusOidLookup(parameters.Parameters));
+                    PqcUtilities.SphincsPlusOidLookup(sphincsPlusPrivateKeyParameters.Parameters));
                 return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes, pubEncoding);
             }
-            if (privateKey is CmcePrivateKeyParameters)
+            if (privateKey is CmcePrivateKeyParameters cmcePrivateKeyParameters)
             {
-                CmcePrivateKeyParameters parameters = (CmcePrivateKeyParameters) privateKey;
-
-                byte[] encoding = parameters.GetEncoded();
+                byte[] encoding = cmcePrivateKeyParameters.GetEncoded();
                 AlgorithmIdentifier algorithmIdentifier =
-                    new AlgorithmIdentifier(PqcUtilities.McElieceOidLookup(parameters.Parameters));
+                    new AlgorithmIdentifier(PqcUtilities.McElieceOidLookup(cmcePrivateKeyParameters.Parameters));
 
-                CmcePublicKey CmcePub = new CmcePublicKey(parameters.ReconstructPublicKey());
-                CmcePrivateKey CmcePriv = new CmcePrivateKey(0, parameters.Delta, parameters.C, parameters.G,
-                    parameters.Alpha, parameters.S, CmcePub);
+                CmcePublicKey CmcePub = new CmcePublicKey(cmcePrivateKeyParameters.ReconstructPublicKey());
+                CmcePrivateKey CmcePriv = new CmcePrivateKey(0, cmcePrivateKeyParameters.Delta,
+                    cmcePrivateKeyParameters.C, cmcePrivateKeyParameters.G, cmcePrivateKeyParameters.Alpha,
+                    cmcePrivateKeyParameters.S, CmcePub);
                 return new PrivateKeyInfo(algorithmIdentifier, CmcePriv, attributes);
             }
-            if (privateKey is SaberPrivateKeyParameters)
+            if (privateKey is SaberPrivateKeyParameters saberPrivateKeyParameters)
             {
-                SaberPrivateKeyParameters parameters = (SaberPrivateKeyParameters)privateKey;
-
-                byte[] encoding = parameters.GetEncoded();
+                byte[] encoding = saberPrivateKeyParameters.GetEncoded();
 
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.SaberOidLookup(parameters.GetParameters()));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.SaberOidLookup(saberPrivateKeyParameters.Parameters));
 
                 return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes);
             }
-            if (privateKey is PicnicPrivateKeyParameters)
+            if (privateKey is PicnicPrivateKeyParameters picnicPrivateKeyParameters)
             {
-                PicnicPrivateKeyParameters parameters = (PicnicPrivateKeyParameters)privateKey;
+                byte[] encoding = picnicPrivateKeyParameters.GetEncoded();
 
-                byte[] encoding = parameters.GetEncoded();
-
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.PicnicOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.PicnicOidLookup(picnicPrivateKeyParameters.Parameters));
                 return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes);
             }
-            if (privateKey is SIKEPrivateKeyParameters)
+            if (privateKey is SikePrivateKeyParameters sikePrivateKeyParameters)
             {
-                SIKEPrivateKeyParameters parameters = (SIKEPrivateKeyParameters)privateKey;
+                byte[] encoding = sikePrivateKeyParameters.GetEncoded();
 
-                byte[] encoding = parameters.GetEncoded();
-
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.SikeOidLookup(parameters.GetParameters()));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.SikeOidLookup(sikePrivateKeyParameters.Parameters));
                 return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes);
             }
-            if (privateKey is FalconPrivateKeyParameters)
+            if (privateKey is FalconPrivateKeyParameters falconPrivateKeyParameters)
             {
-                FalconPrivateKeyParameters parameters = (FalconPrivateKeyParameters)privateKey;
-
                 Asn1EncodableVector v = new Asn1EncodableVector();
 
                 v.Add(new DerInteger(1));
-                v.Add(new DerOctetString(parameters.GetSpolyf()));
-                v.Add(new DerOctetString(parameters.GetG()));
-                v.Add(new DerOctetString(parameters.GetSpolyF()));
+                v.Add(new DerOctetString(falconPrivateKeyParameters.GetSpolyf()));
+                v.Add(new DerOctetString(falconPrivateKeyParameters.GetG()));
+                v.Add(new DerOctetString(falconPrivateKeyParameters.GetSpolyF()));
 
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.FalconOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.FalconOidLookup(falconPrivateKeyParameters.Parameters));
 
-                return new PrivateKeyInfo(algorithmIdentifier, new DerSequence(v), attributes, parameters.GetPublicKey());
+                return new PrivateKeyInfo(algorithmIdentifier, new DerSequence(v), attributes,
+                    falconPrivateKeyParameters.GetPublicKey());
             }
-            if (privateKey is KyberPrivateKeyParameters)
+            if (privateKey is KyberPrivateKeyParameters kyberPrivateKeyParameters)
             {
-                KyberPrivateKeyParameters parameters = (KyberPrivateKeyParameters)privateKey;
-            
                 Asn1EncodableVector v = new Asn1EncodableVector();
 
                 v.Add(new DerInteger(0));
-                v.Add(new DerOctetString(parameters.S));
-                v.Add(new DerOctetString(parameters.Hpk));
-                v.Add(new DerOctetString(parameters.Nonce));
+                v.Add(new DerOctetString(kyberPrivateKeyParameters.S));
+                v.Add(new DerOctetString(kyberPrivateKeyParameters.Hpk));
+                v.Add(new DerOctetString(kyberPrivateKeyParameters.Nonce));
 
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.KyberOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.KyberOidLookup(kyberPrivateKeyParameters.Parameters));
 
                 Asn1EncodableVector vPub = new Asn1EncodableVector();
-                vPub.Add(new DerOctetString(parameters.T));
-                vPub.Add(new DerOctetString(parameters.Rho));
+                vPub.Add(new DerOctetString(kyberPrivateKeyParameters.T));
+                vPub.Add(new DerOctetString(kyberPrivateKeyParameters.Rho));
 
-                return new PrivateKeyInfo(algorithmIdentifier, new DerSequence(v), attributes, new DerSequence(vPub).GetEncoded());
+                return new PrivateKeyInfo(algorithmIdentifier, new DerSequence(v), attributes,
+                    new DerSequence(vPub).GetEncoded());
             }
-            if (privateKey is DilithiumPrivateKeyParameters)
+            if (privateKey is DilithiumPrivateKeyParameters dilithiumPrivateKeyParameters)
             {
-                DilithiumPrivateKeyParameters parameters = (DilithiumPrivateKeyParameters)privateKey;
-
                 Asn1EncodableVector v = new Asn1EncodableVector();
 
                 v.Add(new DerInteger(0));
-                v.Add(new DerBitString(parameters.Rho));
-                v.Add(new DerBitString(parameters.K));
-                v.Add(new DerBitString(parameters.Tr));
-                v.Add(new DerBitString(parameters.S1));
-                v.Add(new DerBitString(parameters.S2));
-                v.Add(new DerBitString(parameters.T0));
+                v.Add(new DerBitString(dilithiumPrivateKeyParameters.Rho));
+                v.Add(new DerBitString(dilithiumPrivateKeyParameters.K));
+                v.Add(new DerBitString(dilithiumPrivateKeyParameters.Tr));
+                v.Add(new DerBitString(dilithiumPrivateKeyParameters.S1));
+                v.Add(new DerBitString(dilithiumPrivateKeyParameters.S2));
+                v.Add(new DerBitString(dilithiumPrivateKeyParameters.T0));
 
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.DilithiumOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.DilithiumOidLookup(dilithiumPrivateKeyParameters.Parameters));
 
                 Asn1EncodableVector vPub = new Asn1EncodableVector();
-                vPub.Add(new DerOctetString(parameters.Rho));
-                vPub.Add(new DerOctetString(parameters.T1));
+                vPub.Add(new DerOctetString(dilithiumPrivateKeyParameters.Rho));
+                vPub.Add(new DerOctetString(dilithiumPrivateKeyParameters.T1));
 
-                return new PrivateKeyInfo(algorithmIdentifier, new DerSequence(v), attributes, new DerSequence(vPub).GetEncoded());
+                return new PrivateKeyInfo(algorithmIdentifier, new DerSequence(v), attributes,
+                    new DerSequence(vPub).GetEncoded());
             }
-            if (privateKey is BikePrivateKeyParameters)
+            if (privateKey is BikePrivateKeyParameters bikePrivateKeyParameters)
             {
-                BikePrivateKeyParameters parameters = (BikePrivateKeyParameters)privateKey;
+                byte[] encoding = bikePrivateKeyParameters.GetEncoded();
 
-                byte[] encoding = parameters.GetEncoded();
-
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.BikeOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.BikeOidLookup(bikePrivateKeyParameters.Parameters));
                 return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes);
             }
-            if (privateKey is HqcPrivateKeyParameters)
+            else if (privateKey is HqcPrivateKeyParameters hqcPrivateKeyParameters)
             {
-                HqcPrivateKeyParameters parameters = (HqcPrivateKeyParameters)privateKey;
-
-                byte[] encoding = parameters.GetEncoded();
-
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.HqcOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.HqcOidLookup(hqcPrivateKeyParameters.Parameters));
+                byte[] encoding = hqcPrivateKeyParameters.PrivateKey;
                 return new PrivateKeyInfo(algorithmIdentifier, new DerOctetString(encoding), attributes);
             }
 
             throw new ArgumentException("Class provided is not convertible: " + Platform.GetTypeName(privateKey));
         }
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs b/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs
index 53aa28c36..5d55a73aa 100644
--- a/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs
+++ b/crypto/src/pqc/crypto/utils/PublicKeyFactory.cs
@@ -4,6 +4,7 @@ using System.IO;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.BC;
+using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Utilities;
@@ -15,6 +16,7 @@ using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
 using Org.BouncyCastle.Pqc.Crypto.Falcon;
 using Org.BouncyCastle.Pqc.Crypto.Hqc;
+using Org.BouncyCastle.Pqc.Crypto.Lms;
 using Org.BouncyCastle.Pqc.Crypto.Picnic;
 using Org.BouncyCastle.Pqc.Crypto.Saber;
 using Org.BouncyCastle.Pqc.Crypto.Sike;
@@ -23,88 +25,99 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 {
-    public class PublicKeyFactory
+    public static class PublicKeyFactory
     {
-        private static Dictionary<DerObjectIdentifier, SubjectPublicKeyInfoConverter> converters = new Dictionary<DerObjectIdentifier, SubjectPublicKeyInfoConverter>();
-
+        private static Dictionary<DerObjectIdentifier, SubjectPublicKeyInfoConverter> Converters =
+            new Dictionary<DerObjectIdentifier, SubjectPublicKeyInfoConverter>();
 
         static PublicKeyFactory()
         {
-            converters[BCObjectIdentifiers.sphincsPlus] = new SphincsPlusConverter();
-            converters[BCObjectIdentifiers.sphincsPlus_shake_256] = new SphincsPlusConverter();
-            converters[BCObjectIdentifiers.sphincsPlus_sha_256] = new SphincsPlusConverter();
-            converters[BCObjectIdentifiers.sphincsPlus_sha_512] = new SphincsPlusConverter();
+            Converters[PkcsObjectIdentifiers.IdAlgHssLmsHashsig] = new LmsConverter();
+
+            Converters[BCObjectIdentifiers.sphincsPlus] = new SphincsPlusConverter();
+            Converters[BCObjectIdentifiers.sphincsPlus_shake_256] = new SphincsPlusConverter();
+            Converters[BCObjectIdentifiers.sphincsPlus_sha_256] = new SphincsPlusConverter();
+            Converters[BCObjectIdentifiers.sphincsPlus_sha_512] = new SphincsPlusConverter();
             
-            converters[BCObjectIdentifiers.mceliece348864_r3] = new CmceConverter();
-            converters[BCObjectIdentifiers.mceliece348864f_r3] = new CmceConverter();
-            converters[BCObjectIdentifiers.mceliece460896_r3] = new CmceConverter();
-            converters[BCObjectIdentifiers.mceliece460896f_r3] = new CmceConverter();
-            converters[BCObjectIdentifiers.mceliece6688128_r3] = new CmceConverter();
-            converters[BCObjectIdentifiers.mceliece6688128f_r3] = new CmceConverter();
-            converters[BCObjectIdentifiers.mceliece6960119_r3] = new CmceConverter();
-            converters[BCObjectIdentifiers.mceliece6960119f_r3] = new CmceConverter();
-            converters[BCObjectIdentifiers.mceliece8192128_r3] = new CmceConverter();
-            converters[BCObjectIdentifiers.mceliece8192128f_r3] = new CmceConverter();
+            Converters[BCObjectIdentifiers.mceliece348864_r3] = new CmceConverter();
+            Converters[BCObjectIdentifiers.mceliece348864f_r3] = new CmceConverter();
+            Converters[BCObjectIdentifiers.mceliece460896_r3] = new CmceConverter();
+            Converters[BCObjectIdentifiers.mceliece460896f_r3] = new CmceConverter();
+            Converters[BCObjectIdentifiers.mceliece6688128_r3] = new CmceConverter();
+            Converters[BCObjectIdentifiers.mceliece6688128f_r3] = new CmceConverter();
+            Converters[BCObjectIdentifiers.mceliece6960119_r3] = new CmceConverter();
+            Converters[BCObjectIdentifiers.mceliece6960119f_r3] = new CmceConverter();
+            Converters[BCObjectIdentifiers.mceliece8192128_r3] = new CmceConverter();
+            Converters[BCObjectIdentifiers.mceliece8192128f_r3] = new CmceConverter();
            
-            converters[BCObjectIdentifiers.lightsaberkem128r3] = new SaberConverter();
-            converters[BCObjectIdentifiers.saberkem128r3] = new SaberConverter();
-            converters[BCObjectIdentifiers.firesaberkem128r3] = new SaberConverter();
-            converters[BCObjectIdentifiers.lightsaberkem192r3] = new SaberConverter();
-            converters[BCObjectIdentifiers.saberkem192r3] = new SaberConverter();
-            converters[BCObjectIdentifiers.firesaberkem192r3] = new SaberConverter();
-            converters[BCObjectIdentifiers.lightsaberkem256r3] = new SaberConverter();
-            converters[BCObjectIdentifiers.saberkem256r3] = new SaberConverter();
-            converters[BCObjectIdentifiers.firesaberkem256r3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.lightsaberkem128r3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.saberkem128r3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.firesaberkem128r3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.lightsaberkem192r3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.saberkem192r3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.firesaberkem192r3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.lightsaberkem256r3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.saberkem256r3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.firesaberkem256r3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.ulightsaberkemr3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.usaberkemr3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.ufiresaberkemr3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.lightsaberkem90sr3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.saberkem90sr3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.firesaberkem90sr3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.ulightsaberkem90sr3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.usaberkem90sr3] = new SaberConverter();
+            Converters[BCObjectIdentifiers.ufiresaberkem90sr3] = new SaberConverter();
             
-            converters[BCObjectIdentifiers.picnic] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnicl1fs] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnicl1ur] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnicl3fs] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnicl3ur] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnicl5fs] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnicl5ur] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnic3l1] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnic3l3] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnic3l5] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnicl1full] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnicl3full] = new PicnicConverter();
-            converters[BCObjectIdentifiers.picnicl5full] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnic] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnicl1fs] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnicl1ur] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnicl3fs] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnicl3ur] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnicl5fs] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnicl5ur] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnic3l1] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnic3l3] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnic3l5] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnicl1full] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnicl3full] = new PicnicConverter();
+            Converters[BCObjectIdentifiers.picnicl5full] = new PicnicConverter();
             
-            converters[BCObjectIdentifiers.sikep434] = new SikeConverter();
-            converters[BCObjectIdentifiers.sikep503] = new SikeConverter();
-            converters[BCObjectIdentifiers.sikep610] = new SikeConverter();
-            converters[BCObjectIdentifiers.sikep751] = new SikeConverter();
-            converters[BCObjectIdentifiers.sikep434_compressed] = new SikeConverter();
-            converters[BCObjectIdentifiers.sikep503_compressed] = new SikeConverter();
-            converters[BCObjectIdentifiers.sikep610_compressed] = new SikeConverter();
-            converters[BCObjectIdentifiers.sikep751_compressed] = new SikeConverter();
+            Converters[BCObjectIdentifiers.sikep434] = new SikeConverter();
+            Converters[BCObjectIdentifiers.sikep503] = new SikeConverter();
+            Converters[BCObjectIdentifiers.sikep610] = new SikeConverter();
+            Converters[BCObjectIdentifiers.sikep751] = new SikeConverter();
+            Converters[BCObjectIdentifiers.sikep434_compressed] = new SikeConverter();
+            Converters[BCObjectIdentifiers.sikep503_compressed] = new SikeConverter();
+            Converters[BCObjectIdentifiers.sikep610_compressed] = new SikeConverter();
+            Converters[BCObjectIdentifiers.sikep751_compressed] = new SikeConverter();
             
-            converters[BCObjectIdentifiers.dilithium2] = new DilithiumConverter();
-            converters[BCObjectIdentifiers.dilithium3] = new DilithiumConverter();
-            converters[BCObjectIdentifiers.dilithium5] = new DilithiumConverter();
-            converters[BCObjectIdentifiers.dilithium2_aes] = new DilithiumConverter();
-            converters[BCObjectIdentifiers.dilithium3_aes] = new DilithiumConverter();
-            converters[BCObjectIdentifiers.dilithium5_aes] = new DilithiumConverter();
+            Converters[BCObjectIdentifiers.dilithium2] = new DilithiumConverter();
+            Converters[BCObjectIdentifiers.dilithium3] = new DilithiumConverter();
+            Converters[BCObjectIdentifiers.dilithium5] = new DilithiumConverter();
+            Converters[BCObjectIdentifiers.dilithium2_aes] = new DilithiumConverter();
+            Converters[BCObjectIdentifiers.dilithium3_aes] = new DilithiumConverter();
+            Converters[BCObjectIdentifiers.dilithium5_aes] = new DilithiumConverter();
             
-            converters[BCObjectIdentifiers.falcon_512] = new FalconConverter();
-            converters[BCObjectIdentifiers.falcon_1024] = new FalconConverter();
+            Converters[BCObjectIdentifiers.falcon_512] = new FalconConverter();
+            Converters[BCObjectIdentifiers.falcon_1024] = new FalconConverter();
             
-            converters[BCObjectIdentifiers.kyber512] = new KyberConverter();
-            converters[BCObjectIdentifiers.kyber512_aes] = new KyberConverter();
-            converters[BCObjectIdentifiers.kyber768] = new KyberConverter();
-            converters[BCObjectIdentifiers.kyber768_aes] = new KyberConverter();
-            converters[BCObjectIdentifiers.kyber1024] = new KyberConverter();
-            converters[BCObjectIdentifiers.kyber1024_aes] = new KyberConverter();
-
-            converters[BCObjectIdentifiers.bike128] = new BikeConverter();
-            converters[BCObjectIdentifiers.bike192] = new BikeConverter();
-            converters[BCObjectIdentifiers.bike256] = new BikeConverter();
-
-            converters[BCObjectIdentifiers.hqc128] = new HqcConverter();
-            converters[BCObjectIdentifiers.hqc192] = new HqcConverter();
-            converters[BCObjectIdentifiers.hqc256] = new HqcConverter();
+            Converters[BCObjectIdentifiers.kyber512] = new KyberConverter();
+            Converters[BCObjectIdentifiers.kyber512_aes] = new KyberConverter();
+            Converters[BCObjectIdentifiers.kyber768] = new KyberConverter();
+            Converters[BCObjectIdentifiers.kyber768_aes] = new KyberConverter();
+            Converters[BCObjectIdentifiers.kyber1024] = new KyberConverter();
+            Converters[BCObjectIdentifiers.kyber1024_aes] = new KyberConverter();
+
+            Converters[BCObjectIdentifiers.bike128] = new BikeConverter();
+            Converters[BCObjectIdentifiers.bike192] = new BikeConverter();
+            Converters[BCObjectIdentifiers.bike256] = new BikeConverter();
+
+            Converters[BCObjectIdentifiers.hqc128] = new HqcConverter();
+            Converters[BCObjectIdentifiers.hqc192] = new HqcConverter();
+            Converters[BCObjectIdentifiers.hqc256] = new HqcConverter();
         }
-        
+
         /// <summary> Create a public key from a SubjectPublicKeyInfo encoding</summary>
         /// <param name="keyInfoData"> the SubjectPublicKeyInfo encoding</param>
         /// <returns> the appropriate key parameter</returns>
@@ -140,7 +153,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
         public static AsymmetricKeyParameter CreateKey(SubjectPublicKeyInfo keyInfo, object defaultParams)
         {
             AlgorithmIdentifier algId = keyInfo.AlgorithmID;
-            SubjectPublicKeyInfoConverter converter = (SubjectPublicKeyInfoConverter)converters[algId.Algorithm];
+            SubjectPublicKeyInfoConverter converter = (SubjectPublicKeyInfoConverter)Converters[algId.Algorithm];
 
             if (converter != null)
             {
@@ -155,7 +168,30 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
         {
             internal abstract AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams);
         }
-        
+
+        private class LmsConverter
+        :   SubjectPublicKeyInfoConverter
+        {
+            internal override AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams)
+            {
+                byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
+
+                if (Pack.BE_To_UInt32(keyEnc, 0) == 1U)
+                {
+                    return LmsPublicKeyParameters.GetInstance(Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length));
+                }
+                else
+                {
+                    // public key with extra tree height
+                    if (keyEnc.Length == 64)
+                    {
+                        keyEnc = Arrays.CopyOfRange(keyEnc, 4, keyEnc.Length);
+                    }
+                    return HssPublicKeyParameters.GetInstance(keyEnc);
+                }
+            }
+        }
+
         private class SphincsPlusConverter
             : SubjectPublicKeyInfoConverter
         {
@@ -215,9 +251,9 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             {
                 byte[] keyEnc = DerOctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
 
-                SIKEParameters sikeParams = PqcUtilities.SikeParamsLookup(keyInfo.AlgorithmID.Algorithm);
+                SikeParameters sikeParams = PqcUtilities.SikeParamsLookup(keyInfo.AlgorithmID.Algorithm);
 
-                return new SIKEPublicKeyParameters(sikeParams, keyEnc);
+                return new SikePublicKeyParameters(sikeParams, keyEnc);
             }
         }
         private class DilithiumConverter
@@ -302,7 +338,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
         {
             internal override AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams)
             {
-                byte[] keyEnc = DerOctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
+                byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
 
                 BikeParameters bikeParams = PqcUtilities.BikeParamsLookup(keyInfo.AlgorithmID.Algorithm);
 
@@ -314,7 +350,7 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
         {
             internal override AsymmetricKeyParameter GetPublicKeyParameters(SubjectPublicKeyInfo keyInfo, object defaultParams)
             {
-                byte[] keyEnc = DerOctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
+                byte[] keyEnc = Asn1OctetString.GetInstance(keyInfo.ParsePublicKey()).GetOctets();
 
                 HqcParameters hqcParams = PqcUtilities.HqcParamsLookup(keyInfo.AlgorithmID.Algorithm);
 
@@ -322,4 +358,4 @@ namespace Org.BouncyCastle.Pqc.Crypto.Utilities
             }
         }
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/pqc/crypto/utils/SecretWithEncapsulationImpl.cs b/crypto/src/pqc/crypto/utils/SecretWithEncapsulationImpl.cs
index 17057ebfd..c4d3eb44f 100644
--- a/crypto/src/pqc/crypto/utils/SecretWithEncapsulationImpl.cs
+++ b/crypto/src/pqc/crypto/utils/SecretWithEncapsulationImpl.cs
@@ -1,59 +1,59 @@
 using System;
+
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 {
     public class SecretWithEncapsulationImpl
-            : ISecretWithEncapsulation
-        {
-            private volatile bool hasBeenDestroyed = false;
+        : ISecretWithEncapsulation
+    {
+        private volatile bool hasBeenDestroyed = false;
 
-            private byte[] sessionKey;
-            private byte[] cipher_text;
+        private byte[] sessionKey;
+        private byte[] cipher_text;
 
-            public SecretWithEncapsulationImpl(byte[] sessionKey, byte[] cipher_text)
-            {
-                this.sessionKey = sessionKey;
-                this.cipher_text = cipher_text;
-            }
+        public SecretWithEncapsulationImpl(byte[] sessionKey, byte[] cipher_text)
+        {
+            this.sessionKey = sessionKey;
+            this.cipher_text = cipher_text;
+        }
 
-            public byte[] GetSecret()
-            {
-                CheckDestroyed();
+        public byte[] GetSecret()
+        {
+            CheckDestroyed();
 
-                return Arrays.Clone(sessionKey);
-            }
+            return Arrays.Clone(sessionKey);
+        }
 
-            public byte[] GetEncapsulation()
-            {
-                CheckDestroyed();
+        public byte[] GetEncapsulation()
+        {
+            CheckDestroyed();
 
-                return Arrays.Clone(cipher_text);
-            }
+            return Arrays.Clone(cipher_text);
+        }
 
-            public void Dispose()
+        public void Dispose()
+        {
+            if (!hasBeenDestroyed)
             {
-                if (!hasBeenDestroyed)
-                {
-                    hasBeenDestroyed = true;
-                    Arrays.Clear(sessionKey);
-                    Arrays.Clear(cipher_text);
-                }
+                hasBeenDestroyed = true;
+                Arrays.Clear(sessionKey);
+                Arrays.Clear(cipher_text);
             }
+        }
 
-            public bool IsDestroyed()
-            {
-                return hasBeenDestroyed;
-            }
+        public bool IsDestroyed()
+        {
+            return hasBeenDestroyed;
+        }
 
-            void CheckDestroyed()
+        void CheckDestroyed()
+        {
+            if (IsDestroyed())
             {
-                if (IsDestroyed())
-                {
-                    throw new Exception("data has been destroyed");
-                }
+                throw new Exception("data has been destroyed");
             }
         }
-    
-}
\ No newline at end of file
+    }
+}
diff --git a/crypto/src/pqc/crypto/utils/SubjectPublicKeyInfoFactory.cs b/crypto/src/pqc/crypto/utils/SubjectPublicKeyInfoFactory.cs
index 47cb3e4cb..39d437320 100644
--- a/crypto/src/pqc/crypto/utils/SubjectPublicKeyInfoFactory.cs
+++ b/crypto/src/pqc/crypto/utils/SubjectPublicKeyInfoFactory.cs
@@ -1,9 +1,9 @@
 using System;
 
 using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Pkcs;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
-using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Pqc.Asn1;
 using Org.BouncyCastle.Pqc.Crypto.Bike;
 using Org.BouncyCastle.Pqc.Crypto.Cmce;
@@ -11,6 +11,7 @@ using Org.BouncyCastle.Pqc.Crypto.Crystals.Dilithium;
 using Org.BouncyCastle.Pqc.Crypto.Crystals.Kyber;
 using Org.BouncyCastle.Pqc.Crypto.Falcon;
 using Org.BouncyCastle.Pqc.Crypto.Hqc;
+using Org.BouncyCastle.Pqc.Crypto.Lms;
 using Org.BouncyCastle.Pqc.Crypto.Picnic;
 using Org.BouncyCastle.Pqc.Crypto.Saber;
 using Org.BouncyCastle.Pqc.Crypto.Sike;
@@ -19,161 +20,127 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Pqc.Crypto.Utilities
 {
-    
     /// <summary>
     /// A factory to produce Public Key Info Objects.
     /// </summary>
-    public class SubjectPublicKeyInfoFactory
+    public static class SubjectPublicKeyInfoFactory
     {
-        private SubjectPublicKeyInfoFactory()
-        {
-        }
-
         /// <summary>
         /// Create a Subject Public Key Info object for a given public key.
         /// </summary>
         /// <param name="publicKey">One of ElGammalPublicKeyParameters, DSAPublicKeyParameter, DHPublicKeyParameters, RsaKeyParameters or ECPublicKeyParameters</param>
         /// <returns>A subject public key info object.</returns>
         /// <exception cref="Exception">Throw exception if object provided is not one of the above.</exception>
-        public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo(
-            AsymmetricKeyParameter publicKey)
+        public static SubjectPublicKeyInfo CreateSubjectPublicKeyInfo(AsymmetricKeyParameter publicKey)
         {
             if (publicKey == null)
                 throw new ArgumentNullException("publicKey");
             if (publicKey.IsPrivate)
                 throw new ArgumentException("Private key passed - public key expected.", "publicKey");
-            
-            if (publicKey is SphincsPlusPublicKeyParameters)
+
+            if (publicKey is LmsPublicKeyParameters lmsPublicKeyParameters)
             {
-                SphincsPlusPublicKeyParameters parameters = (SphincsPlusPublicKeyParameters)publicKey;
+                byte[] encoding = Composer.Compose().U32Str(1).Bytes(lmsPublicKeyParameters).Build();
 
-                byte[] encoding = parameters.GetEncoded();
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdAlgHssLmsHashsig);
+                return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding));
+            }
+            if (publicKey is HssPublicKeyParameters hssPublicKeyParameters)
+            {
+                int L = hssPublicKeyParameters.L;
+                byte[] encoding = Composer.Compose().U32Str(L).Bytes(hssPublicKeyParameters.LmsPublicKey).Build();
 
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
-                    PqcUtilities.SphincsPlusOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PkcsObjectIdentifiers.IdAlgHssLmsHashsig);
                 return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding));
             }
-            if (publicKey is CmcePublicKeyParameters)
+            if (publicKey is SphincsPlusPublicKeyParameters sphincsPlusPublicKeyParameters)
             {
-                CmcePublicKeyParameters key = (CmcePublicKeyParameters)publicKey;
+                byte[] encoding = sphincsPlusPublicKeyParameters.GetEncoded();
 
-                byte[] encoding = key.GetEncoded();
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.SphincsPlusOidLookup(sphincsPlusPublicKeyParameters.Parameters));
+                return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding));
+            }
+            if (publicKey is CmcePublicKeyParameters cmcePublicKeyParameters)
+            {
+                byte[] encoding = cmcePublicKeyParameters.GetEncoded();
 
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.McElieceOidLookup(key.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.McElieceOidLookup(cmcePublicKeyParameters.Parameters));
 
                 // https://datatracker.ietf.org/doc/draft-uni-qsckeys/
                 return new SubjectPublicKeyInfo(algorithmIdentifier, new CmcePublicKey(encoding));
             }
-            if (publicKey is SaberPublicKeyParameters)
+            if (publicKey is SaberPublicKeyParameters saberPublicKeyParameters)
             {
-                SaberPublicKeyParameters parameters = (SaberPublicKeyParameters)publicKey;
-
-                byte[] encoding = parameters.GetEncoded();
+                byte[] encoding = saberPublicKeyParameters.GetEncoded();
 
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.SaberOidLookup(parameters.GetParameters()));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.SaberOidLookup(saberPublicKeyParameters.Parameters));
 
                 // https://datatracker.ietf.org/doc/draft-uni-qsckeys/
                 return new SubjectPublicKeyInfo(algorithmIdentifier, new DerSequence(new DerOctetString(encoding)));
             }
-            if (publicKey is PicnicPublicKeyParameters)
+            if (publicKey is PicnicPublicKeyParameters picnicPublicKeyParameters)
             {
-                PicnicPublicKeyParameters parameters = (PicnicPublicKeyParameters)publicKey;
-
-                byte[] encoding = parameters.GetEncoded();
+                byte[] encoding = picnicPublicKeyParameters.GetEncoded();
 
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.PicnicOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.PicnicOidLookup(picnicPublicKeyParameters.Parameters));
                 return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding));
             }
-            if (publicKey is SIKEPublicKeyParameters)
+            if (publicKey is SikePublicKeyParameters sikePublicKeyParameters)
             {
-                SIKEPublicKeyParameters parameters = (SIKEPublicKeyParameters)publicKey;
+                byte[] encoding = sikePublicKeyParameters.GetEncoded();
 
-                byte[] encoding = parameters.GetEncoded();
-
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.SikeOidLookup(parameters.GetParameters()));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.SikeOidLookup(sikePublicKeyParameters.Parameters));
                 return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding));
             }
-            if (publicKey is FalconPublicKeyParameters)
+            if (publicKey is FalconPublicKeyParameters falconPublicKeyParameters)
             {
-                FalconPublicKeyParameters parameters = (FalconPublicKeyParameters)publicKey;
-
-                byte[] encoding = parameters.GetEncoded();
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.FalconOidLookup(parameters.Parameters));
+                byte[] encoding = falconPublicKeyParameters.GetEncoded();
 
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.FalconOidLookup(falconPublicKeyParameters.Parameters));
                 return new SubjectPublicKeyInfo(algorithmIdentifier, new DerSequence(new DerOctetString(encoding)));
             }
-            if (publicKey is KyberPublicKeyParameters)
+            if (publicKey is KyberPublicKeyParameters kyberPublicKeyParameters)
             {
-                KyberPublicKeyParameters parameters = (KyberPublicKeyParameters)publicKey;
-
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.KyberOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.KyberOidLookup(kyberPublicKeyParameters.Parameters));
                 Asn1EncodableVector v = new Asn1EncodableVector();
-                v.Add(new DerOctetString(parameters.T));
-                v.Add(new DerOctetString(parameters.Rho));
+                v.Add(new DerOctetString(kyberPublicKeyParameters.T));
+                v.Add(new DerOctetString(kyberPublicKeyParameters.Rho));
                 return new SubjectPublicKeyInfo(algorithmIdentifier, new DerSequence(v));
             }
-            if (publicKey is DilithiumPublicKeyParameters)
+            if (publicKey is DilithiumPublicKeyParameters dilithiumPublicKeyParameters)
             {
-                DilithiumPublicKeyParameters parameters = (DilithiumPublicKeyParameters)publicKey;
-
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.DilithiumOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.DilithiumOidLookup(dilithiumPublicKeyParameters.Parameters));
             
-                return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(Arrays.Concatenate(parameters.Rho, parameters.T1)));
+                return new SubjectPublicKeyInfo(algorithmIdentifier,
+                    new DerOctetString(Arrays.Concatenate(dilithiumPublicKeyParameters.Rho, dilithiumPublicKeyParameters.T1)));
             }
-            if (publicKey is BikePublicKeyParameters)
+            if (publicKey is BikePublicKeyParameters bikePublicKeyParameters)
             { 
-                BikePublicKeyParameters parameters = (BikePublicKeyParameters)publicKey;
-
-       
-                byte[] encoding = parameters.GetEncoded();
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.BikeOidLookup(parameters.Parameters));
+                byte[] encoding = bikePublicKeyParameters.GetEncoded();
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.BikeOidLookup(bikePublicKeyParameters.Parameters));
 
                 return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding));
             }
-            if (publicKey is HqcPublicKeyParameters)
+            if (publicKey is HqcPublicKeyParameters hqcPublicKeyParameters)
             {
-                HqcPublicKeyParameters parameters = (HqcPublicKeyParameters)publicKey;
-
+                byte[] encoding = hqcPublicKeyParameters.GetEncoded();
 
-                byte[] encoding = parameters.GetEncoded();
-                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(PqcUtilities.HqcOidLookup(parameters.Parameters));
+                AlgorithmIdentifier algorithmIdentifier = new AlgorithmIdentifier(
+                    PqcUtilities.HqcOidLookup(hqcPublicKeyParameters.Parameters));
 
                 return new SubjectPublicKeyInfo(algorithmIdentifier, new DerOctetString(encoding));
             }
 
             throw new ArgumentException("Class provided no convertible: " + Platform.GetTypeName(publicKey));
         }
-        
-        private static void ExtractBytes(
-            byte[]		encKey,
-            int			offset,
-            BigInteger	bI)
-        {
-            byte[] val = bI.ToByteArray();
-            int n = (bI.BitLength + 7) / 8;
-
-            for (int i = 0; i < n; ++i)
-            {
-                encKey[offset + i] = val[val.Length - 1 - i];
-            }
-        }
-
-
-        private static void ExtractBytes(byte[] encKey, int size, int offSet, BigInteger bI)
-        {
-            byte[] val = bI.ToByteArray();
-            if (val.Length < size)
-            {
-                byte[] tmp = new byte[size];
-                Array.Copy(val, 0, tmp, tmp.Length - val.Length, val.Length);
-                val = tmp;
-            }
-
-            for (int i = 0; i != size; i++)
-            {
-                encKey[offSet + i] = val[val.Length - 1 - i];
-            }
-        }
-
     }
-}
\ No newline at end of file
+}
diff --git a/crypto/src/security/CipherUtilities.cs b/crypto/src/security/CipherUtilities.cs
index 8fbf19218..11bf45680 100644
--- a/crypto/src/security/CipherUtilities.cs
+++ b/crypto/src/security/CipherUtilities.cs
@@ -246,7 +246,7 @@ namespace Org.BouncyCastle.Security
 
             Algorithms["GOST"] = "GOST28147";
             Algorithms["GOST-28147"] = "GOST28147";
-            Algorithms[CryptoProObjectIdentifiers.GostR28147Cbc.Id] = "GOST28147/CBC/PKCS7PADDING";
+            Algorithms[CryptoProObjectIdentifiers.GostR28147Gcfb.Id] = "GOST28147/CBC/PKCS7PADDING";
 
             Algorithms["RC5-32"] = "RC5";
 
diff --git a/crypto/src/security/DotNetUtilities.cs b/crypto/src/security/DotNetUtilities.cs
index ccfb2b2b8..3a7c5f0cb 100644
--- a/crypto/src/security/DotNetUtilities.cs
+++ b/crypto/src/security/DotNetUtilities.cs
@@ -18,9 +18,6 @@ namespace Org.BouncyCastle.Security
     /// <summary>
     /// A class containing methods to interface the BouncyCastle world to the .NET Crypto world.
     /// </summary>
-#if NET5_0_OR_GREATER
-    [SupportedOSPlatform("windows")]
-#endif
     public static class DotNetUtilities
     {
         /// <summary>
@@ -153,33 +150,51 @@ namespace Org.BouncyCastle.Security
             throw new ArgumentException("Unsupported algorithm specified", "privateKey");
         }
 
+#if NET5_0_OR_GREATER
+        [SupportedOSPlatform("windows")]
+#endif
         public static RSA ToRSA(RsaKeyParameters rsaKey)
         {
             // TODO This appears to not work for private keys (when no CRT info)
             return CreateRSAProvider(ToRSAParameters(rsaKey));
         }
 
+#if NET5_0_OR_GREATER
+        [SupportedOSPlatform("windows")]
+#endif
         public static RSA ToRSA(RsaKeyParameters rsaKey, CspParameters csp)
         {
             // TODO This appears to not work for private keys (when no CRT info)
             return CreateRSAProvider(ToRSAParameters(rsaKey), csp);
         }
 
+#if NET5_0_OR_GREATER
+        [SupportedOSPlatform("windows")]
+#endif
         public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey)
         {
             return CreateRSAProvider(ToRSAParameters(privKey));
         }
 
+#if NET5_0_OR_GREATER
+        [SupportedOSPlatform("windows")]
+#endif
         public static RSA ToRSA(RsaPrivateCrtKeyParameters privKey, CspParameters csp)
         {
             return CreateRSAProvider(ToRSAParameters(privKey), csp);
         }
 
+#if NET5_0_OR_GREATER
+        [SupportedOSPlatform("windows")]
+#endif
         public static RSA ToRSA(RsaPrivateKeyStructure privKey)
         {
             return CreateRSAProvider(ToRSAParameters(privKey));
         }
 
+#if NET5_0_OR_GREATER
+        [SupportedOSPlatform("windows")]
+#endif
         public static RSA ToRSA(RsaPrivateKeyStructure privKey, CspParameters csp)
         {
             return CreateRSAProvider(ToRSAParameters(privKey), csp);
@@ -229,6 +244,9 @@ namespace Org.BouncyCastle.Security
             return BigIntegers.AsUnsignedByteArray(size, n);
         }
 
+#if NET5_0_OR_GREATER
+        [SupportedOSPlatform("windows")]
+#endif
         private static RSACryptoServiceProvider CreateRSAProvider(RSAParameters rp)
         {
             CspParameters csp = new CspParameters();
@@ -236,6 +254,9 @@ namespace Org.BouncyCastle.Security
             return CreateRSAProvider(rp, csp);
         }
 
+#if NET5_0_OR_GREATER
+        [SupportedOSPlatform("windows")]
+#endif
         private static RSACryptoServiceProvider CreateRSAProvider(RSAParameters rp, CspParameters csp)
         {
             RSACryptoServiceProvider rsaCsp = new RSACryptoServiceProvider(csp);
diff --git a/crypto/src/security/GeneratorUtilities.cs b/crypto/src/security/GeneratorUtilities.cs
index c48a71f2e..26898aaf8 100644
--- a/crypto/src/security/GeneratorUtilities.cs
+++ b/crypto/src/security/GeneratorUtilities.cs
@@ -127,7 +127,7 @@ namespace Org.BouncyCastle.Security
             AddKgAlgorithm("GOST28147",
                 "GOST",
                 "GOST-28147",
-                CryptoProObjectIdentifiers.GostR28147Cbc);
+                CryptoProObjectIdentifiers.GostR28147Gcfb);
             AddKgAlgorithm("HC128");
             AddKgAlgorithm("HC256");
             AddKgAlgorithm("IDEA",
@@ -222,6 +222,8 @@ namespace Org.BouncyCastle.Security
             AddKpgAlgorithm("ECGOST3410",
                 "ECGOST-3410",
                 "GOST-3410-2001");
+            AddKpgAlgorithm("ECGOST3410-2012",
+                "GOST-3410-2012");
             AddKpgAlgorithm("Ed25519",
                 "Ed25519ctx",
                 "Ed25519ph",
@@ -358,7 +360,7 @@ namespace Org.BouncyCastle.Security
             if (canonicalName == "DSA")
                 return new DsaKeyPairGenerator();
 
-            // "EC", "ECDH", "ECDHC", "ECDSA", "ECGOST3410", "ECMQV"
+            // "EC", "ECDH", "ECDHC", "ECDSA", "ECGOST3410", "ECGOST3410-2012", "ECMQV"
             if (Platform.StartsWith(canonicalName, "EC"))
                 return new ECKeyPairGenerator(canonicalName);
 
diff --git a/crypto/src/security/JksStore.cs b/crypto/src/security/JksStore.cs
index 9b4269278..30b21fad2 100644
--- a/crypto/src/security/JksStore.cs
+++ b/crypto/src/security/JksStore.cs
@@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Security
             using (var br = new BinaryReader(stream))
             try
             {
-                return Magic == ReadInt32(br);
+                return Magic == BinaryReaders.ReadInt32BigEndian(br);
             }
             catch (EndOfStreamException)
             {
@@ -154,7 +154,7 @@ namespace Org.BouncyCastle.Security
             byte[] pkcs8Key = PrivateKeyInfoFactory.CreatePrivateKeyInfo(key).GetEncoded();
             byte[] protectedKey = new byte[pkcs8Key.Length + 40];
 
-            SecureRandom rnd = new SecureRandom();
+            SecureRandom rnd = CryptoServicesRegistrar.GetSecureRandom();
             rnd.NextBytes(protectedKey, 0, 20);
 
             IDigest digest = DigestUtilities.GetDigest("SHA-1");
@@ -263,24 +263,24 @@ namespace Org.BouncyCastle.Security
             IDigest checksumDigest = CreateChecksumDigest(password);
             BinaryWriter bw = new BinaryWriter(new DigestStream(stream, null, checksumDigest));
 
-            WriteInt32(bw, Magic);
-            WriteInt32(bw, 2);
+            BinaryWriters.WriteInt32BigEndian(bw, Magic);
+            BinaryWriters.WriteInt32BigEndian(bw, 2);
 
-            WriteInt32(bw, Count);
+            BinaryWriters.WriteInt32BigEndian(bw, Count);
 
             foreach (var entry in m_keyEntries)
             {
                 string alias = entry.Key;
                 JksKeyEntry keyEntry = entry.Value;
 
-                WriteInt32(bw, 1);
+                BinaryWriters.WriteInt32BigEndian(bw, 1);
                 WriteUtf(bw, alias);
                 WriteDateTime(bw, keyEntry.date);
-                WriteBufferWithLength(bw, keyEntry.keyData.GetEncoded());
+                WriteBufferWithInt32Length(bw, keyEntry.keyData.GetEncoded());
 
                 X509Certificate[] chain = keyEntry.chain;
                 int chainLength = chain == null ? 0 : chain.Length;
-                WriteInt32(bw, chainLength);
+                BinaryWriters.WriteInt32BigEndian(bw, chainLength);
                 for (int i = 0; i < chainLength; ++i)
                 {
                     WriteTypedCertificate(bw, chain[i]);
@@ -292,7 +292,7 @@ namespace Org.BouncyCastle.Security
                 string alias = entry.Key;
                 JksTrustedCertEntry certEntry = entry.Value;
 
-                WriteInt32(bw, 2);
+                BinaryWriters.WriteInt32BigEndian(bw, 2);
                 WriteUtf(bw, alias);
                 WriteDateTime(bw, certEntry.date);
                 WriteTypedCertificate(bw, certEntry.cert);
@@ -314,39 +314,39 @@ namespace Org.BouncyCastle.Security
 
             using (var storeStream = ValidateStream(stream, password))
             {
-                BinaryReader dIn = new BinaryReader(storeStream);
+                BinaryReader br = new BinaryReader(storeStream);
 
-                int magic = ReadInt32(dIn);
-                int storeVersion = ReadInt32(dIn);
+                int magic = BinaryReaders.ReadInt32BigEndian(br);
+                int storeVersion = BinaryReaders.ReadInt32BigEndian(br);
 
                 if (!(magic == Magic && (storeVersion == 1 || storeVersion == 2)))
                     throw new IOException("Invalid keystore format");
 
-                int numEntries = ReadInt32(dIn);
+                int numEntries = BinaryReaders.ReadInt32BigEndian(br);
 
                 for (int t = 0; t < numEntries; t++)
                 {
-                    int tag = ReadInt32(dIn);
+                    int tag = BinaryReaders.ReadInt32BigEndian(br);
 
                     switch (tag)
                     {
                     case 1: // keys
                     {
-                        string alias = ReadUtf(dIn);
-                        DateTime date = ReadDateTime(dIn);
+                        string alias = ReadUtf(br);
+                        DateTime date = ReadDateTime(br);
 
                         // encrypted key data
-                        byte[] keyData = ReadBufferWithLength(dIn);
+                        byte[] keyData = ReadBufferWithInt32Length(br);
 
                         // certificate chain
-                        int chainLength = ReadInt32(dIn);
+                        int chainLength = BinaryReaders.ReadInt32BigEndian(br);
                         X509Certificate[] chain = null;
                         if (chainLength > 0)
                         {
                             var certs = new List<X509Certificate>(System.Math.Min(10, chainLength));
                             for (int certNo = 0; certNo != chainLength; certNo++)
                             {
-                                certs.Add(ReadTypedCertificate(dIn, storeVersion));
+                                certs.Add(ReadTypedCertificate(br, storeVersion));
                             }
                             chain = certs.ToArray();
                         }
@@ -355,10 +355,10 @@ namespace Org.BouncyCastle.Security
                     }
                     case 2: // certificate
                     {
-                        string alias = ReadUtf(dIn);
-                        DateTime date = ReadDateTime(dIn);
+                        string alias = ReadUtf(br);
+                        DateTime date = ReadDateTime(br);
 
-                        X509Certificate cert = ReadTypedCertificate(dIn, storeVersion);
+                        X509Certificate cert = ReadTypedCertificate(br, storeVersion);
 
                         m_certificateEntries.Add(alias, new JksTrustedCertEntry(date, cert));
                         break;
@@ -446,29 +446,22 @@ namespace Org.BouncyCastle.Security
             return digest;
         }
 
-        private static byte[] ReadBufferWithLength(BinaryReader br)
+        private static byte[] ReadBufferWithInt16Length(BinaryReader br)
         {
-            int length = ReadInt32(br);
-            return br.ReadBytes(length);
+            int length = BinaryReaders.ReadInt16BigEndian(br);
+            return BinaryReaders.ReadBytesFully(br, length);
         }
 
-        private static DateTime ReadDateTime(BinaryReader br)
-        {
-            DateTime unixMs = DateTimeUtilities.UnixMsToDateTime(Longs.ReverseBytes(br.ReadInt64()));
-            DateTime utc = new DateTime(unixMs.Ticks, DateTimeKind.Utc);
-            return utc;
-        }
-
-        private static short ReadInt16(BinaryReader br)
+        private static byte[] ReadBufferWithInt32Length(BinaryReader br)
         {
-            short n = br.ReadInt16();
-            n = (short)(((n & 0xFF) << 8) | ((n >> 8) & 0xFF));
-            return n;
+            int length = BinaryReaders.ReadInt32BigEndian(br);
+            return BinaryReaders.ReadBytesFully(br, length);
         }
 
-        private static int ReadInt32(BinaryReader br)
+        private static DateTime ReadDateTime(BinaryReader br)
         {
-            return Integers.ReverseBytes(br.ReadInt32());
+            long unixMS = BinaryReaders.ReadInt64BigEndian(br);
+            return DateTimeUtilities.UnixMsToDateTime(unixMS);
         }
 
         private static X509Certificate ReadTypedCertificate(BinaryReader br, int storeVersion)
@@ -480,7 +473,7 @@ namespace Org.BouncyCastle.Security
                     throw new IOException("Unsupported certificate format: " + certFormat);
             }
 
-            byte[] certData = ReadBufferWithLength(br);
+            byte[] certData = ReadBufferWithInt32Length(br);
             try
             {
                 return new X509Certificate(certData);
@@ -493,8 +486,7 @@ namespace Org.BouncyCastle.Security
 
         private static string ReadUtf(BinaryReader br)
         {
-            short length = ReadInt16(br);
-            byte[] utfBytes = br.ReadBytes(length);
+            byte[] utfBytes = ReadBufferWithInt16Length(br);
 
             /*
              * FIXME JKS actually uses a "modified UTF-8" format. For the moment we will just support single-byte
@@ -510,32 +502,28 @@ namespace Org.BouncyCastle.Security
             return Encoding.UTF8.GetString(utfBytes);
         }
 
-        private static void WriteBufferWithLength(BinaryWriter bw, byte[] buffer)
+        private static void WriteBufferWithInt16Length(BinaryWriter bw, byte[] buffer)
         {
-            WriteInt32(bw, buffer.Length);
+            BinaryWriters.WriteInt16BigEndian(bw, Convert.ToInt16(buffer.Length));
             bw.Write(buffer);
         }
 
-        private static void WriteDateTime(BinaryWriter bw, DateTime dateTime)
+        private static void WriteBufferWithInt32Length(BinaryWriter bw, byte[] buffer)
         {
-            bw.Write(Longs.ReverseBytes(DateTimeUtilities.DateTimeToUnixMs(dateTime.ToUniversalTime())));
-        }
-
-        private static void WriteInt16(BinaryWriter bw, short n)
-        {
-            n = (short)(((n & 0xFF) << 8) | ((n >> 8) & 0xFF));
-            bw.Write(n);
+            BinaryWriters.WriteInt32BigEndian(bw, buffer.Length);
+            bw.Write(buffer);
         }
 
-        private static void WriteInt32(BinaryWriter bw, int n)
+        private static void WriteDateTime(BinaryWriter bw, DateTime dateTime)
         {
-            bw.Write(Integers.ReverseBytes(n));
+            long unixMS = DateTimeUtilities.DateTimeToUnixMs(dateTime);
+            BinaryWriters.WriteInt64BigEndian(bw, unixMS);
         }
 
         private static void WriteTypedCertificate(BinaryWriter bw, X509Certificate cert)
         {
             WriteUtf(bw, "X.509");
-            WriteBufferWithLength(bw, cert.GetEncoded());
+            WriteBufferWithInt32Length(bw, cert.GetEncoded());
         }
 
         private static void WriteUtf(BinaryWriter bw, string s)
@@ -553,8 +541,7 @@ namespace Org.BouncyCastle.Security
                     throw new NotSupportedException("Currently missing support for modified UTF-8 encoding in JKS");
             }
 
-            WriteInt16(bw, Convert.ToInt16(utfBytes.Length));
-            bw.Write(utfBytes);
+            WriteBufferWithInt16Length(bw, utfBytes);
         }
 
         /**
diff --git a/crypto/src/security/ParameterUtilities.cs b/crypto/src/security/ParameterUtilities.cs
index 5a407fc9d..d79f15359 100644
--- a/crypto/src/security/ParameterUtilities.cs
+++ b/crypto/src/security/ParameterUtilities.cs
@@ -118,7 +118,7 @@ namespace Org.BouncyCastle.Security
             AddAlgorithm("GOST28147",
                 "GOST",
                 "GOST-28147",
-                CryptoProObjectIdentifiers.GostR28147Cbc);
+                CryptoProObjectIdentifiers.GostR28147Gcfb);
             AddAlgorithm("HC128");
             AddAlgorithm("HC256");
             AddAlgorithm("IDEA",
diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs
index 10b837b03..521e7db0e 100644
--- a/crypto/src/security/SecureRandom.cs
+++ b/crypto/src/security/SecureRandom.cs
@@ -17,7 +17,8 @@ namespace Org.BouncyCastle.Security
             return Interlocked.Increment(ref counter);
         }
 
-        private static readonly SecureRandom Master = new SecureRandom(new CryptoApiRandomGenerator());
+        private static readonly SecureRandom MasterRandom = new SecureRandom(new CryptoApiRandomGenerator());
+        internal static readonly SecureRandom ArbitraryRandom = new SecureRandom(new VmpcRandomGenerator(), 16);
 
         private static DigestRandomGenerator CreatePrng(string digestName, bool autoSeed)
         {
@@ -27,18 +28,7 @@ namespace Org.BouncyCastle.Security
             DigestRandomGenerator prng = new DigestRandomGenerator(digest);
             if (autoSeed)
             {
-                prng.AddSeedMaterial(NextCounterValue());
-
-                int seedLength = digest.GetDigestSize();
-#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
-                Span<byte> seed = seedLength <= 128
-                    ? stackalloc byte[seedLength]
-                    : new byte[seedLength];
-#else
-                byte[] seed = new byte[seedLength];
-#endif
-                Master.NextBytes(seed);
-                prng.AddSeedMaterial(seed);
+                AutoSeed(prng, digest.GetDigestSize());
             }
             return prng;
         }
@@ -103,15 +93,23 @@ namespace Org.BouncyCastle.Security
             this.generator = generator;
         }
 
+        public SecureRandom(IRandomGenerator generator, int autoSeedLengthInBytes)
+            : base(0)
+        {
+            AutoSeed(generator, autoSeedLengthInBytes);
+
+            this.generator = generator;
+        }
+
         public virtual byte[] GenerateSeed(int length)
         {
-            return GetNextBytes(Master, length);
+            return GetNextBytes(MasterRandom, length);
         }
 
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public virtual void GenerateSeed(Span<byte> seed)
         {
-            Master.NextBytes(seed);
+            MasterRandom.NextBytes(seed);
         }
 #endif
 
@@ -246,5 +244,20 @@ namespace Org.BouncyCastle.Security
             NextBytes(bytes);
             return (long)Pack.BE_To_UInt64(bytes);
         }
+
+        private static void AutoSeed(IRandomGenerator generator, int seedLength)
+        {
+            generator.AddSeedMaterial(NextCounterValue());
+
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            Span<byte> seed = seedLength <= 128
+                ? stackalloc byte[seedLength]
+                : new byte[seedLength];
+#else
+                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 e42e217cc..e6210dad7 100644
--- a/crypto/src/security/SignerUtilities.cs
+++ b/crypto/src/security/SignerUtilities.cs
@@ -19,6 +19,7 @@ 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
 {
@@ -367,13 +368,29 @@ namespace Org.BouncyCastle.Security
             AlgorithmMap["GOST-3410"] = "GOST3410";
             AlgorithmMap["GOST-3410-94"] = "GOST3410";
             AlgorithmMap["GOST3411WITHGOST3410"] = "GOST3410";
+            AlgorithmMap["GOST3411/GOST3410"] = "GOST3410";
             AlgorithmMap[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94.Id] = "GOST3410";
 
             AlgorithmMap["ECGOST-3410"] = "ECGOST3410";
-            AlgorithmMap["ECGOST-3410-2001"] = "ECGOST3410";
+            AlgorithmMap["GOST-3410-2001"] = "ECGOST3410";
             AlgorithmMap["GOST3411WITHECGOST3410"] = "ECGOST3410";
+            AlgorithmMap["GOST3411/ECGOST3410"] = "ECGOST3410";
             AlgorithmMap[CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001.Id] = "ECGOST3410";
 
+            AlgorithmMap["GOST-3410-2012-256"] = "ECGOST3410-2012-256";
+            AlgorithmMap["GOST3411WITHECGOST3410-2012-256"] = "ECGOST3410-2012-256";
+            AlgorithmMap["GOST3411-2012-256WITHECGOST3410-2012-256"] = "ECGOST3410-2012-256";
+            AlgorithmMap["GOST3411-2012-256/ECGOST3410-2012-256"] = "ECGOST3410-2012-256";
+            AlgorithmMap[RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256.Id] =
+                "ECGOST3410-2012-256";
+
+            AlgorithmMap["GOST-3410-2012-512"] = "ECGOST3410-2012-512";
+            AlgorithmMap["GOST3411WITHECGOST3410-2012-512"] = "ECGOST3410-2012-512";
+            AlgorithmMap["GOST3411-2012-512WITHECGOST3410-2012-512"] = "ECGOST3410-2012-512";
+            AlgorithmMap["GOST3411-2012-512/ECGOST3410-2012-512"] = "ECGOST3410-2012-512";
+            AlgorithmMap[RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512.Id] =
+                "ECGOST3410-2012-512";
+
             AlgorithmMap["ED25519"] = "Ed25519";
             AlgorithmMap[EdECObjectIdentifiers.id_Ed25519.Id] = "Ed25519";
             AlgorithmMap["ED25519CTX"] = "Ed25519ctx";
@@ -439,6 +456,9 @@ namespace Org.BouncyCastle.Security
             Oids["GOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94;
             Oids["ECGOST3410"] = CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001;
 
+            Oids["ECGOST3410-2012-256"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_256;
+            Oids["ECGOST3410-2012-512"] = RosstandartObjectIdentifiers.id_tc26_signwithdigest_gost_3410_12_512;
+
             Oids["Ed25519"] = EdECObjectIdentifiers.id_Ed25519;
             Oids["Ed448"] = EdECObjectIdentifiers.id_Ed448;
 
@@ -618,6 +638,14 @@ namespace Org.BouncyCastle.Security
             {
                 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"))
             {
diff --git a/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs b/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs
index 66f47c091..8e193f187 100644
--- a/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs
+++ b/crypto/src/tls/crypto/impl/bc/BcTlsCrypto.cs
@@ -28,12 +28,15 @@ namespace Org.BouncyCastle.Tls.Crypto.Impl.BC
         private readonly SecureRandom m_entropySource;
 
         public BcTlsCrypto()
-            : this(new SecureRandom())
+            : this(CryptoServicesRegistrar.GetSecureRandom())
         {
         }
 
         public BcTlsCrypto(SecureRandom entropySource)
         {
+            if (entropySource == null)
+                throw new ArgumentNullException(nameof(entropySource));
+
             this.m_entropySource = entropySource;
         }
 
diff --git a/crypto/src/tsp/TimeStampTokenGenerator.cs b/crypto/src/tsp/TimeStampTokenGenerator.cs
index 79b8c6a3a..9e6a21f9c 100644
--- a/crypto/src/tsp/TimeStampTokenGenerator.cs
+++ b/crypto/src/tsp/TimeStampTokenGenerator.cs
@@ -334,21 +334,18 @@ namespace Org.BouncyCastle.Tsp
                 respExtensions = extGen.Generate();
             }
 
-
-
-            DerGeneralizedTime generalizedTime;
-            if (resolution != Resolution.R_SECONDS)
+            Asn1GeneralizedTime timeStampTime;
+            if (resolution == Resolution.R_SECONDS)
             {
-                generalizedTime = new DerGeneralizedTime(createGeneralizedTime(genTime));
-            } 
+                timeStampTime = new Asn1GeneralizedTime(genTime);
+            }
             else
             {
-                generalizedTime = new DerGeneralizedTime(genTime);
-            }
-
+                timeStampTime = CreateGeneralizedTime(genTime);
+            } 
 
             TstInfo tstInfo = new TstInfo(tsaPolicy, messageImprint,
-                new DerInteger(serialNumber), generalizedTime, accuracy,
+                new DerInteger(serialNumber), timeStampTime, accuracy,
                 derOrdering, nonce, tsa, respExtensions);
 
             try
@@ -382,13 +379,13 @@ namespace Org.BouncyCastle.Tsp
             {
                 throw new TspException("Exception encoding info", e);
             }
-            //			catch (InvalidAlgorithmParameterException e)
-            //			{
-            //				throw new TspException("Exception handling CertStore CRLs", e);
-            //			}
+            //catch (InvalidAlgorithmParameterException e)
+            //{
+            //    throw new TspException("Exception handling CertStore CRLs", e);
+            //}
         }
 
-        private string createGeneralizedTime(DateTime genTime)
+        private Asn1GeneralizedTime CreateGeneralizedTime(DateTime genTime)
         {
             string format = "yyyyMMddHHmmss.fff";
            
@@ -398,33 +395,31 @@ namespace Org.BouncyCastle.Tsp
             if (dotIndex <0)
             {
                 sBuild.Append("Z");
-                return sBuild.ToString();
+                return new Asn1GeneralizedTime(sBuild.ToString());
             }
 
             switch(resolution)
             {
-                case Resolution.R_TENTHS_OF_SECONDS:
-                    if (sBuild.Length > dotIndex + 2)
-                    {
-                        sBuild.Remove(dotIndex + 2, sBuild.Length-(dotIndex+2));
-                    }
-                    break;
-                case Resolution.R_HUNDREDTHS_OF_SECONDS:
-                    if (sBuild.Length > dotIndex + 3)
-                    {
-                        sBuild.Remove(dotIndex + 3, sBuild.Length-(dotIndex+3));
-                    }
-                    break;
+            case Resolution.R_TENTHS_OF_SECONDS:
+                if (sBuild.Length > dotIndex + 2)
+                {
+                    sBuild.Remove(dotIndex + 2, sBuild.Length-(dotIndex+2));
+                }
+                break;
+            case Resolution.R_HUNDREDTHS_OF_SECONDS:
+                if (sBuild.Length > dotIndex + 3)
+                {
+                    sBuild.Remove(dotIndex + 3, sBuild.Length-(dotIndex+3));
+                }
+                break;
 
 
-                case Resolution.R_SECONDS:
-                case Resolution.R_MILLISECONDS:
-                    // do nothing.
-                    break;
-             
+            case Resolution.R_SECONDS:
+            case Resolution.R_MILLISECONDS:
+                // do nothing.
+                break;
             }
 
-           
             while (sBuild[sBuild.Length - 1] == '0')
             {
                 sBuild.Remove(sBuild.Length - 1,1);
@@ -436,7 +431,7 @@ namespace Org.BouncyCastle.Tsp
             }
 
             sBuild.Append("Z");
-            return sBuild.ToString();
+            return new Asn1GeneralizedTime(sBuild.ToString());
         }
 
         private class TableGen
diff --git a/crypto/src/util/Arrays.cs b/crypto/src/util/Arrays.cs
index e8dd02148..936e510be 100644
--- a/crypto/src/util/Arrays.cs
+++ b/crypto/src/util/Arrays.cs
@@ -631,10 +631,7 @@ namespace Org.BouncyCastle.Utilities
 #if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
         public static void Fill<T>(Span<T> ts, T t)
         {
-            for (int i = 0; i < ts.Length; ++i)
-            {
-                ts[i] = t;
-            }
+            ts.Fill(t);
         }
 #endif
 
diff --git a/crypto/src/util/BigIntegers.cs b/crypto/src/util/BigIntegers.cs
index 93dc8e8eb..e63af7c7c 100644
--- a/crypto/src/util/BigIntegers.cs
+++ b/crypto/src/util/BigIntegers.cs
@@ -9,7 +9,7 @@ namespace Org.BouncyCastle.Utilities
     /**
      * BigInteger utilities.
      */
-    public abstract class BigIntegers
+    public static class BigIntegers
     {
         public static readonly BigInteger Zero = BigInteger.Zero;
         public static readonly BigInteger One = BigInteger.One;
diff --git a/crypto/src/util/Bytes.cs b/crypto/src/util/Bytes.cs
index ecde85dde..466eba576 100644
--- a/crypto/src/util/Bytes.cs
+++ b/crypto/src/util/Bytes.cs
@@ -2,7 +2,7 @@
 
 namespace Org.BouncyCastle.Utilities
 {
-    public abstract class Bytes
+    public static class Bytes
     {
         public const int NumBits = 8;
         public const int NumBytes = 1;
diff --git a/crypto/src/util/Integers.cs b/crypto/src/util/Integers.cs
index 75ba566e3..ab1868b74 100644
--- a/crypto/src/util/Integers.cs
+++ b/crypto/src/util/Integers.cs
@@ -1,4 +1,7 @@
 using System;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+using System.Buffers.Binary;
+#endif
 #if NETCOREAPP3_0_OR_GREATER
 using System.Numerics;
 using System.Runtime.Intrinsics.X86;
@@ -8,7 +11,7 @@ using Org.BouncyCastle.Math.Raw;
 
 namespace Org.BouncyCastle.Utilities
 {
-    public abstract class Integers
+    public static class Integers
     {
         public const int NumBits = 32;
         public const int NumBytes = 4;
@@ -96,14 +99,22 @@ namespace Org.BouncyCastle.Utilities
 
         public static int ReverseBytes(int i)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return BinaryPrimitives.ReverseEndianness(i);
+#else
             return (int)ReverseBytes((uint)i);
+#endif
         }
 
         [CLSCompliant(false)]
         public static uint ReverseBytes(uint i)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return BinaryPrimitives.ReverseEndianness(i);
+#else
             return RotateLeft(i & 0xFF00FF00U,  8) |
                    RotateLeft(i & 0x00FF00FFU, 24);
+#endif
         }
 
         public static int RotateLeft(int i, int distance)
diff --git a/crypto/src/util/Longs.cs b/crypto/src/util/Longs.cs
index 9e34dab99..02ffb7676 100644
--- a/crypto/src/util/Longs.cs
+++ b/crypto/src/util/Longs.cs
@@ -1,4 +1,7 @@
 using System;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+using System.Buffers.Binary;
+#endif
 #if NETCOREAPP3_0_OR_GREATER
 using System.Numerics;
 using System.Runtime.Intrinsics.X86;
@@ -8,7 +11,7 @@ using Org.BouncyCastle.Math.Raw;
 
 namespace Org.BouncyCastle.Utilities
 {
-    public abstract class Longs
+    public static class Longs
     {
         public const int NumBits = 64;
         public const int NumBytes = 8;
@@ -95,16 +98,24 @@ namespace Org.BouncyCastle.Utilities
 
         public static long ReverseBytes(long i)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return BinaryPrimitives.ReverseEndianness(i);
+#else
             return (long)ReverseBytes((ulong)i);
+#endif
         }
 
         [CLSCompliant(false)]
         public static ulong ReverseBytes(ulong i)
         {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return BinaryPrimitives.ReverseEndianness(i);
+#else
             return RotateLeft(i & 0xFF000000FF000000UL,  8) |
                    RotateLeft(i & 0x00FF000000FF0000UL, 24) |
                    RotateLeft(i & 0x0000FF000000FF00UL, 40) |
                    RotateLeft(i & 0x000000FF000000FFUL, 56);
+#endif
         }
 
         public static long RotateLeft(long i, int distance)
diff --git a/crypto/src/util/Platform.cs b/crypto/src/util/Platform.cs
index 75b728bd9..118c29918 100644
--- a/crypto/src/util/Platform.cs
+++ b/crypto/src/util/Platform.cs
@@ -3,7 +3,7 @@ using System.Globalization;
 
 namespace Org.BouncyCastle.Utilities
 {
-    internal abstract class Platform
+    internal static class Platform
     {
         private static readonly CompareInfo InvariantCompareInfo = CultureInfo.InvariantCulture.CompareInfo;
 
diff --git a/crypto/src/util/Shorts.cs b/crypto/src/util/Shorts.cs
new file mode 100644
index 000000000..eb9f13fa1
--- /dev/null
+++ b/crypto/src/util/Shorts.cs
@@ -0,0 +1,54 @@
+using System;
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+using System.Buffers.Binary;
+#endif
+
+namespace Org.BouncyCastle.Utilities
+{
+    public static class Shorts
+    {
+        public const int NumBits = 16;
+        public const int NumBytes = 2;
+
+        public static short ReverseBytes(short i)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return BinaryPrimitives.ReverseEndianness(i);
+#else
+            return RotateLeft(i, 8);
+#endif
+        }
+
+        [CLSCompliant(false)]
+        public static ushort ReverseBytes(ushort i)
+        {
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+            return BinaryPrimitives.ReverseEndianness(i);
+#else
+            return RotateLeft(i, 8);
+#endif
+        }
+
+        public static short RotateLeft(short i, int distance)
+        {
+            return (short)RotateLeft((ushort)i, distance);
+        }
+
+        [CLSCompliant(false)]
+        public static ushort RotateLeft(ushort i, int distance)
+        {
+            return (ushort)((i << distance) | (i >> (16 - distance)));
+        }
+
+        public static short RotateRight(short i, int distance)
+        {
+            return (short)RotateRight((ushort)i, distance);
+        }
+
+        [CLSCompliant(false)]
+        public static ushort RotateRight(ushort i, int distance)
+        {
+            return (ushort)((i >> distance) | (i << (16 - distance)));
+        }
+    }
+}
diff --git a/crypto/src/util/Strings.cs b/crypto/src/util/Strings.cs
index baee573be..12eafd21e 100644
--- a/crypto/src/util/Strings.cs
+++ b/crypto/src/util/Strings.cs
@@ -4,7 +4,7 @@ using System.Text;
 namespace Org.BouncyCastle.Utilities
 {
     /// <summary> General string utilities.</summary>
-    public abstract class Strings
+    public static class Strings
     {
         internal static bool IsOneOf(string s, params string[] candidates)
         {
diff --git a/crypto/src/bzip2/BZip2Constants.cs b/crypto/src/util/bzip2/BZip2Constants.cs
index 81db7fa57..6fc15e55f 100644
--- a/crypto/src/bzip2/BZip2Constants.cs
+++ b/crypto/src/util/bzip2/BZip2Constants.cs
@@ -22,9 +22,7 @@
  * great code.
  */
 
-using System;
-
-namespace Org.BouncyCastle.Bzip2
+namespace Org.BouncyCastle.Utilities.Bzip2
 {
     /**
     * Base class for both the compress and decompress classes.
diff --git a/crypto/src/bzip2/CBZip2InputStream.cs b/crypto/src/util/bzip2/CBZip2InputStream.cs
index b73e52a01..7879f28af 100644
--- a/crypto/src/bzip2/CBZip2InputStream.cs
+++ b/crypto/src/util/bzip2/CBZip2InputStream.cs
@@ -26,10 +26,9 @@ using System;
 using System.Diagnostics;
 using System.IO;
 
-using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.IO;
 
-namespace Org.BouncyCastle.Bzip2
+namespace Org.BouncyCastle.Utilities.Bzip2
 {
 	/**
     * An input stream that decompresses from the BZip2 format (with the file
diff --git a/crypto/src/bzip2/CBZip2OutputStream.cs b/crypto/src/util/bzip2/CBZip2OutputStream.cs
index 5521dce56..b896f36c6 100644
--- a/crypto/src/bzip2/CBZip2OutputStream.cs
+++ b/crypto/src/util/bzip2/CBZip2OutputStream.cs
@@ -27,10 +27,9 @@ using System.Collections.Generic;
 using System.Diagnostics;
 using System.IO;
 
-using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.IO;
 
-namespace Org.BouncyCastle.Bzip2
+namespace Org.BouncyCastle.Utilities.Bzip2
 {
 	/**
     * An output stream that compresses into the BZip2 format (with the file
@@ -1598,4 +1597,23 @@ namespace Org.BouncyCastle.Bzip2
             return a;
         }
     }
+
+    public class CBZip2OutputStreamLeaveOpen
+        : CBZip2OutputStream
+    {
+        public CBZip2OutputStreamLeaveOpen(Stream outStream)
+            : base(outStream)
+        {
+        }
+
+        public CBZip2OutputStreamLeaveOpen(Stream outStream, int blockSize)
+            : base(outStream, blockSize)
+        {
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            Detach(disposing);
+        }
+    }
 }
diff --git a/crypto/src/bzip2/CRC.cs b/crypto/src/util/bzip2/CRC.cs
index 70d05e084..30c7e9c7d 100644
--- a/crypto/src/bzip2/CRC.cs
+++ b/crypto/src/util/bzip2/CRC.cs
@@ -22,12 +22,9 @@
  * great code.
  */
 
-using System;
 using System.Diagnostics;
 
-using Org.BouncyCastle.Utilities;
-
-namespace Org.BouncyCastle.Bzip2
+namespace Org.BouncyCastle.Utilities.Bzip2
 {
     /**
     * A simple class the hold and calculate the CRC for sanity checking
diff --git a/crypto/src/util/date/DateTimeUtilities.cs b/crypto/src/util/date/DateTimeUtilities.cs
index 72e5123a2..3660e29c2 100644
--- a/crypto/src/util/date/DateTimeUtilities.cs
+++ b/crypto/src/util/date/DateTimeUtilities.cs
@@ -2,38 +2,48 @@ using System;
 
 namespace Org.BouncyCastle.Utilities.Date
 {
-	public class DateTimeUtilities
+	public static class DateTimeUtilities
 	{
-		public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+#if NETCOREAPP2_1_OR_GREATER || NETSTANDARD2_1_OR_GREATER
+        public static readonly DateTime UnixEpoch = DateTime.UnixEpoch;
+#else
+        public static readonly DateTime UnixEpoch = new DateTime(1970, 1, 1, 0, 0, 0, DateTimeKind.Utc);
+#endif
 
-		private DateTimeUtilities()
-		{
-		}
+        public static readonly long MaxUnixMs =
+            (DateTime.MaxValue.Ticks - UnixEpoch.Ticks) / TimeSpan.TicksPerMillisecond;
+        public static readonly long MinUnixMs = 0L;
 
-		/// <summary>
-		/// Return the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC) for a given DateTime value.
-		/// </summary>
-		/// <param name="dateTime">A UTC DateTime value not before epoch.</param>
-		/// <returns>Number of whole milliseconds after epoch.</returns>
-		/// <exception cref="ArgumentException">'dateTime' is before epoch.</exception>
-		public static long DateTimeToUnixMs(
-			DateTime dateTime)
+        /// <summary>
+        /// Return the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC) for a given DateTime value.
+        /// </summary>
+        /// <remarks>The DateTime value will be converted to UTC (using <see cref="DateTime.ToUniversalTime"/> before
+        /// conversion.</remarks>
+        /// <param name="dateTime">A DateTime value not before the epoch.</param>
+        /// <returns>Number of whole milliseconds after epoch.</returns>
+        /// <exception cref="ArgumentOutOfRangeException">'dateTime' is before the epoch.</exception>
+        public static long DateTimeToUnixMs(DateTime dateTime)
 		{
-			if (dateTime.CompareTo(UnixEpoch) < 0)
-				throw new ArgumentException("DateTime value may not be before the epoch", "dateTime");
+            DateTime utc = dateTime.ToUniversalTime();
+            if (utc.CompareTo(UnixEpoch) < 0)
+				throw new ArgumentOutOfRangeException(nameof(dateTime), "DateTime value may not be before the epoch");
 
-			return (dateTime.Ticks - UnixEpoch.Ticks) / TimeSpan.TicksPerMillisecond;
+			return (utc.Ticks - UnixEpoch.Ticks) / TimeSpan.TicksPerMillisecond;
 		}
 
-		/// <summary>
-		/// Create a DateTime value from the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC).
-		/// </summary>
-		/// <param name="unixMs">Number of milliseconds since the epoch.</param>
-		/// <returns>A UTC DateTime value</returns>
-		public static DateTime UnixMsToDateTime(
-			long unixMs)
+        /// <summary>
+        /// Create a UTC DateTime value from the number of milliseconds since the Unix epoch (1 Jan., 1970 UTC).
+        /// </summary>
+        /// <param name="unixMs">Number of milliseconds since the epoch.</param>
+        /// <returns>A UTC DateTime value</returns>
+        /// <exception cref="ArgumentOutOfRangeException">'unixMs' is before 'MinUnixMs' or after 'MaxUnixMs'.
+        /// </exception>
+        public static DateTime UnixMsToDateTime(long unixMs)
 		{
-			return new DateTime(unixMs * TimeSpan.TicksPerMillisecond + UnixEpoch.Ticks, DateTimeKind.Utc);
+			if (unixMs < MinUnixMs || unixMs > MaxUnixMs)
+				throw new ArgumentOutOfRangeException(nameof(unixMs));
+
+            return new DateTime(unixMs * TimeSpan.TicksPerMillisecond + UnixEpoch.Ticks, DateTimeKind.Utc);
 		}
 
 		/// <summary>
diff --git a/crypto/src/util/io/BinaryReaders.cs b/crypto/src/util/io/BinaryReaders.cs
new file mode 100644
index 000000000..c5f99a712
--- /dev/null
+++ b/crypto/src/util/io/BinaryReaders.cs
@@ -0,0 +1,94 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public static class BinaryReaders
+    {
+        public static byte[] ReadBytesFully(BinaryReader binaryReader, int count)
+        {
+            byte[] bytes = binaryReader.ReadBytes(count);
+            if (bytes == null || bytes.Length != count)
+                throw new EndOfStreamException();
+            return bytes;
+        }
+
+        public static short ReadInt16BigEndian(BinaryReader binaryReader)
+        {
+            short n = binaryReader.ReadInt16();
+            return BitConverter.IsLittleEndian ? Shorts.ReverseBytes(n) : n;
+        }
+
+        public static short ReadInt16LittleEndian(BinaryReader binaryReader)
+        {
+            short n = binaryReader.ReadInt16();
+            return BitConverter.IsLittleEndian ? n : Shorts.ReverseBytes(n);
+        }
+
+        public static int ReadInt32BigEndian(BinaryReader binaryReader)
+        {
+            int n = binaryReader.ReadInt32();
+            return BitConverter.IsLittleEndian ? Integers.ReverseBytes(n) : n;
+        }
+
+        public static int ReadInt32LittleEndian(BinaryReader binaryReader)
+        {
+            int n = binaryReader.ReadInt32();
+            return BitConverter.IsLittleEndian ? n : Integers.ReverseBytes(n);
+        }
+
+        public static long ReadInt64BigEndian(BinaryReader binaryReader)
+        {
+            long n = binaryReader.ReadInt64();
+            return BitConverter.IsLittleEndian ? Longs.ReverseBytes(n) : n;
+        }
+
+        public static long ReadInt64LittleEndian(BinaryReader binaryReader)
+        {
+            long n = binaryReader.ReadInt64();
+            return BitConverter.IsLittleEndian ? n : Longs.ReverseBytes(n);
+        }
+
+        [CLSCompliant(false)]
+        public static ushort ReadUInt16BigEndian(BinaryReader binaryReader)
+        {
+            ushort n = binaryReader.ReadUInt16();
+            return BitConverter.IsLittleEndian ? Shorts.ReverseBytes(n) : n;
+        }
+
+        [CLSCompliant(false)]
+        public static ushort ReadUInt16LittleEndian(BinaryReader binaryReader)
+        {
+            ushort n = binaryReader.ReadUInt16();
+            return BitConverter.IsLittleEndian ? n : Shorts.ReverseBytes(n);
+        }
+
+        [CLSCompliant(false)]
+        public static uint ReadUInt32BigEndian(BinaryReader binaryReader)
+        {
+            uint n = binaryReader.ReadUInt32();
+            return BitConverter.IsLittleEndian ? Integers.ReverseBytes(n) : n;
+        }
+
+        [CLSCompliant(false)]
+        public static uint ReadUInt32LittleEndian(BinaryReader binaryReader)
+        {
+            uint n = binaryReader.ReadUInt32();
+            return BitConverter.IsLittleEndian ? n : Integers.ReverseBytes(n);
+        }
+
+        [CLSCompliant(false)]
+        public static ulong ReadUInt64BigEndian(BinaryReader binaryReader)
+        {
+            ulong n = binaryReader.ReadUInt64();
+            return BitConverter.IsLittleEndian ? Longs.ReverseBytes(n) : n;
+        }
+
+        [CLSCompliant(false)]
+        public static ulong ReadUInt64LittleEndian(BinaryReader binaryReader)
+        {
+            ulong n = binaryReader.ReadUInt64();
+            return BitConverter.IsLittleEndian ? n : Longs.ReverseBytes(n);
+        }
+    }
+}
diff --git a/crypto/src/util/io/BinaryWriters.cs b/crypto/src/util/io/BinaryWriters.cs
new file mode 100644
index 000000000..6650dcda5
--- /dev/null
+++ b/crypto/src/util/io/BinaryWriters.cs
@@ -0,0 +1,86 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public static class BinaryWriters
+    {
+        public static void WriteInt16BigEndian(BinaryWriter binaryWriter, short n)
+        {
+            short bigEndian = BitConverter.IsLittleEndian ? Shorts.ReverseBytes(n) : n;
+            binaryWriter.Write(bigEndian);
+        }
+
+        public static void WriteInt16LittleEndian(BinaryWriter binaryWriter, short n)
+        {
+            short littleEndian = BitConverter.IsLittleEndian ? n : Shorts.ReverseBytes(n);
+            binaryWriter.Write(littleEndian);
+        }
+
+        public static void WriteInt32BigEndian(BinaryWriter binaryWriter, int n)
+        {
+            int bigEndian = BitConverter.IsLittleEndian ? Integers.ReverseBytes(n) : n;
+            binaryWriter.Write(bigEndian);
+        }
+
+        public static void WriteInt32LittleEndian(BinaryWriter binaryWriter, int n)
+        {
+            int littleEndian = BitConverter.IsLittleEndian ? n : Integers.ReverseBytes(n);
+            binaryWriter.Write(littleEndian);
+        }
+
+        public static void WriteInt64BigEndian(BinaryWriter binaryWriter, long n)
+        {
+            long bigEndian = BitConverter.IsLittleEndian ? Longs.ReverseBytes(n) : n;
+            binaryWriter.Write(bigEndian);
+        }
+
+        public static void WriteInt64LittleEndian(BinaryWriter binaryWriter, long n)
+        {
+            long littleEndian = BitConverter.IsLittleEndian ? n : Longs.ReverseBytes(n);
+            binaryWriter.Write(littleEndian);
+        }
+
+        [CLSCompliant(false)]
+        public static void WriteUInt16BigEndian(BinaryWriter binaryWriter, ushort n)
+        {
+            ushort bigEndian = BitConverter.IsLittleEndian ? Shorts.ReverseBytes(n) : n;
+            binaryWriter.Write(bigEndian);
+        }
+
+        [CLSCompliant(false)]
+        public static void WriteUInt16LittleEndian(BinaryWriter binaryWriter, ushort n)
+        {
+            ushort littleEndian = BitConverter.IsLittleEndian ? n : Shorts.ReverseBytes(n);
+            binaryWriter.Write(littleEndian);
+        }
+
+        [CLSCompliant(false)]
+        public static void WriteUInt32BigEndian(BinaryWriter binaryWriter, uint n)
+        {
+            uint bigEndian = BitConverter.IsLittleEndian ? Integers.ReverseBytes(n) : n;
+            binaryWriter.Write(bigEndian);
+        }
+
+        [CLSCompliant(false)]
+        public static void WriteUInt32LittleEndian(BinaryWriter binaryWriter, uint n)
+        {
+            uint littleEndian = BitConverter.IsLittleEndian ? n : Integers.ReverseBytes(n);
+            binaryWriter.Write(littleEndian);
+        }
+
+        [CLSCompliant(false)]
+        public static void WriteUInt64BigEndian(BinaryWriter binaryWriter, ulong n)
+        {
+            ulong bigEndian = BitConverter.IsLittleEndian ? Longs.ReverseBytes(n) : n;
+            binaryWriter.Write(bigEndian);
+        }
+
+        [CLSCompliant(false)]
+        public static void WriteUInt64LittleEndian(BinaryWriter binaryWriter, ulong n)
+        {
+            ulong littleEndian = BitConverter.IsLittleEndian ? n : Longs.ReverseBytes(n);
+            binaryWriter.Write(littleEndian);
+        }
+    }
+}
diff --git a/crypto/src/util/io/Streams.cs b/crypto/src/util/io/Streams.cs
index c23332909..da8f01068 100644
--- a/crypto/src/util/io/Streams.cs
+++ b/crypto/src/util/io/Streams.cs
@@ -3,14 +3,10 @@ using System.IO;
 
 namespace Org.BouncyCastle.Utilities.IO
 {
-	public sealed class Streams
+	public static class Streams
 	{
 		private const int BufferSize = 4096;
 
-		private Streams()
-		{
-		}
-
 		public static void Drain(Stream inStr)
 		{
 			inStr.CopyTo(Stream.Null, BufferSize);
@@ -64,7 +60,12 @@ namespace Org.BouncyCastle.Utilities.IO
 			return buf.ToArray();
 		}
 
-		public static byte[] ReadAllLimited(Stream inStr, int limit)
+        public static byte[] ReadAll(MemoryStream inStr)
+        {
+			return inStr.ToArray();
+        }
+
+        public static byte[] ReadAllLimited(Stream inStr, int limit)
 		{
 			MemoryStream buf = new MemoryStream();
 			PipeAllLimited(inStr, limit, buf);
diff --git a/crypto/src/util/io/compression/Bzip2.cs b/crypto/src/util/io/compression/Bzip2.cs
new file mode 100644
index 000000000..72b006dc9
--- /dev/null
+++ b/crypto/src/util/io/compression/Bzip2.cs
@@ -0,0 +1,21 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO.Compression
+{
+    using Impl = Utilities.Bzip2;
+
+    internal static class Bzip2
+    {
+        internal static Stream CompressOutput(Stream stream, bool leaveOpen = false)
+        {
+            return leaveOpen
+                ?   new Impl.CBZip2OutputStreamLeaveOpen(stream)
+                :   new Impl.CBZip2OutputStream(stream);
+        }
+
+        internal static Stream DecompressInput(Stream stream)
+        {
+            return new Impl.CBZip2InputStream(stream);
+        }
+    }
+}
diff --git a/crypto/src/util/io/compression/ZLib.cs b/crypto/src/util/io/compression/ZLib.cs
new file mode 100644
index 000000000..1254da012
--- /dev/null
+++ b/crypto/src/util/io/compression/ZLib.cs
@@ -0,0 +1,46 @@
+using System.IO;
+
+#if NET6_0_OR_GREATER
+using System.IO.Compression;
+#else
+using Org.BouncyCastle.Utilities.Zlib;
+#endif
+
+namespace Org.BouncyCastle.Utilities.IO.Compression
+{
+    internal static class ZLib
+    {
+        internal static Stream CompressOutput(Stream stream, int zlibCompressionLevel, bool leaveOpen = false)
+        {
+#if NET6_0_OR_GREATER
+            return new ZLibStream(stream, GetCompressionLevel(zlibCompressionLevel), leaveOpen);
+#else
+            return leaveOpen
+                ?   new ZOutputStreamLeaveOpen(stream, zlibCompressionLevel, false)
+                :   new ZOutputStream(stream, zlibCompressionLevel, false);
+#endif
+        }
+
+        internal static Stream DecompressInput(Stream stream)
+        {
+#if NET6_0_OR_GREATER
+            return new ZLibStream(stream, CompressionMode.Decompress, leaveOpen: false);
+#else
+            return new ZInputStream(stream);
+#endif
+        }
+
+#if NET6_0_OR_GREATER
+        internal static CompressionLevel GetCompressionLevel(int zlibCompressionLevel)
+        {
+            return zlibCompressionLevel switch
+            {
+                0           => CompressionLevel.NoCompression,
+                1 or 2 or 3 => CompressionLevel.Fastest,
+                7 or 8 or 9 => CompressionLevel.SmallestSize,
+                _           => CompressionLevel.Optimal,
+            };
+        }
+#endif
+    }
+}
diff --git a/crypto/src/util/io/compression/Zip.cs b/crypto/src/util/io/compression/Zip.cs
new file mode 100644
index 000000000..f2773d63b
--- /dev/null
+++ b/crypto/src/util/io/compression/Zip.cs
@@ -0,0 +1,33 @@
+using System.IO;
+
+#if NET6_0_OR_GREATER
+using System.IO.Compression;
+#else
+using Org.BouncyCastle.Utilities.Zlib;
+#endif
+
+namespace Org.BouncyCastle.Utilities.IO.Compression
+{
+    internal static class Zip
+    {
+        internal static Stream CompressOutput(Stream stream, int zlibCompressionLevel, bool leaveOpen = false)
+        {
+#if NET6_0_OR_GREATER
+            return new DeflateStream(stream, ZLib.GetCompressionLevel(zlibCompressionLevel), leaveOpen);
+#else
+            return leaveOpen
+                ?   new ZOutputStreamLeaveOpen(stream, zlibCompressionLevel, true)
+                :   new ZOutputStream(stream, zlibCompressionLevel, true);
+#endif
+        }
+
+        internal static Stream DecompressInput(Stream stream)
+        {
+#if NET6_0_OR_GREATER
+            return new DeflateStream(stream, CompressionMode.Decompress, leaveOpen: false);
+#else
+            return new ZInputStream(stream, true);
+#endif
+        }
+    }
+}
diff --git a/crypto/src/util/zlib/ZOutputStream.cs b/crypto/src/util/zlib/ZOutputStream.cs
index 301516e57..51a5050dd 100644
--- a/crypto/src/util/zlib/ZOutputStream.cs
+++ b/crypto/src/util/zlib/ZOutputStream.cs
@@ -264,4 +264,38 @@ namespace Org.BouncyCastle.Utilities.Zlib
             Write(buf1, 0, 1);
         }
     }
+
+    public class ZOutputStreamLeaveOpen
+        : ZOutputStream
+    {
+        public ZOutputStreamLeaveOpen(Stream output)
+            : base(output)
+        {
+        }
+
+        public ZOutputStreamLeaveOpen(Stream output, bool nowrap)
+            : base(output, nowrap)
+        {
+        }
+
+        public ZOutputStreamLeaveOpen(Stream output, ZStream z)
+            : base(output, z)
+        {
+        }
+
+        public ZOutputStreamLeaveOpen(Stream output, int level)
+            : base(output, level)
+        {
+        }
+
+        public ZOutputStreamLeaveOpen(Stream output, int level, bool nowrap)
+            : base(output, level, nowrap)
+        {
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            Detach(disposing);
+        }
+    }
 }
diff --git a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
index 1cb239e87..3a0a02ea9 100644
--- a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
+++ b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
@@ -54,13 +54,13 @@ namespace Org.BouncyCastle.X509
 		public void SetNotBefore(
 			DateTime date)
 		{
-			acInfoGen.SetStartDate(new DerGeneralizedTime(date));
+			acInfoGen.SetStartDate(new Asn1GeneralizedTime(date));
 		}
 
 		public void SetNotAfter(
 			DateTime date)
 		{
-			acInfoGen.SetEndDate(new DerGeneralizedTime(date));
+			acInfoGen.SetEndDate(new Asn1GeneralizedTime(date));
 		}
 
 		/// <summary>Add an attribute.</summary>
diff --git a/crypto/src/x509/X509V2CRLGenerator.cs b/crypto/src/x509/X509V2CRLGenerator.cs
index dc3f8c662..a57383613 100644
--- a/crypto/src/x509/X509V2CRLGenerator.cs
+++ b/crypto/src/x509/X509V2CRLGenerator.cs
@@ -79,7 +79,8 @@ namespace Org.BouncyCastle.X509
 			int			reason,
 			DateTime	invalidityDate)
 		{
-			tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason, new DerGeneralizedTime(invalidityDate));
+			tbsGen.AddCrlEntry(new DerInteger(userCertificate), new Time(revocationDate), reason,
+				new Asn1GeneralizedTime(invalidityDate));
 		}
 
 		/**