summary refs log tree commit diff
path: root/crypto/src
diff options
context:
space:
mode:
authorOren Novotny <oren@novotny.org>2015-10-16 20:23:05 -0400
committerOren Novotny <oren@novotny.org>2015-10-16 20:23:05 -0400
commitde17e96f2d52a25a33e742d0f81e9052da77f49b (patch)
tree03ccef76aacc1bac6340df9faedf1d64dda76077 /crypto/src
parentprep release for 1.8.0-rc2 (diff)
parentMerge branch 'master' into master-vs12 (diff)
downloadBouncyCastle.NET-ed25519-de17e96f2d52a25a33e742d0f81e9052da77f49b.tar.xz
Merge branch 'master-vs12' into pcl
Diffstat (limited to 'crypto/src')
-rw-r--r--crypto/src/asn1/Asn1InputStream.cs1
-rw-r--r--crypto/src/asn1/DerOutputStream.cs2
-rw-r--r--crypto/src/asn1/anssi/ANSSINamedCurves.cs2
-rw-r--r--crypto/src/asn1/misc/MiscObjectIdentifiers.cs30
-rw-r--r--crypto/src/asn1/nist/NISTObjectIdentifiers.cs6
-rw-r--r--crypto/src/asn1/sec/SECNamedCurves.cs132
-rw-r--r--crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs28
-rw-r--r--crypto/src/asn1/util/FilterStream.cs2
-rw-r--r--crypto/src/asn1/x509/AlgorithmIdentifier.cs11
-rw-r--r--crypto/src/asn1/x9/ECNamedCurveTable.cs22
-rw-r--r--crypto/src/asn1/x9/X962NamedCurves.cs46
-rw-r--r--crypto/src/asn1/x9/X9ECParameters.cs98
-rw-r--r--crypto/src/asn1/x9/X9ECParametersHolder.cs18
-rw-r--r--crypto/src/asn1/x9/X9ECPoint.cs54
-rw-r--r--crypto/src/asn1/x9/X9FieldID.cs16
-rw-r--r--crypto/src/bcpg/BcpgInputStream.cs18
-rw-r--r--crypto/src/bcpg/ECDHPublicBCPGKey.cs24
-rw-r--r--crypto/src/bcpg/PublicKeyAlgorithmTags.cs3
-rw-r--r--crypto/src/bcpg/PublicKeyEncSessionPacket.cs54
-rw-r--r--crypto/src/bcpg/PublicKeyPacket.cs2
-rw-r--r--crypto/src/bcpg/S2k.cs10
-rw-r--r--crypto/src/bcpg/SignatureSubpacket.cs50
-rw-r--r--crypto/src/bcpg/SignatureSubpacketsReader.cs84
-rw-r--r--crypto/src/bcpg/sig/EmbeddedSignature.cs3
-rw-r--r--crypto/src/bcpg/sig/Exportable.cs9
-rw-r--r--crypto/src/bcpg/sig/Features.cs75
-rw-r--r--crypto/src/bcpg/sig/IssuerKeyId.cs9
-rw-r--r--crypto/src/bcpg/sig/KeyExpirationTime.cs11
-rw-r--r--crypto/src/bcpg/sig/KeyFlags.cs11
-rw-r--r--crypto/src/bcpg/sig/NotationData.cs11
-rw-r--r--crypto/src/bcpg/sig/PreferredAlgorithms.cs21
-rw-r--r--crypto/src/bcpg/sig/PrimaryUserId.cs9
-rw-r--r--crypto/src/bcpg/sig/Revocable.cs13
-rw-r--r--crypto/src/bcpg/sig/RevocationKey.cs9
-rw-r--r--crypto/src/bcpg/sig/RevocationReason.cs14
-rw-r--r--crypto/src/bcpg/sig/SignatureCreationTime.cs16
-rw-r--r--crypto/src/bcpg/sig/SignatureExpirationTime.cs19
-rw-r--r--crypto/src/bcpg/sig/SignerUserId.cs17
-rw-r--r--crypto/src/bcpg/sig/TrustSignature.cs15
-rw-r--r--crypto/src/cms/CMSTypedStream.cs1
-rw-r--r--crypto/src/cms/SignerInformation.cs7
-rw-r--r--crypto/src/crypto/IBlockResult.cs24
-rw-r--r--crypto/src/crypto/ISignatureCalculator.cs23
-rw-r--r--crypto/src/crypto/ISignatureVerifier.cs21
-rw-r--r--crypto/src/crypto/ISignatureVerifierProvider.cs18
-rw-r--r--crypto/src/crypto/IStreamCalculator.cs23
-rw-r--r--crypto/src/crypto/IVerifier.cs25
-rw-r--r--crypto/src/crypto/IXof.cs22
-rw-r--r--crypto/src/crypto/digests/KeccakDigest.cs534
-rw-r--r--crypto/src/crypto/digests/SHA3Digest.cs538
-rw-r--r--crypto/src/crypto/digests/ShakeDigest.cs111
-rw-r--r--crypto/src/crypto/ec/CustomNamedCurves.cs62
-rw-r--r--crypto/src/crypto/engines/AesEngine.cs23
-rw-r--r--crypto/src/crypto/engines/AesFastEngine.cs23
-rw-r--r--crypto/src/crypto/engines/AesLightEngine.cs29
-rw-r--r--crypto/src/crypto/engines/RSABlindedEngine.cs198
-rw-r--r--crypto/src/crypto/modes/gcm/GcmUtilities.cs53
-rw-r--r--crypto/src/crypto/operators/Asn1Signature.cs560
-rw-r--r--crypto/src/crypto/parameters/DHParameters.cs1
-rw-r--r--crypto/src/crypto/signers/Iso9796d2PssSigner.cs50
-rw-r--r--crypto/src/crypto/signers/Iso9796d2Signer.cs61
-rw-r--r--crypto/src/crypto/signers/IsoTrailers.cs57
-rw-r--r--crypto/src/crypto/signers/X931Signer.cs63
-rw-r--r--crypto/src/crypto/tls/AbstractTlsContext.cs13
-rw-r--r--crypto/src/crypto/tls/ByteQueueStream.cs115
-rw-r--r--crypto/src/crypto/tls/RecordStream.cs25
-rw-r--r--crypto/src/crypto/tls/TlsClientProtocol.cs48
-rw-r--r--crypto/src/crypto/tls/TlsProtocol.cs182
-rw-r--r--crypto/src/crypto/tls/TlsServerProtocol.cs50
-rw-r--r--crypto/src/crypto/util/Pack.cs25
-rw-r--r--crypto/src/math/Primes.cs366
-rw-r--r--crypto/src/math/ec/ECCurve.cs194
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113Field.cs29
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113R1Curve.cs92
-rw-r--r--crypto/src/math/ec/custom/sec/SecT113R2Curve.cs92
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131Field.cs29
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131R1Curve.cs90
-rw-r--r--crypto/src/math/ec/custom/sec/SecT131R2Curve.cs92
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163Field.cs41
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163K1Curve.cs90
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163R1Curve.cs92
-rw-r--r--crypto/src/math/ec/custom/sec/SecT163R2Curve.cs90
-rw-r--r--crypto/src/math/ec/custom/sec/SecT193Field.cs43
-rw-r--r--crypto/src/math/ec/custom/sec/SecT193FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT193R1Curve.cs92
-rw-r--r--crypto/src/math/ec/custom/sec/SecT193R2Curve.cs92
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233Field.cs33
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233K1Curve.cs92
-rw-r--r--crypto/src/math/ec/custom/sec/SecT233R1Curve.cs90
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239Field.cs37
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT239K1Curve.cs90
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283Field.cs35
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283K1Curve.cs90
-rw-r--r--crypto/src/math/ec/custom/sec/SecT283R1Curve.cs90
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409Field.cs51
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409K1Curve.cs90
-rw-r--r--crypto/src/math/ec/custom/sec/SecT409R1Curve.cs90
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571Field.cs51
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571FieldElement.cs5
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571K1Curve.cs92
-rw-r--r--crypto/src/math/ec/custom/sec/SecT571R1Curve.cs91
-rw-r--r--crypto/src/math/raw/Interleave.cs109
-rw-r--r--crypto/src/openpgp/PgpEncryptedDataGenerator.cs154
-rw-r--r--crypto/src/openpgp/PgpKeyPair.cs2
-rw-r--r--crypto/src/openpgp/PgpPad.cs45
-rw-r--r--crypto/src/openpgp/PgpPrivateKey.cs37
-rw-r--r--crypto/src/openpgp/PgpPublicKey.cs132
-rw-r--r--crypto/src/openpgp/PgpPublicKeyEncryptedData.cs140
-rw-r--r--crypto/src/openpgp/PgpSecretKey.cs235
-rw-r--r--crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs23
-rw-r--r--crypto/src/openpgp/PgpSignatureSubpacketVector.cs12
-rw-r--r--crypto/src/openpgp/PgpUtilities.cs29
-rw-r--r--crypto/src/openpgp/Rfc6637Utilities.cs138
-rw-r--r--crypto/src/openpgp/SXprUtilities.cs102
-rw-r--r--crypto/src/openpgp/WrappedGeneratorStream.cs2
-rw-r--r--crypto/src/openssl/PEMReader.cs1
-rw-r--r--crypto/src/pkcs/Pkcs10CertificationRequest.cs257
-rw-r--r--crypto/src/security/AgreementUtilities.cs10
-rw-r--r--crypto/src/security/DigestUtilities.cs24
-rw-r--r--crypto/src/security/SecureRandom.cs13
-rw-r--r--crypto/src/util/io/FilterStream.cs70
-rw-r--r--crypto/src/x509/X509Certificate.cs35
-rw-r--r--crypto/src/x509/X509Crl.cs51
-rw-r--r--crypto/src/x509/X509V1CertificateGenerator.cs50
-rw-r--r--crypto/src/x509/X509V2AttributeCertificate.cs42
-rw-r--r--crypto/src/x509/X509V2AttributeCertificateGenerator.cs69
-rw-r--r--crypto/src/x509/X509V2CRLGenerator.cs92
-rw-r--r--crypto/src/x509/X509V3CertificateGenerator.cs65
135 files changed, 4999 insertions, 3491 deletions
diff --git a/crypto/src/asn1/Asn1InputStream.cs b/crypto/src/asn1/Asn1InputStream.cs
index 18d13c32d..501e788a0 100644
--- a/crypto/src/asn1/Asn1InputStream.cs
+++ b/crypto/src/asn1/Asn1InputStream.cs
@@ -2,7 +2,6 @@ using System;
 using System.Diagnostics;
 using System.IO;
 
-using Org.BouncyCastle.Asn1.Utilities;
 using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Asn1
diff --git a/crypto/src/asn1/DerOutputStream.cs b/crypto/src/asn1/DerOutputStream.cs
index f95d123f9..c03d9dc11 100644
--- a/crypto/src/asn1/DerOutputStream.cs
+++ b/crypto/src/asn1/DerOutputStream.cs
@@ -1,7 +1,7 @@
 using System;
 using System.IO;
 
-using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Asn1
 {
diff --git a/crypto/src/asn1/anssi/ANSSINamedCurves.cs b/crypto/src/asn1/anssi/ANSSINamedCurves.cs
index 04e30bb07..c7f9545f2 100644
--- a/crypto/src/asn1/anssi/ANSSINamedCurves.cs
+++ b/crypto/src/asn1/anssi/ANSSINamedCurves.cs
@@ -42,7 +42,7 @@ namespace Org.BouncyCastle.Asn1.Anssi
                 BigInteger h = BigInteger.One;
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "B6B3D4C356C139EB31183D4749D423958C27D2DCAF98B70164C97A2DD98F5CFF"
                     + "6142E0F7C8B204911F9271F0F3ECEF8C2701C307E8E4C9E183115A1554062CFB"));
 
diff --git a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
index 45adce4f7..8128b6952 100644
--- a/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
+++ b/crypto/src/asn1/misc/MiscObjectIdentifiers.cs
@@ -41,13 +41,39 @@ namespace Org.BouncyCastle.Asn1.Misc
         //       iso/itu(2) country(16) us(840) organization(1) novell(113719)
         //
         public static readonly string				Novell					= "2.16.840.1.113719";
-        public static readonly DerObjectIdentifier	NovellSecurityAttribs	= new DerObjectIdentifier(Novell + ".1.9.4.1");
+        public static readonly DerObjectIdentifier NovellSecurityAttribs	= new DerObjectIdentifier(Novell + ".1.9.4.1");
 
         //
         // Entrust
         //       iso(1) member-body(16) us(840) nortelnetworks(113533) entrust(7)
         //
         public static readonly string				Entrust					= "1.2.840.113533.7";
-        public static readonly DerObjectIdentifier	EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0");
+        public static readonly DerObjectIdentifier EntrustVersionExtension = new DerObjectIdentifier(Entrust + ".65.0");
+
+        //
+        // Ascom
+        //
+        public static readonly DerObjectIdentifier as_sys_sec_alg_ideaCBC = new DerObjectIdentifier("1.3.6.1.4.1.188.7.1.1.2");
+
+        //
+        // Peter Gutmann's Cryptlib
+        //
+        public static readonly DerObjectIdentifier cryptlib = new DerObjectIdentifier("1.3.6.1.4.1.3029");
+
+        public static readonly DerObjectIdentifier cryptlib_algorithm = cryptlib.Branch("1");
+        public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_ECB = cryptlib_algorithm.Branch("1.1");
+        public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_CBC = cryptlib_algorithm.Branch("1.2");
+        public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_CFB = cryptlib_algorithm.Branch("1.3");
+        public static readonly DerObjectIdentifier cryptlib_algorithm_blowfish_OFB = cryptlib_algorithm.Branch("1.4");
+
+        //
+        // Blake2b
+        //
+        public static readonly DerObjectIdentifier blake2 = new DerObjectIdentifier("1.3.6.1.4.1.1722.12.2");
+
+        public static readonly DerObjectIdentifier id_blake2b160 = blake2.Branch("1.5");
+        public static readonly DerObjectIdentifier id_blake2b256 = blake2.Branch("1.8");
+        public static readonly DerObjectIdentifier id_blake2b384 = blake2.Branch("1.12");
+        public static readonly DerObjectIdentifier id_blake2b512 = blake2.Branch("1.16");
     }
 }
diff --git a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
index 8eb5ed437..55b9d8e68 100644
--- a/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
+++ b/crypto/src/asn1/nist/NISTObjectIdentifiers.cs
@@ -25,6 +25,12 @@ namespace Org.BouncyCastle.Asn1.Nist
         public static readonly DerObjectIdentifier IdSha224 = HashAlgs.Branch("4");
         public static readonly DerObjectIdentifier IdSha512_224 = HashAlgs.Branch("5");
         public static readonly DerObjectIdentifier IdSha512_256 = HashAlgs.Branch("6");
+        public static readonly DerObjectIdentifier IdSha3_224 = HashAlgs.Branch("7");
+        public static readonly DerObjectIdentifier IdSha3_256 = HashAlgs.Branch("8");
+        public static readonly DerObjectIdentifier IdSha3_384 = HashAlgs.Branch("9");
+        public static readonly DerObjectIdentifier IdSha3_512 = HashAlgs.Branch("10");
+        public static readonly DerObjectIdentifier IdShake128 = HashAlgs.Branch("11");
+        public static readonly DerObjectIdentifier IdShake256 = HashAlgs.Branch("12");
 
         public static readonly DerObjectIdentifier Aes = new DerObjectIdentifier(NistAlgorithm + ".1");
 
diff --git a/crypto/src/asn1/sec/SECNamedCurves.cs b/crypto/src/asn1/sec/SECNamedCurves.cs
index 0bd60b0b8..ca71a4e66 100644
--- a/crypto/src/asn1/sec/SECNamedCurves.cs
+++ b/crypto/src/asn1/sec/SECNamedCurves.cs
@@ -54,9 +54,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.One;
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                //+ "09487239995A5EE76B55F9C2F098"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "09487239995A5EE76B55F9C2F098"
                     + "A89CE5AF8724C0A23E0E0FF77500"));
 
@@ -85,9 +83,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(4);
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "4BA30AB5E892B4E1649DD0928643"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "4BA30AB5E892B4E1649DD0928643"
                     + "ADCD46F5882E3747DEF36E956E97"));
 
@@ -116,9 +112,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.One;
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "161FF7528B899B2D0C28607CA52C5B86"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "161FF7528B899B2D0C28607CA52C5B86"
                     + "CF5AC8395BAFEB13C02DA292DDED7A83"));
 
@@ -147,9 +141,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(4);
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                //+ "7B6AA5D85E572983E6FB32A7CDEBC140"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "7B6AA5D85E572983E6FB32A7CDEBC140"
                     + "27B6916A894D3AEE7106FE805FC34B44"));
 
@@ -191,9 +183,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                     176);
 
                 ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                    //+ "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
                     + "938CF935318FDCED6BC28286531733C3F03C4FEE"));
 
@@ -222,9 +212,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.One;
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                    //+ "4A96B5688EF573284664698968C38BB913CBFC82"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "4A96B5688EF573284664698968C38BB913CBFC82"
                     + "23A628553168947D59DCC912042351377AC5FB32"));
 
@@ -253,9 +241,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.One;
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                //+ "52DCB034293A117E1F4FF11B30F7199D3144CE6D"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
                     + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
 
@@ -297,9 +283,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                     208);
 
                 ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
                     + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
 
@@ -328,9 +312,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.One;
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
                     + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
 
@@ -372,9 +354,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                     240);
 
                 ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
                     + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
 
@@ -403,9 +383,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.One;
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                //+ "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
                     + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
 
@@ -447,9 +425,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                     272);
 
                 ECCurve curve = ConfigureCurveGlv(new FpCurve(p, a, b, n, h), glv);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                //+ "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
                     + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
 
@@ -478,9 +454,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.One;
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
                     + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
 
@@ -509,9 +483,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.One;
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
                     + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
 
@@ -540,9 +512,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.One;
 
                 ECCurve curve = ConfigureCurve(new FpCurve(p, a, b, n, h));
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                //+ "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
                     + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
 
@@ -572,9 +542,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "009D73616F35F4AB1407D73562C10F"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "009D73616F35F4AB1407D73562C10F"
                     + "00A52830277958EE84D1315ED31886"));
 
@@ -604,9 +572,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "01A57A6A7B26CA5EF52FCDB8164797"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "01A57A6A7B26CA5EF52FCDB8164797"
                     + "00B3ADC94ED1FE674C06E695BABA1D"));
 
@@ -638,9 +604,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "0081BAF91FDF9833C40F9C181343638399"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0081BAF91FDF9833C40F9C181343638399"
                     + "078C6E7EA38C001F73C8134B1B4EF9E150"));
 
@@ -672,9 +636,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "0356DCD8F2F95031AD652D23951BB366A8"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0356DCD8F2F95031AD652D23951BB366A8"
                     + "0648F06D867940A5366D9E265DE9EB240F"));
 
@@ -706,9 +668,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
                     + "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
 
@@ -740,9 +700,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "0369979697AB43897789566789567F787A7876A654"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0369979697AB43897789566789567F787A7876A654"
                     + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
 
@@ -774,9 +732,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "03F0EBA16286A2D57EA0991168D4994637E8343E36"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
                     + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
 
@@ -806,9 +762,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
                     + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
 
@@ -838,9 +792,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
                     + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
 
@@ -870,9 +822,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(4);
 
                 ECCurve curve = new F2mCurve(m, k, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                //+ "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
                     + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
 
@@ -902,9 +852,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
                     + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
 
@@ -934,9 +882,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(4);
 
                 ECCurve curve = new F2mCurve(m, k, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
                     + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
 
@@ -968,9 +914,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(4);
 
                 ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                //+ "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
                     + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
 
@@ -1002,9 +946,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
                     + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
 
@@ -1034,9 +976,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(4);
 
                 ECCurve curve = new F2mCurve(m, k, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
                     + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
 
@@ -1066,9 +1006,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
                     + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
 
@@ -1100,9 +1038,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(4);
 
                 ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("02"
-                //+ "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
                     + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
 
@@ -1134,9 +1070,7 @@ namespace Org.BouncyCastle.Asn1.Sec
                 BigInteger h = BigInteger.ValueOf(2);
 
                 ECCurve curve = new F2mCurve(m, k1, k2, k3, a, b, n, h);
-                //ECPoint G = curve.DecodePoint(Hex.Decode("03"
-                //+ "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"));
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
                     + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
 
diff --git a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
index f476619a7..ba3eda620 100644
--- a/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
+++ b/crypto/src/asn1/teletrust/TeleTrusTNamedCurves.cs
@@ -40,7 +40,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G
+                    new X9ECPoint(curve, Hex.Decode("04BED5AF16EA3F6A4F62938C4631EB5AF7BDBCDBC31667CB477A1A8EC338F94741669C976316DA6321")), // G
                     n, h);
             }
         }
@@ -66,7 +66,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G
+                    new X9ECPoint(curve, Hex.Decode("04B199B13B9B34EFC1397E64BAEB05ACC265FF2378ADD6718B7C7C1961F0991B842443772152C9E0AD")), // G
                     n, h);
             }
         }
@@ -91,7 +91,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G
+                    new X9ECPoint(curve, Hex.Decode("04C0A0647EAAB6A48753B033C56CB0F0900A2F5C4853375FD614B690866ABD5BB88B5F4828C1490002E6773FA2FA299B8F")), // G
                     n, h);
             }
         }
@@ -117,7 +117,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G'
+                    new X9ECPoint(curve, Hex.Decode("043AE9E58C82F63C30282E1FE7BBF43FA72C446AF6F4618129097E2C5667C2223A902AB5CA449D0084B7E5B3DE7CCC01C9")), // G'
                     n, h);
             }
         }
@@ -142,7 +142,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G
+                    new X9ECPoint(curve, Hex.Decode("040D9029AD2C7E5CF4340823B2A87DC68C9E4CE3174C1E6EFDEE12C07D58AA56F772C0726F24C6B89E4ECDAC24354B9E99CAA3F6D3761402CD")), // G
                     n, h);
             }
         }
@@ -168,7 +168,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G'
+                    new X9ECPoint(curve, Hex.Decode("046AB1E344CE25FF3896424E7FFE14762ECB49F8928AC0C76029B4D5800374E9F5143E568CD23F3F4D7C0D4B1E41C8CC0D1C6ABD5F1A46DB4C")), // G'
                     n, h);
             }
         }
@@ -193,7 +193,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G
+                    new X9ECPoint(curve, Hex.Decode("048BD2AEB9CB7E57CB2C4B482FFC81B7AFB9DE27E1E3BD23C23A4453BD9ACE3262547EF835C3DAC4FD97F8461A14611DC9C27745132DED8E545C1D54C72F046997")), // G
                     n, h);
             }
         }
@@ -219,7 +219,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G'
+                    new X9ECPoint(curve, Hex.Decode("04A3E8EB3CC1CFE7B7732213B23A656149AFA142C47AAFBC2B79A191562E1305F42D996C823439C56D7F7B22E14644417E69BCB6DE39D027001DABE8F35B25C9BE")), // G'
                     n, h);
             }
         }
@@ -244,7 +244,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G
+                    new X9ECPoint(curve, Hex.Decode("0443BD7E9AFB53D8B85289BCC48EE5BFE6F20137D10A087EB6E7871E2A10A599C710AF8D0D39E2061114FDD05545EC1CC8AB4093247F77275E0743FFED117182EAA9C77877AAAC6AC7D35245D1692E8EE1")), // G
                     n, h);
             }
         }
@@ -270,7 +270,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G'
+                    new X9ECPoint(curve, Hex.Decode("04925BE9FB01AFC6FB4D3E7D4990010F813408AB106C4F09CB7EE07868CC136FFF3357F624A21BED5263BA3A7A27483EBF6671DBEF7ABB30EBEE084E58A0B077AD42A5A0989D1EE71B1B9BC0455FB0D2C3")), // G'
                     n, h);
             }
         }
@@ -295,7 +295,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G
+                    new X9ECPoint(curve, Hex.Decode("041D1C64F068CF45FFA2A63A81B7C13F6B8847A3E77EF14FE3DB7FCAFE0CBD10E8E826E03436D646AAEF87B2E247D4AF1E8ABE1D7520F9C2A45CB1EB8E95CFD55262B70B29FEEC5864E19C054FF99129280E4646217791811142820341263C5315")), // G
                     n, h);
             }
         }
@@ -321,7 +321,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G'
+                    new X9ECPoint(curve, Hex.Decode("0418DE98B02DB9A306F2AFCD7235F72A819B80AB12EBD653172476FECD462AABFFC4FF191B946A5F54D8D0AA2F418808CC25AB056962D30651A114AFD2755AD336747F93475B7A1FCA3B88F2B6A208CCFE469408584DC2B2912675BF5B9E582928")), // G'
                     n, h);
             }
         }
@@ -346,7 +346,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G
+                    new X9ECPoint(curve, Hex.Decode("0481AEE4BDD82ED9645A21322E9C4C6A9385ED9F70B5D916C1B43B62EEF4D0098EFF3B1F78E2D0D48D50D1687B93B97D5F7C6D5047406A5E688B352209BCB9F8227DDE385D566332ECC0EABFA9CF7822FDF209F70024A57B1AA000C55B881F8111B2DCDE494A5F485E5BCA4BD88A2763AED1CA2B2FA8F0540678CD1E0F3AD80892")), // G
                     n, h);
             }
         }
@@ -372,7 +372,7 @@ namespace Org.BouncyCastle.Asn1.TeleTrust
 
                 return new X9ECParameters(
                     curve,
-                    curve.DecodePoint(Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G'
+                    new X9ECPoint(curve, Hex.Decode("04640ECE5C12788717B9C1BA06CBC2A6FEBA85842458C56DDE9DB1758D39C0313D82BA51735CDB3EA499AA77A7D6943A64F7A3F25FE26F06B51BAA2696FA9035DA5B534BD595F5AF0FA2C892376C84ACE1BB4E3019B71634C01131159CAE03CEE9D9932184BEEF216BD71DF2DADF86A627306ECFF96DBB8BACE198B61E00F8B332")), // G'
                     n, h);
             }
         }
diff --git a/crypto/src/asn1/util/FilterStream.cs b/crypto/src/asn1/util/FilterStream.cs
index 2b22856a6..3d08446cd 100644
--- a/crypto/src/asn1/util/FilterStream.cs
+++ b/crypto/src/asn1/util/FilterStream.cs
@@ -3,8 +3,10 @@ using System.IO;
 
 namespace Org.BouncyCastle.Asn1.Utilities
 {
+    [Obsolete("Use Org.BouncyCastle.Utilities.IO.FilterStream")]
     public class FilterStream : Stream
     {
+        [Obsolete("Use Org.BouncyCastle.Utilities.IO.FilterStream")]
         public FilterStream(Stream s)
         {
             this.s = s;
diff --git a/crypto/src/asn1/x509/AlgorithmIdentifier.cs b/crypto/src/asn1/x509/AlgorithmIdentifier.cs
index 4ed3a400d..c6f4af5bf 100644
--- a/crypto/src/asn1/x509/AlgorithmIdentifier.cs
+++ b/crypto/src/asn1/x509/AlgorithmIdentifier.cs
@@ -69,11 +69,22 @@ namespace Org.BouncyCastle.Asn1.X509
             }
         }
 
+        /// <summary>
+        /// Return the OID in the Algorithm entry of this identifier.
+        /// </summary>
+		public virtual DerObjectIdentifier Algorithm
+		{
+			get { return objectID; }
+		}
+
         public virtual DerObjectIdentifier ObjectID
         {
             get { return objectID; }
         }
 
+        /// <summary>
+        /// Return the parameters structure in the Parameters entry of this identifier.
+        /// </summary>
         public Asn1Encodable Parameters
         {
             get { return parameters; }
diff --git a/crypto/src/asn1/x9/ECNamedCurveTable.cs b/crypto/src/asn1/x9/ECNamedCurveTable.cs
index d8315c16f..92d4393a8 100644
--- a/crypto/src/asn1/x9/ECNamedCurveTable.cs
+++ b/crypto/src/asn1/x9/ECNamedCurveTable.cs
@@ -49,6 +49,28 @@ namespace Org.BouncyCastle.Asn1.X9
             return ecP;
         }
 
+        public static string GetName(DerObjectIdentifier oid)
+        {
+            string name = X962NamedCurves.GetName(oid);
+            if (name == null)
+            {
+                name = SecNamedCurves.GetName(oid);
+            }
+            if (name == null)
+            {
+                name = NistNamedCurves.GetName(oid);
+            }
+            if (name == null)
+            {
+                name = TeleTrusTNamedCurves.GetName(oid);
+            }
+            if (name == null)
+            {
+                name = AnssiNamedCurves.GetName(oid);
+            }
+            return name;
+        }
+
         /**
          * return the object identifier signified by the passed in name. Null
          * if there is no object identifier associated with name.
diff --git a/crypto/src/asn1/x9/X962NamedCurves.cs b/crypto/src/asn1/x9/X962NamedCurves.cs
index a9ea0240c..6fa4e7c4b 100644
--- a/crypto/src/asn1/x9/X962NamedCurves.cs
+++ b/crypto/src/asn1/x9/X962NamedCurves.cs
@@ -38,7 +38,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     cFp192v1,
-                    cFp192v1.DecodePoint(
+                    new X9ECPoint(cFp192v1,
                         Hex.Decode("03188da80eb03090f67cbf20eb43a18800f4ff0afd82ff1012")),
                     n, h,
                     Hex.Decode("3045AE6FC8422f64ED579528D38120EAE12196D5"));
@@ -65,7 +65,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     cFp192v2,
-                    cFp192v2.DecodePoint(
+                    new X9ECPoint(cFp192v2,
                         Hex.Decode("03eea2bae7e1497842f2de7769cfe9c989c072ad696f48034a")),
                     n, h,
                     Hex.Decode("31a92ee2029fd10d901b113e990710f0d21ac6b6"));
@@ -92,7 +92,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     cFp192v3,
-                    cFp192v3.DecodePoint(
+                    new X9ECPoint(cFp192v3,
                         Hex.Decode("027d29778100c65a1da1783716588dce2b8b4aee8e228f1896")),
                     n, h,
                     Hex.Decode("c469684435deb378c4b65ca9591e2a5763059a2e"));
@@ -119,7 +119,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     cFp239v1,
-                    cFp239v1.DecodePoint(
+                    new X9ECPoint(cFp239v1,
                         Hex.Decode("020ffa963cdca8816ccc33b8642bedf905c3d358573d3f27fbbd3b3cb9aaaf")),
                     n, h,
                     Hex.Decode("e43bb460f0b80cc0c0b075798e948060f8321b7d"));
@@ -146,7 +146,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     cFp239v2,
-                    cFp239v2.DecodePoint(
+                    new X9ECPoint(cFp239v2,
                         Hex.Decode("0238af09d98727705120c921bb5e9e26296a3cdcf2f35757a0eafd87b830e7")),
                     n, h,
                     Hex.Decode("e8b4011604095303ca3b8099982be09fcb9ae616"));
@@ -173,7 +173,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     cFp239v3,
-                    cFp239v3.DecodePoint(
+                    new X9ECPoint(cFp239v3,
                         Hex.Decode("036768ae8e18bb92cfcf005c949aa2c6d94853d0e660bbf854b1c9505fe95a")),
                     n, h,
                     Hex.Decode("7d7374168ffe3471b60a857686a19475d3bfa2ff"));
@@ -200,7 +200,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     cFp256v1,
-                    cFp256v1.DecodePoint(
+                    new X9ECPoint(cFp256v1,
                         Hex.Decode("036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296")),
                     n, h,
                     Hex.Decode("c49d360886e704936a6678e1139d26b7819f7e90"));
@@ -231,7 +231,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m163v1,
-                    c2m163v1.DecodePoint(
+                    new X9ECPoint(c2m163v1,
                         Hex.Decode("0307AF69989546103D79329FCC3D74880F33BBE803CB")),
                     n, h,
                     Hex.Decode("D2C0FB15760860DEF1EEF4D696E6768756151754"));
@@ -259,7 +259,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m163v2,
-                    c2m163v2.DecodePoint(
+                    new X9ECPoint(c2m163v2,
                         Hex.Decode("030024266E4EB5106D0A964D92C4860E2671DB9B6CC5")),
                     n, h,
                     null);
@@ -287,7 +287,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m163v3,
-                    c2m163v3.DecodePoint(Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
+                    new X9ECPoint(c2m163v3, Hex.Decode("0202F9F87B7C574D0BDECF8A22E6524775F98CDEBDCB")),
                     n, h,
                     null);
             }
@@ -314,7 +314,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m176w1,
-                    c2m176w1.DecodePoint(
+                    new X9ECPoint(c2m176w1,
                         Hex.Decode("038D16C2866798B600F9F08BB4A8E860F3298CE04A5798")),
                     n, h,
                     null);
@@ -342,7 +342,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m191v1,
-                    c2m191v1.DecodePoint(
+                    new X9ECPoint(c2m191v1,
                         Hex.Decode("0236B3DAF8A23206F9C4F299D7B21A9C369137F2C84AE1AA0D")),
                     n, h,
                     Hex.Decode("4E13CA542744D696E67687561517552F279A8C84"));
@@ -370,7 +370,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m191v2,
-                    c2m191v2.DecodePoint(
+                    new X9ECPoint(c2m191v2,
                         Hex.Decode("023809B2B7CC1B28CC5A87926AAD83FD28789E81E2C9E3BF10")),
                     n, h,
                     null);
@@ -398,7 +398,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m191v3,
-                    c2m191v3.DecodePoint(
+                    new X9ECPoint(c2m191v3,
                         Hex.Decode("03375D4CE24FDE434489DE8746E71786015009E66E38A926DD")),
                     n, h,
                     null);
@@ -426,7 +426,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m208w1,
-                    c2m208w1.DecodePoint(
+                    new X9ECPoint(c2m208w1,
                         Hex.Decode("0289FDFBE4ABE193DF9559ECF07AC0CE78554E2784EB8C1ED1A57A")),
                     n, h,
                     null);
@@ -454,7 +454,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m239v1,
-                    c2m239v1.DecodePoint(
+                    new X9ECPoint(c2m239v1,
                         Hex.Decode("0257927098FA932E7C0A96D3FD5B706EF7E5F5C156E16B7E7C86038552E91D")),
                     n, h,
                     null);
@@ -482,7 +482,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m239v2,
-                    c2m239v2.DecodePoint(
+                    new X9ECPoint(c2m239v2,
                         Hex.Decode("0228F9D04E900069C8DC47A08534FE76D2B900B7D7EF31F5709F200C4CA205")),
                     n, h,
                     null);
@@ -510,7 +510,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m239v3,
-                    c2m239v3.DecodePoint(
+                    new X9ECPoint(c2m239v3,
                         Hex.Decode("0370F6E9D04D289C4E89913CE3530BFDE903977D42B146D539BF1BDE4E9C92")),
                     n, h,
                     null);
@@ -538,7 +538,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m272w1,
-                    c2m272w1.DecodePoint(
+                    new X9ECPoint(c2m272w1,
                         Hex.Decode("026108BABB2CEEBCF787058A056CBE0CFE622D7723A289E08A07AE13EF0D10D171DD8D")),
                     n, h,
                     null);
@@ -566,7 +566,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m304w1,
-                    c2m304w1.DecodePoint(
+                    new X9ECPoint(c2m304w1,
                         Hex.Decode("02197B07845E9BE2D96ADB0F5F3C7F2CFFBD7A3EB8B6FEC35C7FD67F26DDF6285A644F740A2614")),
                     n, h,
                     null);
@@ -594,7 +594,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m359v1,
-                    c2m359v1.DecodePoint(
+                    new X9ECPoint(c2m359v1,
                         Hex.Decode("033C258EF3047767E7EDE0F1FDAA79DAEE3841366A132E163ACED4ED2401DF9C6BDCDE98E8E707C07A2239B1B097")),
                     n, h,
                     null);
@@ -622,7 +622,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m368w1,
-                    c2m368w1.DecodePoint(
+                    new X9ECPoint(c2m368w1,
                         Hex.Decode("021085E2755381DCCCE3C1557AFA10C2F0C0C2825646C5B34A394CBCFA8BC16B22E7E789E927BE216F02E1FB136A5F")),
                     n, h,
                     null);
@@ -650,7 +650,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
                 return new X9ECParameters(
                     c2m431r1,
-                    c2m431r1.DecodePoint(
+                    new X9ECPoint(c2m431r1,
                         Hex.Decode("02120FC05D3C67A99DE161D2F4092622FECA701BE4F50F4758714E8A87BBF2A658EF8C21E7C5EFE965361F6C2999C0C247B0DBD70CE6B7")),
                     n, h,
                     null);
diff --git a/crypto/src/asn1/x9/X9ECParameters.cs b/crypto/src/asn1/x9/X9ECParameters.cs
index a192e4c52..2b6b14bcb 100644
--- a/crypto/src/asn1/x9/X9ECParameters.cs
+++ b/crypto/src/asn1/x9/X9ECParameters.cs
@@ -15,7 +15,7 @@ namespace Org.BouncyCastle.Asn1.X9
     {
         private X9FieldID	fieldID;
         private ECCurve		curve;
-        private ECPoint		g;
+        private X9ECPoint	g;
         private BigInteger	n;
         private BigInteger	h;
         private byte[]		seed;
@@ -29,36 +29,28 @@ namespace Org.BouncyCastle.Asn1.X9
                 throw new ArgumentException("bad version in X9ECParameters");
             }
 
-            X9Curve x9c = null;
-            if (seq[2] is X9Curve)
-            {
-                x9c = (X9Curve) seq[2];
-            }
-            else
-            {
-                x9c = new X9Curve(
-                    new X9FieldID(
-                        (Asn1Sequence) seq[1]),
-                        (Asn1Sequence) seq[2]);
-            }
+            X9Curve x9c = new X9Curve(
+                X9FieldID.GetInstance(seq[1]),
+                Asn1Sequence.GetInstance(seq[2]));
 
             this.curve = x9c.Curve;
+            object p = seq[3];
 
-            if (seq[3] is X9ECPoint)
+            if (p is X9ECPoint)
             {
-                this.g = ((X9ECPoint) seq[3]).Point;
+                this.g = ((X9ECPoint)p);
             }
             else
             {
-                this.g = new X9ECPoint(curve, (Asn1OctetString) seq[3]).Point;
+                this.g = new X9ECPoint(curve, (Asn1OctetString)p);
             }
 
-            this.n = ((DerInteger) seq[4]).Value;
+            this.n = ((DerInteger)seq[4]).Value;
             this.seed = x9c.GetSeed();
 
             if (seq.Count == 6)
             {
-                this.h = ((DerInteger) seq[5]).Value;
+                this.h = ((DerInteger)seq[5]).Value;
             }
         }
 
@@ -66,7 +58,16 @@ namespace Org.BouncyCastle.Asn1.X9
             ECCurve		curve,
             ECPoint		g,
             BigInteger	n)
-            : this(curve, g, n, BigInteger.One, null)
+            : this(curve, g, n, null, null)
+        {
+        }
+
+        public X9ECParameters(
+            ECCurve     curve,
+            X9ECPoint   g,
+            BigInteger  n,
+            BigInteger  h)
+            : this(curve, g, n, h, null)
         {
         }
 
@@ -85,9 +86,19 @@ namespace Org.BouncyCastle.Asn1.X9
             BigInteger	n,
             BigInteger	h,
             byte[]		seed)
+            : this(curve, new X9ECPoint(g), n, h, seed)
+        {
+        }
+
+        public X9ECParameters(
+            ECCurve     curve,
+            X9ECPoint   g,
+            BigInteger  n,
+            BigInteger  h,
+            byte[]      seed)
         {
             this.curve = curve;
-            this.g = g.Normalize();
+            this.g = g;
             this.n = n;
             this.h = h;
             this.seed = seed;
@@ -126,7 +137,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
         public ECPoint G
         {
-            get { return g; }
+            get { return g.Point; }
         }
 
         public BigInteger N
@@ -136,16 +147,7 @@ namespace Org.BouncyCastle.Asn1.X9
 
         public BigInteger H
         {
-            get
-            {
-                if (h == null)
-                {
-                    // TODO - this should be calculated, it will cause issues with custom curves.
-                    return BigInteger.One;
-                }
-
-                return h;
-            }
+            get { return h; }
         }
 
         public byte[] GetSeed()
@@ -154,6 +156,36 @@ namespace Org.BouncyCastle.Asn1.X9
         }
 
         /**
+         * Return the ASN.1 entry representing the Curve.
+         *
+         * @return the X9Curve for the curve in these parameters.
+         */
+        public X9Curve CurveEntry
+        {
+            get { return new X9Curve(curve, seed); }
+        }
+
+        /**
+         * Return the ASN.1 entry representing the FieldID.
+         *
+         * @return the X9FieldID for the FieldID in these parameters.
+         */
+        public X9FieldID FieldIDEntry
+        {
+            get { return fieldID; }
+        }
+
+        /**
+         * Return the ASN.1 entry representing the base point G.
+         *
+         * @return the X9ECPoint for the base point in these parameters.
+         */
+        public X9ECPoint BaseEntry
+        {
+            get { return g; }
+        }
+
+        /**
          * Produce an object suitable for an Asn1OutputStream.
          * <pre>
          *  ECParameters ::= Sequence {
@@ -169,10 +201,10 @@ namespace Org.BouncyCastle.Asn1.X9
         public override Asn1Object ToAsn1Object()
         {
             Asn1EncodableVector v = new Asn1EncodableVector(
-                new DerInteger(1),
+                new DerInteger(BigInteger.One),
                 fieldID,
                 new X9Curve(curve, seed),
-                new X9ECPoint(g),
+                g,
                 new DerInteger(n));
 
             if (h != null)
diff --git a/crypto/src/asn1/x9/X9ECParametersHolder.cs b/crypto/src/asn1/x9/X9ECParametersHolder.cs
index dd59e9f56..e802b738c 100644
--- a/crypto/src/asn1/x9/X9ECParametersHolder.cs
+++ b/crypto/src/asn1/x9/X9ECParametersHolder.cs
@@ -1,13 +1,13 @@
 namespace Org.BouncyCastle.Asn1.X9
 {
-    public abstract class X9ECParametersHolder
-    {
-        private X9ECParameters parameters;
+	public abstract class X9ECParametersHolder
+	{
+		private X9ECParameters parameters;
 
-        public X9ECParameters Parameters
-        {
-            get
-            {
+		public X9ECParameters Parameters
+		{
+			get
+			{
                 lock (this)
                 {
                     if (parameters == null)
@@ -20,6 +20,6 @@ namespace Org.BouncyCastle.Asn1.X9
             }
         }
 
-        protected abstract X9ECParameters CreateParameters();
-    }
+		protected abstract X9ECParameters CreateParameters();
+	}
 }
diff --git a/crypto/src/asn1/x9/X9ECPoint.cs b/crypto/src/asn1/x9/X9ECPoint.cs
index 75d58cd38..7ef4f13bc 100644
--- a/crypto/src/asn1/x9/X9ECPoint.cs
+++ b/crypto/src/asn1/x9/X9ECPoint.cs
@@ -1,5 +1,7 @@
 using Org.BouncyCastle.Math.EC;
 
+using Org.BouncyCastle.Utilities;
+
 namespace Org.BouncyCastle.Asn1.X9
 {
     /**
@@ -8,24 +10,58 @@ namespace Org.BouncyCastle.Asn1.X9
     public class X9ECPoint
         : Asn1Encodable
     {
-        private readonly ECPoint p;
+        private readonly Asn1OctetString encoding;
+
+        private ECCurve c;
+        private ECPoint p;
+
+        public X9ECPoint(ECPoint p)
+            : this(p, false)
+        {
+        }
 
-        public X9ECPoint(
-            ECPoint p)
+        public X9ECPoint(ECPoint p, bool compressed)
         {
             this.p = p.Normalize();
+            this.encoding = new DerOctetString(p.GetEncoded(compressed));
+        }
+
+        public X9ECPoint(ECCurve c, byte[] encoding)
+        {
+            this.c = c;
+            this.encoding = new DerOctetString(Arrays.Clone(encoding));
         }
 
-        public X9ECPoint(
-            ECCurve			c,
-            Asn1OctetString	s)
+        public X9ECPoint(ECCurve c, Asn1OctetString s)
+            : this(c, s.GetOctets())
         {
-            this.p = c.DecodePoint(s.GetOctets());
+        }
+
+        public byte[] GetPointEncoding()
+        {
+            return Arrays.Clone(encoding.GetOctets());
         }
 
         public ECPoint Point
         {
-            get { return p; }
+            get
+            {
+                if (p == null)
+                {
+                    p = c.DecodePoint(encoding.GetOctets()).Normalize();
+                }
+
+                return p;
+            }
+        }
+
+        public bool IsPointCompressed
+        {
+            get
+            {
+                byte[] octets = encoding.GetOctets();
+                return octets != null && octets.Length > 0 && (octets[0] == 2 || octets[0] == 3);
+            }
         }
 
         /**
@@ -38,7 +74,7 @@ namespace Org.BouncyCastle.Asn1.X9
          */
         public override Asn1Object ToAsn1Object()
         {
-            return new DerOctetString(p.GetEncoded());
+            return encoding;
         }
     }
 }
diff --git a/crypto/src/asn1/x9/X9FieldID.cs b/crypto/src/asn1/x9/X9FieldID.cs
index 58823a285..08d7d71b4 100644
--- a/crypto/src/asn1/x9/X9FieldID.cs
+++ b/crypto/src/asn1/x9/X9FieldID.cs
@@ -90,11 +90,19 @@ namespace Org.BouncyCastle.Asn1.X9
             this.parameters = new DerSequence(fieldIdParams);
         }
 
-        internal X9FieldID(
-            Asn1Sequence seq)
+        private X9FieldID(Asn1Sequence seq)
         {
-            this.id = (DerObjectIdentifier) seq[0];
-            this.parameters = (Asn1Object) seq[1];
+            this.id = DerObjectIdentifier.GetInstance(seq[0]);
+            this.parameters = seq[1].ToAsn1Object();
+        }
+
+        public static X9FieldID GetInstance(object obj)
+        {
+            if (obj is X9FieldID)
+                return (X9FieldID)obj;
+            if (obj == null)
+                return null;
+            return new X9FieldID(Asn1Sequence.GetInstance(obj));
         }
 
         public DerObjectIdentifier Identifier
diff --git a/crypto/src/bcpg/BcpgInputStream.cs b/crypto/src/bcpg/BcpgInputStream.cs
index e8a4f048d..9835891b1 100644
--- a/crypto/src/bcpg/BcpgInputStream.cs
+++ b/crypto/src/bcpg/BcpgInputStream.cs
@@ -105,19 +105,15 @@ namespace Org.BouncyCastle.Bcpg
                 next = true;
             }
 
-            if (nextB >= 0)
+            if (nextB < 0)
+                return (PacketTag)nextB;
+
+            int maskB = nextB & 0x3f;
+            if ((nextB & 0x40) == 0)    // old
             {
-                if ((nextB & 0x40) != 0)    // new
-                {
-                    return (PacketTag)(nextB & 0x3f);
-                }
-                else    // old
-                {
-                    return (PacketTag)((nextB & 0x3f) >> 2);
-                }
+                maskB >>= 2;
             }
-
-            return (PacketTag) nextB;
+            return (PacketTag)maskB;
         }
 
         public Packet ReadPacket()
diff --git a/crypto/src/bcpg/ECDHPublicBCPGKey.cs b/crypto/src/bcpg/ECDHPublicBCPGKey.cs
index b85379586..dc225e31e 100644
--- a/crypto/src/bcpg/ECDHPublicBCPGKey.cs
+++ b/crypto/src/bcpg/ECDHPublicBCPGKey.cs
@@ -10,8 +10,8 @@ namespace Org.BouncyCastle.Bcpg
         : ECPublicBcpgKey
     {
         private byte reserved;
-        private byte hashFunctionId;
-        private byte symAlgorithmId;
+        private HashAlgorithmTag hashFunctionId;
+        private SymmetricKeyAlgorithmTag symAlgorithmId;
 
         /// <param name="bcpgIn">The stream to read the packet from.</param>
         public ECDHPublicBcpgKey(
@@ -26,8 +26,8 @@ namespace Org.BouncyCastle.Bcpg
             bcpgIn.ReadFully(kdfParameters);
 
             reserved = kdfParameters[0];
-            hashFunctionId = kdfParameters[1];
-            symAlgorithmId = kdfParameters[2];
+            hashFunctionId = (HashAlgorithmTag)kdfParameters[1];
+            symAlgorithmId = (SymmetricKeyAlgorithmTag)kdfParameters[2];
 
             VerifyHashAlgorithm();
             VerifySymmetricKeyAlgorithm();
@@ -36,13 +36,13 @@ namespace Org.BouncyCastle.Bcpg
         public ECDHPublicBcpgKey(
             DerObjectIdentifier oid,
             ECPoint point,
-            int hashAlgorithm,
-            int symmetricKeyAlgorithm)
+            HashAlgorithmTag hashAlgorithm,
+            SymmetricKeyAlgorithmTag symmetricKeyAlgorithm)
             : base(oid, point)
         {
             reserved = 1;
-            hashFunctionId = (byte)hashAlgorithm;
-            symAlgorithmId = (byte)symmetricKeyAlgorithm;
+            hashFunctionId = hashAlgorithm;
+            symAlgorithmId = symmetricKeyAlgorithm;
 
             VerifyHashAlgorithm();
             VerifySymmetricKeyAlgorithm();
@@ -53,12 +53,12 @@ namespace Org.BouncyCastle.Bcpg
             get { return reserved; }
         }
 
-        public virtual byte HashAlgorithm
+        public virtual HashAlgorithmTag HashAlgorithm
         {
             get { return hashFunctionId; }
         }
 
-        public virtual byte SymmetricKeyAlgorithm
+        public virtual SymmetricKeyAlgorithmTag SymmetricKeyAlgorithm
         {
             get { return symAlgorithmId; }
         }
@@ -69,8 +69,8 @@ namespace Org.BouncyCastle.Bcpg
             base.Encode(bcpgOut);
             bcpgOut.WriteByte(0x3);
             bcpgOut.WriteByte(reserved);
-            bcpgOut.WriteByte(hashFunctionId);
-            bcpgOut.WriteByte(symAlgorithmId);
+            bcpgOut.WriteByte((byte)hashFunctionId);
+            bcpgOut.WriteByte((byte)symAlgorithmId);
         }
 
         private void VerifyHashAlgorithm()
diff --git a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
index 4a6704c14..9e30b54f7 100644
--- a/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
+++ b/crypto/src/bcpg/PublicKeyAlgorithmTags.cs
@@ -1,3 +1,5 @@
+using System;
+
 namespace Org.BouncyCastle.Bcpg
 {
     /// <remarks>Public Key Algorithm tag numbers.</remarks>
@@ -8,6 +10,7 @@ namespace Org.BouncyCastle.Bcpg
         RsaSign = 3,			// RSA Sign-Only
         ElGamalEncrypt = 16,	// Elgamal (Encrypt-Only), see [ELGAMAL]
         Dsa = 17,				// DSA (Digital Signature Standard)
+        [Obsolete("Use 'ECDH' instead")]
         EC = 18,				// Reserved for Elliptic Curve
         ECDH = 18,              // Reserved for Elliptic Curve (actual algorithm name)
         ECDsa = 19,				// Reserved for ECDSA
diff --git a/crypto/src/bcpg/PublicKeyEncSessionPacket.cs b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
index d10605f1d..eefe4495b 100644
--- a/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
+++ b/crypto/src/bcpg/PublicKeyEncSessionPacket.cs
@@ -2,6 +2,8 @@ using System;
 using System.IO;
 
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Bcpg
 {
@@ -12,7 +14,7 @@ namespace Org.BouncyCastle.Bcpg
 		private int version;
 		private long keyId;
 		private PublicKeyAlgorithmTag algorithm;
-		private BigInteger[] data;
+        private byte[][] data;
 
 		internal PublicKeyEncSessionPacket(
 			BcpgInputStream bcpgIn)
@@ -34,33 +36,41 @@ namespace Org.BouncyCastle.Bcpg
 			{
 				case PublicKeyAlgorithmTag.RsaEncrypt:
 				case PublicKeyAlgorithmTag.RsaGeneral:
-					data = new BigInteger[]{ new MPInteger(bcpgIn).Value };
+					data = new byte[][]{ new MPInteger(bcpgIn).GetEncoded() };
 					break;
 				case PublicKeyAlgorithmTag.ElGamalEncrypt:
 				case PublicKeyAlgorithmTag.ElGamalGeneral:
-					data = new BigInteger[]
-					{
-						new MPInteger(bcpgIn).Value,
-						new MPInteger(bcpgIn).Value
-					};
+                    MPInteger p = new MPInteger(bcpgIn);
+                    MPInteger g = new MPInteger(bcpgIn);
+					data = new byte[][]{
+                        p.GetEncoded(),
+                        g.GetEncoded(),
+                    };
 					break;
+                case PublicKeyAlgorithmTag.ECDH:
+                    data = new byte[][]{ Streams.ReadAll(bcpgIn) };
+                    break;
 				default:
 					throw new IOException("unknown PGP public key algorithm encountered");
 			}
 		}
 
-		public PublicKeyEncSessionPacket(
-			long					keyId,
-			PublicKeyAlgorithmTag	algorithm,
-			BigInteger[]			data)
+        public PublicKeyEncSessionPacket(
+			long                    keyId,
+			PublicKeyAlgorithmTag   algorithm,
+			byte[][]                data)
 		{
 			this.version = 3;
 			this.keyId = keyId;
 			this.algorithm = algorithm;
-			this.data = (BigInteger[]) data.Clone();
+            this.data = new byte[data.Length][];
+            for (int i = 0; i < data.Length; ++i)
+            {
+                this.data[i] = Arrays.Clone(data[i]);
+            }
 		}
 
-		public int Version
+        public int Version
 		{
 			get { return version; }
 		}
@@ -75,12 +85,12 @@ namespace Org.BouncyCastle.Bcpg
 			get { return algorithm; }
 		}
 
-		public BigInteger[] GetEncSessionKey()
+        public byte[][] GetEncSessionKey()
 		{
-			return (BigInteger[]) data.Clone();
+			return data;
 		}
 
-		public override void Encode(
+        public override void Encode(
 			BcpgOutputStream bcpgOut)
 		{
 			MemoryStream bOut = new MemoryStream();
@@ -92,12 +102,14 @@ namespace Org.BouncyCastle.Bcpg
 
 			pOut.WriteByte((byte)algorithm);
 
-			for (int i = 0; i != data.Length; i++)
-			{
-				MPInteger.Encode(pOut, data[i]);
-			}
+            for (int i = 0; i < data.Length; ++i)
+            {
+                pOut.Write(data[i]);
+            }
+
+            pOut.Dispose();
 
-			bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true);
+            bcpgOut.WritePacket(PacketTag.PublicKeyEncryptedSession , bOut.ToArray(), true);
 		}
 	}
 }
diff --git a/crypto/src/bcpg/PublicKeyPacket.cs b/crypto/src/bcpg/PublicKeyPacket.cs
index cea5c8ed2..bbed941dc 100644
--- a/crypto/src/bcpg/PublicKeyPacket.cs
+++ b/crypto/src/bcpg/PublicKeyPacket.cs
@@ -44,7 +44,7 @@ namespace Org.BouncyCastle.Bcpg
                 case PublicKeyAlgorithmTag.ElGamalGeneral:
                     key = new ElGamalPublicBcpgKey(bcpgIn);
                     break;
-                case PublicKeyAlgorithmTag.EC:
+                case PublicKeyAlgorithmTag.ECDH:
                     key = new ECDHPublicBcpgKey(bcpgIn);
                     break;
                 case PublicKeyAlgorithmTag.ECDsa:
diff --git a/crypto/src/bcpg/S2k.cs b/crypto/src/bcpg/S2k.cs
index f6d306890..33fd792fe 100644
--- a/crypto/src/bcpg/S2k.cs
+++ b/crypto/src/bcpg/S2k.cs
@@ -84,19 +84,19 @@ namespace Org.BouncyCastle.Bcpg
             this.itCount = itCount;
         }
 
-        public int Type
+        public virtual int Type
         {
 			get { return type; }
         }
 
 		/// <summary>The hash algorithm.</summary>
-        public HashAlgorithmTag HashAlgorithm
+        public virtual HashAlgorithmTag HashAlgorithm
         {
 			get { return algorithm; }
 		}
 
 		/// <summary>The IV for the key generation algorithm.</summary>
-        public byte[] GetIV()
+        public virtual byte[] GetIV()
         {
             return Arrays.Clone(iv);
         }
@@ -108,13 +108,13 @@ namespace Org.BouncyCastle.Bcpg
         }
 
 		/// <summary>The iteration count</summary>
-		public long IterationCount
+        public virtual long IterationCount
 		{
 			get { return (16 + (itCount & 15)) << ((itCount >> 4) + ExpBias); }
 		}
 
 		/// <summary>The protection mode - only if GnuDummyS2K</summary>
-        public int ProtectionMode
+        public virtual int ProtectionMode
         {
 			get { return protectionMode; }
         }
diff --git a/crypto/src/bcpg/SignatureSubpacket.cs b/crypto/src/bcpg/SignatureSubpacket.cs
index ac26f8a3c..d99315599 100644
--- a/crypto/src/bcpg/SignatureSubpacket.cs
+++ b/crypto/src/bcpg/SignatureSubpacket.cs
@@ -7,20 +7,22 @@ namespace Org.BouncyCastle.Bcpg
     {
         private readonly SignatureSubpacketTag type;
         private readonly bool critical;
-
-		internal readonly byte[] data;
+        private readonly bool isLongLength;
+		internal byte[] data;
 
 		protected internal SignatureSubpacket(
             SignatureSubpacketTag	type,
             bool					critical,
+            bool                    isLongLength,
             byte[]					data)
         {
             this.type = type;
             this.critical = critical;
+            this.isLongLength = isLongLength;
             this.data = data;
         }
 
-		public SignatureSubpacketTag SubpacketType
+        public SignatureSubpacketTag SubpacketType
         {
 			get { return type; }
         }
@@ -30,7 +32,12 @@ namespace Org.BouncyCastle.Bcpg
             return critical;
         }
 
-		/// <summary>Return the generic data making up the packet.</summary>
+        public bool IsLongLength()
+        {
+            return isLongLength;
+        }
+
+        /// <summary>Return the generic data making up the packet.</summary>
         public byte[] GetData()
         {
             return (byte[]) data.Clone();
@@ -41,18 +48,7 @@ namespace Org.BouncyCastle.Bcpg
         {
             int bodyLen = data.Length + 1;
 
-            if (bodyLen < 192)
-            {
-                os.WriteByte((byte)bodyLen);
-            }
-            else if (bodyLen <= 8383)
-            {
-                bodyLen -= 192;
-
-                os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
-                os.WriteByte((byte)bodyLen);
-            }
-            else
+            if (isLongLength)
             {
                 os.WriteByte(0xff);
                 os.WriteByte((byte)(bodyLen >> 24));
@@ -60,6 +56,28 @@ namespace Org.BouncyCastle.Bcpg
                 os.WriteByte((byte)(bodyLen >> 8));
                 os.WriteByte((byte)bodyLen);
             }
+            else
+            {
+                if (bodyLen < 192)
+                {
+                    os.WriteByte((byte)bodyLen);
+                }
+                else if (bodyLen <= 8383)
+                {
+                    bodyLen -= 192;
+
+                    os.WriteByte((byte)(((bodyLen >> 8) & 0xff) + 192));
+                    os.WriteByte((byte)bodyLen);
+                }
+                else
+                {
+                    os.WriteByte(0xff);
+                    os.WriteByte((byte)(bodyLen >> 24));
+                    os.WriteByte((byte)(bodyLen >> 16));
+                    os.WriteByte((byte)(bodyLen >> 8));
+                    os.WriteByte((byte)bodyLen);
+                }
+            }
 
             if (critical)
             {
diff --git a/crypto/src/bcpg/SignatureSubpacketsReader.cs b/crypto/src/bcpg/SignatureSubpacketsReader.cs
index 8dd1af332..80bedb07c 100644
--- a/crypto/src/bcpg/SignatureSubpacketsReader.cs
+++ b/crypto/src/bcpg/SignatureSubpacketsReader.cs
@@ -1,6 +1,8 @@
 using System;
 using System.IO;
+
 using Org.BouncyCastle.Bcpg.Sig;
+using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Bcpg
@@ -25,7 +27,9 @@ namespace Org.BouncyCastle.Bcpg
 				return null;
 
 			int bodyLen = 0;
-			if (l < 192)
+            bool isLongLength = false;
+
+            if (l < 192)
 			{
 				bodyLen = l;
 			}
@@ -35,54 +39,90 @@ namespace Org.BouncyCastle.Bcpg
 			}
 			else if (l == 255)
 			{
+                isLongLength = true;
 				bodyLen = (input.ReadByte() << 24) | (input.ReadByte() << 16)
 					|  (input.ReadByte() << 8)  | input.ReadByte();
 			}
 			else
 			{
-				// TODO Error?
+                throw new IOException("unexpected length header");
 			}
 
-			int tag = input.ReadByte();
+            int tag = input.ReadByte();
 			if (tag < 0)
 				throw new EndOfStreamException("unexpected EOF reading signature sub packet");
 
-			byte[] data = new byte[bodyLen - 1];
-			if (Streams.ReadFully(input, data) < data.Length)
-				throw new EndOfStreamException();
+            byte[] data = new byte[bodyLen - 1];
+
+            //
+            // this may seem a bit strange but it turns out some applications miscode the length
+            // in fixed length fields, so we check the length we do get, only throwing an exception if
+            // we really cannot continue
+            //
+            int bytesRead = Streams.ReadFully(input, data);
+
+            bool isCritical = ((tag & 0x80) != 0);
+            SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f);
 
-			bool isCritical = ((tag & 0x80) != 0);
-			SignatureSubpacketTag type = (SignatureSubpacketTag)(tag & 0x7f);
-			switch (type)
+            if (bytesRead != data.Length)
+            {
+                switch (type)
+                {
+                case SignatureSubpacketTag.CreationTime:
+                    data = CheckData(data, 4, bytesRead, "Signature Creation Time");
+                    break;
+                case SignatureSubpacketTag.IssuerKeyId:
+                    data = CheckData(data, 8, bytesRead, "Issuer");
+                    break;
+                case SignatureSubpacketTag.KeyExpireTime:
+                    data = CheckData(data, 4, bytesRead, "Signature Key Expiration Time");
+                    break;
+                case SignatureSubpacketTag.ExpireTime:
+                    data = CheckData(data, 4, bytesRead, "Signature Expiration Time");
+                    break;
+                default:
+                    throw new EndOfStreamException("truncated subpacket data.");
+                }
+            }
+
+            switch (type)
 			{
 				case SignatureSubpacketTag.CreationTime:
-					return new SignatureCreationTime(isCritical, data);
+					return new SignatureCreationTime(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.KeyExpireTime:
-					return new KeyExpirationTime(isCritical, data);
+                    return new KeyExpirationTime(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.ExpireTime:
-					return new SignatureExpirationTime(isCritical, data);
+                    return new SignatureExpirationTime(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.Revocable:
-					return new Revocable(isCritical, data);
+                    return new Revocable(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.Exportable:
-					return new Exportable(isCritical, data);
+                    return new Exportable(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.IssuerKeyId:
-					return new IssuerKeyId(isCritical, data);
+                    return new IssuerKeyId(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.TrustSig:
-					return new TrustSignature(isCritical, data);
+                    return new TrustSignature(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.PreferredCompressionAlgorithms:
 				case SignatureSubpacketTag.PreferredHashAlgorithms:
 				case SignatureSubpacketTag.PreferredSymmetricAlgorithms:
-					return new PreferredAlgorithms(type, isCritical, data);
+                    return new PreferredAlgorithms(type, isCritical, isLongLength, data);
 				case SignatureSubpacketTag.KeyFlags:
-					return new KeyFlags(isCritical, data);
+                    return new KeyFlags(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.PrimaryUserId:
-					return new PrimaryUserId(isCritical, data);
+                    return new PrimaryUserId(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.SignerUserId:
-					return new SignerUserId(isCritical, data);
+                    return new SignerUserId(isCritical, isLongLength, data);
 				case SignatureSubpacketTag.NotationData:
-					return new NotationData(isCritical, data);
+                    return new NotationData(isCritical, isLongLength, data);
 			}
-			return new SignatureSubpacket(type, isCritical, data);
+            return new SignatureSubpacket(type, isCritical, isLongLength, data);
 		}
+
+        private byte[] CheckData(byte[] data, int expected, int bytesRead, string name)
+        {
+            if (bytesRead != expected)
+                throw new EndOfStreamException("truncated " + name + " subpacket data.");
+
+            return Arrays.CopyOfRange(data, 0, expected);
+        }
 	}
 }
diff --git a/crypto/src/bcpg/sig/EmbeddedSignature.cs b/crypto/src/bcpg/sig/EmbeddedSignature.cs
index e47604ac8..fffdaef73 100644
--- a/crypto/src/bcpg/sig/EmbeddedSignature.cs
+++ b/crypto/src/bcpg/sig/EmbeddedSignature.cs
@@ -10,8 +10,9 @@ namespace Org.BouncyCastle.Bcpg.Sig
 	{
 		public EmbeddedSignature(
 			bool	critical,
+            bool    isLongLength,
 			byte[]	data)
-			: base(SignatureSubpacketTag.EmbeddedSignature, critical, data)
+			: base(SignatureSubpacketTag.EmbeddedSignature, critical, isLongLength, data)
 		{
 		}
 	}
diff --git a/crypto/src/bcpg/sig/Exportable.cs b/crypto/src/bcpg/sig/Exportable.cs
index 4455c3814..4d030346f 100644
--- a/crypto/src/bcpg/sig/Exportable.cs
+++ b/crypto/src/bcpg/sig/Exportable.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -27,15 +25,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
         public Exportable(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.Exportable, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.Exportable, critical, isLongLength, data)
         {
         }
 
         public Exportable(
             bool    critical,
             bool    isExportable)
-            : base(SignatureSubpacketTag.Exportable, critical, BooleanToByteArray(isExportable))
+            : base(SignatureSubpacketTag.Exportable, critical, false, BooleanToByteArray(isExportable))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/Features.cs b/crypto/src/bcpg/sig/Features.cs
new file mode 100644
index 000000000..29584239a
--- /dev/null
+++ b/crypto/src/bcpg/sig/Features.cs
@@ -0,0 +1,75 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Bcpg.Sig
+{
+    /**
+    * packet giving signature expiration time.
+    */
+    public class Features
+        : SignatureSubpacket
+    {
+        /** Identifier for the modification detection feature */
+        public static readonly byte FEATURE_MODIFICATION_DETECTION = 1;
+
+        private static byte[] FeatureToByteArray(byte feature)
+        {
+            return new byte[]{ feature };
+        }
+
+        public Features(
+            bool    critical,
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.Features, critical, isLongLength, data)
+        {
+        }
+
+        public Features(bool critical, byte feature)
+            : base(SignatureSubpacketTag.Features, critical, false, FeatureToByteArray(feature))
+        {
+        }
+
+        /**
+         * Returns if modification detection is supported.
+         */
+        public bool SupportsModificationDetection
+        {
+            get { return SupportsFeature(FEATURE_MODIFICATION_DETECTION); }
+        }
+
+        /**
+         * Returns if a particular feature is supported.
+         */
+        public bool SupportsFeature(byte feature)
+        {
+            return Array.IndexOf(data, feature) >= 0;
+        }
+
+        /**
+         * Sets support for a particular feature.
+         */
+        private void SetSupportsFeature(byte feature, bool support)
+        {
+            if (feature == 0)
+                throw new ArgumentException("cannot be 0", "feature");
+
+            int i = Array.IndexOf(data, feature);
+            if ((i >= 0) == support)
+                return;
+
+            if (support)
+            {
+                data = Arrays.Append(data, feature);
+            }
+            else
+            {
+                byte[] temp = new byte[data.Length - 1];
+                Array.Copy(data, 0, temp, 0, i);
+                Array.Copy(data, i + 1, temp, i, temp.Length - i);
+                data = temp;
+            }
+        }
+    }
+}
diff --git a/crypto/src/bcpg/sig/IssuerKeyId.cs b/crypto/src/bcpg/sig/IssuerKeyId.cs
index 91490d33b..627ea3ecf 100644
--- a/crypto/src/bcpg/sig/IssuerKeyId.cs
+++ b/crypto/src/bcpg/sig/IssuerKeyId.cs
@@ -29,15 +29,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
         public IssuerKeyId(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.IssuerKeyId, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.IssuerKeyId, critical, isLongLength, data)
         {
         }
 
         public IssuerKeyId(
             bool    critical,
-            long       keyId)
-            : base(SignatureSubpacketTag.IssuerKeyId, critical, KeyIdToBytes(keyId))
+            long    keyId)
+            : base(SignatureSubpacketTag.IssuerKeyId, critical, false, KeyIdToBytes(keyId))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/KeyExpirationTime.cs b/crypto/src/bcpg/sig/KeyExpirationTime.cs
index 23b4cac29..dfd3e76fd 100644
--- a/crypto/src/bcpg/sig/KeyExpirationTime.cs
+++ b/crypto/src/bcpg/sig/KeyExpirationTime.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -25,15 +23,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
         public KeyExpirationTime(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.KeyExpireTime, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.KeyExpireTime, critical, isLongLength, data)
         {
         }
 
         public KeyExpirationTime(
             bool    critical,
-            long       seconds)
-            : base(SignatureSubpacketTag.KeyExpireTime, critical, TimeToBytes(seconds))
+            long    seconds)
+            : base(SignatureSubpacketTag.KeyExpireTime, critical, false, TimeToBytes(seconds))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/KeyFlags.cs b/crypto/src/bcpg/sig/KeyFlags.cs
index 0592301b3..5b5d85a72 100644
--- a/crypto/src/bcpg/sig/KeyFlags.cs
+++ b/crypto/src/bcpg/sig/KeyFlags.cs
@@ -40,15 +40,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
 		public KeyFlags(
             bool	critical,
-            byte[]	data)
-            : base(SignatureSubpacketTag.KeyFlags, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.KeyFlags, critical, isLongLength, data)
         {
         }
 
 		public KeyFlags(
-			bool	critical,
-			int		flags)
-            : base(SignatureSubpacketTag.KeyFlags, critical, IntToByteArray(flags))
+			bool    critical,
+			int     flags)
+            : base(SignatureSubpacketTag.KeyFlags, critical, false, IntToByteArray(flags))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/NotationData.cs b/crypto/src/bcpg/sig/NotationData.cs
index ccc9aa745..9ac6f89cf 100644
--- a/crypto/src/bcpg/sig/NotationData.cs
+++ b/crypto/src/bcpg/sig/NotationData.cs
@@ -17,8 +17,9 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
 		public NotationData(
 			bool	critical,
-			byte[]	data)
-			: base(SignatureSubpacketTag.NotationData, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+			: base(SignatureSubpacketTag.NotationData, critical, isLongLength, data)
 		{
 		}
 
@@ -27,12 +28,12 @@ namespace Org.BouncyCastle.Bcpg.Sig
 			bool	humanReadable,
 			string	notationName,
 			string	notationValue)
-			: base(SignatureSubpacketTag.NotationData, critical,
-				createData(humanReadable, notationName, notationValue))
+			: base(SignatureSubpacketTag.NotationData, critical, false,
+				CreateData(humanReadable, notationName, notationValue))
 		{
 		}
 
-		private static byte[] createData(
+		private static byte[] CreateData(
 			bool	humanReadable,
 			string	notationName,
 			string	notationValue)
diff --git a/crypto/src/bcpg/sig/PreferredAlgorithms.cs b/crypto/src/bcpg/sig/PreferredAlgorithms.cs
index 0f282a38c..9514bed2b 100644
--- a/crypto/src/bcpg/sig/PreferredAlgorithms.cs
+++ b/crypto/src/bcpg/sig/PreferredAlgorithms.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -24,24 +22,25 @@ namespace Org.BouncyCastle.Bcpg.Sig
         }
 
         public PreferredAlgorithms(
-            SignatureSubpacketTag        type,
-            bool    critical,
-            byte[]     data)
-            : base(type, critical, data)
+            SignatureSubpacketTag   type,
+            bool                    critical,
+            bool                    isLongLength,
+            byte[]                  data)
+            : base(type, critical, isLongLength, data)
         {
         }
 
         public PreferredAlgorithms(
-            SignatureSubpacketTag        type,
-            bool    critical,
-            int[]      preferences)
-            : base(type, critical, IntToByteArray(preferences))
+            SignatureSubpacketTag   type,
+            bool                    critical,
+            int[]                   preferences)
+            : base(type, critical, false, IntToByteArray(preferences))
         {
         }
 
         public int[] GetPreferences()
         {
-            int[]    v = new int[data.Length];
+            int[] v = new int[data.Length];
 
             for (int i = 0; i != v.Length; i++)
             {
diff --git a/crypto/src/bcpg/sig/PrimaryUserId.cs b/crypto/src/bcpg/sig/PrimaryUserId.cs
index fc0353afd..1f16f40eb 100644
--- a/crypto/src/bcpg/sig/PrimaryUserId.cs
+++ b/crypto/src/bcpg/sig/PrimaryUserId.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -28,15 +26,16 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
         public PrimaryUserId(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.PrimaryUserId, critical, data)
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.PrimaryUserId, critical, isLongLength, data)
         {
         }
 
         public PrimaryUserId(
             bool    critical,
             bool    isPrimaryUserId)
-            : base(SignatureSubpacketTag.PrimaryUserId, critical, BooleanToByteArray(isPrimaryUserId))
+            : base(SignatureSubpacketTag.PrimaryUserId, critical, false, BooleanToByteArray(isPrimaryUserId))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/Revocable.cs b/crypto/src/bcpg/sig/Revocable.cs
index b5e94feec..7aa91391f 100644
--- a/crypto/src/bcpg/sig/Revocable.cs
+++ b/crypto/src/bcpg/sig/Revocable.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -28,16 +26,17 @@ namespace Org.BouncyCastle.Bcpg.Sig
 
         public Revocable(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.Revocable, critical, data)
-    {
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.Revocable, critical, isLongLength, data)
+        {
         }
 
         public Revocable(
             bool    critical,
             bool    isRevocable)
-            : base(SignatureSubpacketTag.Revocable, critical, BooleanToByteArray(isRevocable))
-    {
+            : base(SignatureSubpacketTag.Revocable, critical, false, BooleanToByteArray(isRevocable))
+        {
         }
 
         public bool IsRevocable()
diff --git a/crypto/src/bcpg/sig/RevocationKey.cs b/crypto/src/bcpg/sig/RevocationKey.cs
index 66982cb5a..11467d2af 100644
--- a/crypto/src/bcpg/sig/RevocationKey.cs
+++ b/crypto/src/bcpg/sig/RevocationKey.cs
@@ -14,17 +14,18 @@ namespace Org.BouncyCastle.Bcpg
 		// 20 octets of fingerprint
 		public RevocationKey(
 			bool	isCritical,
-			byte[]	data)
-			: base(SignatureSubpacketTag.RevocationKey, isCritical, data)
+            bool    isLongLength,
+            byte[]  data)
+			: base(SignatureSubpacketTag.RevocationKey, isCritical, isLongLength, data)
 		{
 		}
 
-		public RevocationKey(
+        public RevocationKey(
 			bool					isCritical,
 			RevocationKeyTag		signatureClass,
 			PublicKeyAlgorithmTag	keyAlgorithm,
 			byte[]					fingerprint)
-			: base(SignatureSubpacketTag.RevocationKey, isCritical,
+			: base(SignatureSubpacketTag.RevocationKey, isCritical, false,
 				CreateData(signatureClass, keyAlgorithm, fingerprint))
 		{
 		}
diff --git a/crypto/src/bcpg/sig/RevocationReason.cs b/crypto/src/bcpg/sig/RevocationReason.cs
index 98e9b0a3d..42afd5f5b 100644
--- a/crypto/src/bcpg/sig/RevocationReason.cs
+++ b/crypto/src/bcpg/sig/RevocationReason.cs
@@ -11,16 +11,16 @@ namespace Org.BouncyCastle.Bcpg
     public class RevocationReason
 		: SignatureSubpacket
     {
-        public RevocationReason(bool isCritical, byte[] data)
-            : base(SignatureSubpacketTag.RevocationReason, isCritical, data)
+        public RevocationReason(bool isCritical, bool isLongLength, byte[] data)
+            : base(SignatureSubpacketTag.RevocationReason, isCritical, isLongLength, data)
         {
         }
 
-		public RevocationReason(
-			bool				isCritical,
-			RevocationReasonTag	reason,
-			string				description)
-            : base(SignatureSubpacketTag.RevocationReason, isCritical, CreateData(reason, description))
+        public RevocationReason(
+			bool                isCritical,
+			RevocationReasonTag reason,
+			string              description)
+            : base(SignatureSubpacketTag.RevocationReason, isCritical, false, CreateData(reason, description))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/SignatureCreationTime.cs b/crypto/src/bcpg/sig/SignatureCreationTime.cs
index e6f241f11..d172e5d52 100644
--- a/crypto/src/bcpg/sig/SignatureCreationTime.cs
+++ b/crypto/src/bcpg/sig/SignatureCreationTime.cs
@@ -21,18 +21,22 @@ namespace Org.BouncyCastle.Bcpg.Sig
             data[3] = (byte)t;
             return data;
         }
+
         public SignatureCreationTime(
-            bool	critical,
-            byte[]	data)
-            : base(SignatureSubpacketTag.CreationTime, critical, data)
+            bool    critical,
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.CreationTime, critical, isLongLength, data)
         {
         }
+
         public SignatureCreationTime(
-            bool		critical,
-            DateTime	date)
-            : base(SignatureSubpacketTag.CreationTime, critical, TimeToBytes(date))
+            bool        critical,
+            DateTime    date)
+            : base(SignatureSubpacketTag.CreationTime, critical, false, TimeToBytes(date))
         {
         }
+
         public DateTime GetTime()
         {
 			long time = (long)(
diff --git a/crypto/src/bcpg/sig/SignatureExpirationTime.cs b/crypto/src/bcpg/sig/SignatureExpirationTime.cs
index 7fddf5743..24f0a9f8a 100644
--- a/crypto/src/bcpg/sig/SignatureExpirationTime.cs
+++ b/crypto/src/bcpg/sig/SignatureExpirationTime.cs
@@ -1,7 +1,5 @@
 using System;
 
-
-
 namespace Org.BouncyCastle.Bcpg.Sig
 {
     /**
@@ -11,29 +9,28 @@ namespace Org.BouncyCastle.Bcpg.Sig
         : SignatureSubpacket
     {
         protected static byte[] TimeToBytes(
-            long      t)
+            long    t)
         {
-            byte[]    data = new byte[4];
-
+            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;
         }
 
         public SignatureExpirationTime(
             bool    critical,
-            byte[]     data)
-            : base(SignatureSubpacketTag.ExpireTime, critical, data)
-    {
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.ExpireTime, critical, isLongLength, data)
+        {
         }
 
         public SignatureExpirationTime(
             bool    critical,
-            long       seconds)
-            : base(SignatureSubpacketTag.ExpireTime, critical, TimeToBytes(seconds))
+            long    seconds)
+            : base(SignatureSubpacketTag.ExpireTime, critical, false, TimeToBytes(seconds))
         {
         }
 
diff --git a/crypto/src/bcpg/sig/SignerUserId.cs b/crypto/src/bcpg/sig/SignerUserId.cs
index 98cc808e7..8ab62ed2e 100644
--- a/crypto/src/bcpg/sig/SignerUserId.cs
+++ b/crypto/src/bcpg/sig/SignerUserId.cs
@@ -24,20 +24,21 @@ namespace Org.BouncyCastle.Bcpg.Sig
         }
 
         public SignerUserId(
-            bool	critical,
-            byte[]	data)
-            : base(SignatureSubpacketTag.SignerUserId, critical, data)
+            bool    critical,
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.SignerUserId, critical, isLongLength, data)
 		{
 		}
 
-		public SignerUserId(
-            bool	critical,
-            string	userId)
-            : base(SignatureSubpacketTag.SignerUserId, critical, UserIdToBytes(userId))
+        public SignerUserId(
+            bool    critical,
+            string  userId)
+            : base(SignatureSubpacketTag.SignerUserId, critical, false, UserIdToBytes(userId))
 		{
         }
 
-		public string GetId()
+        public string GetId()
         {
             char[] chars = new char[data.Length];
 
diff --git a/crypto/src/bcpg/sig/TrustSignature.cs b/crypto/src/bcpg/sig/TrustSignature.cs
index bbadd3067..91458826d 100644
--- a/crypto/src/bcpg/sig/TrustSignature.cs
+++ b/crypto/src/bcpg/sig/TrustSignature.cs
@@ -16,17 +16,18 @@ namespace Org.BouncyCastle.Bcpg.Sig
         }
 
 		public TrustSignature(
-            bool	critical,
-            byte[]	data)
-            : base(SignatureSubpacketTag.TrustSig, critical, data)
+            bool    critical,
+            bool    isLongLength,
+            byte[]  data)
+            : base(SignatureSubpacketTag.TrustSig, critical, isLongLength, data)
         {
         }
 
         public TrustSignature(
-            bool	critical,
-            int		depth,
-            int		trustAmount)
-            : base(SignatureSubpacketTag.TrustSig, critical, IntToByteArray(depth, trustAmount))
+            bool    critical,
+            int     depth,
+            int     trustAmount)
+            : base(SignatureSubpacketTag.TrustSig, critical, false, IntToByteArray(depth, trustAmount))
         {
         }
 
diff --git a/crypto/src/cms/CMSTypedStream.cs b/crypto/src/cms/CMSTypedStream.cs
index edb22dd3d..8cf5d370b 100644
--- a/crypto/src/cms/CMSTypedStream.cs
+++ b/crypto/src/cms/CMSTypedStream.cs
@@ -2,7 +2,6 @@ using System;
 using System.IO;
 
 using Org.BouncyCastle.Asn1.Pkcs;
-using Org.BouncyCastle.Asn1.Utilities;
 using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Cms
diff --git a/crypto/src/cms/SignerInformation.cs b/crypto/src/cms/SignerInformation.cs
index 20af29a50..581286a3f 100644
--- a/crypto/src/cms/SignerInformation.cs
+++ b/crypto/src/cms/SignerInformation.cs
@@ -345,9 +345,12 @@ namespace Org.BouncyCastle.Cms
 //				if (sigParams != null)
 //					throw new CmsException("unrecognised signature parameters provided");
 
-				string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
+                string signatureName = digestName + "with" + Helper.GetEncryptionAlgName(this.EncryptionAlgOid);
 
-				sig = Helper.GetSignatureInstance(signatureName);
+                sig = Helper.GetSignatureInstance(signatureName);
+
+                //sig = Helper.GetSignatureInstance(this.EncryptionAlgOid);
+                //sig = SignerUtilities.GetSigner(sigAlgOid);
 			}
 
 			try
diff --git a/crypto/src/crypto/IBlockResult.cs b/crypto/src/crypto/IBlockResult.cs
new file mode 100644
index 000000000..c12bdaa1d
--- /dev/null
+++ b/crypto/src/crypto/IBlockResult.cs
@@ -0,0 +1,24 @@
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <summary>
+    /// Operators that reduce their input to a single block return an object
+    /// of this type.
+    /// </summary>
+    public interface IBlockResult
+    {
+        /// <summary>
+        /// Return the final result of the operation.
+        /// </summary>
+        /// <returns>A block of bytes, representing the result of an operation.</returns>
+        byte[] DoFinal();
+
+        /// <summary>
+        /// Store the final result of the operation by copying it into the destination array.
+        /// </summary>
+        /// <returns>The number of bytes copied into destination.</returns>
+        /// <param name="destination">The byte array to copy the result into.</param>
+        /// <param name="offset">The offset into destination to start copying the result at.</param>
+        int DoFinal(byte[] destination, int offset);
+    }
+}
diff --git a/crypto/src/crypto/ISignatureCalculator.cs b/crypto/src/crypto/ISignatureCalculator.cs
new file mode 100644
index 000000000..bb733818d
--- /dev/null
+++ b/crypto/src/crypto/ISignatureCalculator.cs
@@ -0,0 +1,23 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <summary>
+    /// Base interface for operators that serve as stream-based signature calculators.
+    /// </summary>
+    public interface ISignatureCalculator
+	{
+        /// <summary>The algorithm details object for this calculator.</summary>
+        Object AlgorithmDetails { get ; }
+
+        /// <summary>
+        /// Create a stream calculator for this signature calculator. The stream
+        /// calculator is used for the actual operation of entering the data to be signed
+        /// and producing the signature block.
+        /// </summary>
+        /// <returns>A calculator producing an IBlockResult with a signature in it.</returns>
+        IStreamCalculator CreateCalculator();
+    }
+}
+
+
diff --git a/crypto/src/crypto/ISignatureVerifier.cs b/crypto/src/crypto/ISignatureVerifier.cs
new file mode 100644
index 000000000..1f42a0256
--- /dev/null
+++ b/crypto/src/crypto/ISignatureVerifier.cs
@@ -0,0 +1,21 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <summary>
+    /// Base interface for operators that serve as stream-based signature verifiers.
+    /// </summary>
+    public interface ISignatureVerifier
+	{
+        /// <summary>The algorithm details object for this verifier.</summary>
+        Object AlgorithmDetails { get ; }
+
+        /// <summary>
+        /// Create a stream calculator for this verifier. The stream
+        /// calculator is used for the actual operation of entering the data to be verified
+        /// and producing a result which can be used to verify the original signature.
+        /// </summary>
+        /// <returns>A calculator producing an IVerifier which can verify the signature.</returns>
+        IStreamCalculator CreateCalculator();
+    }
+}
diff --git a/crypto/src/crypto/ISignatureVerifierProvider.cs b/crypto/src/crypto/ISignatureVerifierProvider.cs
new file mode 100644
index 000000000..20180e22a
--- /dev/null
+++ b/crypto/src/crypto/ISignatureVerifierProvider.cs
@@ -0,0 +1,18 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <summary>
+    /// Base interface for a provider to support the dynamic creation of signature verifiers.
+    /// </summary>
+    public interface ISignatureVerifierProvider
+	{
+        /// <summary>
+        /// Return a signature verfier for signature algorithm described in the passed in algorithm details object.
+        /// </summary>
+        /// <param name="algorithmDetails">The details of the signature algorithm verification is required for.</param>
+        /// <returns>A new signature verifier.</returns>
+		ISignatureVerifier CreateSignatureVerifier (Object algorithmDetails);
+	}
+}
+
diff --git a/crypto/src/crypto/IStreamCalculator.cs b/crypto/src/crypto/IStreamCalculator.cs
new file mode 100644
index 000000000..19a542845
--- /dev/null
+++ b/crypto/src/crypto/IStreamCalculator.cs
@@ -0,0 +1,23 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <summary>
+    /// Base interface for cryptographic operations such as Hashes, MACs, and Signatures which reduce a stream of data
+    /// to a single value.
+    /// </summary>
+    public interface IStreamCalculator
+    {
+        /// <summary>Return a "sink" stream which only exists to update the implementing object.</summary>
+        /// <returns>A stream to write to in order to update the implementing object.</returns>
+        Stream Stream { get; }
+
+        /// <summary>
+        /// Return the result of processing the stream. This value is only available once the stream
+        /// has been closed.
+        /// </summary>
+        /// <returns>The result of processing the stream.</returns>
+        Object GetResult();
+    }
+}
diff --git a/crypto/src/crypto/IVerifier.cs b/crypto/src/crypto/IVerifier.cs
new file mode 100644
index 000000000..560cabf8e
--- /dev/null
+++ b/crypto/src/crypto/IVerifier.cs
@@ -0,0 +1,25 @@
+namespace Org.BouncyCastle.Crypto
+{
+    /// <summary>
+    /// Operators that reduce their input to the validation of a signature produce this type.
+    /// </summary>
+    public interface IVerifier
+    {
+        /// <summary>
+        /// Return true if the passed in data matches what is expected by the verification result.
+        /// </summary>
+        /// <param name="data">The bytes representing the signature.</param>
+        /// <returns>true if the signature verifies, false otherwise.</returns>
+        bool IsVerified(byte[] data);
+
+        /// <summary>
+        /// Return true if the length bytes from off in the source array match the signature
+        /// expected by the verification result.
+        /// </summary>
+        /// <param name="source">Byte array containing the signature.</param>
+        /// <param name="off">The offset into the source array where the signature starts.</param>
+        /// <param name="length">The number of bytes in source making up the signature.</param>
+        /// <returns>true if the signature verifies, false otherwise.</returns>
+        bool IsVerified(byte[] source, int off, int length);
+    }
+}
diff --git a/crypto/src/crypto/IXof.cs b/crypto/src/crypto/IXof.cs
new file mode 100644
index 000000000..e9e2253a0
--- /dev/null
+++ b/crypto/src/crypto/IXof.cs
@@ -0,0 +1,22 @@
+using System;
+
+namespace Org.BouncyCastle.Crypto
+{
+    /// <remarks>
+    /// With FIPS PUB 202 a new kind of message digest was announced which supported extendable output, or variable digest sizes.
+    /// This interface provides the extra method required to support variable output on a digest implementation.
+    /// </remarks>
+    public interface IXof
+        : IDigest
+    {
+        /**
+         * Output the results of the final calculation for this digest to outLen number of bytes.
+         *
+         * @param out output array to write the output bytes to.
+         * @param outOff offset to start writing the bytes at.
+         * @param outLen the number of output bytes requested.
+         * @return the number of bytes written
+         */
+        int DoFinal(byte[] output, int outOff, int outLen);
+    }
+}
diff --git a/crypto/src/crypto/digests/KeccakDigest.cs b/crypto/src/crypto/digests/KeccakDigest.cs
new file mode 100644
index 000000000..2d6cf393c
--- /dev/null
+++ b/crypto/src/crypto/digests/KeccakDigest.cs
@@ -0,0 +1,534 @@
+using System;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /// <summary>
+    /// Implementation of Keccak based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
+    /// </summary>
+    /// <remarks>
+    /// Following the naming conventions used in the C source code to enable easy review of the implementation.
+    /// </remarks>
+    public class KeccakDigest
+        : IDigest, IMemoable
+    {
+        private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants();
+
+        private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets();
+
+        private static ulong[] KeccakInitializeRoundConstants()
+        {
+            ulong[] keccakRoundConstants = new ulong[24];
+            byte LFSRState = 0x01;
+
+            for (int i = 0; i < 24; i++)
+            {
+                keccakRoundConstants[i] = 0;
+                for (int j = 0; j < 7; j++)
+                {
+                    int bitPosition = (1 << j) - 1;
+
+                    // LFSR86540
+
+                    bool loBit = (LFSRState & 0x01) != 0;
+                    if (loBit)
+                    {
+                        keccakRoundConstants[i] ^= 1UL << bitPosition;
+                    }
+
+                    bool hiBit = (LFSRState & 0x80) != 0;
+                    LFSRState <<= 1;
+                    if (hiBit)
+                    {
+                        LFSRState ^= 0x71;
+                    }
+
+                }
+            }
+
+            return keccakRoundConstants;
+        }
+
+        private static int[] KeccakInitializeRhoOffsets()
+        {
+            int[] keccakRhoOffsets = new int[25];
+            int x, y, t, newX, newY;
+
+            int rhoOffset = 0;
+            keccakRhoOffsets[(((0) % 5) + 5 * ((0) % 5))] = rhoOffset;
+            x = 1;
+            y = 0;
+            for (t = 1; t < 25; t++)
+            {
+                //rhoOffset = ((t + 1) * (t + 2) / 2) % 64;
+                rhoOffset = (rhoOffset + t) & 63;
+                keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset;
+                newX = (0 * x + 1 * y) % 5;
+                newY = (2 * x + 3 * y) % 5;
+                x = newX;
+                y = newY;
+            }
+
+            return keccakRhoOffsets;
+        }
+
+        protected byte[] state = new byte[(1600 / 8)];
+        protected byte[] dataQueue = new byte[(1536 / 8)];
+        protected int rate;
+        protected int bitsInQueue;
+        protected int fixedOutputLength;
+        protected bool squeezing;
+        protected int bitsAvailableForSqueezing;
+        protected byte[] chunk;
+        protected byte[] oneByte;
+
+        private void ClearDataQueueSection(int off, int len)
+        {
+            for (int i = off; i != off + len; i++)
+            {
+                dataQueue[i] = 0;
+            }
+        }
+
+        public KeccakDigest()
+            : this(288)
+        {
+        }
+
+        public KeccakDigest(int bitLength)
+        {
+            Init(bitLength);
+        }
+
+        public KeccakDigest(KeccakDigest source)
+        {
+            CopyIn(source);
+        }
+
+        private void CopyIn(KeccakDigest source)
+        {
+            Array.Copy(source.state, 0, this.state, 0, source.state.Length);
+            Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length);
+            this.rate = source.rate;
+            this.bitsInQueue = source.bitsInQueue;
+            this.fixedOutputLength = source.fixedOutputLength;
+            this.squeezing = source.squeezing;
+            this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing;
+            this.chunk = Arrays.Clone(source.chunk);
+            this.oneByte = Arrays.Clone(source.oneByte);
+        }
+
+        public virtual string AlgorithmName
+        {
+            get { return "Keccak-" + fixedOutputLength; }
+        }
+
+        public virtual int GetDigestSize()
+        {
+            return fixedOutputLength / 8;
+        }
+
+        public virtual void Update(byte input)
+        {
+            oneByte[0] = input;
+
+            Absorb(oneByte, 0, 8L);
+        }
+
+        public virtual void BlockUpdate(byte[] input, int inOff, int len)
+        {
+            Absorb(input, inOff, len * 8L);
+        }
+
+        public virtual int DoFinal(byte[] output, int outOff)
+        {
+            Squeeze(output, outOff, fixedOutputLength);
+
+            Reset();
+
+            return GetDigestSize();
+        }
+
+        /*
+         * TODO Possible API change to support partial-byte suffixes.
+         */
+        protected virtual int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+        {
+            if (partialBits > 0)
+            {
+                oneByte[0] = partialByte;
+                Absorb(oneByte, 0, partialBits);
+            }
+
+            Squeeze(output, outOff, fixedOutputLength);
+
+            Reset();
+
+            return GetDigestSize();
+        }
+
+        public virtual void Reset()
+        {
+            Init(fixedOutputLength);
+        }
+
+        /**
+         * Return the size of block that the compression function is applied to in bytes.
+         *
+         * @return internal byte length of a block.
+         */
+        public virtual int GetByteLength()
+        {
+            return rate / 8;
+        }
+
+        private void Init(int bitLength)
+        {
+            switch (bitLength)
+            {
+                case 128:
+                    InitSponge(1344, 256);
+                    break;
+                case 224:
+                    InitSponge(1152, 448);
+                    break;
+                case 256:
+                    InitSponge(1088, 512);
+                    break;
+                case 288:
+                    InitSponge(1024, 576);
+                    break;
+                case 384:
+                    InitSponge(832, 768);
+                    break;
+                case 512:
+                    InitSponge(576, 1024);
+                    break;
+                default:
+                    throw new ArgumentException("must be one of 128, 224, 256, 288, 384, or 512.", "bitLength");
+            }
+        }
+
+        private void InitSponge(int rate, int capacity)
+        {
+            if (rate + capacity != 1600)
+            {
+                throw new InvalidOperationException("rate + capacity != 1600");
+            }
+            if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
+            {
+                throw new InvalidOperationException("invalid rate value");
+            }
+
+            this.rate = rate;
+            // this is never read, need to check to see why we want to save it
+            //  this.capacity = capacity;
+            this.fixedOutputLength = 0;
+            Arrays.Fill(this.state, (byte)0);
+            Arrays.Fill(this.dataQueue, (byte)0);
+            this.bitsInQueue = 0;
+            this.squeezing = false;
+            this.bitsAvailableForSqueezing = 0;
+            this.fixedOutputLength = capacity / 2;
+            this.chunk = new byte[rate / 8];
+            this.oneByte = new byte[1];
+        }
+
+        private void AbsorbQueue()
+        {
+            KeccakAbsorb(state, dataQueue, rate / 8);
+
+            bitsInQueue = 0;
+        }
+
+        protected virtual void Absorb(byte[] data, int off, long databitlen)
+        {
+            long i, j, wholeBlocks;
+
+            if ((bitsInQueue % 8) != 0)
+            {
+                throw new InvalidOperationException("attempt to absorb with odd length queue.");
+            }
+            if (squeezing)
+            {
+                throw new InvalidOperationException("attempt to absorb while squeezing.");
+            }
+
+            i = 0;
+            while (i < databitlen)
+            {
+                if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate)))
+                {
+                    wholeBlocks = (databitlen - i) / rate;
+
+                    for (j = 0; j < wholeBlocks; j++)
+                    {
+                        Array.Copy(data, (int)(off + (i / 8) + (j * chunk.Length)), chunk, 0, chunk.Length);
+
+                        KeccakAbsorb(state, chunk, chunk.Length);
+                    }
+
+                    i += wholeBlocks * rate;
+                }
+                else
+                {
+                    int partialBlock = (int)(databitlen - i);
+                    if (partialBlock + bitsInQueue > rate)
+                    {
+                        partialBlock = rate - bitsInQueue;
+                    }
+                    int partialByte = partialBlock % 8;
+                    partialBlock -= partialByte;
+                    Array.Copy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8);
+
+                    bitsInQueue += partialBlock;
+                    i += partialBlock;
+                    if (bitsInQueue == rate)
+                    {
+                        AbsorbQueue();
+                    }
+                    if (partialByte > 0)
+                    {
+                        int mask = (1 << partialByte) - 1;
+                        dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask);
+                        bitsInQueue += partialByte;
+                        i += partialByte;
+                    }
+                }
+            }
+        }
+
+        private void PadAndSwitchToSqueezingPhase()
+        {
+            if (bitsInQueue + 1 == rate)
+            {
+                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
+                AbsorbQueue();
+                ClearDataQueueSection(0, rate / 8);
+            }
+            else
+            {
+                ClearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8);
+                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
+            }
+            dataQueue[(rate - 1) / 8] |= (byte)(1U << ((rate - 1) % 8));
+            AbsorbQueue();
+
+            if (rate == 1024)
+            {
+                KeccakExtract1024bits(state, dataQueue);
+                bitsAvailableForSqueezing = 1024;
+            }
+            else
+            {
+                KeccakExtract(state, dataQueue, rate / 64);
+                bitsAvailableForSqueezing = rate;
+            }
+
+            squeezing = true;
+        }
+
+        protected virtual void Squeeze(byte[] output, int offset, long outputLength)
+        {
+            long i;
+            int partialBlock;
+
+            if (!squeezing)
+            {
+                PadAndSwitchToSqueezingPhase();
+            }
+            if ((outputLength % 8) != 0)
+            {
+                throw new InvalidOperationException("outputLength not a multiple of 8");
+            }
+
+            i = 0;
+            while (i < outputLength)
+            {
+                if (bitsAvailableForSqueezing == 0)
+                {
+                    KeccakPermutation(state);
+
+                    if (rate == 1024)
+                    {
+                        KeccakExtract1024bits(state, dataQueue);
+                        bitsAvailableForSqueezing = 1024;
+                    }
+                    else
+                    {
+                        KeccakExtract(state, dataQueue, rate / 64);
+                        bitsAvailableForSqueezing = rate;
+                    }
+                }
+                partialBlock = bitsAvailableForSqueezing;
+                if ((long)partialBlock > outputLength - i)
+                {
+                    partialBlock = (int)(outputLength - i);
+                }
+
+                Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8);
+                bitsAvailableForSqueezing -= partialBlock;
+                i += partialBlock;
+            }
+        }
+
+        private static void FromBytesToWords(ulong[] stateAsWords, byte[] state)
+        {
+            for (int i = 0; i < (1600 / 64); i++)
+            {
+                stateAsWords[i] = 0;
+                int index = i * (64 / 8);
+                for (int j = 0; j < (64 / 8); j++)
+                {
+                    stateAsWords[i] |= ((ulong)state[index + j] & 0xff) << ((8 * j));
+                }
+            }
+        }
+
+        private static void FromWordsToBytes(byte[] state, ulong[] stateAsWords)
+        {
+            for (int i = 0; i < (1600 / 64); i++)
+            {
+                int index = i * (64 / 8);
+                for (int j = 0; j < (64 / 8); j++)
+                {
+                    state[index + j] = (byte)(stateAsWords[i] >> (8 * j));
+                }
+            }
+        }
+
+        private void KeccakPermutation(byte[] state)
+        {
+            ulong[] longState = new ulong[state.Length / 8];
+
+            FromBytesToWords(longState, state);
+
+            KeccakPermutationOnWords(longState);
+
+            FromWordsToBytes(state, longState);
+        }
+
+        private void KeccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes)
+        {
+            for (int i = 0; i < dataLengthInBytes; i++)
+            {
+                state[i] ^= data[i];
+            }
+
+            KeccakPermutation(state);
+        }
+
+        private void KeccakPermutationOnWords(ulong[] state)
+        {
+            int i;
+
+            for (i = 0; i < 24; i++)
+            {
+                Theta(state);
+                Rho(state);
+                Pi(state);
+                Chi(state);
+                Iota(state, i);
+            }
+        }
+
+        ulong[] C = new ulong[5];
+
+        private void Theta(ulong[] A)
+        {
+            for (int x = 0; x < 5; x++)
+            {
+                C[x] = 0;
+                for (int y = 0; y < 5; y++)
+                {
+                    C[x] ^= A[x + 5 * y];
+                }
+            }
+            for (int x = 0; x < 5; x++)
+            {
+                ulong dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >> (64 - 1)))) ^ C[(x + 4) % 5];
+                for (int y = 0; y < 5; y++)
+                {
+                    A[x + 5 * y] ^= dX;
+                }
+            }
+        }
+
+        private void Rho(ulong[] A)
+        {
+            for (int x = 0; x < 5; x++)
+            {
+                for (int y = 0; y < 5; y++)
+                {
+                    int index = x + 5 * y;
+                    A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >> (64 - KeccakRhoOffsets[index]))) : A[index]);
+                }
+            }
+        }
+
+        ulong[] tempA = new ulong[25];
+
+        private void Pi(ulong[] A)
+        {
+            Array.Copy(A, 0, tempA, 0, tempA.Length);
+
+            for (int x = 0; x < 5; x++)
+            {
+                for (int y = 0; y < 5; y++)
+                {
+                    A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y];
+                }
+            }
+        }
+
+        ulong[] chiC = new ulong[5];
+
+        private void Chi(ulong[] A)
+        {
+            for (int y = 0; y < 5; y++)
+            {
+                for (int x = 0; x < 5; x++)
+                {
+                    chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]);
+                }
+                for (int x = 0; x < 5; x++)
+                {
+                    A[x + 5 * y] = chiC[x];
+                }
+            }
+        }
+
+        private static void Iota(ulong[] A, int indexRound)
+        {
+            A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound];
+        }
+
+        private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes)
+        {
+            KeccakPermutationAfterXor(byteState, data, dataInBytes);
+        }
+
+        private void KeccakExtract1024bits(byte[] byteState, byte[] data)
+        {
+            Array.Copy(byteState, 0, data, 0, 128);
+        }
+
+        private void KeccakExtract(byte[] byteState, byte[] data, int laneCount)
+        {
+            Array.Copy(byteState, 0, data, 0, laneCount * 8);
+        }
+
+        public virtual IMemoable Copy()
+        {
+            return new KeccakDigest(this);
+        }
+
+        public virtual void Reset(IMemoable other)
+        {
+            KeccakDigest d = (KeccakDigest)other;
+
+            CopyIn(d);
+        }
+    }
+}
diff --git a/crypto/src/crypto/digests/SHA3Digest.cs b/crypto/src/crypto/digests/SHA3Digest.cs
index 2c6837b3c..890b665cf 100644
--- a/crypto/src/crypto/digests/SHA3Digest.cs
+++ b/crypto/src/crypto/digests/SHA3Digest.cs
@@ -1,4 +1,5 @@
 using System;
+using System.Diagnostics;
 
 using Org.BouncyCastle.Utilities;
 
@@ -11,550 +12,75 @@ namespace Org.BouncyCastle.Crypto.Digests
     /// Following the naming conventions used in the C source code to enable easy review of the implementation.
     /// </remarks>
     public class Sha3Digest
-        : IDigest, IMemoable
+        : KeccakDigest
     {
-        private static readonly ulong[] KeccakRoundConstants = KeccakInitializeRoundConstants();
-
-        private static readonly int[] KeccakRhoOffsets = KeccakInitializeRhoOffsets();
-
-        private static ulong[] KeccakInitializeRoundConstants()
-        {
-            ulong[] keccakRoundConstants = new ulong[24];
-            byte LFSRState = 0x01;
-
-            for (int i = 0; i < 24; i++)
-            {
-                keccakRoundConstants[i] = 0;
-                for (int j = 0; j < 7; j++)
-                {
-                    int bitPosition = (1 << j) - 1;
-
-                    // LFSR86540
-
-                    bool loBit = (LFSRState & 0x01) != 0;
-                    if (loBit)
-                    {
-                        keccakRoundConstants[i] ^= 1UL << bitPosition;
-                    }
-
-                    bool hiBit = (LFSRState & 0x80) != 0;
-                    LFSRState <<= 1;
-                    if (hiBit)
-                    {
-                        LFSRState ^= 0x71;
-                    }
-
-                }
-            }
-
-            return keccakRoundConstants;
-        }
-
-        private static int[] KeccakInitializeRhoOffsets()
-        {
-            int[] keccakRhoOffsets = new int[25];
-            int x, y, t, newX, newY;
-
-            int rhoOffset = 0;
-            keccakRhoOffsets[(((0) % 5) + 5 * ((0) % 5))] = rhoOffset;
-            x = 1;
-            y = 0;
-            for (t = 1; t < 25; t++)
-            {
-                //rhoOffset = ((t + 1) * (t + 2) / 2) % 64;
-                rhoOffset = (rhoOffset + t) & 63;
-                keccakRhoOffsets[(((x) % 5) + 5 * ((y) % 5))] = rhoOffset;
-                newX = (0 * x + 1 * y) % 5;
-                newY = (2 * x + 3 * y) % 5;
-                x = newX;
-                y = newY;
-            }
-
-            return keccakRhoOffsets;
-        }
-
-        private byte[] state = new byte[(1600 / 8)];
-        private byte[] dataQueue = new byte[(1536 / 8)];
-        private int rate;
-        private int bitsInQueue;
-        private int fixedOutputLength;
-        private bool squeezing;
-        private int bitsAvailableForSqueezing;
-        private byte[] chunk;
-        private byte[] oneByte;
-
-        private void ClearDataQueueSection(int off, int len)
-        {
-            for (int i = off; i != off + len; i++)
-            {
-                dataQueue[i] = 0;
-            }
-        }
-
-        public Sha3Digest()
-        {
-            Init(0);
-        }
-
-        public Sha3Digest(int bitLength)
-        {
-            Init(bitLength);
-        }
-
-        public Sha3Digest(Sha3Digest source)
-        {
-			CopyIn(source);
-		}
-
-		private void CopyIn(Sha3Digest source)
-		{
-            Array.Copy(source.state, 0, this.state, 0, source.state.Length);
-            Array.Copy(source.dataQueue, 0, this.dataQueue, 0, source.dataQueue.Length);
-            this.rate = source.rate;
-            this.bitsInQueue = source.bitsInQueue;
-            this.fixedOutputLength = source.fixedOutputLength;
-            this.squeezing = source.squeezing;
-            this.bitsAvailableForSqueezing = source.bitsAvailableForSqueezing;
-            this.chunk = Arrays.Clone(source.chunk);
-            this.oneByte = Arrays.Clone(source.oneByte);
-        }
-
-        public virtual string AlgorithmName
-        {
-            get { return "SHA3-" + fixedOutputLength; }
-        }
-
-        public virtual int GetDigestSize()
-        {
-            return fixedOutputLength / 8;
-        }
-
-        public virtual void Update(byte input)
-        {
-            oneByte[0] = input;
-
-            DoUpdate(oneByte, 0, 8L);
-        }
-
-        public virtual void BlockUpdate(byte[] input, int inOff, int len)
-        {
-            DoUpdate(input, inOff, len * 8L);
-        }
-
-        public virtual int DoFinal(byte[] output, int outOff)
-        {
-            Squeeze(output, outOff, fixedOutputLength);
-
-            Reset();
-
-            return GetDigestSize();
-        }
-
-        public virtual void Reset()
-        {
-            Init(fixedOutputLength);
-        }
-
-        /**
-         * Return the size of block that the compression function is applied to in bytes.
-         *
-         * @return internal byte length of a block.
-         */
-        public virtual int GetByteLength()
-        {
-            return rate / 8;
-        }
-
-        private void Init(int bitLength)
+        private static int CheckBitLength(int bitLength)
         {
             switch (bitLength)
             {
-            case 0:
-            case 288:
-                InitSponge(1024, 576);
-                break;
             case 224:
-                InitSponge(1152, 448);
-                break;
             case 256:
-                InitSponge(1088, 512);
-                break;
             case 384:
-                InitSponge(832, 768);
-                break;
             case 512:
-                InitSponge(576, 1024);
-                break;
+                return bitLength;
             default:
-                throw new ArgumentException("must be one of 224, 256, 384, or 512.", "bitLength");
-            }
-        }
-
-        private void DoUpdate(byte[] data, int off, long databitlen)
-        {
-            if ((databitlen % 8) == 0)
-            {
-                Absorb(data, off, databitlen);
-            }
-            else
-            {
-                Absorb(data, off, databitlen - (databitlen % 8));
-
-                byte[] lastByte = new byte[1];
-
-                lastByte[0] = (byte)(data[off + (int)(databitlen / 8)] >> (int)(8 - (databitlen % 8)));
-                Absorb(lastByte, off, databitlen % 8);
-            }
-        }
-
-        private void InitSponge(int rate, int capacity)
-        {
-            if (rate + capacity != 1600)
-            {
-                throw new InvalidOperationException("rate + capacity != 1600");
-            }
-            if ((rate <= 0) || (rate >= 1600) || ((rate % 64) != 0))
-            {
-                throw new InvalidOperationException("invalid rate value");
-            }
-
-            this.rate = rate;
-            // this is never read, need to check to see why we want to save it
-            //  this.capacity = capacity;
-            this.fixedOutputLength = 0;
-            Arrays.Fill(this.state, (byte)0);
-            Arrays.Fill(this.dataQueue, (byte)0);
-            this.bitsInQueue = 0;
-            this.squeezing = false;
-            this.bitsAvailableForSqueezing = 0;
-            this.fixedOutputLength = capacity / 2;
-            this.chunk = new byte[rate / 8];
-            this.oneByte = new byte[1];
-        }
-
-        private void AbsorbQueue()
-        {
-            KeccakAbsorb(state, dataQueue, rate / 8);
-
-            bitsInQueue = 0;
-        }
-
-        private void Absorb(byte[] data, int off, long databitlen)
-        {
-            long i, j, wholeBlocks;
-
-            if ((bitsInQueue % 8) != 0)
-            {
-                throw new InvalidOperationException("attempt to absorb with odd length queue.");
-            }
-            if (squeezing)
-            {
-                throw new InvalidOperationException("attempt to absorb while squeezing.");
-            }
-
-            i = 0;
-            while (i < databitlen)
-            {
-                if ((bitsInQueue == 0) && (databitlen >= rate) && (i <= (databitlen - rate)))
-                {
-                    wholeBlocks = (databitlen - i) / rate;
-
-                    for (j = 0; j < wholeBlocks; j++)
-                    {
-                        Array.Copy(data, (int)(off + (i / 8) + (j * chunk.Length)), chunk, 0, chunk.Length);
-
-                        //displayIntermediateValues.displayBytes(1, "Block to be absorbed", curData, rate / 8);
-
-                        KeccakAbsorb(state, chunk, chunk.Length);
-                    }
-
-                    i += wholeBlocks * rate;
-                }
-                else
-                {
-                    int partialBlock = (int)(databitlen - i);
-                    if (partialBlock + bitsInQueue > rate)
-                    {
-                        partialBlock = rate - bitsInQueue;
-                    }
-                    int partialByte = partialBlock % 8;
-                    partialBlock -= partialByte;
-                    Array.Copy(data, off + (int)(i / 8), dataQueue, bitsInQueue / 8, partialBlock / 8);
-
-                    bitsInQueue += partialBlock;
-                    i += partialBlock;
-                    if (bitsInQueue == rate)
-                    {
-                        AbsorbQueue();
-                    }
-                    if (partialByte > 0)
-                    {
-                        int mask = (1 << partialByte) - 1;
-                        dataQueue[bitsInQueue / 8] = (byte)(data[off + ((int)(i / 8))] & mask);
-                        bitsInQueue += partialByte;
-                        i += partialByte;
-                    }
-                }
+                throw new ArgumentException(bitLength + " not supported for SHA-3", "bitLength");
             }
         }
 
-        private void PadAndSwitchToSqueezingPhase()
-        {
-            if (bitsInQueue + 1 == rate)
-            {
-                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
-                AbsorbQueue();
-                ClearDataQueueSection(0, rate / 8);
-            }
-            else
-            {
-                ClearDataQueueSection((bitsInQueue + 7) / 8, rate / 8 - (bitsInQueue + 7) / 8);
-                dataQueue[bitsInQueue / 8] |= (byte)(1U << (bitsInQueue % 8));
-            }
-            dataQueue[(rate - 1) / 8] |= (byte)(1U << ((rate - 1) % 8));
-            AbsorbQueue();
-
-            //displayIntermediateValues.displayText(1, "--- Switching to squeezing phase ---");
-
-            if (rate == 1024)
-            {
-                KeccakExtract1024bits(state, dataQueue);
-                bitsAvailableForSqueezing = 1024;
-            }
-            else
-            {
-                KeccakExtract(state, dataQueue, rate / 64);
-                bitsAvailableForSqueezing = rate;
-            }
-
-            //displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8);
-
-            squeezing = true;
-        }
-
-        private void Squeeze(byte[] output, int offset, long outputLength)
-        {
-            long i;
-            int partialBlock;
-
-            if (!squeezing)
-            {
-                PadAndSwitchToSqueezingPhase();
-            }
-            if ((outputLength % 8) != 0)
-            {
-                throw new InvalidOperationException("outputLength not a multiple of 8");
-            }
-
-            i = 0;
-            while (i < outputLength)
-            {
-                if (bitsAvailableForSqueezing == 0)
-                {
-                    KeccakPermutation(state);
-
-                    if (rate == 1024)
-                    {
-                        KeccakExtract1024bits(state, dataQueue);
-                        bitsAvailableForSqueezing = 1024;
-                    }
-                    else
-
-                    {
-                        KeccakExtract(state, dataQueue, rate / 64);
-                        bitsAvailableForSqueezing = rate;
-                    }
-
-                    //displayIntermediateValues.displayBytes(1, "Block available for squeezing", dataQueue, bitsAvailableForSqueezing / 8);
-
-                }
-                partialBlock = bitsAvailableForSqueezing;
-                if ((long)partialBlock > outputLength - i)
-                {
-                    partialBlock = (int)(outputLength - i);
-                }
-
-                Array.Copy(dataQueue, (rate - bitsAvailableForSqueezing) / 8, output, offset + (int)(i / 8), partialBlock / 8);
-                bitsAvailableForSqueezing -= partialBlock;
-                i += partialBlock;
-            }
-        }
-
-        private static void FromBytesToWords(ulong[] stateAsWords, byte[] state)
-        {
-            for (int i = 0; i < (1600 / 64); i++)
-            {
-                stateAsWords[i] = 0;
-                int index = i * (64 / 8);
-                for (int j = 0; j < (64 / 8); j++)
-                {
-                    stateAsWords[i] |= ((ulong)state[index + j] & 0xff) << ((8 * j));
-                }
-            }
-        }
-
-        private static void FromWordsToBytes(byte[] state, ulong[] stateAsWords)
+        public Sha3Digest()
+            : this(256)
         {
-            for (int i = 0; i < (1600 / 64); i++)
-            {
-                int index = i * (64 / 8);
-                for (int j = 0; j < (64 / 8); j++)
-                {
-                    state[index + j] = (byte)(stateAsWords[i] >> (8 * j));
-                }
-            }
         }
 
-        private void KeccakPermutation(byte[] state)
+        public Sha3Digest(int bitLength)
+            : base(CheckBitLength(bitLength))
         {
-            ulong[] longState = new ulong[state.Length / 8];
-
-            FromBytesToWords(longState, state);
-
-            //displayIntermediateValues.displayStateAsBytes(1, "Input of permutation", longState);
-
-            KeccakPermutationOnWords(longState);
-
-            //displayIntermediateValues.displayStateAsBytes(1, "State after permutation", longState);
-
-            FromWordsToBytes(state, longState);
         }
 
-        private void KeccakPermutationAfterXor(byte[] state, byte[] data, int dataLengthInBytes)
+        public Sha3Digest(Sha3Digest source)
+            : base(source)
         {
-            for (int i = 0; i < dataLengthInBytes; i++)
-            {
-                state[i] ^= data[i];
-            }
-
-            KeccakPermutation(state);
         }
 
-        private void KeccakPermutationOnWords(ulong[] state)
+        public override string AlgorithmName
         {
-            int i;
-
-            //displayIntermediateValues.displayStateAs64bitWords(3, "Same, with lanes as 64-bit words", state);
-
-            for (i = 0; i < 24; i++)
-            {
-                //displayIntermediateValues.displayRoundNumber(3, i);
-
-                Theta(state);
-                //displayIntermediateValues.displayStateAs64bitWords(3, "After theta", state);
-
-                Rho(state);
-                //displayIntermediateValues.displayStateAs64bitWords(3, "After rho", state);
-
-                Pi(state);
-                //displayIntermediateValues.displayStateAs64bitWords(3, "After pi", state);
-
-                Chi(state);
-                //displayIntermediateValues.displayStateAs64bitWords(3, "After chi", state);
-
-                Iota(state, i);
-                //displayIntermediateValues.displayStateAs64bitWords(3, "After iota", state);
-            }
+            get { return "SHA3-" + fixedOutputLength; }
         }
 
-        ulong[] C = new ulong[5];
-
-        private void Theta(ulong[] A)
+        public override int DoFinal(byte[] output, int outOff)
         {
-            for (int x = 0; x < 5; x++)
-            {
-                C[x] = 0;
-                for (int y = 0; y < 5; y++)
-                {
-                    C[x] ^= A[x + 5 * y];
-                }
-            }
-            for (int x = 0; x < 5; x++)
-            {
-                ulong dX = ((((C[(x + 1) % 5]) << 1) ^ ((C[(x + 1) % 5]) >> (64 - 1)))) ^ C[(x + 4) % 5];
-                for (int y = 0; y < 5; y++)
-                {
-                    A[x + 5 * y] ^= dX;
-                }
-            }
-        }
+            Absorb(new byte[]{ 0x02 }, 0, 2);
 
-        private void Rho(ulong[] A)
-        {
-            for (int x = 0; x < 5; x++)
-            {
-                for (int y = 0; y < 5; y++)
-                {
-                    int index = x + 5 * y;
-                    A[index] = ((KeccakRhoOffsets[index] != 0) ? (((A[index]) << KeccakRhoOffsets[index]) ^ ((A[index]) >> (64 - KeccakRhoOffsets[index]))) : A[index]);
-                }
-            }
+            return base.DoFinal(output,  outOff);
         }
 
-        ulong[] tempA = new ulong[25];
-
-        private void Pi(ulong[] A)
+        /*
+         * TODO Possible API change to support partial-byte suffixes.
+         */
+        protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
         {
-            Array.Copy(A, 0, tempA, 0, tempA.Length);
-
-            for (int x = 0; x < 5; x++)
-            {
-                for (int y = 0; y < 5; y++)
-                {
-                    A[y + 5 * ((2 * x + 3 * y) % 5)] = tempA[x + 5 * y];
-                }
-            }
-        }
+            if (partialBits < 0 || partialBits > 7)
+                throw new ArgumentException("must be in the range [0,7]", "partialBits");
 
-        ulong[] chiC = new ulong[5];
+            int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x02 << partialBits);
+            Debug.Assert(finalInput >= 0);
+            int finalBits = partialBits + 2;
 
-        private void Chi(ulong[] A)
-        {
-            for (int y = 0; y < 5; y++)
+            if (finalBits >= 8)
             {
-                for (int x = 0; x < 5; x++)
-                {
-                    chiC[x] = A[x + 5 * y] ^ ((~A[(((x + 1) % 5) + 5 * y)]) & A[(((x + 2) % 5) + 5 * y)]);
-                }
-                for (int x = 0; x < 5; x++)
-                {
-                    A[x + 5 * y] = chiC[x];
-                }
+                oneByte[0] = (byte)finalInput;
+                Absorb(oneByte, 0, 8);
+                finalBits -= 8;
+                finalInput >>= 8;
             }
-        }
-
-        private static void Iota(ulong[] A, int indexRound)
-        {
-            A[(((0) % 5) + 5 * ((0) % 5))] ^= KeccakRoundConstants[indexRound];
-        }
-
-        private void KeccakAbsorb(byte[] byteState, byte[] data, int dataInBytes)
-        {
-            KeccakPermutationAfterXor(byteState, data, dataInBytes);
-        }
-
-        private void KeccakExtract1024bits(byte[] byteState, byte[] data)
-        {
-            Array.Copy(byteState, 0, data, 0, 128);
-        }
 
-        private void KeccakExtract(byte[] byteState, byte[] data, int laneCount)
-        {
-            Array.Copy(byteState, 0, data, 0, laneCount * 8);
+            return base.DoFinal(output, outOff, (byte)finalInput, finalBits);
         }
 
-		public IMemoable Copy()
+        public override IMemoable Copy()
 		{
 			return new Sha3Digest(this);
 		}
-
-		public void Reset(IMemoable other)
-		{
-			Sha3Digest d = (Sha3Digest)other;
-
-			CopyIn(d);
-		}
-
-
     }
 }
diff --git a/crypto/src/crypto/digests/ShakeDigest.cs b/crypto/src/crypto/digests/ShakeDigest.cs
new file mode 100644
index 000000000..fd7d85681
--- /dev/null
+++ b/crypto/src/crypto/digests/ShakeDigest.cs
@@ -0,0 +1,111 @@
+using System;
+using System.Diagnostics;
+
+using Org.BouncyCastle.Utilities;
+
+namespace Org.BouncyCastle.Crypto.Digests
+{
+    /// <summary>
+    /// Implementation of SHAKE based on following KeccakNISTInterface.c from http://keccak.noekeon.org/
+    /// </summary>
+    /// <remarks>
+    /// Following the naming conventions used in the C source code to enable easy review of the implementation.
+    /// </remarks>
+    public class ShakeDigest
+        : KeccakDigest, IXof
+    {
+        private static int CheckBitLength(int bitLength)
+        {
+            switch (bitLength)
+            {
+            case 128:
+            case 256:
+                return bitLength;
+            default:
+                throw new ArgumentException(bitLength + " not supported for SHAKE", "bitLength");
+            }
+        }
+
+        public ShakeDigest()
+            : this(128)
+        {
+        }
+
+        public ShakeDigest(int bitLength)
+            : base(CheckBitLength(bitLength))
+        {
+        }
+
+        public ShakeDigest(ShakeDigest source)
+            : base(source)
+        {
+        }
+
+        public override string AlgorithmName
+        {
+            get { return "SHAKE" + fixedOutputLength; }
+        }
+
+        public override int DoFinal(byte[] output, int outOff)
+        {
+            return DoFinal(output, outOff, GetDigestSize());
+        }
+
+        public virtual int DoFinal(byte[] output, int outOff, int outLen)
+        {
+            Absorb(new byte[]{ 0x0F }, 0, 4);
+
+            Squeeze(output, outOff, ((long)outLen) * 8);
+
+            Reset();
+
+            return outLen;
+        }
+
+        /*
+         * TODO Possible API change to support partial-byte suffixes.
+         */
+        protected override int DoFinal(byte[] output, int outOff, byte partialByte, int partialBits)
+        {
+            return DoFinal(output, outOff, GetDigestSize(), partialByte, partialBits);
+        }
+
+        /*
+         * TODO Possible API change to support partial-byte suffixes.
+         */
+        protected virtual int DoFinal(byte[] output, int outOff, int outLen, byte partialByte, int partialBits)
+        {
+            if (partialBits < 0 || partialBits > 7)
+                throw new ArgumentException("must be in the range [0,7]", "partialBits");
+
+            int finalInput = (partialByte & ((1 << partialBits) - 1)) | (0x0F << partialBits);
+            Debug.Assert(finalInput >= 0);
+            int finalBits = partialBits + 4;
+
+            if (finalBits >= 8)
+            {
+                oneByte[0] = (byte)finalInput;
+                Absorb(oneByte, 0, 8);
+                finalBits -= 8;
+                finalInput >>= 8;
+            }
+
+            if (finalBits > 0)
+            {
+                oneByte[0] = (byte)finalInput;
+                Absorb(oneByte, 0, finalBits);
+            }
+
+            Squeeze(output, outOff, ((long)outLen) * 8);
+
+            Reset();
+
+            return outLen;
+        }
+
+        public override IMemoable Copy()
+        {
+            return new ShakeDigest(this);
+        }
+    }
+}
diff --git a/crypto/src/crypto/ec/CustomNamedCurves.cs b/crypto/src/crypto/ec/CustomNamedCurves.cs
index 0f13b4571..51bb1829a 100644
--- a/crypto/src/crypto/ec/CustomNamedCurves.cs
+++ b/crypto/src/crypto/ec/CustomNamedCurves.cs
@@ -60,7 +60,7 @@ namespace Org.BouncyCastle.Crypto.EC
                  * 
                  * (The other possible y value is 5F51E65E475F794B1FE122D388B72EB36DC2B28192839E4DD6163A5D81312C14) 
                  */
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "2AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD245A"
                     + "20AE19A1B8A086B4E01EDD2C7748D14C923D4D7E6D7C61B229E9C5A27ECED3D9"));
 
@@ -82,7 +82,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("000E0D4D696E6768756151750CC03A4473D03679");
                 ECCurve curve = ConfigureCurve(new SecP128R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "161FF7528B899B2D0C28607CA52C5B86"
                     + "CF5AC8395BAFEB13C02DA292DDED7A83"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -115,7 +115,7 @@ namespace Org.BouncyCastle.Crypto.EC
                     new BigInteger("96341f1138933bc2f503fd44", 16),
                     176);
                 ECCurve curve = ConfigureCurveGlv(new SecP160K1Curve(), glv);
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "3B4C382CE37AA192A4019E763036F4F5DD4D7EBB"
                     + "938CF935318FDCED6BC28286531733C3F03C4FEE"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -136,7 +136,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("1053CDE42C14D696E67687561517533BF3F83345");
                 ECCurve curve = ConfigureCurve(new SecP160R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "4A96B5688EF573284664698968C38BB913CBFC82"
                     + "23A628553168947D59DCC912042351377AC5FB32"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -157,7 +157,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("B99B99B099B323E02709A4D696E6768756151751");
                 ECCurve curve = ConfigureCurve(new SecP160R2Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "52DCB034293A117E1F4FF11B30F7199D3144CE6D"
                     + "FEAFFEF2E331F296E071FA0DF9982CFEA7D43F2E"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -190,7 +190,7 @@ namespace Org.BouncyCastle.Crypto.EC
                     new BigInteger("b3fb3400dec5c4adceb8655d4c94", 16),
                     208);
                 ECCurve curve = ConfigureCurveGlv(new SecP192K1Curve(), glv);
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "DB4FF10EC057E9AE26B07D0280B7F4341DA5D1B1EAE06C7D"
                     + "9B2F2F6D9C5628A7844163D015BE86344082AA88D95E2F9D"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -211,7 +211,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("3045AE6FC8422F64ED579528D38120EAE12196D5");
                 ECCurve curve = ConfigureCurve(new SecP192R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "188DA80EB03090F67CBF20EB43A18800F4FF0AFD82FF1012"
                     + "07192B95FFC8DA78631011ED6B24CDD573F977A11E794811"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -244,7 +244,7 @@ namespace Org.BouncyCastle.Crypto.EC
                     new BigInteger("b8adf1378a6eb73409fa6c9c637ba7f5", 16),
                     240);
                 ECCurve curve = ConfigureCurveGlv(new SecP224K1Curve(), glv);
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "A1455B334DF099DF30FC28A169A467E9E47075A90F7E650EB6B7A45C"
                     + "7E089FED7FBA344282CAFBD6F7E319F7C0B0BD59E2CA4BDB556D61A5"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -265,7 +265,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("BD71344799D5C7FCDC45B59FA3B9AB8F6A948BC5");
                 ECCurve curve = ConfigureCurve(new SecP224R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "B70E0CBD6BB4BF7F321390B94A03C1D356C21122343280D6115C1D21"
                     + "BD376388B5F723FB4C22DFE6CD4375A05A07476444D5819985007E34"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -298,7 +298,7 @@ namespace Org.BouncyCastle.Crypto.EC
                     new BigInteger("e4437ed6010e88286f547fa90abfe4c42212", 16),
                     272);
                 ECCurve curve = ConfigureCurveGlv(new SecP256K1Curve(), glv);
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "79BE667EF9DCBBAC55A06295CE870B07029BFCDB2DCE28D959F2815B16F81798"
                     + "483ADA7726A3C4655DA4FBFC0E1108A8FD17B448A68554199C47D08FFB10D4B8"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -319,7 +319,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("C49D360886E704936A6678E1139D26B7819F7E90");
                 ECCurve curve = ConfigureCurve(new SecP256R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "6B17D1F2E12C4247F8BCE6E563A440F277037D812DEB33A0F4A13945D898C296"
                     + "4FE342E2FE1A7F9B8EE7EB4A7C0F9E162BCE33576B315ECECBB6406837BF51F5"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -340,7 +340,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("A335926AA319A27A1D00896A6773A4827ACDAC73");
                 ECCurve curve = ConfigureCurve(new SecP384R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "AA87CA22BE8B05378EB1C71EF320AD746E1D3B628BA79B9859F741E082542A385502F25DBF55296C3A545E3872760AB7"
                     + "3617DE4A96262C6F5D9E98BF9292DC29F8F41DBD289A147CE9DA3113B5F0B8C00A60B1CE1D7E819D7A431D7C90EA0E5F"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -361,7 +361,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("D09E8800291CB85396CC6717393284AAA0DA64BA");
                 ECCurve curve = ConfigureCurve(new SecP521R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "00C6858E06B70404E9CD9E3ECB662395B4429C648139053FB521F828AF606B4D3DBAA14B5E77EFE75928FE1DC127A2FFA8DE3348B3C1856A429BF97E7E31C2E5BD66"
                     + "011839296A789A3BC0045C8A5FB42C7D1BD998F54449579B446817AFBD17273E662C97EE72995EF42640C550B9013FAD0761353C7086A272C24088BE94769FD16650"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -382,7 +382,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("10E723AB14D696E6768756151756FEBF8FCB49A9");
                 ECCurve curve = ConfigureCurve(new SecT113R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "009D73616F35F4AB1407D73562C10F"
                     + "00A52830277958EE84D1315ED31886"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -403,7 +403,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("10C0FB15760860DEF1EEF4D696E676875615175D");
                 ECCurve curve = ConfigureCurve(new SecT113R2Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "01A57A6A7B26CA5EF52FCDB8164797"
                     + "00B3ADC94ED1FE674C06E695BABA1D"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -424,7 +424,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("4D696E676875615175985BD3ADBADA21B43A97E2");
                 ECCurve curve = ConfigureCurve(new SecT131R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0081BAF91FDF9833C40F9C181343638399"
                     + "078C6E7EA38C001F73C8134B1B4EF9E150"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -445,7 +445,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("985BD3ADBAD4D696E676875615175A21B43A97E3");
                 ECCurve curve = ConfigureCurve(new SecT131R2Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0356DCD8F2F95031AD652D23951BB366A8"
                     + "0648F06D867940A5366D9E265DE9EB240F"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -466,7 +466,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = null;
                 ECCurve curve = ConfigureCurve(new SecT163K1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "02FE13C0537BBC11ACAA07D793DE4E6D5E5C94EEE8"
                     + "0289070FB05D38FF58321F2E800536D538CCDAA3D9"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -487,7 +487,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("24B7B137C8A14D696E6768756151756FD0DA2E5C");
                 ECCurve curve = ConfigureCurve(new SecT163R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0369979697AB43897789566789567F787A7876A654"
                     + "00435EDB42EFAFB2989D51FEFCE3C80988F41FF883"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -508,7 +508,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("85E25BFE5C86226CDB12016F7553F9D0E693A268");
                 ECCurve curve = ConfigureCurve(new SecT163R2Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "03F0EBA16286A2D57EA0991168D4994637E8343E36"
                     + "00D51FBC6C71A0094FA2CDD545B11C5C0C797324F1"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -529,7 +529,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("103FAEC74D696E676875615175777FC5B191EF30");
                 ECCurve curve = ConfigureCurve(new SecT193R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "01F481BC5F0FF84A74AD6CDF6FDEF4BF6179625372D8C0C5E1"
                     + "0025E399F2903712CCF3EA9E3A1AD17FB0B3201B6AF7CE1B05"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -550,7 +550,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("10B7B4D696E676875615175137C8A16FD0DA2211");
                 ECCurve curve = ConfigureCurve(new SecT193R2Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "00D9B67D192E0367C803F39E1A7E82CA14A651350AAE617E8F"
                     + "01CE94335607C304AC29E7DEFBD9CA01F596F927224CDECF6C"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -571,7 +571,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = null;
                 ECCurve curve = ConfigureCurve(new SecT233K1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "017232BA853A7E731AF129F22FF4149563A419C26BF50A4C9D6EEFAD6126"
                     + "01DB537DECE819B7F70F555A67C427A8CD9BF18AEB9B56E0C11056FAE6A3"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -592,7 +592,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("74D59FF07F6B413D0EA14B344B20A2DB049B50C3");
                 ECCurve curve = ConfigureCurve(new SecT233R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "00FAC9DFCBAC8313BB2139F1BB755FEF65BC391F8B36F8F8EB7371FD558B"
                     + "01006A08A41903350678E58528BEBF8A0BEFF867A7CA36716F7E01F81052"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -613,7 +613,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = null;
                 ECCurve curve = ConfigureCurve(new SecT239K1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "29A0B6A887A983E9730988A68727A8B2D126C44CC2CC7B2A6555193035DC"
                     + "76310804F12E549BDB011C103089E73510ACB275FC312A5DC6B76553F0CA"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -634,7 +634,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = null;
                 ECCurve curve = ConfigureCurve(new SecT283K1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0503213F78CA44883F1A3B8162F188E553CD265F23C1567A16876913B0C2AC2458492836"
                     + "01CCDA380F1C9E318D90F95D07E5426FE87E45C0E8184698E45962364E34116177DD2259"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -655,7 +655,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("77E2B07370EB0F832A6DD5B62DFC88CD06BB84BE");
                 ECCurve curve = ConfigureCurve(new SecT283R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "05F939258DB7DD90E1934F8C70B0DFEC2EED25B8557EAC9C80E2E198F8CDBECD86B12053"
                     + "03676854FE24141CB98FE6D4B20D02B4516FF702350EDDB0826779C813F0DF45BE8112F4"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -676,7 +676,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = null;
                 ECCurve curve = ConfigureCurve(new SecT409K1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0060F05F658F49C1AD3AB1890F7184210EFD0987E307C84C27ACCFB8F9F67CC2C460189EB5AAAA62EE222EB1B35540CFE9023746"
                     + "01E369050B7C4E42ACBA1DACBF04299C3460782F918EA427E6325165E9EA10E3DA5F6C42E9C55215AA9CA27A5863EC48D8E0286B"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -697,7 +697,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("4099B5A457F9D69F79213D094C4BCD4D4262210B");
                 ECCurve curve = ConfigureCurve(new SecT409R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "015D4860D088DDB3496B0C6064756260441CDE4AF1771D4DB01FFE5B34E59703DC255A868A1180515603AEAB60794E54BB7996A7"
                     + "0061B1CFAB6BE5F32BBFA78324ED106A7636B9C5A7BD198D0158AA4F5488D08F38514F1FDF4B4F40D2181B3681C364BA0273C706"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -718,7 +718,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = null;
                 ECCurve curve = ConfigureCurve(new SecT571K1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "026EB7A859923FBC82189631F8103FE4AC9CA2970012D5D46024804801841CA44370958493B205E647DA304DB4CEB08CBBD1BA39494776FB988B47174DCA88C7E2945283A01C8972"
                     + "0349DC807F4FBF374F4AEADE3BCA95314DD58CEC9F307A54FFC61EFC006D8A2C9D4979C0AC44AEA74FBEBBB9F772AEDCB620B01A7BA7AF1B320430C8591984F601CD4C143EF1C7A3"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
@@ -739,7 +739,7 @@ namespace Org.BouncyCastle.Crypto.EC
             {
                 byte[] S = Hex.Decode("2AA058F73A0E33AB486B0F610410C53A7F132310");
                 ECCurve curve = ConfigureCurve(new SecT571R1Curve());
-                ECPoint G = curve.DecodePoint(Hex.Decode("04"
+                X9ECPoint G = new X9ECPoint(curve, Hex.Decode("04"
                     + "0303001D34B856296C16C0D40D3CD7750A93D1D2955FA80AA5F40FC8DB7B2ABDBDE53950F4C0D293CDD711A35B67FB1499AE60038614F1394ABFA3B4C850D927E1E7769C8EEC2D19"
                     + "037BF27342DA639B6DCCFFFEB73D69D78C6C27A6009CBBCA1980F8533921E8A684423E43BAB08A576291AF8F461BB2A8B3531D2F0485C19B16E2F1516E23DD3C1A4827AF1B8AC15B"));
                 return new X9ECParameters(curve, G, curve.Order, curve.Cofactor, S);
diff --git a/crypto/src/crypto/engines/AesEngine.cs b/crypto/src/crypto/engines/AesEngine.cs
index 9d7f76c05..164c43ee9 100644
--- a/crypto/src/crypto/engines/AesEngine.cs
+++ b/crypto/src/crypto/engines/AesEngine.cs
@@ -237,12 +237,22 @@ namespace Org.BouncyCastle.Crypto.Engines
         private const uint m1 = 0x80808080;
         private const uint m2 = 0x7f7f7f7f;
         private const uint m3 = 0x0000001b;
+        private const uint m4 = 0xC0C0C0C0;
+        private const uint m5 = 0x3f3f3f3f;
 
         private static uint FFmulX(uint x)
         {
             return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
         }
 
+        private static uint FFmulX2(uint x)
+        {
+            uint t0  = (x & m5) << 2;
+            uint t1  = (x & m4);
+                 t1 ^= (t1 >> 1);
+            return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+        }
+
         /*
         The following defines provide alternative definitions of FFmulX that might
         give improved performance if a fast 32-bit multiply is not available.
@@ -255,12 +265,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         private static uint Inv_Mcol(uint x)
         {
-            uint f2 = FFmulX(x);
-            uint f4 = FFmulX(f2);
-            uint f8 = FFmulX(f4);
-            uint f9 = x ^ f8;
-
-            return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+            uint t0, t1;
+            t0  = x;
+            t1  = t0 ^ Shift(t0, 8);
+            t0 ^= FFmulX(t1);
+            t1 ^= FFmulX2(t0);
+            t0 ^= t1 ^ Shift(t1, 16);
+            return t0;
         }
 
         private static uint SubWord(uint x)
diff --git a/crypto/src/crypto/engines/AesFastEngine.cs b/crypto/src/crypto/engines/AesFastEngine.cs
index a1b544568..38ce1a946 100644
--- a/crypto/src/crypto/engines/AesFastEngine.cs
+++ b/crypto/src/crypto/engines/AesFastEngine.cs
@@ -573,12 +573,22 @@ namespace Org.BouncyCastle.Crypto.Engines
         private const uint m1 = 0x80808080;
         private const uint m2 = 0x7f7f7f7f;
         private const uint m3 = 0x0000001b;
+        private const uint m4 = 0xC0C0C0C0;
+        private const uint m5 = 0x3f3f3f3f;
 
         private static uint FFmulX(uint x)
         {
             return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
         }
 
+        private static uint FFmulX2(uint x)
+        {
+            uint t0  = (x & m5) << 2;
+            uint t1  = (x & m4);
+                 t1 ^= (t1 >> 1);
+            return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+        }
+
         /*
         The following defines provide alternative definitions of FFmulX that might
         give improved performance if a fast 32-bit multiply is not available.
@@ -591,12 +601,13 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         private static uint Inv_Mcol(uint x)
         {
-            uint f2 = FFmulX(x);
-            uint f4 = FFmulX(f2);
-            uint f8 = FFmulX(f4);
-            uint f9 = x ^ f8;
-
-            return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+            uint t0, t1;
+            t0  = x;
+            t1  = t0 ^ Shift(t0, 8);
+            t0 ^= FFmulX(t1);
+            t1 ^= FFmulX2(t0);
+            t0 ^= t1 ^ Shift(t1, 16);
+            return t0;
         }
 
         private static uint SubWord(uint x)
diff --git a/crypto/src/crypto/engines/AesLightEngine.cs b/crypto/src/crypto/engines/AesLightEngine.cs
index a6b9e3bd4..a42b34971 100644
--- a/crypto/src/crypto/engines/AesLightEngine.cs
+++ b/crypto/src/crypto/engines/AesLightEngine.cs
@@ -126,12 +126,22 @@ namespace Org.BouncyCastle.Crypto.Engines
         private const uint m1 = 0x80808080;
         private const uint m2 = 0x7f7f7f7f;
         private const uint m3 = 0x0000001b;
+        private const uint m4 = 0xC0C0C0C0;
+        private const uint m5 = 0x3f3f3f3f;
 
         private static uint FFmulX(uint x)
         {
             return ((x & m2) << 1) ^ (((x & m1) >> 7) * m3);
         }
 
+        private static uint FFmulX2(uint x)
+        {
+            uint t0  = (x & m5) << 2;
+            uint t1  = (x & m4);
+                 t1 ^= (t1 >> 1);
+            return t0 ^ (t1 >> 2) ^ (t1 >> 5);
+        }
+
         /*
         The following defines provide alternative definitions of FFmulX that might
         give improved performance if a fast 32-bit multiply is not available.
@@ -144,18 +154,21 @@ namespace Org.BouncyCastle.Crypto.Engines
 
         private static uint Mcol(uint x)
         {
-            uint f2 = FFmulX(x);
-            return f2 ^ Shift(x ^ f2, 8) ^ Shift(x, 16) ^ Shift(x, 24);
+            uint t0, t1;
+            t0 = Shift(x, 8);
+            t1 = x ^ t0;
+            return Shift(t1, 16) ^ t0 ^ FFmulX(t1);
         }
 
         private static uint Inv_Mcol(uint x)
         {
-            uint f2 = FFmulX(x);
-            uint f4 = FFmulX(f2);
-            uint f8 = FFmulX(f4);
-            uint f9 = x ^ f8;
-
-            return f2 ^ f4 ^ f8 ^ Shift(f2 ^ f9, 8) ^ Shift(f4 ^ f9, 16) ^ Shift(f9, 24);
+            uint t0, t1;
+            t0  = x;
+            t1  = t0 ^ Shift(t0, 8);
+            t0 ^= FFmulX(t1);
+            t1 ^= FFmulX2(t0);
+            t0 ^= t1 ^ Shift(t1, 16);
+            return t0;
         }
 
         private static uint SubWord(uint x)
diff --git a/crypto/src/crypto/engines/RSABlindedEngine.cs b/crypto/src/crypto/engines/RSABlindedEngine.cs
index 037abf7e9..f95f145f6 100644
--- a/crypto/src/crypto/engines/RSABlindedEngine.cs
+++ b/crypto/src/crypto/engines/RSABlindedEngine.cs
@@ -7,118 +7,122 @@ using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Crypto.Engines
 {
-	/**
-	 * this does your basic RSA algorithm with blinding
-	 */
-	public class RsaBlindedEngine
-		: IAsymmetricBlockCipher
-	{
-		private readonly RsaCoreEngine core = new RsaCoreEngine();
-		private RsaKeyParameters key;
-		private SecureRandom random;
+    /**
+     * this does your basic RSA algorithm with blinding
+     */
+    public class RsaBlindedEngine
+        : IAsymmetricBlockCipher
+    {
+        private readonly RsaCoreEngine core = new RsaCoreEngine();
+        private RsaKeyParameters key;
+        private SecureRandom random;
 
         public virtual string AlgorithmName
-		{
-			get { return "RSA"; }
-		}
+        {
+            get { return "RSA"; }
+        }
 
-		/**
-		 * initialise the RSA engine.
-		 *
-		 * @param forEncryption true if we are encrypting, false otherwise.
-		 * @param param the necessary RSA key parameters.
-		 */
+        /**
+         * initialise the RSA engine.
+         *
+         * @param forEncryption true if we are encrypting, false otherwise.
+         * @param param the necessary RSA key parameters.
+         */
         public virtual void Init(
-			bool				forEncryption,
-			ICipherParameters	param)
-		{
-			core.Init(forEncryption, param);
+            bool forEncryption,
+            ICipherParameters param)
+        {
+            core.Init(forEncryption, param);
 
-			if (param is ParametersWithRandom)
-			{
-				ParametersWithRandom rParam = (ParametersWithRandom)param;
+            if (param is ParametersWithRandom)
+            {
+                ParametersWithRandom rParam = (ParametersWithRandom)param;
 
-				key = (RsaKeyParameters)rParam.Parameters;
-				random = rParam.Random;
-			}
-			else
-			{
-				key = (RsaKeyParameters)param;
-				random = new SecureRandom();
-			}
-		}
+                key = (RsaKeyParameters)rParam.Parameters;
+                random = rParam.Random;
+            }
+            else
+            {
+                key = (RsaKeyParameters)param;
+                random = new SecureRandom();
+            }
+        }
 
-		/**
-		 * Return the maximum size for an input block to this engine.
-		 * For RSA this is always one byte less than the key size on
-		 * encryption, and the same length as the key size on decryption.
-		 *
-		 * @return maximum size for an input block.
-		 */
+        /**
+         * Return the maximum size for an input block to this engine.
+         * For RSA this is always one byte less than the key size on
+         * encryption, and the same length as the key size on decryption.
+         *
+         * @return maximum size for an input block.
+         */
         public virtual int GetInputBlockSize()
-		{
-			return core.GetInputBlockSize();
-		}
+        {
+            return core.GetInputBlockSize();
+        }
 
-		/**
-		 * Return the maximum size for an output block to this engine.
-		 * For RSA this is always one byte less than the key size on
-		 * decryption, and the same length as the key size on encryption.
-		 *
-		 * @return maximum size for an output block.
-		 */
+        /**
+         * Return the maximum size for an output block to this engine.
+         * For RSA this is always one byte less than the key size on
+         * decryption, and the same length as the key size on encryption.
+         *
+         * @return maximum size for an output block.
+         */
         public virtual int GetOutputBlockSize()
-		{
-			return core.GetOutputBlockSize();
-		}
+        {
+            return core.GetOutputBlockSize();
+        }
 
-		/**
-		 * Process a single block using the basic RSA algorithm.
-		 *
-		 * @param inBuf the input array.
-		 * @param inOff the offset into the input buffer where the data starts.
-		 * @param inLen the length of the data to be processed.
-		 * @return the result of the RSA process.
-		 * @exception DataLengthException the input block is too large.
-		 */
+        /**
+         * Process a single block using the basic RSA algorithm.
+         *
+         * @param inBuf the input array.
+         * @param inOff the offset into the input buffer where the data starts.
+         * @param inLen the length of the data to be processed.
+         * @return the result of the RSA process.
+         * @exception DataLengthException the input block is too large.
+         */
         public virtual byte[] ProcessBlock(
-			byte[]	inBuf,
-			int		inOff,
-			int		inLen)
-		{
-			if (key == null)
-				throw new InvalidOperationException("RSA engine not initialised");
+            byte[] inBuf,
+            int inOff,
+            int inLen)
+        {
+            if (key == null)
+                throw new InvalidOperationException("RSA engine not initialised");
 
-			BigInteger input = core.ConvertInput(inBuf, inOff, inLen);
+            BigInteger input = core.ConvertInput(inBuf, inOff, inLen);
 
-			BigInteger result;
-			if (key is RsaPrivateCrtKeyParameters)
-			{
-				RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key;
-				BigInteger e = k.PublicExponent;
-				if (e != null)   // can't do blinding without a public exponent
-				{
-					BigInteger m = k.Modulus;
-					BigInteger r = BigIntegers.CreateRandomInRange(
-						BigInteger.One, m.Subtract(BigInteger.One), random);
+            BigInteger result;
+            if (key is RsaPrivateCrtKeyParameters)
+            {
+                RsaPrivateCrtKeyParameters k = (RsaPrivateCrtKeyParameters)key;
+                BigInteger e = k.PublicExponent;
+                if (e != null)   // can't do blinding without a public exponent
+                {
+                    BigInteger m = k.Modulus;
+                    BigInteger r = BigIntegers.CreateRandomInRange(
+                        BigInteger.One, m.Subtract(BigInteger.One), random);
 
-					BigInteger blindedInput = r.ModPow(e, m).Multiply(input).Mod(m);
-					BigInteger blindedResult = core.ProcessBlock(blindedInput);
+                    BigInteger blindedInput = r.ModPow(e, m).Multiply(input).Mod(m);
+                    BigInteger blindedResult = core.ProcessBlock(blindedInput);
 
-					BigInteger rInv = r.ModInverse(m);
-					result = blindedResult.Multiply(rInv).Mod(m);
-				}
-				else
-				{
-					result = core.ProcessBlock(input);
-				}
-			}
-			else
-			{
-				result = core.ProcessBlock(input);
-			}
+                    BigInteger rInv = r.ModInverse(m);
+                    result = blindedResult.Multiply(rInv).Mod(m);
 
-			return core.ConvertOutput(result);
-		}
-	}
+                    // defence against Arjen Lenstra’s CRT attack
+                    if (!input.Equals(result.ModPow(e, m)))
+                        throw new InvalidOperationException("RSA engine faulty decryption/signing detected");
+                }
+                else
+                {
+                    result = core.ProcessBlock(input);
+                }
+            }
+            else
+            {
+                result = core.ProcessBlock(input);
+            }
+
+            return core.ConvertOutput(result);
+        }
+    }
 }
diff --git a/crypto/src/crypto/modes/gcm/GcmUtilities.cs b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
index de41d88f4..d8ab2ca73 100644
--- a/crypto/src/crypto/modes/gcm/GcmUtilities.cs
+++ b/crypto/src/crypto/modes/gcm/GcmUtilities.cs
@@ -46,6 +46,13 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             return tmp;
         }
 
+        internal static ulong[] OneAsUlongs()
+        {
+            ulong[] tmp = new ulong[2];
+            tmp[0] = 1UL << 63;
+            return tmp;
+        }
+
         internal static byte[] AsBytes(uint[] x)
         {
             return Pack.UInt32_To_BE(x);
@@ -56,6 +63,18 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             Pack.UInt32_To_BE(x, z, 0);
         }
 
+        internal static byte[] AsBytes(ulong[] x)
+        {
+            byte[] z = new byte[16];
+            Pack.UInt64_To_BE(x, z, 0);
+            return z;
+        }
+
+        internal static void AsBytes(ulong[] x, byte[] z)
+        {
+            Pack.UInt64_To_BE(x, z, 0);
+        }
+
         internal static uint[] AsUints(byte[] bs)
         {
             uint[] output = new uint[4];
@@ -68,6 +87,18 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             Pack.BE_To_UInt32(bs, 0, output);
         }
 
+        internal static ulong[] AsUlongs(byte[] x)
+        {
+            ulong[] z = new ulong[2];
+            Pack.BE_To_UInt64(x, 0, z);
+            return z;
+        }
+
+        public static void AsUlongs(byte[] x, ulong[] z)
+        {
+            Pack.BE_To_UInt64(x, 0, z);
+        }
+
         internal static void Multiply(byte[] x, byte[] y)
         {
             uint[] t1 = GcmUtilities.AsUints(x);
@@ -80,7 +111,7 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
         {
             uint r00 = x[0], r01 = x[1], r02 = x[2], r03 = x[3];
             uint r10 = 0, r11 = 0, r12 = 0, r13 = 0;
-        
+
             for (int i = 0; i < 4; ++i)
             {
                 int bits = (int)y[i];
@@ -93,9 +124,9 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
                     r13 ^= (r03 & m1);
 
                     uint m2 = (uint)((int)(r03 << 31) >> 8);
-                    r03 = (r03 >> 1) | (r02 << 63);
-                    r02 = (r02 >> 1) | (r01 << 63);
-                    r01 = (r01 >> 1) | (r00 << 63);
+                    r03 = (r03 >> 1) | (r02 << 31);
+                    r02 = (r02 >> 1) | (r01 << 31);
+                    r01 = (r01 >> 1) | (r00 << 31);
                     r00 = (r00 >> 1) ^ (m2 & E1);
                 }
             }
@@ -119,7 +150,7 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
                     r10 ^= (r00 & m1);
                     r11 ^= (r01 & m1);
 
-                    ulong m2 = (r01 << 63) >> 8;
+                    ulong m2 = (ulong)((long)(r01 << 63) >> 8);
                     r01 = (r01 >> 1) | (r00 << 63);
                     r00 = (r00 >> 1) ^ (m2 & E1L);
                 }
@@ -272,5 +303,17 @@ namespace Org.BouncyCastle.Crypto.Modes.Gcm
             z[2] = x[2] ^ y[2];
             z[3] = x[3] ^ y[3];
         }
+
+        internal static void Xor(ulong[] x, ulong[] y)
+        {
+            x[0] ^= y[0];
+            x[1] ^= y[1];
+        }
+
+        internal static void Xor(ulong[] x, ulong[] y, ulong[] z)
+        {
+            z[0] = x[0] ^ y[0];
+            z[1] = x[1] ^ y[1];
+        }
     }
 }
diff --git a/crypto/src/crypto/operators/Asn1Signature.cs b/crypto/src/crypto/operators/Asn1Signature.cs
new file mode 100644
index 000000000..23151d9c4
--- /dev/null
+++ b/crypto/src/crypto/operators/Asn1Signature.cs
@@ -0,0 +1,560 @@
+using System;
+using System.Collections;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.CryptoPro;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Asn1.Oiw;
+using Org.BouncyCastle.Asn1.Pkcs;
+using Org.BouncyCastle.Asn1.TeleTrust;
+using Org.BouncyCastle.Asn1.X509;
+using Org.BouncyCastle.Asn1.X9;
+using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Crypto.Operators
+{
+	internal class X509Utilities
+	{
+        private static readonly Asn1Null derNull = DerNull.Instance;
+
+        private static readonly IDictionary algorithms = Platform.CreateHashtable();
+		private static readonly IDictionary exParams = Platform.CreateHashtable();
+		private static readonly ISet        noParams = new HashSet();
+
+		static X509Utilities()
+		{
+			algorithms.Add("MD2WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+			algorithms.Add("MD2WITHRSA", PkcsObjectIdentifiers.MD2WithRsaEncryption);
+			algorithms.Add("MD5WITHRSAENCRYPTION", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+			algorithms.Add("MD5WITHRSA", PkcsObjectIdentifiers.MD5WithRsaEncryption);
+			algorithms.Add("SHA1WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+			algorithms.Add("SHA1WITHRSA", PkcsObjectIdentifiers.Sha1WithRsaEncryption);
+			algorithms.Add("SHA224WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+			algorithms.Add("SHA224WITHRSA", PkcsObjectIdentifiers.Sha224WithRsaEncryption);
+			algorithms.Add("SHA256WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+			algorithms.Add("SHA256WITHRSA", PkcsObjectIdentifiers.Sha256WithRsaEncryption);
+			algorithms.Add("SHA384WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+			algorithms.Add("SHA384WITHRSA", PkcsObjectIdentifiers.Sha384WithRsaEncryption);
+			algorithms.Add("SHA512WITHRSAENCRYPTION", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+			algorithms.Add("SHA512WITHRSA", PkcsObjectIdentifiers.Sha512WithRsaEncryption);
+			algorithms.Add("SHA1WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA224WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA256WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA384WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("SHA512WITHRSAANDMGF1", PkcsObjectIdentifiers.IdRsassaPss);
+			algorithms.Add("RIPEMD160WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+			algorithms.Add("RIPEMD160WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD160);
+			algorithms.Add("RIPEMD128WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+			algorithms.Add("RIPEMD128WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD128);
+			algorithms.Add("RIPEMD256WITHRSAENCRYPTION", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+			algorithms.Add("RIPEMD256WITHRSA", TeleTrusTObjectIdentifiers.RsaSignatureWithRipeMD256);
+			algorithms.Add("SHA1WITHDSA", X9ObjectIdentifiers.IdDsaWithSha1);
+			algorithms.Add("DSAWITHSHA1", X9ObjectIdentifiers.IdDsaWithSha1);
+			algorithms.Add("SHA224WITHDSA", NistObjectIdentifiers.DsaWithSha224);
+			algorithms.Add("SHA256WITHDSA", NistObjectIdentifiers.DsaWithSha256);
+			algorithms.Add("SHA384WITHDSA", NistObjectIdentifiers.DsaWithSha384);
+			algorithms.Add("SHA512WITHDSA", NistObjectIdentifiers.DsaWithSha512);
+			algorithms.Add("SHA1WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha1);
+			algorithms.Add("ECDSAWITHSHA1", X9ObjectIdentifiers.ECDsaWithSha1);
+			algorithms.Add("SHA224WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha224);
+			algorithms.Add("SHA256WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha256);
+			algorithms.Add("SHA384WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha384);
+			algorithms.Add("SHA512WITHECDSA", X9ObjectIdentifiers.ECDsaWithSha512);
+			algorithms.Add("GOST3411WITHGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+			algorithms.Add("GOST3411WITHGOST3410-94", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+			algorithms.Add("GOST3411WITHECGOST3410", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+			algorithms.Add("GOST3411WITHECGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+			algorithms.Add("GOST3411WITHGOST3410-2001", CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+			//
+			// According to RFC 3279, the ASN.1 encoding SHALL (id-dsa-with-sha1) or MUST (ecdsa-with-SHA*) omit the parameters field.
+			// The parameters field SHALL be NULL for RSA based signature algorithms.
+			//
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha1);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha224);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha256);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha384);
+			noParams.Add(X9ObjectIdentifiers.ECDsaWithSha512);
+			noParams.Add(X9ObjectIdentifiers.IdDsaWithSha1);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha224);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha256);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha384);
+			noParams.Add(NistObjectIdentifiers.DsaWithSha512);
+
+			//
+			// RFC 4491
+			//
+			noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x94);
+			noParams.Add(CryptoProObjectIdentifiers.GostR3411x94WithGostR3410x2001);
+
+			//
+			// explicit params
+			//
+			AlgorithmIdentifier sha1AlgId = new AlgorithmIdentifier(OiwObjectIdentifiers.IdSha1, DerNull.Instance);
+			exParams.Add("SHA1WITHRSAANDMGF1", CreatePssParams(sha1AlgId, 20));
+
+			AlgorithmIdentifier sha224AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha224, DerNull.Instance);
+			exParams.Add("SHA224WITHRSAANDMGF1", CreatePssParams(sha224AlgId, 28));
+
+			AlgorithmIdentifier sha256AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha256, DerNull.Instance);
+			exParams.Add("SHA256WITHRSAANDMGF1", CreatePssParams(sha256AlgId, 32));
+
+			AlgorithmIdentifier sha384AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha384, DerNull.Instance);
+			exParams.Add("SHA384WITHRSAANDMGF1", CreatePssParams(sha384AlgId, 48));
+
+			AlgorithmIdentifier sha512AlgId = new AlgorithmIdentifier(NistObjectIdentifiers.IdSha512, DerNull.Instance);
+			exParams.Add("SHA512WITHRSAANDMGF1", CreatePssParams(sha512AlgId, 64));
+		}
+
+        /**
+		 * Return the digest algorithm using one of the standard JCA string
+		 * representations rather than the algorithm identifier (if possible).
+		 */
+        private static string GetDigestAlgName(
+            DerObjectIdentifier digestAlgOID)
+        {
+            if (PkcsObjectIdentifiers.MD5.Equals(digestAlgOID))
+            {
+                return "MD5";
+            }
+            else if (OiwObjectIdentifiers.IdSha1.Equals(digestAlgOID))
+            {
+                return "SHA1";
+            }
+            else if (NistObjectIdentifiers.IdSha224.Equals(digestAlgOID))
+            {
+                return "SHA224";
+            }
+            else if (NistObjectIdentifiers.IdSha256.Equals(digestAlgOID))
+            {
+                return "SHA256";
+            }
+            else if (NistObjectIdentifiers.IdSha384.Equals(digestAlgOID))
+            {
+                return "SHA384";
+            }
+            else if (NistObjectIdentifiers.IdSha512.Equals(digestAlgOID))
+            {
+                return "SHA512";
+            }
+            else if (TeleTrusTObjectIdentifiers.RipeMD128.Equals(digestAlgOID))
+            {
+                return "RIPEMD128";
+            }
+            else if (TeleTrusTObjectIdentifiers.RipeMD160.Equals(digestAlgOID))
+            {
+                return "RIPEMD160";
+            }
+            else if (TeleTrusTObjectIdentifiers.RipeMD256.Equals(digestAlgOID))
+            {
+                return "RIPEMD256";
+            }
+            else if (CryptoProObjectIdentifiers.GostR3411.Equals(digestAlgOID))
+            {
+                return "GOST3411";
+            }
+            else
+            {
+                return digestAlgOID.Id;
+            }
+        }
+
+        internal static string GetSignatureName(AlgorithmIdentifier sigAlgId)
+        {
+            Asn1Encodable parameters = sigAlgId.Parameters;
+
+            if (parameters != null && !derNull.Equals(parameters))
+            {
+                if (sigAlgId.ObjectID.Equals(PkcsObjectIdentifiers.IdRsassaPss))
+                {
+                    RsassaPssParameters rsaParams = RsassaPssParameters.GetInstance(parameters);
+
+                    return GetDigestAlgName(rsaParams.HashAlgorithm.ObjectID) + "withRSAandMGF1";
+                }
+                if (sigAlgId.ObjectID.Equals(X9ObjectIdentifiers.ECDsaWithSha2))
+                {
+                    Asn1Sequence ecDsaParams = Asn1Sequence.GetInstance(parameters);
+
+                    return GetDigestAlgName((DerObjectIdentifier)ecDsaParams[0]) + "withECDSA";
+                }
+            }
+
+            return sigAlgId.ObjectID.Id;
+        }
+
+        private static RsassaPssParameters CreatePssParams(
+			AlgorithmIdentifier	hashAlgId,
+			int					saltSize)
+		{
+			return new RsassaPssParameters(
+				hashAlgId,
+				new AlgorithmIdentifier(PkcsObjectIdentifiers.IdMgf1, hashAlgId),
+				new DerInteger(saltSize),
+				new DerInteger(1));
+		}
+
+		internal static DerObjectIdentifier GetAlgorithmOid(
+			string algorithmName)
+		{
+			algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+			if (algorithms.Contains(algorithmName))
+			{
+				return (DerObjectIdentifier) algorithms[algorithmName];
+			}
+
+			return new DerObjectIdentifier(algorithmName);
+		}
+
+		internal static AlgorithmIdentifier GetSigAlgID(
+			DerObjectIdentifier sigOid,
+			string				algorithmName)
+		{
+			if (noParams.Contains(sigOid))
+			{
+				return new AlgorithmIdentifier(sigOid);
+			}
+
+			algorithmName = Platform.ToUpperInvariant(algorithmName);
+
+			if (exParams.Contains(algorithmName))
+			{
+				return new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
+			}
+
+			return new AlgorithmIdentifier(sigOid, DerNull.Instance);
+		}
+
+		internal static IEnumerable GetAlgNames()
+		{
+			return new EnumerableProxy(algorithms.Keys);
+		}
+	}
+
+	internal class SignerBucket
+		: Stream
+	{
+		protected readonly ISigner signer;
+
+		public SignerBucket(
+			ISigner	signer)
+		{
+			this.signer = signer;
+		}
+
+		public override int Read(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+		{
+			throw new NotImplementedException ();
+		}
+
+		public override int ReadByte()
+		{
+			throw new NotImplementedException ();
+		}
+
+		public override void Write(
+			byte[]	buffer,
+			int		offset,
+			int		count)
+		{
+			if (count > 0)
+			{
+				signer.BlockUpdate(buffer, offset, count);
+			}
+		}
+
+		public override void WriteByte(
+			byte b)
+		{
+			signer.Update(b);
+		}
+
+		public override bool CanRead
+		{
+			get { return false; }
+		}
+
+		public override bool CanWrite
+		{
+			get { return true; }
+		}
+
+		public override bool CanSeek
+		{
+			get { return false; }
+		}
+
+		public override long Length
+		{
+			get { return 0; }
+		}
+
+		public override long Position
+		{
+			get { throw new NotImplementedException (); }
+			set { throw new NotImplementedException (); }
+		}
+
+        protected override void Dispose(bool disposing)
+        {
+            base.Dispose(disposing);
+        }
+
+        public override  void Flush()
+		{
+		}
+
+		public override long Seek(
+			long		offset,
+			SeekOrigin	origin)
+		{
+			throw new NotImplementedException ();
+		}
+
+		public override void SetLength(
+			long length)
+		{
+			throw new NotImplementedException ();
+		}
+	}
+
+    /// <summary>
+    /// Calculator class for signature generation in ASN.1 based profiles that use an AlgorithmIdentifier to preserve
+    /// signature algorithm details.
+    /// </summary>
+	public class Asn1SignatureCalculator: ISignatureCalculator
+	{
+		private readonly AlgorithmIdentifier algID;
+        private readonly string algorithm;
+        private readonly AsymmetricKeyParameter privateKey;
+        private readonly SecureRandom random;
+
+        /// <summary>
+        /// Base constructor.
+        /// </summary>
+        /// <param name="algorithm">The name of the signature algorithm to use.</param>
+        /// <param name="privateKey">The private key to be used in the signing operation.</param>
+		public Asn1SignatureCalculator (string algorithm, AsymmetricKeyParameter privateKey): this(algorithm, privateKey, null)
+		{
+		}
+
+        /// <summary>
+        /// Constructor which also specifies a source of randomness to be used if one is required.
+        /// </summary>
+        /// <param name="algorithm">The name of the signature algorithm to use.</param>
+        /// <param name="privateKey">The private key to be used in the signing operation.</param>
+        /// <param name="random">The source of randomness to be used in signature calculation.</param>
+		public Asn1SignatureCalculator (string algorithm, AsymmetricKeyParameter privateKey, SecureRandom random)
+		{
+			DerObjectIdentifier sigOid = X509Utilities.GetAlgorithmOid (algorithm);
+
+            this.algorithm = algorithm;
+            this.privateKey = privateKey;
+            this.random = random;
+			this.algID = X509Utilities.GetSigAlgID (sigOid, algorithm);
+		}
+
+		public Object AlgorithmDetails
+		{
+			get { return this.algID; }
+		}
+
+        public IStreamCalculator CreateCalculator()
+        {
+            ISigner sig = SignerUtilities.GetSigner(algorithm);
+
+            if (random != null)
+            {
+                sig.Init(true, new ParametersWithRandom(privateKey, random));
+            }
+            else
+            {
+                sig.Init(true, privateKey);
+            }
+
+            return new SigCalculator(sig);
+        }
+
+        /// <summary>
+        /// Allows enumeration of the signature names supported by the verifier provider.
+        /// </summary>
+        public static IEnumerable SignatureAlgNames
+        {
+            get { return X509Utilities.GetAlgNames(); }
+        }
+    }
+
+    internal class SigCalculator : IStreamCalculator
+    {
+        private readonly ISigner sig;
+        private readonly Stream stream;
+
+        internal SigCalculator(ISigner sig)
+        {
+            this.sig = sig;
+            this.stream = new SignerBucket(sig);
+        }
+
+        public Stream Stream
+        {
+            get { return stream; }
+        }
+
+        public object GetResult()
+        {
+            return new SigResult(sig);
+        }
+    }
+
+    internal class SigResult : IBlockResult
+    {
+        private readonly ISigner sig;
+
+        internal SigResult(ISigner sig)
+        {
+            this.sig = sig;
+        }
+
+        public byte[] DoFinal()
+        {
+            return sig.GenerateSignature();
+        }
+
+        public int DoFinal(byte[] destination, int offset)
+        {
+            byte[] signature = DoFinal();
+
+            Array.Copy(signature, 0, destination, offset, signature.Length);
+
+            return signature.Length;
+        }
+    }
+
+    /// <summary>
+    /// Verifier class for signature verification in ASN.1 based profiles that use an AlgorithmIdentifier to preserve
+    /// signature algorithm details.
+    /// </summary>
+    public class Asn1SignatureVerifier: ISignatureVerifier
+	{
+		private readonly AlgorithmIdentifier algID;
+        private readonly AsymmetricKeyParameter publicKey;
+
+        /// <summary>
+        /// Base constructor.
+        /// </summary>
+        /// <param name="algorithm">The name of the signature algorithm to use.</param>
+        /// <param name="publicKey">The public key to be used in the verification operation.</param>
+        public Asn1SignatureVerifier (String algorithm, AsymmetricKeyParameter publicKey)
+		{
+			DerObjectIdentifier sigOid = X509Utilities.GetAlgorithmOid (algorithm);
+
+            this.publicKey = publicKey;
+			this.algID = X509Utilities.GetSigAlgID (sigOid, algorithm);
+		}
+
+		public Asn1SignatureVerifier (AlgorithmIdentifier algorithm, AsymmetricKeyParameter publicKey)
+		{
+            this.publicKey = publicKey;
+			this.algID = algorithm;
+		}
+
+		public Object AlgorithmDetails
+		{
+			get { return this.algID; }
+		}
+
+        public IStreamCalculator CreateCalculator()
+        {
+            ISigner sig = SignerUtilities.GetSigner(X509Utilities.GetSignatureName(algID));
+
+            sig.Init(false, publicKey);
+          
+            return new VerifierCalculator(sig);
+        }
+    }
+
+    internal class VerifierCalculator : IStreamCalculator
+    {
+        private readonly ISigner sig;
+        private readonly Stream stream;
+
+        internal VerifierCalculator(ISigner sig)
+        {
+            this.sig = sig;
+            this.stream = new SignerBucket(sig);
+        }
+
+        public Stream Stream
+        {
+            get { return stream; }
+        }
+
+        public object GetResult()
+        {
+            return new VerifierResult(sig);
+        }
+    }
+
+    internal class VerifierResult : IVerifier
+    {
+        private readonly ISigner sig;
+
+        internal VerifierResult(ISigner sig)
+        {
+            this.sig = sig;
+        }
+
+        public bool IsVerified(byte[] signature)
+        {
+            return sig.VerifySignature(signature);
+        }
+
+        public bool IsVerified(byte[] signature, int off, int length)
+        {
+            byte[] sigBytes = new byte[length];
+
+            Array.Copy(signature, 0, sigBytes, off, sigBytes.Length);
+
+            return sig.VerifySignature(signature);
+        }
+    }
+
+    /// <summary>
+    /// Provider class which supports dynamic creation of signature verifiers.
+    /// </summary>
+	public class Asn1SignatureVerifierProvider: ISignatureVerifierProvider
+	{
+		private readonly AsymmetricKeyParameter publicKey;
+
+        /// <summary>
+        /// Base constructor - specify the public key to be used in verification.
+        /// </summary>
+        /// <param name="publicKey">The public key to be used in creating verifiers provided by this object.</param>
+		public Asn1SignatureVerifierProvider(AsymmetricKeyParameter publicKey)
+		{
+			this.publicKey = publicKey;
+		}
+
+		public ISignatureVerifier CreateSignatureVerifier(Object algorithmDetails)
+		{
+			return new Asn1SignatureVerifier ((AlgorithmIdentifier)algorithmDetails, publicKey);
+		}
+
+		/// <summary>
+		/// Allows enumeration of the signature names supported by the verifier provider.
+		/// </summary>
+		public IEnumerable SignatureAlgNames
+		{
+			get { return X509Utilities.GetAlgNames(); }
+		}
+	}
+}
+
diff --git a/crypto/src/crypto/parameters/DHParameters.cs b/crypto/src/crypto/parameters/DHParameters.cs
index a0544e73b..4258df5c5 100644
--- a/crypto/src/crypto/parameters/DHParameters.cs
+++ b/crypto/src/crypto/parameters/DHParameters.cs
@@ -91,6 +91,7 @@ namespace Org.BouncyCastle.Crypto.Parameters
 				throw new ArgumentException("m value must be < bitlength of p", "m");
 			if (l != 0)
 			{ 
+                // TODO Check this against the Java version, which has 'l > p.BitLength' here
 	            if (l >= p.BitLength)
                 	throw new ArgumentException("when l value specified, it must be less than bitlength(p)", "l");
 				if (l < m)
diff --git a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
index 1486656bd..fb117c19d 100644
--- a/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
+++ b/crypto/src/crypto/signers/Iso9796d2PssSigner.cs
@@ -26,29 +26,23 @@ namespace Org.BouncyCastle.Crypto.Signers
             return recoveredMessage;
         }
 
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerImplicit = 0xBC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerRipeMD160 = 0x31CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerRipeMD128 = 0x32CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha1 = 0x33CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha256 = 0x34CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha512 = 0x35CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha384 = 0x36CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerWhirlpool = 0x37CC;
 
-        private static readonly IDictionary trailerMap = Platform.CreateHashtable();
-
-        static Iso9796d2PssSigner()
-        {
-            trailerMap.Add("RIPEMD128", TrailerRipeMD128);
-            trailerMap.Add("RIPEMD160", TrailerRipeMD160);
-            trailerMap.Add("SHA-1", TrailerSha1);
-            trailerMap.Add("SHA-256", TrailerSha256);
-            trailerMap.Add("SHA-384", TrailerSha384);
-            trailerMap.Add("SHA-512", TrailerSha512);
-
-            trailerMap.Add("Whirlpool", TrailerWhirlpool);
-        }
-
         private IDigest digest;
         private IAsymmetricBlockCipher cipher;
 
@@ -71,8 +65,7 @@ namespace Org.BouncyCastle.Crypto.Signers
         private int preTLength;
 
         /// <summary>
-        /// Generate a signer for the with either implicit or explicit trailers
-        /// for ISO9796-2, scheme 2 or 3.
+        /// Generate a signer with either implicit or explicit trailers for ISO9796-2, scheme 2 or 3.
         /// </summary>
         /// <param name="cipher">base cipher to use for signature creation/verification</param>
         /// <param name="digest">digest to use.</param>
@@ -91,15 +84,15 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             if (isImplicit)
             {
-                trailer = TrailerImplicit;
+                trailer = IsoTrailers.TRAILER_IMPLICIT;
+            }
+            else if (IsoTrailers.NoTrailerAvailable(digest))
+            {
+                throw new ArgumentException("no valid trailer", "digest");
             }
             else
             {
-                string digestAlg = digest.AlgorithmName;
-                if (!trailerMap.Contains(digestAlg))
-                    throw new ArgumentException("no valid trailer for digest");
-
-                trailer = (int)trailerMap[digestAlg];
+                trailer = IsoTrailers.GetTrailer(digest);
             }
         }
 
@@ -180,7 +173,7 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             block = new byte[(keyBits + 7) / 8];
 
-            if (trailer == TrailerImplicit)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
                 mBuf = new byte[block.Length - digest.GetDigestSize() - saltLength - 1 - 1];
             }
@@ -247,11 +240,10 @@ namespace Org.BouncyCastle.Crypto.Signers
             {
                 int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
 
-                string digestAlg = digest.AlgorithmName;
-                if (!trailerMap.Contains(digestAlg))
+                if (IsoTrailers.NoTrailerAvailable(digest))
                     throw new ArgumentException("unrecognised hash in signature");
 
-                if (sigTrail != (int)trailerMap[digestAlg])
+                if (sigTrail != IsoTrailers.GetTrailer(digest))
                     throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
 
                 tLength = 2;
@@ -395,7 +387,7 @@ namespace Org.BouncyCastle.Crypto.Signers
             digest.DoFinal(hash, 0);
 
             int tLength = 2;
-            if (trailer == TrailerImplicit)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
                 tLength = 1;
             }
@@ -415,9 +407,9 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             Array.Copy(hash, 0, block, block.Length - hLen - tLength, hLen);
 
-            if (trailer == TrailerImplicit)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
-                block[block.Length - 1] = (byte)TrailerImplicit;
+                block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
             }
             else
             {
diff --git a/crypto/src/crypto/signers/Iso9796d2Signer.cs b/crypto/src/crypto/signers/Iso9796d2Signer.cs
index 4bb4d17a6..b90ed8f0b 100644
--- a/crypto/src/crypto/signers/Iso9796d2Signer.cs
+++ b/crypto/src/crypto/signers/Iso9796d2Signer.cs
@@ -21,30 +21,23 @@ namespace Org.BouncyCastle.Crypto.Signers
             return recoveredMessage;
         }
 
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerImplicit = 0xBC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerRipeMD160 = 0x31CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerRipeMD128 = 0x32CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha1 = 0x33CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha256 = 0x34CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha512 = 0x35CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerSha384 = 0x36CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
         public const int TrailerWhirlpool = 0x37CC;
 
-        private static IDictionary trailerMap = Platform.CreateHashtable();
-
-        static Iso9796d2Signer()
-        {
-            trailerMap.Add("RIPEMD128", TrailerRipeMD128);
-            trailerMap.Add("RIPEMD160", TrailerRipeMD160);
-
-            trailerMap.Add("SHA-1", TrailerSha1);
-            trailerMap.Add("SHA-256", TrailerSha256);
-            trailerMap.Add("SHA-384", TrailerSha384);
-            trailerMap.Add("SHA-512", TrailerSha512);
-
-            trailerMap.Add("Whirlpool", TrailerWhirlpool);
-        }
-
         private IDigest digest;
         private IAsymmetricBlockCipher cipher;
 
@@ -60,8 +53,7 @@ namespace Org.BouncyCastle.Crypto.Signers
         private byte[] preBlock;
 
         /// <summary>
-        /// Generate a signer for the with either implicit or explicit trailers
-        /// for ISO9796-2.
+        /// Generate a signer with either implicit or explicit trailers for ISO9796-2.
         /// </summary>
         /// <param name="cipher">base cipher to use for signature creation/verification</param>
         /// <param name="digest">digest to use.</param>
@@ -76,20 +68,15 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             if (isImplicit)
             {
-                trailer = TrailerImplicit;
+                trailer = IsoTrailers.TRAILER_IMPLICIT;
+            }
+            else if (IsoTrailers.NoTrailerAvailable(digest))
+            {
+                throw new ArgumentException("no valid trailer", "digest");
             }
             else
             {
-                string digestName = digest.AlgorithmName;
-
-                if (trailerMap.Contains(digestName))
-                {
-                    trailer = (int)trailerMap[digest.AlgorithmName];
-                }
-                else
-                {
-                    throw new System.ArgumentException("no valid trailer for digest");
-                }
+                trailer = IsoTrailers.GetTrailer(digest);
             }
         }
 
@@ -119,7 +106,7 @@ namespace Org.BouncyCastle.Crypto.Signers
             keyBits = kParam.Modulus.BitLength;
 
             block = new byte[(keyBits + 7) / 8];
-            if (trailer == TrailerImplicit)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
                 mBuf = new byte[block.Length - digest.GetDigestSize() - 2];
             }
@@ -195,10 +182,10 @@ namespace Org.BouncyCastle.Crypto.Signers
             {
                 int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
 
-                string digestName = digest.AlgorithmName;
-                if (!trailerMap.Contains(digestName))
+                if (IsoTrailers.NoTrailerAvailable(digest))
                     throw new ArgumentException("unrecognised hash in signature");
-                if (sigTrail != (int)trailerMap[digestName])
+
+                if (sigTrail != IsoTrailers.GetTrailer(digest))
                     throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
 
                 delta = 2;
@@ -319,12 +306,12 @@ namespace Org.BouncyCastle.Crypto.Signers
             int t = 0;
             int delta = 0;
 
-            if (trailer == TrailerImplicit)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
                 t = 8;
                 delta = block.Length - digSize - 1;
                 digest.DoFinal(block, delta);
-                block[block.Length - 1] = (byte) TrailerImplicit;
+                block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
             }
             else
             {
@@ -424,10 +411,10 @@ namespace Org.BouncyCastle.Crypto.Signers
             {
                 int sigTrail = ((block[block.Length - 2] & 0xFF) << 8) | (block[block.Length - 1] & 0xFF);
 
-                string digestName = digest.AlgorithmName;
-                if (!trailerMap.Contains(digestName))
+                if (IsoTrailers.NoTrailerAvailable(digest))
                     throw new ArgumentException("unrecognised hash in signature");
-                if (sigTrail != (int)trailerMap[digestName])
+
+                if (sigTrail != IsoTrailers.GetTrailer(digest))
                     throw new InvalidOperationException("signer initialised with wrong digest for trailer " + sigTrail);
 
                 delta = 2;
diff --git a/crypto/src/crypto/signers/IsoTrailers.cs b/crypto/src/crypto/signers/IsoTrailers.cs
new file mode 100644
index 000000000..497ffaf78
--- /dev/null
+++ b/crypto/src/crypto/signers/IsoTrailers.cs
@@ -0,0 +1,57 @@
+using System;
+using System.Collections;
+
+using Org.BouncyCastle.Crypto.Digests;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Collections;
+
+namespace Org.BouncyCastle.Crypto.Signers
+{
+    public class IsoTrailers
+    {
+        public const int TRAILER_IMPLICIT    = 0xBC;
+        public const int TRAILER_RIPEMD160   = 0x31CC;
+        public const int TRAILER_RIPEMD128   = 0x32CC;
+        public const int TRAILER_SHA1        = 0x33CC;
+        public const int TRAILER_SHA256      = 0x34CC;
+        public const int TRAILER_SHA512      = 0x35CC;
+        public const int TRAILER_SHA384      = 0x36CC;
+        public const int TRAILER_WHIRLPOOL   = 0x37CC;
+        public const int TRAILER_SHA224      = 0x38CC;
+        public const int TRAILER_SHA512_224  = 0x39CC;
+        public const int TRAILER_SHA512_256  = 0x40CC;
+
+        private static IDictionary CreateTrailerMap()
+        {
+            IDictionary trailers = Platform.CreateHashtable();
+
+            trailers.Add("RIPEMD128", TRAILER_RIPEMD128);
+            trailers.Add("RIPEMD160", TRAILER_RIPEMD160);
+
+            trailers.Add("SHA-1", TRAILER_SHA1);
+            trailers.Add("SHA-224", TRAILER_SHA224);
+            trailers.Add("SHA-256", TRAILER_SHA256);
+            trailers.Add("SHA-384", TRAILER_SHA384);
+            trailers.Add("SHA-512", TRAILER_SHA512);
+            trailers.Add("SHA-512/224", TRAILER_SHA512_224);
+            trailers.Add("SHA-512/256", TRAILER_SHA512_256);
+
+            trailers.Add("Whirlpool", TRAILER_WHIRLPOOL);
+
+            return CollectionUtilities.ReadOnly(trailers);
+        }
+
+        // IDictionary is (string -> Int32)
+        private static readonly IDictionary trailerMap = CreateTrailerMap();
+
+        public static int GetTrailer(IDigest digest)
+        {
+            return (int)trailerMap[digest.AlgorithmName];
+        }
+
+        public static bool NoTrailerAvailable(IDigest digest)
+        {
+            return !trailerMap.Contains(digest.AlgorithmName);
+        }
+    }
+}
diff --git a/crypto/src/crypto/signers/X931Signer.cs b/crypto/src/crypto/signers/X931Signer.cs
index 89f512b78..36483fe17 100644
--- a/crypto/src/crypto/signers/X931Signer.cs
+++ b/crypto/src/crypto/signers/X931Signer.cs
@@ -20,31 +20,24 @@ namespace Org.BouncyCastle.Crypto.Signers
     public class X931Signer
         :   ISigner
     {
-        public const int TRAILER_IMPLICIT    = 0xBC;
-        public const int TRAILER_RIPEMD160   = 0x31CC;
-        public const int TRAILER_RIPEMD128   = 0x32CC;
-        public const int TRAILER_SHA1        = 0x33CC;
-        public const int TRAILER_SHA256      = 0x34CC;
-        public const int TRAILER_SHA512      = 0x35CC;
-        public const int TRAILER_SHA384      = 0x36CC;
-        public const int TRAILER_WHIRLPOOL   = 0x37CC;
-        public const int TRAILER_SHA224      = 0x38CC;
-
-        private static readonly IDictionary trailerMap = Platform.CreateHashtable();
-
-        static X931Signer()
-        {
-            trailerMap.Add("RIPEMD128", TRAILER_RIPEMD128);
-            trailerMap.Add("RIPEMD160", TRAILER_RIPEMD160);
-
-            trailerMap.Add("SHA-1", TRAILER_SHA1);
-            trailerMap.Add("SHA-224", TRAILER_SHA224);
-            trailerMap.Add("SHA-256", TRAILER_SHA256);
-            trailerMap.Add("SHA-384", TRAILER_SHA384);
-            trailerMap.Add("SHA-512", TRAILER_SHA512);
-
-            trailerMap.Add("Whirlpool", TRAILER_WHIRLPOOL);
-        }
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_IMPLICIT = 0xBC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_RIPEMD160 = 0x31CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_RIPEMD128 = 0x32CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_SHA1 = 0x33CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_SHA256 = 0x34CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_SHA512 = 0x35CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_SHA384 = 0x36CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_WHIRLPOOL = 0x37CC;
+        [Obsolete("Use 'IsoTrailers' instead")]
+        public const int TRAILER_SHA224 = 0x38CC;
 
         private IDigest                     digest;
         private IAsymmetricBlockCipher      cipher;
@@ -55,8 +48,7 @@ namespace Org.BouncyCastle.Crypto.Signers
         private byte[]      block;
 
         /**
-         * Generate a signer for the with either implicit or explicit trailers
-         * for ISO9796-2.
+         * Generate a signer with either implicit or explicit trailers for X9.31.
          *
          * @param cipher base cipher to use for signature creation/verification
          * @param digest digest to use.
@@ -69,15 +61,15 @@ namespace Org.BouncyCastle.Crypto.Signers
 
             if (isImplicit)
             {
-                trailer = TRAILER_IMPLICIT;
+                trailer = IsoTrailers.TRAILER_IMPLICIT;
+            }
+            else if (IsoTrailers.NoTrailerAvailable(digest))
+            {
+                throw new ArgumentException("no valid trailer", "digest");
             }
             else
             {
-                string name = digest.AlgorithmName;
-                if (!trailerMap.Contains(name))
-                    throw new ArgumentException("no valid trailer", "digest");
-
-                trailer = (int)trailerMap[name];
+                trailer = IsoTrailers.GetTrailer(digest);
             }
         }
 
@@ -161,12 +153,11 @@ namespace Org.BouncyCastle.Crypto.Signers
             int digSize = digest.GetDigestSize();
 
             int delta;
-
-            if (trailer == TRAILER_IMPLICIT)
+            if (trailer == IsoTrailers.TRAILER_IMPLICIT)
             {
                 delta = block.Length - digSize - 1;
                 digest.DoFinal(block, delta);
-                block[block.Length - 1] = (byte)TRAILER_IMPLICIT;
+                block[block.Length - 1] = (byte)IsoTrailers.TRAILER_IMPLICIT;
             }
             else
             {
diff --git a/crypto/src/crypto/tls/AbstractTlsContext.cs b/crypto/src/crypto/tls/AbstractTlsContext.cs
index e283ee58c..ae7efc64d 100644
--- a/crypto/src/crypto/tls/AbstractTlsContext.cs
+++ b/crypto/src/crypto/tls/AbstractTlsContext.cs
@@ -12,10 +12,21 @@ namespace Org.BouncyCastle.Crypto.Tls
     {
         private static long counter = Times.NanoTime();
 
+#if NETCF_1_0
+        private static object counterLock = new object();
+        private static long NextCounterValue()
+        {
+            lock (counterLock)
+            {
+                return ++counter;
+            }
+        }
+#else
         private static long NextCounterValue()
         {
             return Interlocked.Increment(ref counter);
         }
+#endif
 
         private readonly IRandomGenerator mNonceRandom;
         private readonly SecureRandom mSecureRandom;
@@ -26,7 +37,7 @@ namespace Org.BouncyCastle.Crypto.Tls
         private TlsSession mSession = null;
         private object mUserObject = null;
 
-       internal AbstractTlsContext(SecureRandom secureRandom, SecurityParameters securityParameters)
+        internal AbstractTlsContext(SecureRandom secureRandom, SecurityParameters securityParameters)
         {
             IDigest d = TlsUtilities.CreateHash(HashAlgorithm.sha256);
             byte[] seed = new byte[d.GetDigestSize()];
diff --git a/crypto/src/crypto/tls/ByteQueueStream.cs b/crypto/src/crypto/tls/ByteQueueStream.cs
new file mode 100644
index 000000000..3b8ffb02f
--- /dev/null
+++ b/crypto/src/crypto/tls/ByteQueueStream.cs
@@ -0,0 +1,115 @@
+using System;
+using System.IO;
+
+namespace Org.BouncyCastle.Crypto.Tls
+{
+    public class ByteQueueStream
+        : Stream
+    {
+        private readonly ByteQueue buffer;
+
+        public ByteQueueStream()
+        {
+            this.buffer = new ByteQueue();
+        }
+
+        public virtual int Available
+        {
+            get { return buffer.Available; }
+        }
+
+        public override bool CanRead
+        {
+            get { return true; }
+        }
+
+        public override bool CanSeek
+        {
+            get { return false; }
+        }
+
+        public override bool CanWrite
+        {
+            get { return true; }
+        }
+
+        protected override void Dispose(bool disposing)
+        {
+            base.Dispose(disposing);
+        }
+
+        public override void Flush()
+        {
+        }
+
+        public override long Length
+        {
+            get { throw new NotSupportedException(); }
+        }
+
+        public virtual int Peek(byte[] buf)
+        {
+            int bytesToRead = System.Math.Min(buffer.Available, buf.Length);
+            buffer.Read(buf, 0, bytesToRead, 0);
+            return bytesToRead;
+        }
+
+        public override long Position
+        {
+            get { throw new NotSupportedException(); }
+            set { throw new NotSupportedException(); }
+        }
+
+        public virtual int Read(byte[] buf)
+        {
+            return Read(buf, 0, buf.Length);
+        }
+
+        public override int Read(byte[] buf, int off, int len)
+        {
+            int bytesToRead = System.Math.Min(buffer.Available, len);
+            buffer.RemoveData(buf, off, bytesToRead, 0);
+            return bytesToRead;
+        }
+
+        public override int ReadByte()
+        {
+            if (buffer.Available == 0)
+                return -1;
+
+            return buffer.RemoveData(1, 0)[0] & 0xFF;
+        }
+
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            throw new NotSupportedException();
+        }
+
+        public override void SetLength(long value)
+        {
+            throw new NotSupportedException();
+        }
+
+        public virtual int Skip(int n)
+        {
+            int bytesToSkip = System.Math.Min(buffer.Available, n);
+            buffer.RemoveData(bytesToSkip);
+            return bytesToSkip;
+        }
+
+        public virtual void Write(byte[] buf)
+        {
+            buffer.AddData(buf, 0, buf.Length);
+        }
+
+        public override void Write(byte[] buf, int off, int len)
+        {
+            buffer.AddData(buf, off, len);
+        }
+
+        public override void WriteByte(byte b)
+        {
+            buffer.AddData(new byte[]{ b }, 0, 1);
+        }
+    }
+}
diff --git a/crypto/src/crypto/tls/RecordStream.cs b/crypto/src/crypto/tls/RecordStream.cs
index e5d0febeb..4c57da502 100644
--- a/crypto/src/crypto/tls/RecordStream.cs
+++ b/crypto/src/crypto/tls/RecordStream.cs
@@ -8,6 +8,11 @@ namespace Org.BouncyCastle.Crypto.Tls
     {
         private const int DEFAULT_PLAINTEXT_LIMIT = (1 << 14);
 
+        internal const int TLS_HEADER_SIZE = 5;
+        internal const int TLS_HEADER_TYPE_OFFSET = 0;
+        internal const int TLS_HEADER_VERSION_OFFSET = 1;
+        internal const int TLS_HEADER_LENGTH_OFFSET = 3;
+
         private TlsProtocol mHandler;
         private Stream mInput;
         private Stream mOutput;
@@ -116,11 +121,11 @@ namespace Org.BouncyCastle.Crypto.Tls
 
         internal virtual bool ReadRecord()
         {
-            byte[] recordHeader = TlsUtilities.ReadAllOrNothing(5, mInput);
+            byte[] recordHeader = TlsUtilities.ReadAllOrNothing(TLS_HEADER_SIZE, mInput);
             if (recordHeader == null)
                 return false;
 
-            byte type = TlsUtilities.ReadUint8(recordHeader, 0);
+            byte type = TlsUtilities.ReadUint8(recordHeader, TLS_HEADER_TYPE_OFFSET);
 
             /*
              * RFC 5246 6. If a TLS implementation receives an unexpected record type, it MUST send an
@@ -130,13 +135,13 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             if (!mRestrictReadVersion)
             {
-                int version = TlsUtilities.ReadVersionRaw(recordHeader, 1);
+                int version = TlsUtilities.ReadVersionRaw(recordHeader, TLS_HEADER_VERSION_OFFSET);
                 if ((version & 0xffffff00) != 0x0300)
                     throw new TlsFatalAlert(AlertDescription.illegal_parameter);
             }
             else
             {
-                ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, 1);
+                ProtocolVersion version = TlsUtilities.ReadVersion(recordHeader, TLS_HEADER_VERSION_OFFSET);
                 if (mReadVersion == null)
                 {
                     mReadVersion = version;
@@ -147,7 +152,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 }
             }
 
-            int length = TlsUtilities.ReadUint16(recordHeader, 3);
+            int length = TlsUtilities.ReadUint16(recordHeader, TLS_HEADER_LENGTH_OFFSET);
             byte[] plaintext = DecodeAndVerify(type, mInput, length);
             mHandler.ProcessRecord(type, plaintext, 0, plaintext.Length);
             return true;
@@ -247,11 +252,11 @@ namespace Org.BouncyCastle.Crypto.Tls
              */
             CheckLength(ciphertext.Length, mCiphertextLimit, AlertDescription.internal_error);
 
-            byte[] record = new byte[ciphertext.Length + 5];
-            TlsUtilities.WriteUint8(type, record, 0);
-            TlsUtilities.WriteVersion(mWriteVersion, record, 1);
-            TlsUtilities.WriteUint16(ciphertext.Length, record, 3);
-            Array.Copy(ciphertext, 0, record, 5, ciphertext.Length);
+            byte[] record = new byte[ciphertext.Length + TLS_HEADER_SIZE];
+            TlsUtilities.WriteUint8(type, record, TLS_HEADER_TYPE_OFFSET);
+            TlsUtilities.WriteVersion(mWriteVersion, record, TLS_HEADER_VERSION_OFFSET);
+            TlsUtilities.WriteUint16(ciphertext.Length, record, TLS_HEADER_LENGTH_OFFSET);
+            Array.Copy(ciphertext, 0, record, TLS_HEADER_SIZE, ciphertext.Length);
             mOutput.Write(record, 0, record.Length);
             mOutput.Flush();
         }
diff --git a/crypto/src/crypto/tls/TlsClientProtocol.cs b/crypto/src/crypto/tls/TlsClientProtocol.cs
index 7b8439acc..14c1cf4a4 100644
--- a/crypto/src/crypto/tls/TlsClientProtocol.cs
+++ b/crypto/src/crypto/tls/TlsClientProtocol.cs
@@ -21,21 +21,56 @@ namespace Org.BouncyCastle.Crypto.Tls
         protected CertificateStatus mCertificateStatus = null;
         protected CertificateRequest mCertificateRequest = null;
 
+        /**
+         * Constructor for blocking mode.
+         * @param stream The bi-directional stream of data to/from the server
+         * @param secureRandom Random number generator for various cryptographic functions
+         */
         public TlsClientProtocol(Stream stream, SecureRandom secureRandom)
-            :   base(stream, secureRandom)
+            : base(stream, secureRandom)
         {
         }
 
+        /**
+         * Constructor for blocking mode.
+         * @param input The stream of data from the server
+         * @param output The stream of data to the server
+         * @param secureRandom Random number generator for various cryptographic functions
+         */
         public TlsClientProtocol(Stream input, Stream output, SecureRandom secureRandom)
-            :   base(input, output, secureRandom)
+            : base(input, output, secureRandom)
+        {
+        }
+
+        /**
+         * Constructor for non-blocking mode.<br>
+         * <br>
+         * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to
+         * provide the received ciphertext, then use
+         * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.<br>
+         * <br>
+         * Similarly, when data needs to be sent, use
+         * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use
+         * {@link #readOutput(byte[], int, int)} to get the corresponding
+         * ciphertext.
+         * 
+         * @param secureRandom
+         *            Random number generator for various cryptographic functions
+         */
+        public TlsClientProtocol(SecureRandom secureRandom)
+            : base(secureRandom)
         {
         }
 
         /**
-         * Initiates a TLS handshake in the role of client
+         * Initiates a TLS handshake in the role of client.<br>
+         * <br>
+         * In blocking mode, this will not return until the handshake is complete.
+         * In non-blocking mode, use {@link TlsPeer#NotifyHandshakeComplete()} to
+         * receive a callback when the handshake is complete.
          *
          * @param tlsClient The {@link TlsClient} to use for the handshake.
-         * @throws IOException If handshake was not successful.
+         * @throws IOException If in blocking mode and handshake was not successful.
          */
         public virtual void Connect(TlsClient tlsClient)
         {
@@ -71,7 +106,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             SendClientHelloMessage();
             this.mConnectionState = CS_CLIENT_HELLO;
 
-            CompleteHandshake();
+            BlockForHandshake();
         }
 
         protected override void CleanupHandshake()
@@ -116,6 +151,7 @@ namespace Org.BouncyCastle.Crypto.Tls
                 this.mConnectionState = CS_CLIENT_FINISHED;
                 this.mConnectionState = CS_END;
 
+                CompleteHandshake();
                 return;
             }
 
@@ -208,6 +244,8 @@ namespace Org.BouncyCastle.Crypto.Tls
                     ProcessFinishedMessage(buf);
                     this.mConnectionState = CS_SERVER_FINISHED;
                     this.mConnectionState = CS_END;
+
+                    CompleteHandshake();
                     break;
                 }
                 default:
diff --git a/crypto/src/crypto/tls/TlsProtocol.cs b/crypto/src/crypto/tls/TlsProtocol.cs
index b80290fc4..56dd25605 100644
--- a/crypto/src/crypto/tls/TlsProtocol.cs
+++ b/crypto/src/crypto/tls/TlsProtocol.cs
@@ -72,6 +72,10 @@ namespace Org.BouncyCastle.Crypto.Tls
         protected bool mAllowCertificateStatus = false;
         protected bool mExpectSessionTicket = false;
 
+        protected bool mBlocking = true;
+        protected ByteQueueStream mInputBuffers = null;
+        protected ByteQueueStream mOutputBuffer = null;
+
         public TlsProtocol(Stream stream, SecureRandom secureRandom)
             :   this(stream, stream, secureRandom)
         {
@@ -83,6 +87,15 @@ namespace Org.BouncyCastle.Crypto.Tls
             this.mSecureRandom = secureRandom;
         }
 
+        public TlsProtocol(SecureRandom secureRandom)
+        {
+            this.mBlocking = false;
+            this.mInputBuffers = new ByteQueueStream();
+            this.mOutputBuffer = new ByteQueueStream();
+            this.mRecordStream = new RecordStream(this, mInputBuffers, mOutputBuffer);
+            this.mSecureRandom = secureRandom;
+        }
+
         protected abstract TlsContext Context { get; }
 
         internal abstract AbstractTlsContext ContextAdmin { get; }
@@ -140,13 +153,10 @@ namespace Org.BouncyCastle.Crypto.Tls
             this.mExpectSessionTicket = false;
         }
 
-        protected virtual void CompleteHandshake()
+        protected virtual void BlockForHandshake()
         {
-            try
+            if (mBlocking)
             {
-                /*
-                 * We will now read data, until we have completed the handshake.
-                 */
                 while (this.mConnectionState != CS_END)
                 {
                     if (this.mClosed)
@@ -156,7 +166,13 @@ namespace Org.BouncyCastle.Crypto.Tls
 
                     SafeReadRecord();
                 }
+            }
+        }
 
+        protected virtual void CompleteHandshake()
+        {
+            try
+            {
                 this.mRecordStream.FinaliseHandshake();
 
                 this.mSplitApplicationDataRecords = !TlsUtilities.IsTlsV11(Context);
@@ -168,7 +184,10 @@ namespace Org.BouncyCastle.Crypto.Tls
                 {
                     this.mAppDataReady = true;
 
-                    this.mTlsStream = new TlsStream(this);
+                    if (mBlocking)
+                    {
+                        this.mTlsStream = new TlsStream(this);
+                    }
                 }
 
                 if (this.mTlsSession != null)
@@ -573,9 +592,156 @@ namespace Org.BouncyCastle.Crypto.Tls
         }
 
         /// <summary>The secure bidirectional stream for this connection</summary>
+        /// <remarks>Only allowed in blocking mode.</remarks>
         public virtual Stream Stream
         {
-            get { return this.mTlsStream; }
+            get
+            {
+                if (!mBlocking)
+                    throw new InvalidOperationException("Cannot use Stream in non-blocking mode! Use OfferInput()/OfferOutput() instead.");
+                return this.mTlsStream;
+            }
+        }
+
+        /**
+         * Offer input from an arbitrary source. Only allowed in non-blocking mode.<br>
+         * <br>
+         * After this method returns, the input buffer is "owned" by this object. Other code
+         * must not attempt to do anything with it.<br>
+         * <br>
+         * This method will decrypt and process all records that are fully available.
+         * If only part of a record is available, the buffer will be retained until the
+         * remainder of the record is offered.<br>
+         * <br>
+         * If any records containing application data were processed, the decrypted data
+         * can be obtained using {@link #readInput(byte[], int, int)}. If any records
+         * containing protocol data were processed, a response may have been generated.
+         * You should always check to see if there is any available output after calling
+         * this method by calling {@link #getAvailableOutputBytes()}.
+         * @param input The input buffer to offer
+         * @throws IOException If an error occurs while decrypting or processing a record
+         */
+        public virtual void OfferInput(byte[] input)
+        {
+            if (mBlocking)
+                throw new InvalidOperationException("Cannot use OfferInput() in blocking mode! Use Stream instead.");
+            if (mClosed)
+                throw new IOException("Connection is closed, cannot accept any more input");
+
+            mInputBuffers.Write(input);
+
+            // loop while there are enough bytes to read the length of the next record
+            while (mInputBuffers.Available >= RecordStream.TLS_HEADER_SIZE)
+            {
+                byte[] header = new byte[RecordStream.TLS_HEADER_SIZE];
+                mInputBuffers.Peek(header);
+
+                int totalLength = TlsUtilities.ReadUint16(header, RecordStream.TLS_HEADER_LENGTH_OFFSET) + RecordStream.TLS_HEADER_SIZE;
+                if (mInputBuffers.Available < totalLength)
+                {
+                    // not enough bytes to read a whole record
+                    break;
+                }
+
+                SafeReadRecord();
+            }
+        }
+
+        /**
+         * Gets the amount of received application data. A call to {@link #readInput(byte[], int, int)}
+         * is guaranteed to be able to return at least this much data.<br>
+         * <br>
+         * Only allowed in non-blocking mode.
+         * @return The number of bytes of available application data
+         */
+        public virtual int GetAvailableInputBytes()
+        {
+            if (mBlocking)
+                throw new InvalidOperationException("Cannot use GetAvailableInputBytes() in blocking mode! Use ApplicationDataAvailable() instead.");
+
+            return ApplicationDataAvailable();
+        }
+
+        /**
+         * Retrieves received application data. Use {@link #getAvailableInputBytes()} to check
+         * how much application data is currently available. This method functions similarly to
+         * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data
+         * is available, nothing will be copied and zero will be returned.<br>
+         * <br>
+         * Only allowed in non-blocking mode.
+         * @param buffer The buffer to hold the application data
+         * @param offset The start offset in the buffer at which the data is written
+         * @param length The maximum number of bytes to read
+         * @return The total number of bytes copied to the buffer. May be less than the
+         *          length specified if the length was greater than the amount of available data.
+         */
+        public virtual int ReadInput(byte[] buffer, int offset, int length)
+        {
+            if (mBlocking)
+                throw new InvalidOperationException("Cannot use ReadInput() in blocking mode! Use Stream instead.");
+
+            return ReadApplicationData(buffer, offset, System.Math.Min(length, ApplicationDataAvailable()));
+        }
+
+        /**
+         * Offer output from an arbitrary source. Only allowed in non-blocking mode.<br>
+         * <br>
+         * After this method returns, the specified section of the buffer will have been
+         * processed. Use {@link #readOutput(byte[], int, int)} to get the bytes to
+         * transmit to the other peer.<br>
+         * <br>
+         * This method must not be called until after the handshake is complete! Attempting
+         * to call it before the handshake is complete will result in an exception.
+         * @param buffer The buffer containing application data to encrypt
+         * @param offset The offset at which to begin reading data
+         * @param length The number of bytes of data to read
+         * @throws IOException If an error occurs encrypting the data, or the handshake is not complete
+         */
+        public virtual void OfferOutput(byte[] buffer, int offset, int length)
+        {
+            if (mBlocking)
+                throw new InvalidOperationException("Cannot use OfferOutput() in blocking mode! Use Stream instead.");
+            if (!mAppDataReady)
+                throw new IOException("Application data cannot be sent until the handshake is complete!");
+
+            WriteData(buffer, offset, length);
+        }
+
+        /**
+         * Gets the amount of encrypted data available to be sent. A call to
+         * {@link #readOutput(byte[], int, int)} is guaranteed to be able to return at
+         * least this much data.<br>
+         * <br>
+         * Only allowed in non-blocking mode.
+         * @return The number of bytes of available encrypted data
+         */
+        public virtual int GetAvailableOutputBytes()
+        {
+            if (mBlocking)
+                throw new InvalidOperationException("Cannot use GetAvailableOutputBytes() in blocking mode! Use Stream instead.");
+
+            return mOutputBuffer.Available;
+        }
+
+        /**
+         * Retrieves encrypted data to be sent. Use {@link #getAvailableOutputBytes()} to check
+         * how much encrypted data is currently available. This method functions similarly to
+         * {@link InputStream#read(byte[], int, int)}, except that it never blocks. If no data
+         * is available, nothing will be copied and zero will be returned.<br>
+         * <br>
+         * Only allowed in non-blocking mode.
+         * @param buffer The buffer to hold the encrypted data
+         * @param offset The start offset in the buffer at which the data is written
+         * @param length The maximum number of bytes to read
+         * @return The total number of bytes copied to the buffer. May be less than the
+         *          length specified if the length was greater than the amount of available data.
+         */
+        public virtual int ReadOutput(byte[] buffer, int offset, int length)
+        {
+            if (mBlocking)
+                throw new InvalidOperationException("Cannot use ReadOutput() in blocking mode! Use Stream instead.");
+
+            return mOutputBuffer.Read(buffer, offset, length);
         }
 
         /**
@@ -764,7 +930,7 @@ namespace Org.BouncyCastle.Crypto.Tls
             mRecordStream.Flush();
         }
 
-        protected internal virtual bool IsClosed
+        public virtual bool IsClosed
         {
             get { return mClosed; }
         }
diff --git a/crypto/src/crypto/tls/TlsServerProtocol.cs b/crypto/src/crypto/tls/TlsServerProtocol.cs
index b73cb5a30..27f7a1dfd 100644
--- a/crypto/src/crypto/tls/TlsServerProtocol.cs
+++ b/crypto/src/crypto/tls/TlsServerProtocol.cs
@@ -22,21 +22,57 @@ namespace Org.BouncyCastle.Crypto.Tls
         protected short mClientCertificateType = -1;
         protected TlsHandshakeHash mPrepareFinishHash = null;
 
+        /**
+         * Constructor for blocking mode.
+         * @param stream The bi-directional stream of data to/from the client
+         * @param output The stream of data to the client
+         * @param secureRandom Random number generator for various cryptographic functions
+         */
         public TlsServerProtocol(Stream stream, SecureRandom secureRandom)
-            :   base(stream, secureRandom)
+            : base(stream, secureRandom)
         {
         }
 
+        /**
+         * Constructor for blocking mode.
+         * @param input The stream of data from the client
+         * @param output The stream of data to the client
+         * @param secureRandom Random number generator for various cryptographic functions
+         */
         public TlsServerProtocol(Stream input, Stream output, SecureRandom secureRandom)
-            :   base(input, output, secureRandom)
+            : base(input, output, secureRandom)
+        {
+        }
+
+        /**
+         * Constructor for non-blocking mode.<br>
+         * <br>
+         * When data is received, use {@link #offerInput(java.nio.ByteBuffer)} to
+         * provide the received ciphertext, then use
+         * {@link #readInput(byte[], int, int)} to read the corresponding cleartext.<br>
+         * <br>
+         * Similarly, when data needs to be sent, use
+         * {@link #offerOutput(byte[], int, int)} to provide the cleartext, then use
+         * {@link #readOutput(byte[], int, int)} to get the corresponding
+         * ciphertext.
+         * 
+         * @param secureRandom
+         *            Random number generator for various cryptographic functions
+         */
+        public TlsServerProtocol(SecureRandom secureRandom)
+            : base(secureRandom)
         {
         }
 
         /**
-         * Receives a TLS handshake in the role of server
+         * Receives a TLS handshake in the role of server.<br>
+         * <br>
+         * In blocking mode, this will not return until the handshake is complete.
+         * In non-blocking mode, use {@link TlsPeer#notifyHandshakeComplete()} to
+         * receive a callback when the handshake is complete.
          *
-         * @param mTlsServer
-         * @throws IOException If handshake was not successful.
+         * @param tlsServer
+         * @throws IOException If in blocking mode and handshake was not successful.
          */
         public virtual void Accept(TlsServer tlsServer)
         {
@@ -60,7 +96,7 @@ namespace Org.BouncyCastle.Crypto.Tls
 
             this.mRecordStream.SetRestrictReadVersion(false);
 
-            CompleteHandshake();
+            BlockForHandshake();
         }
 
         protected override void CleanupHandshake()
@@ -329,6 +365,8 @@ namespace Org.BouncyCastle.Crypto.Tls
                     SendFinishedMessage();
                     this.mConnectionState = CS_SERVER_FINISHED;
                     this.mConnectionState = CS_END;
+
+                    CompleteHandshake();
                     break;
                 }
                 default:
diff --git a/crypto/src/crypto/util/Pack.cs b/crypto/src/crypto/util/Pack.cs
index 087cb7cea..dc00ab450 100644
--- a/crypto/src/crypto/util/Pack.cs
+++ b/crypto/src/crypto/util/Pack.cs
@@ -117,6 +117,22 @@ namespace Org.BouncyCastle.Crypto.Utilities
             UInt32_To_BE((uint)(n), bs, off + 4);
         }
 
+        internal static byte[] UInt64_To_BE(ulong[] ns)
+        {
+            byte[] bs = new byte[8 * ns.Length];
+            UInt64_To_BE(ns, bs, 0);
+            return bs;
+        }
+
+        internal static void UInt64_To_BE(ulong[] ns, byte[] bs, int off)
+        {
+            for (int i = 0; i < ns.Length; ++i)
+            {
+                UInt64_To_BE(ns[i], bs, off);
+                off += 8;
+            }
+        }
+
         internal static ulong BE_To_UInt64(byte[] bs)
         {
             uint hi = BE_To_UInt32(bs);
@@ -131,6 +147,15 @@ namespace Org.BouncyCastle.Crypto.Utilities
             return ((ulong)hi << 32) | (ulong)lo;
         }
 
+        internal static void BE_To_UInt64(byte[] bs, int off, ulong[] ns)
+        {
+            for (int i = 0; i < ns.Length; ++i)
+            {
+                ns[i] = BE_To_UInt64(bs, off);
+                off += 8;
+            }
+        }
+
         internal static void UInt16_To_LE(ushort n, byte[] bs)
         {
             bs[0] = (byte)(n);
diff --git a/crypto/src/math/Primes.cs b/crypto/src/math/Primes.cs
index b57977983..420c3cc5a 100644
--- a/crypto/src/math/Primes.cs
+++ b/crypto/src/math/Primes.cs
@@ -1,18 +1,69 @@
 using System;
 
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
 namespace Org.BouncyCastle.Math
 {
-    public static class Primes
+    /**
+     * Utility methods for generating primes and testing for primality.
+     */
+    public abstract class Primes
     {
         private static readonly BigInteger One = BigInteger.One;
         private static readonly BigInteger Two = BigInteger.Two;
         private static readonly BigInteger Three = BigInteger.Three;
 
         /**
-         * Used to return the output from the {@linkplain #generateSTRandomPrime(Digest) Shawe-Taylor Random_Prime Routine} 
+         * Used to return the output from the
+         * {@linkplain Primes#enhancedMRProbablePrimeTest(BigInteger, SecureRandom, int) Enhanced
+         * Miller-Rabin Probabilistic Primality Test}
+         */
+        public class MROutput
+        {
+            internal static MROutput ProbablyPrime()
+            {
+                return new MROutput(false, null);
+            }
+
+            internal static MROutput ProvablyCompositeWithFactor(BigInteger factor)
+            {
+                return new MROutput(true, factor);
+            }
+
+            internal static MROutput ProvablyCompositeNotPrimePower()
+            {
+                return new MROutput(true, null);
+            }
+
+            private readonly bool mProvablyComposite;
+            private readonly BigInteger mFactor;
+
+            private MROutput(bool provablyComposite, BigInteger factor)
+            {
+                this.mProvablyComposite = provablyComposite;
+                this.mFactor = factor;
+            }
+
+            public BigInteger Factor
+            {
+                get { return mFactor; }
+            }
+
+            public bool IsProvablyComposite
+            {
+                get { return mProvablyComposite; }
+            }
+
+            public bool IsNotPrimePower
+            {
+                get { return mProvablyComposite && mFactor == null; }
+            }
+        }
+
+        /**
+         * Used to return the output from the {@linkplain Primes#generateSTRandomPrime(Digest, int, byte[]) Shawe-Taylor Random_Prime Routine} 
          */
         public class STOutput
         {
@@ -51,11 +102,11 @@ namespace Org.BouncyCastle.Math
          * @param hash
          *            the {@link Digest} instance to use (as "Hash()"). Cannot be null.
          * @param length
-         *            the length (in bits) of the prime to be generated. Must be >= 2.
+         *            the length (in bits) of the prime to be generated. Must be at least 2.
          * @param inputSeed
          *            the seed to be used for the generation of the requested prime. Cannot be null or
          *            empty.
-         * @returns an {@link STOutput} instance containing the requested prime.
+         * @return an {@link STOutput} instance containing the requested prime.
          */
         public static STOutput GenerateSTRandomPrime(IDigest hash, int length, byte[] inputSeed)
         {
@@ -71,6 +122,269 @@ namespace Org.BouncyCastle.Math
             return ImplSTRandomPrime(hash, length, Arrays.Clone(inputSeed));
         }
 
+        /**
+         * FIPS 186-4 C.3.2 Enhanced Miller-Rabin Probabilistic Primality Test
+         * 
+         * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases. This is an
+         * alternative to {@link #isMRProbablePrime(BigInteger, SecureRandom, int)} that provides more
+         * information about a composite candidate, which may be useful when generating or validating
+         * RSA moduli.
+         * 
+         * @param candidate
+         *            the {@link BigInteger} instance to test for primality.
+         * @param random
+         *            the source of randomness to use to choose bases.
+         * @param iterations
+         *            the number of randomly-chosen bases to perform the test for.
+         * @return an {@link MROutput} instance that can be further queried for details.
+         */
+        public static MROutput EnhancedMRProbablePrimeTest(BigInteger candidate, SecureRandom random, int iterations)
+        {
+            CheckCandidate(candidate, "candidate");
+
+            if (random == null)
+                throw new ArgumentNullException("random");
+            if (iterations < 1)
+                throw new ArgumentException("must be > 0", "iterations");
+
+            if (candidate.BitLength == 2)
+                return MROutput.ProbablyPrime();
+
+            if (!candidate.TestBit(0))
+                return MROutput.ProvablyCompositeWithFactor(Two);
+
+            BigInteger w = candidate;
+            BigInteger wSubOne = candidate.Subtract(One);
+            BigInteger wSubTwo = candidate.Subtract(Two);
+
+            int a = wSubOne.GetLowestSetBit();
+            BigInteger m = wSubOne.ShiftRight(a);
+
+            for (int i = 0; i < iterations; ++i)
+            {
+                BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random);
+                BigInteger g = b.Gcd(w);
+
+                if (g.CompareTo(One) > 0)
+                    return MROutput.ProvablyCompositeWithFactor(g);
+
+                BigInteger z = b.ModPow(m, w);
+
+                if (z.Equals(One) || z.Equals(wSubOne))
+                    continue;
+
+                bool primeToBase = false;
+
+                BigInteger x = z;
+                for (int j = 1; j < a; ++j)
+                {
+                    z = z.ModPow(Two, w);
+
+                    if (z.Equals(wSubOne))
+                    {
+                        primeToBase = true;
+                        break;
+                    }
+
+                    if (z.Equals(One))
+                        break;
+
+                    x = z;
+                }
+
+                if (!primeToBase)
+                {
+                    if (!z.Equals(One))
+                    {
+                        x = z;
+                        z = z.ModPow(Two, w);
+
+                        if (!z.Equals(One))
+                        {
+                            x = z;
+                        }
+                    }
+
+                    g = x.Subtract(One).Gcd(w);
+
+                    if (g.CompareTo(One) > 0)
+                        return MROutput.ProvablyCompositeWithFactor(g);
+
+                    return MROutput.ProvablyCompositeNotPrimePower();
+                }
+            }
+
+            return MROutput.ProbablyPrime();
+        }
+
+        /**
+         * A fast check for small divisors, up to some implementation-specific limit.
+         * 
+         * @param candidate
+         *            the {@link BigInteger} instance to test for division by small factors.
+         * 
+         * @return <code>true</code> if the candidate is found to have any small factors,
+         *         <code>false</code> otherwise.
+         */
+        public static bool HasAnySmallFactors(BigInteger candidate)
+        {
+            CheckCandidate(candidate, "candidate");
+
+            return ImplHasAnySmallFactors(candidate);
+        }
+
+        /**
+         * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test
+         * 
+         * Run several iterations of the Miller-Rabin algorithm with randomly-chosen bases.
+         * 
+         * @param candidate
+         *            the {@link BigInteger} instance to test for primality.
+         * @param random
+         *            the source of randomness to use to choose bases.
+         * @param iterations
+         *            the number of randomly-chosen bases to perform the test for.
+         * @return <code>false</code> if any witness to compositeness is found amongst the chosen bases
+         *         (so <code>candidate</code> is definitely NOT prime), or else <code>true</code>
+         *         (indicating primality with some probability dependent on the number of iterations
+         *         that were performed).
+         */
+        public static bool IsMRProbablePrime(BigInteger candidate, SecureRandom random, int iterations)
+        {
+            CheckCandidate(candidate, "candidate");
+
+            if (random == null)
+                throw new ArgumentException("cannot be null", "random");
+            if (iterations < 1)
+                throw new ArgumentException("must be > 0", "iterations");
+
+            if (candidate.BitLength == 2)
+                return true;
+            if (!candidate.TestBit(0))
+                return false;
+
+            BigInteger w = candidate;
+            BigInteger wSubOne = candidate.Subtract(One);
+            BigInteger wSubTwo = candidate.Subtract(Two);
+
+            int a = wSubOne.GetLowestSetBit();
+            BigInteger m = wSubOne.ShiftRight(a);
+
+            for (int i = 0; i < iterations; ++i)
+            {
+                BigInteger b = BigIntegers.CreateRandomInRange(Two, wSubTwo, random);
+
+                if (!ImplMRProbablePrimeToBase(w, wSubOne, m, a, b))
+                    return false;
+            }
+
+            return true;
+        }
+
+        /**
+         * FIPS 186-4 C.3.1 Miller-Rabin Probabilistic Primality Test (to a fixed base).
+         * 
+         * Run a single iteration of the Miller-Rabin algorithm against the specified base.
+         * 
+         * @param candidate
+         *            the {@link BigInteger} instance to test for primality.
+         * @param baseValue
+         *            the base value to use for this iteration.
+         * @return <code>false</code> if the specified base is a witness to compositeness (so
+         *         <code>candidate</code> is definitely NOT prime), or else <code>true</code>.
+         */
+        public static bool IsMRProbablePrimeToBase(BigInteger candidate, BigInteger baseValue)
+        {
+            CheckCandidate(candidate, "candidate");
+            CheckCandidate(baseValue, "baseValue");
+
+            if (baseValue.CompareTo(candidate.Subtract(One)) >= 0)
+                throw new ArgumentException("must be < ('candidate' - 1)", "baseValue");
+
+            if (candidate.BitLength == 2)
+                return true;
+
+            BigInteger w = candidate;
+            BigInteger wSubOne = candidate.Subtract(One);
+
+            int a = wSubOne.GetLowestSetBit();
+            BigInteger m = wSubOne.ShiftRight(a);
+
+            return ImplMRProbablePrimeToBase(w, wSubOne, m, a, baseValue);
+        }
+
+        private static void CheckCandidate(BigInteger n, string name)
+        {
+            if (n == null || n.SignValue < 1 || n.BitLength < 2)
+                throw new ArgumentException("must be non-null and >= 2", name);
+        }
+
+        private static bool ImplHasAnySmallFactors(BigInteger x)
+        {
+            /*
+             * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders.
+             */
+            int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;
+            int r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+            if ((r & 1) != 0 && (r % 3) != 0 && (r % 5) != 0 && (r % 7) != 0 && (r % 11) != 0
+                && (r % 13) != 0 && (r % 17) != 0 && (r % 19) != 0 && (r % 23) != 0)
+            {
+                m = 29 * 31 * 37 * 41 * 43;
+                r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+                if ((r % 29) != 0 && (r % 31) != 0 && (r % 37) != 0 && (r % 41) != 0 && (r % 43) != 0)
+                {
+                    m = 47 * 53 * 59 * 61 * 67;
+                    r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+                    if ((r % 47) != 0 && (r % 53) != 0 && (r % 59) != 0 && (r % 61) != 0 && (r % 67) != 0)
+                    {
+                        m = 71 * 73 * 79 * 83;
+                        r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+                        if ((r % 71) != 0 && (r % 73) != 0 && (r % 79) != 0 && (r % 83) != 0)
+                        {
+                            m = 89 * 97 * 101 * 103;
+                            r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+                            if ((r % 89) != 0 && (r % 97) != 0 && (r % 101) != 0 && (r % 103) != 0)
+                            {
+                                m = 107 * 109 * 113 * 127;
+                                r = x.Mod(BigInteger.ValueOf(m)).IntValue;
+                                if ((r % 107) != 0 && (r % 109) != 0 && (r % 113) != 0 && (r % 127) != 0)
+                                {
+                                    return false;
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+            return true;
+        }
+
+        private static bool ImplMRProbablePrimeToBase(BigInteger w, BigInteger wSubOne, BigInteger m, int a, BigInteger b)
+        {
+            BigInteger z = b.ModPow(m, w);
+
+            if (z.Equals(One) || z.Equals(wSubOne))
+                return true;
+
+            bool result = false;
+
+            for (int j = 1; j < a; ++j)
+            {
+                z = z.ModPow(Two, w);
+
+                if (z.Equals(wSubOne))
+                {
+                    result = true;
+                    break;
+                }
+
+                if (z.Equals(One))
+                    return false;
+            }
+
+            return result;
+        }
+
         private static STOutput ImplSTRandomPrime(IDigest d, int length, byte[] primeSeed)
         {
             int dLen = d.GetDigestSize();
@@ -131,7 +445,7 @@ namespace Org.BouncyCastle.Math
 
                 /*
                  * TODO Since the candidate primes are generated by constant steps ('c0x2'),
-                 * sieving could be used here in place of the 'mightBePrime' approach.
+                 * sieving could be used here in place of the 'HasAnySmallFactors' approach.
                  */
                 for (;;)
                 {
@@ -149,7 +463,7 @@ namespace Org.BouncyCastle.Math
                      * 
                      * NOTE: 'primeSeed' is still incremented as if we performed the full check!
                      */
-                    if (MightBePrime(c))
+                    if (!ImplHasAnySmallFactors(c))
                     {
                         BigInteger a = HashGen(d, primeSeed, iterations + 1);
                         a = a.Mod(c.Subtract(Three)).Add(Two);
@@ -266,45 +580,5 @@ namespace Org.BouncyCastle.Math
                 }
             }
         }
-
-        private static bool MightBePrime(BigInteger x)
-        {
-            /*
-             * Bundle trial divisors into ~32-bit moduli then use fast tests on the ~32-bit remainders.
-             */
-            int m = 2 * 3 * 5 * 7 * 11 * 13 * 17 * 19 * 23;
-            int r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-            if ((r & 1) != 0 && (r % 3) != 0 && (r % 5) != 0 && (r % 7) != 0 && (r % 11) != 0
-                && (r % 13) != 0 && (r % 17) != 0 && (r % 19) != 0 && (r % 23) != 0)
-            {
-                m = 29 * 31 * 37 * 41 * 43;
-                r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-                if ((r % 29) != 0 && (r % 31) != 0 && (r % 37) != 0 && (r % 41) != 0 && (r % 43) != 0)
-                {
-                    m = 47 * 53 * 59 * 61 * 67;
-                    r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-                    if ((r % 47) != 0 && (r % 53) != 0 && (r % 59) != 0 && (r % 61) != 0 && (r % 67) != 0)
-                    {
-                        m = 71 * 73 * 79 * 83;
-                        r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-                        if ((r % 71) != 0 && (r % 73) != 0 && (r % 79) != 0 && (r % 83) != 0)
-                        {
-                            m = 89 * 97 * 101 * 103;
-                            r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-                            if ((r % 89) != 0 && (r % 97) != 0 && (r % 101) != 0 && (r % 103) != 0)
-                            {
-                                m = 107 * 109 * 113 * 127;
-                                r = x.Mod(BigInteger.ValueOf(m)).IntValue;
-                                if ((r % 107) != 0 && (r % 109) != 0 && (r % 113) != 0 && (r % 127) != 0)
-                                {
-                                    return true;
-                                }
-                            }
-                        }
-                    }
-                }
-            }
-            return false;
-        }
     }
 }
diff --git a/crypto/src/math/ec/ECCurve.cs b/crypto/src/math/ec/ECCurve.cs
index 9fe9e32fd..40b46ce72 100644
--- a/crypto/src/math/ec/ECCurve.cs
+++ b/crypto/src/math/ec/ECCurve.cs
@@ -677,28 +677,110 @@ namespace Org.BouncyCastle.Math.EC
 
             switch (this.CoordinateSystem)
             {
-            case COORD_LAMBDA_AFFINE:
-            case COORD_LAMBDA_PROJECTIVE:
-            {
-                if (X.IsZero)
+                case COORD_LAMBDA_AFFINE:
+                case COORD_LAMBDA_PROJECTIVE:
                 {
-                    if (!Y.Square().Equals(B))
-                        throw new ArgumentException();
+                    if (X.IsZero)
+                    {
+                        if (!Y.Square().Equals(B))
+                            throw new ArgumentException();
+                    }
+                    else
+                    {
+                        // Y becomes Lambda (X + Y/X) here
+                        Y = Y.Divide(X).Add(X);
+                    }
+                    break;
                 }
-                else
+                default:
                 {
-                    // Y becomes Lambda (X + Y/X) here
-                    Y = Y.Divide(X).Add(X);
+                    break;
                 }
-                break;
             }
-            default:
+
+            return CreateRawPoint(X, Y, withCompression);
+        }
+
+        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
+        {
+            ECFieldElement xp = FromBigInteger(X1), yp = null;
+            if (xp.IsZero)
             {
-                break;
+                yp = B.Sqrt();
             }
+            else
+            {
+                ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
+                ECFieldElement z = SolveQuadradicEquation(beta);
+
+                if (z != null)
+                {
+                    if (z.TestBitZero() != (yTilde == 1))
+                    {
+                        z = z.AddOne();
+                    }
+
+                    switch (this.CoordinateSystem)
+                    {
+                        case COORD_LAMBDA_AFFINE:
+                        case COORD_LAMBDA_PROJECTIVE:
+                        {
+                            yp = z.Add(xp);
+                            break;
+                        }
+                        default:
+                        {
+                            yp = z.Multiply(xp);
+                            break;
+                        }
+                    }
+                }
             }
 
-            return CreateRawPoint(X, Y, withCompression);
+            if (yp == null)
+                throw new ArgumentException("Invalid point compression");
+
+            return CreateRawPoint(xp, yp, true);
+        }
+
+        /**
+         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
+         * D.1.6) The other solution is <code>z + 1</code>.
+         *
+         * @param beta
+         *            The value to solve the qradratic equation for.
+         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
+         *         <code>null</code> if no solution exists.
+         */
+        private ECFieldElement SolveQuadradicEquation(ECFieldElement beta)
+        {
+            if (beta.IsZero)
+                return beta;
+
+            ECFieldElement gamma, z, zeroElement = FromBigInteger(BigInteger.Zero);
+
+            int m = FieldSize;
+            Random rand = new Random();
+            do
+            {
+                ECFieldElement t = FromBigInteger(new BigInteger(m, rand));
+                z = zeroElement;
+                ECFieldElement w = beta;
+                for (int i = 1; i < m; i++)
+                {
+                    ECFieldElement w2 = w.Square();
+                    z = z.Square().Add(w2.Multiply(t));
+                    w = w2.Add(beta);
+                }
+                if (!w.IsZero)
+                {
+                    return null;
+                }
+                gamma = z.Square().Add(z);
+            }
+            while (gamma.IsZero);
+
+            return z;
         }
 
         /**
@@ -994,92 +1076,6 @@ namespace Org.BouncyCastle.Math.EC
             get { return m_infinity; }
         }
 
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement xp = FromBigInteger(X1), yp = null;
-            if (xp.IsZero)
-            {
-                yp = m_b.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = xp.Square().Invert().Multiply(B).Add(A).Add(xp);
-                ECFieldElement z = SolveQuadradicEquation(beta);
-
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                        case COORD_LAMBDA_AFFINE:
-                        case COORD_LAMBDA_PROJECTIVE:
-                        {
-                            yp = z.Add(xp);
-                            break;
-                        }
-                        default:
-                        {
-                            yp = z.Multiply(xp);
-                            break;
-                        }
-                    }
-                }
-            }
-
-            if (yp == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return CreateRawPoint(xp, yp, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         *
-         * @param beta
-         *            The value to solve the qradratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadradicEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-            {
-                return beta;
-            }
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(m, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < m; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                {
-                    return null;
-                }
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public int M
         {
             get { return m; }
diff --git a/crypto/src/math/ec/custom/sec/SecT113Field.cs b/crypto/src/math/ec/custom/sec/SecT113Field.cs
index dbb645e6f..640c6e787 100644
--- a/crypto/src/math/ec/custom/sec/SecT113Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT113Field.cs
@@ -37,6 +37,35 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat128.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion
+
+            ulong[] t0 = Nat128.Create64();
+            ulong[] t1 = Nat128.Create64();
+
+            Square(x, t0);
+            Multiply(t0, x, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 3, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 7, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 14, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 28, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 56, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat128.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
index e3a923f62..f217e28cb 100644
--- a/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT113FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT113FieldElement(
-                AbstractF2mCurve.Inverse(113, new int[]{ 9 }, ToBigInteger()));
+            ulong[] z = Nat128.Create64();
+            SecT113Field.Invert(x, z);
+            return new SecT113FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
index 04e69e2a8..2705c94aa 100644
--- a/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT113R1Curve.cs
@@ -65,101 +65,11 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return new SecT113R1Point(this, x, y, zs, withCompression);
         }
 
-       public override bool IsKoblitz
+        public override bool IsKoblitz
         {
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(113, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 113; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 113; }
diff --git a/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
index a02db6b25..abfd26d5b 100644
--- a/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT113R2Curve.cs
@@ -70,98 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-            {
-                return beta;
-            }
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(113, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 113; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 113; }
diff --git a/crypto/src/math/ec/custom/sec/SecT131Field.cs b/crypto/src/math/ec/custom/sec/SecT131Field.cs
index 6a1d2a960..47f97078c 100644
--- a/crypto/src/math/ec/custom/sec/SecT131Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT131Field.cs
@@ -40,6 +40,35 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat192.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion
+
+            ulong[] t0 = Nat192.Create64();
+            ulong[] t1 = Nat192.Create64();
+
+            Square(x, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 2, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 4, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 8, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 16, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 32, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 65, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat192.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
index 65aaf01ba..0ea00ea07 100644
--- a/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT131FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT131FieldElement(
-                AbstractF2mCurve.Inverse(131, new int[] { 2, 3, 8 }, ToBigInteger()));
+            ulong[] z = Nat192.Create64();
+            SecT131Field.Invert(x, z);
+            return new SecT131FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
index 789e3c0c3..b73964c39 100644
--- a/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT131R1Curve.cs
@@ -70,96 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(131, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 131; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 131; }
diff --git a/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
index 2004f84ca..724921c94 100644
--- a/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT131R2Curve.cs
@@ -70,98 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-            {
-                return beta;
-            }
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(131, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 131; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 131; }
diff --git a/crypto/src/math/ec/custom/sec/SecT163Field.cs b/crypto/src/math/ec/custom/sec/SecT163Field.cs
index 165d5b841..f921a5bc7 100644
--- a/crypto/src/math/ec/custom/sec/SecT163Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163Field.cs
@@ -41,6 +41,47 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat192.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion with bases { 2, 3 }
+
+            ulong[] t0 = Nat192.Create64();
+            ulong[] t1 = Nat192.Create64();
+
+            Square(x, t0);
+
+            // 3 | 162
+            SquareN(t0, 1, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 1, t1);
+            Multiply(t0, t1, t0);
+
+            // 3 | 54
+            SquareN(t0, 3, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 3, t1);
+            Multiply(t0, t1, t0);
+
+            // 3 | 18
+            SquareN(t0, 9, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 9, t1);
+            Multiply(t0, t1, t0);
+
+            // 3 | 6
+            SquareN(t0, 27, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 27, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 2
+            SquareN(t0, 81, t1);
+            Multiply(t0, t1, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat192.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
index 3ab383a1d..c7a0b5639 100644
--- a/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT163FieldElement(
-                AbstractF2mCurve.Inverse(163, new int[] { 3, 6, 7 }, ToBigInteger()));
+            ulong[] z = Nat192.Create64();
+            SecT163Field.Invert(x, z);
+            return new SecT163FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
index 1cfd09e1c..68ff646ca 100644
--- a/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163K1Curve.cs
@@ -76,96 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return true; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(163, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 163; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 163; }
diff --git a/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
index fc18e1094..8ae58ccef 100644
--- a/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163R1Curve.cs
@@ -70,98 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-            {
-                return beta;
-            }
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(163, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 163; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 163; }
diff --git a/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
index 9efe11c3e..5a4fa5ad1 100644
--- a/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT163R2Curve.cs
@@ -70,96 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(163, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 163; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 163; }
diff --git a/crypto/src/math/ec/custom/sec/SecT193Field.cs b/crypto/src/math/ec/custom/sec/SecT193Field.cs
index 85db061c3..5154f1e0a 100644
--- a/crypto/src/math/ec/custom/sec/SecT193Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT193Field.cs
@@ -44,6 +44,49 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat256.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion with bases { 2, 3 }
+
+            ulong[] t0 = Nat256.Create64();
+            ulong[] t1 = Nat256.Create64();
+
+            Square(x, t0);
+
+            // 3 | 192
+            SquareN(t0, 1, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 1, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 64
+            SquareN(t0, 3, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 32
+            SquareN(t0, 6, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 16
+            SquareN(t0, 12, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 8
+            SquareN(t0, 24, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 4
+            SquareN(t0, 48, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 2
+            SquareN(t0, 96, t1);
+            Multiply(t0, t1, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat256.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
index 995d2ebdd..eba4d10e6 100644
--- a/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT193FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT193FieldElement(
-                AbstractF2mCurve.Inverse(193, new int[] { 15 }, ToBigInteger()));
+            ulong[] z = Nat256.Create64();
+            SecT193Field.Invert(x, z);
+            return new SecT193FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs
index 802954b01..a2cb5a8ac 100644
--- a/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT193R1Curve.cs
@@ -70,98 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                        case COORD_LAMBDA_AFFINE:
-                        case COORD_LAMBDA_PROJECTIVE:
-                            {
-                                y = z.Add(x);
-                                break;
-                            }
-                        default:
-                            {
-                                y = z.Multiply(x);
-                                break;
-                            }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-            {
-                return beta;
-            }
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(193, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 193; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 193; }
diff --git a/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs b/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs
index b5345730c..1c84a3eac 100644
--- a/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT193R2Curve.cs
@@ -70,98 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                        case COORD_LAMBDA_AFFINE:
-                        case COORD_LAMBDA_PROJECTIVE:
-                            {
-                                y = z.Add(x);
-                                break;
-                            }
-                        default:
-                            {
-                                y = z.Multiply(x);
-                                break;
-                            }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-            {
-                return beta;
-            }
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(193, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 193; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 193; }
diff --git a/crypto/src/math/ec/custom/sec/SecT233Field.cs b/crypto/src/math/ec/custom/sec/SecT233Field.cs
index b36ffba2e..a2f73fd5d 100644
--- a/crypto/src/math/ec/custom/sec/SecT233Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT233Field.cs
@@ -45,6 +45,39 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat256.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion
+
+            ulong[] t0 = Nat256.Create64();
+            ulong[] t1 = Nat256.Create64();
+
+            Square(x, t0);
+            Multiply(t0, x, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 3, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 7, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 14, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 29, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 58, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 116, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat256.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
index 60b204604..a9041efde 100644
--- a/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT233FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT233FieldElement(
-                AbstractF2mCurve.Inverse(233, new int[] { 74 }, ToBigInteger()));
+            ulong[] z = Nat256.Create64();
+            SecT233Field.Invert(x, z);
+            return new SecT233FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
index 8768eaa81..72935913d 100644
--- a/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT233K1Curve.cs
@@ -76,98 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return true; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-            {
-                return beta;
-            }
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(233, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 233; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 233; }
diff --git a/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
index 92795b8a7..db6e6e1d4 100644
--- a/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT233R1Curve.cs
@@ -70,96 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(233, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 233; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 233; }
diff --git a/crypto/src/math/ec/custom/sec/SecT239Field.cs b/crypto/src/math/ec/custom/sec/SecT239Field.cs
index 6dab907dd..6b8ad696f 100644
--- a/crypto/src/math/ec/custom/sec/SecT239Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT239Field.cs
@@ -45,6 +45,43 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat256.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion
+
+            ulong[] t0 = Nat256.Create64();
+            ulong[] t1 = Nat256.Create64();
+
+            Square(x, t0);
+            Multiply(t0, x, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 3, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 7, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 14, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 29, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 59, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 119, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat256.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
index e7bfffd1f..de074c55f 100644
--- a/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT239FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT239FieldElement(
-                AbstractF2mCurve.Inverse(239, new int[] { 158 }, ToBigInteger()));
+            ulong[] z = Nat256.Create64();
+            SecT239Field.Invert(x, z);
+            return new SecT239FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
index 2c73d941f..a499d48b4 100644
--- a/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT239K1Curve.cs
@@ -76,96 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return true; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(239, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 239; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 239; }
diff --git a/crypto/src/math/ec/custom/sec/SecT283Field.cs b/crypto/src/math/ec/custom/sec/SecT283Field.cs
index 435787467..903ea02ff 100644
--- a/crypto/src/math/ec/custom/sec/SecT283Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT283Field.cs
@@ -48,6 +48,41 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat320.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion
+
+            ulong[] t0 = Nat320.Create64();
+            ulong[] t1 = Nat320.Create64();
+
+            Square(x, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 2, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 4, t0);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 8, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, t1);
+            Multiply(t1, x, t1);
+            SquareN(t1, 17, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 35, t1);
+            Multiply(t1, t0, t1);
+            SquareN(t1, 70, t0);
+            Multiply(t0, t1, t0);
+            Square(t0, t0);
+            Multiply(t0, x, t0);
+            SquareN(t0, 141, t1);
+            Multiply(t1, t0, t1);
+            Square(t1, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat320.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
index 9181b8685..e02108f73 100644
--- a/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT283FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT283FieldElement(
-                AbstractF2mCurve.Inverse(283, new int[] { 5, 7, 12 }, ToBigInteger()));
+            ulong[] z = Nat320.Create64();
+            SecT283Field.Invert(x, z);
+            return new SecT283FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
index 42414401f..4053287ec 100644
--- a/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT283K1Curve.cs
@@ -76,96 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return true; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(283, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 283; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 283; }
diff --git a/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
index d8c462eeb..e659675ce 100644
--- a/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT283R1Curve.cs
@@ -70,96 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(283, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 283; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 283; }
diff --git a/crypto/src/math/ec/custom/sec/SecT409Field.cs b/crypto/src/math/ec/custom/sec/SecT409Field.cs
index ce6f43f2e..84eada96e 100644
--- a/crypto/src/math/ec/custom/sec/SecT409Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT409Field.cs
@@ -47,6 +47,57 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat448.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion with bases { 2, 3 }
+
+            ulong[] t0 = Nat448.Create64();
+            ulong[] t1 = Nat448.Create64();
+            ulong[] t2 = Nat448.Create64();
+
+            Square(x, t0);
+
+            // 3 | 408
+            SquareN(t0, 1, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 1, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 136
+            SquareN(t0, 3, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 68
+            SquareN(t0, 6, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 34
+            SquareN(t0, 12, t1);
+            Multiply(t0, t1, t2);
+
+            // ! {2,3} | 17
+            SquareN(t2, 24, t0);
+            SquareN(t0, 24, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 8
+            SquareN(t0, 48, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 4
+            SquareN(t0, 96, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 2
+            SquareN(t0, 192, t1);
+            Multiply(t0, t1, t0);
+
+            Multiply(t0, t2, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat448.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
index b60ceafee..581ea73df 100644
--- a/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT409FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT409FieldElement(
-                AbstractF2mCurve.Inverse(409, new int[] { 87 }, ToBigInteger()));
+            ulong[] z = Nat448.Create64();
+            SecT409Field.Invert(x, z);
+            return new SecT409FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
index edfe1a293..4f573553e 100644
--- a/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT409K1Curve.cs
@@ -76,96 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return true; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(409, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 409; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 409; }
diff --git a/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
index e679094ad..9212fb5d2 100644
--- a/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT409R1Curve.cs
@@ -70,96 +70,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(409, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 409; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 409; }
diff --git a/crypto/src/math/ec/custom/sec/SecT571Field.cs b/crypto/src/math/ec/custom/sec/SecT571Field.cs
index 921c841a9..fc84e336b 100644
--- a/crypto/src/math/ec/custom/sec/SecT571Field.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571Field.cs
@@ -59,6 +59,57 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             return z;
         }
 
+        public static void Invert(ulong[] x, ulong[] z)
+        {
+            if (Nat576.IsZero64(x))
+                throw new InvalidOperationException();
+
+            // Itoh-Tsujii inversion with bases { 2, 3, 5 }
+
+            ulong[] t0 = Nat576.Create64();
+            ulong[] t1 = Nat576.Create64();
+            ulong[] t2 = Nat576.Create64();
+
+            Square(x, t2);
+
+            // 5 | 570
+            Square(t2, t0);
+            Square(t0, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t0, 2, t1);
+            Multiply(t0, t1, t0);
+            Multiply(t0, t2, t0);
+
+            // 3 | 114
+            SquareN(t0, 5, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 5, t1);
+            Multiply(t0, t1, t0);
+
+            // 2 | 38
+            SquareN(t0, 15, t1);
+            Multiply(t0, t1, t2);
+
+            // ! {2,3,5} | 19
+            SquareN(t2, 30, t0);
+            SquareN(t0, 30, t1);
+            Multiply(t0, t1, t0);
+
+            // 3 | 9
+            SquareN(t0, 60, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 60, t1);
+            Multiply(t0, t1, t0);
+
+            // 3 | 3
+            SquareN(t0, 180, t1);
+            Multiply(t0, t1, t0);
+            SquareN(t1, 180, t1);
+            Multiply(t0, t1, t0);
+
+            Multiply(t0, t2, z);
+        }
+
         public static void Multiply(ulong[] x, ulong[] y, ulong[] z)
         {
             ulong[] tt = Nat576.CreateExt64();
diff --git a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
index a26e1e336..5d5458412 100644
--- a/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571FieldElement.cs
@@ -152,8 +152,9 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
 
         public override ECFieldElement Invert()
         {
-            return new SecT571FieldElement(
-                AbstractF2mCurve.Inverse(571, new int[] { 2, 5, 10 }, ToBigInteger()));
+            ulong[] z = Nat576.Create64();
+            SecT571Field.Invert(x, z);
+            return new SecT571FieldElement(z);
         }
 
         public override ECFieldElement Sqrt()
diff --git a/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
index fb136c967..f5806f09c 100644
--- a/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571K1Curve.cs
@@ -76,98 +76,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return true; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-                y = B.Sqrt();
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-            {
-                return beta;
-            }
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(571, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 571; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 571; }
diff --git a/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
index 05d58863e..082afa5bd 100644
--- a/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
+++ b/crypto/src/math/ec/custom/sec/SecT571R1Curve.cs
@@ -74,97 +74,6 @@ namespace Org.BouncyCastle.Math.EC.Custom.Sec
             get { return false; }
         }
 
-        /**
-         * Decompresses a compressed point P = (xp, yp) (X9.62 s 4.2.2).
-         * 
-         * @param yTilde
-         *            ~yp, an indication bit for the decompression of yp.
-         * @param X1
-         *            The field element xp.
-         * @return the decompressed point.
-         */
-        protected override ECPoint DecompressPoint(int yTilde, BigInteger X1)
-        {
-            ECFieldElement x = FromBigInteger(X1), y = null;
-            if (x.IsZero)
-            {
-    //            y = B.Sqrt();
-                y = SecT571R1_B_SQRT;
-            }
-            else
-            {
-                ECFieldElement beta = x.Square().Invert().Multiply(B).Add(A).Add(x);
-                ECFieldElement z = SolveQuadraticEquation(beta);
-                if (z != null)
-                {
-                    if (z.TestBitZero() != (yTilde == 1))
-                    {
-                        z = z.AddOne();
-                    }
-
-                    switch (this.CoordinateSystem)
-                    {
-                    case COORD_LAMBDA_AFFINE:
-                    case COORD_LAMBDA_PROJECTIVE:
-                    {
-                        y = z.Add(x);
-                        break;
-                    }
-                    default:
-                    {
-                        y = z.Multiply(x);
-                        break;
-                    }
-                    }
-                }
-            }
-
-            if (y == null)
-                throw new ArgumentException("Invalid point compression");
-
-            return this.CreateRawPoint(x, y, true);
-        }
-
-        /**
-         * Solves a quadratic equation <code>z<sup>2</sup> + z = beta</code>(X9.62
-         * D.1.6) The other solution is <code>z + 1</code>.
-         * 
-         * @param beta
-         *            The value to solve the quadratic equation for.
-         * @return the solution for <code>z<sup>2</sup> + z = beta</code> or
-         *         <code>null</code> if no solution exists.
-         */
-        private ECFieldElement SolveQuadraticEquation(ECFieldElement beta)
-        {
-            if (beta.IsZero)
-                return beta;
-
-            ECFieldElement zeroElement = FromBigInteger(BigInteger.Zero);
-
-            ECFieldElement z = null;
-            ECFieldElement gamma = null;
-
-            Random rand = new Random();
-            do
-            {
-                ECFieldElement t = FromBigInteger(new BigInteger(571, rand));
-                z = zeroElement;
-                ECFieldElement w = beta;
-                for (int i = 1; i < 571; i++)
-                {
-                    ECFieldElement w2 = w.Square();
-                    z = z.Square().Add(w2.Multiply(t));
-                    w = w2.Add(beta);
-                }
-                if (!w.IsZero)
-                    return null;
-                gamma = z.Square().Add(z);
-            }
-            while (gamma.IsZero);
-
-            return z;
-        }
-
         public virtual int M
         {
             get { return 571; }
diff --git a/crypto/src/math/raw/Interleave.cs b/crypto/src/math/raw/Interleave.cs
index 9755c9d6f..a45ee1e08 100644
--- a/crypto/src/math/raw/Interleave.cs
+++ b/crypto/src/math/raw/Interleave.cs
@@ -4,67 +4,92 @@ namespace Org.BouncyCastle.Math.Raw
 {
     internal abstract class Interleave
     {
+        private const ulong M32 = 0x55555555UL;
+        private const ulong M64 = 0x5555555555555555UL;
+
         /*
          * This expands 8 bit indices into 16 bit contents (high bit 14), by inserting 0s between bits.
          * In a binary field, this operation is the same as squaring an 8 bit number.
          */
-        private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[]
-        {
-            0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
-            0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
-            0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
-            0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
-            0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
-            0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
-            0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
-            0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
-            0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
-            0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
-            0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
-            0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
-            0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
-            0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
-            0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
-            0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
-            0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
-            0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
-            0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
-            0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
-            0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
-            0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
-            0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
-            0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
-            0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
-            0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
-            0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
-            0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
-            0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
-            0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
-            0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
-            0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
-        };
+        //private static readonly ushort[] INTERLEAVE2_TABLE = new ushort[]
+        //{
+        //    0x0000, 0x0001, 0x0004, 0x0005, 0x0010, 0x0011, 0x0014, 0x0015,
+        //    0x0040, 0x0041, 0x0044, 0x0045, 0x0050, 0x0051, 0x0054, 0x0055,
+        //    0x0100, 0x0101, 0x0104, 0x0105, 0x0110, 0x0111, 0x0114, 0x0115,
+        //    0x0140, 0x0141, 0x0144, 0x0145, 0x0150, 0x0151, 0x0154, 0x0155,
+        //    0x0400, 0x0401, 0x0404, 0x0405, 0x0410, 0x0411, 0x0414, 0x0415,
+        //    0x0440, 0x0441, 0x0444, 0x0445, 0x0450, 0x0451, 0x0454, 0x0455,
+        //    0x0500, 0x0501, 0x0504, 0x0505, 0x0510, 0x0511, 0x0514, 0x0515,
+        //    0x0540, 0x0541, 0x0544, 0x0545, 0x0550, 0x0551, 0x0554, 0x0555,
+        //    0x1000, 0x1001, 0x1004, 0x1005, 0x1010, 0x1011, 0x1014, 0x1015,
+        //    0x1040, 0x1041, 0x1044, 0x1045, 0x1050, 0x1051, 0x1054, 0x1055,
+        //    0x1100, 0x1101, 0x1104, 0x1105, 0x1110, 0x1111, 0x1114, 0x1115,
+        //    0x1140, 0x1141, 0x1144, 0x1145, 0x1150, 0x1151, 0x1154, 0x1155,
+        //    0x1400, 0x1401, 0x1404, 0x1405, 0x1410, 0x1411, 0x1414, 0x1415,
+        //    0x1440, 0x1441, 0x1444, 0x1445, 0x1450, 0x1451, 0x1454, 0x1455,
+        //    0x1500, 0x1501, 0x1504, 0x1505, 0x1510, 0x1511, 0x1514, 0x1515,
+        //    0x1540, 0x1541, 0x1544, 0x1545, 0x1550, 0x1551, 0x1554, 0x1555,
+        //    0x4000, 0x4001, 0x4004, 0x4005, 0x4010, 0x4011, 0x4014, 0x4015,
+        //    0x4040, 0x4041, 0x4044, 0x4045, 0x4050, 0x4051, 0x4054, 0x4055,
+        //    0x4100, 0x4101, 0x4104, 0x4105, 0x4110, 0x4111, 0x4114, 0x4115,
+        //    0x4140, 0x4141, 0x4144, 0x4145, 0x4150, 0x4151, 0x4154, 0x4155,
+        //    0x4400, 0x4401, 0x4404, 0x4405, 0x4410, 0x4411, 0x4414, 0x4415,
+        //    0x4440, 0x4441, 0x4444, 0x4445, 0x4450, 0x4451, 0x4454, 0x4455,
+        //    0x4500, 0x4501, 0x4504, 0x4505, 0x4510, 0x4511, 0x4514, 0x4515,
+        //    0x4540, 0x4541, 0x4544, 0x4545, 0x4550, 0x4551, 0x4554, 0x4555,
+        //    0x5000, 0x5001, 0x5004, 0x5005, 0x5010, 0x5011, 0x5014, 0x5015,
+        //    0x5040, 0x5041, 0x5044, 0x5045, 0x5050, 0x5051, 0x5054, 0x5055,
+        //    0x5100, 0x5101, 0x5104, 0x5105, 0x5110, 0x5111, 0x5114, 0x5115,
+        //    0x5140, 0x5141, 0x5144, 0x5145, 0x5150, 0x5151, 0x5154, 0x5155,
+        //    0x5400, 0x5401, 0x5404, 0x5405, 0x5410, 0x5411, 0x5414, 0x5415,
+        //    0x5440, 0x5441, 0x5444, 0x5445, 0x5450, 0x5451, 0x5454, 0x5455,
+        //    0x5500, 0x5501, 0x5504, 0x5505, 0x5510, 0x5511, 0x5514, 0x5515,
+        //    0x5540, 0x5541, 0x5544, 0x5545, 0x5550, 0x5551, 0x5554, 0x5555
+        //};
 
         internal static uint Expand8to16(uint x)
         {
-            return INTERLEAVE2_TABLE[x & 0xFF];
+            x &= 0xFFU;
+            x = (x | (x << 4)) & 0x0F0FU;
+            x = (x | (x << 2)) & 0x3333U;
+            x = (x | (x << 1)) & 0x5555U;
+            return x;
         }
 
         internal static uint Expand16to32(uint x)
         {
-            return (uint)(INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >> 8) & 0xFF] << 16);
+            x &= 0xFFFFU;
+            x = (x | (x << 8)) & 0x00FF00FFU;
+            x = (x | (x << 4)) & 0x0F0F0F0FU;
+            x = (x | (x << 2)) & 0x33333333U;
+            x = (x | (x << 1)) & 0x55555555U;
+            return x;
         }
 
         internal static ulong Expand32to64(uint x)
         {
-            uint r00 = (uint)(INTERLEAVE2_TABLE[x & 0xFF] | INTERLEAVE2_TABLE[(x >> 8) & 0xFF] << 16);
-            uint r32 = (uint)(INTERLEAVE2_TABLE[(x >> 16) & 0xFF] | INTERLEAVE2_TABLE[x >> 24] << 16);
-            return (ulong)r32 << 32 | (ulong)r00;
+            // "shuffle" low half to even bits and high half to odd bits
+            uint t;
+            t = (x ^ (x >>  8)) & 0x0000FF00U; x ^= (t ^ (t <<  8));
+            t = (x ^ (x >>  4)) & 0x00F000F0U; x ^= (t ^ (t <<  4));
+            t = (x ^ (x >>  2)) & 0x0C0C0C0CU; x ^= (t ^ (t <<  2));
+            t = (x ^ (x >>  1)) & 0x22222222U; x ^= (t ^ (t <<  1));
+
+            return ((x >> 1) & M32) << 32 | (x & M32);
         }
 
         internal static void Expand64To128(ulong x, ulong[] z, int zOff)
         {
-            z[zOff    ] = Expand32to64((uint)x);
-            z[zOff + 1] = Expand32to64((uint)(x >> 32));
+            // "shuffle" low half to even bits and high half to odd bits
+            ulong t;
+            t = (x ^ (x >> 16)) & 0x00000000FFFF0000UL; x ^= (t ^ (t << 16));
+            t = (x ^ (x >>  8)) & 0x0000FF000000FF00UL; x ^= (t ^ (t <<  8));
+            t = (x ^ (x >>  4)) & 0x00F000F000F000F0UL; x ^= (t ^ (t <<  4));
+            t = (x ^ (x >>  2)) & 0x0C0C0C0C0C0C0C0CUL; x ^= (t ^ (t <<  2));
+            t = (x ^ (x >>  1)) & 0x2222222222222222UL; x ^= (t ^ (t <<  1));
+
+            z[zOff    ] = (x     ) & M64;
+            z[zOff + 1] = (x >> 1) & M64;
         }
     }
 }
diff --git a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
index f46f99d37..2a2e63961 100644
--- a/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
+++ b/crypto/src/openpgp/PgpEncryptedDataGenerator.cs
@@ -3,10 +3,13 @@ using System.Collections;
 using System.Diagnostics;
 using System.IO;
 
+using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
@@ -79,70 +82,133 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             : EncMethod
         {
 			internal PgpPublicKey pubKey;
-            internal BigInteger[] data;
+            internal byte[][] data;
 
-			internal PubMethod(
-                PgpPublicKey pubKey)
+            internal PubMethod(PgpPublicKey pubKey)
             {
                 this.pubKey = pubKey;
             }
 
-			public override void AddSessionInfo(
-                byte[]			si,
+            public override void AddSessionInfo(
+                byte[]			sessionInfo,
 				SecureRandom	random)
             {
-                IBufferedCipher c;
+                byte[] encryptedSessionInfo = EncryptSessionInfo(sessionInfo, random);
+
+                this.data = ProcessSessionInfo(encryptedSessionInfo);
+            }
 
-				switch (pubKey.Algorithm)
+            private byte[] EncryptSessionInfo(byte[] sessionInfo, SecureRandom random)
+            {
+                if (pubKey.Algorithm != PublicKeyAlgorithmTag.ECDH)
                 {
-                    case PublicKeyAlgorithmTag.RsaEncrypt:
-                    case PublicKeyAlgorithmTag.RsaGeneral:
-                        c = CipherUtilities.GetCipher("RSA//PKCS1Padding");
-                        break;
-                    case PublicKeyAlgorithmTag.ElGamalEncrypt:
-                    case PublicKeyAlgorithmTag.ElGamalGeneral:
-                        c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
-                        break;
-                    case PublicKeyAlgorithmTag.Dsa:
-                        throw new PgpException("Can't use DSA for encryption.");
-                    case PublicKeyAlgorithmTag.ECDsa:
-                        throw new PgpException("Can't use ECDSA for encryption.");
-                    default:
-                        throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
+                    IBufferedCipher c;
+				    switch (pubKey.Algorithm)
+                    {
+                        case PublicKeyAlgorithmTag.RsaEncrypt:
+                        case PublicKeyAlgorithmTag.RsaGeneral:
+                            c = CipherUtilities.GetCipher("RSA//PKCS1Padding");
+                            break;
+                        case PublicKeyAlgorithmTag.ElGamalEncrypt:
+                        case PublicKeyAlgorithmTag.ElGamalGeneral:
+                            c = CipherUtilities.GetCipher("ElGamal/ECB/PKCS1Padding");
+                            break;
+                        case PublicKeyAlgorithmTag.Dsa:
+                            throw new PgpException("Can't use DSA for encryption.");
+                        case PublicKeyAlgorithmTag.ECDsa:
+                            throw new PgpException("Can't use ECDSA for encryption.");
+                        default:
+                            throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
+                    }
+
+                    AsymmetricKeyParameter akp = pubKey.GetKey();
+				    c.Init(true, new ParametersWithRandom(akp, random));
+                    return c.DoFinal(sessionInfo);
                 }
 
-				AsymmetricKeyParameter akp = pubKey.GetKey();
+                ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKey.PublicKeyPacket.Key;
+
+                // Generate the ephemeral key pair
+                IAsymmetricCipherKeyPairGenerator gen = GeneratorUtilities.GetKeyPairGenerator("ECDH");
+                gen.Init(new ECKeyGenerationParameters(ecKey.CurveOid, random));
+
+                AsymmetricCipherKeyPair ephKp = gen.GenerateKeyPair();
+                ECPrivateKeyParameters ephPriv = (ECPrivateKeyParameters)ephKp.Private;
+                ECPublicKeyParameters ephPub = (ECPublicKeyParameters)ephKp.Public;
+
+                ECPublicKeyParameters pub = (ECPublicKeyParameters)pubKey.GetKey();
+                ECPoint S = pub.Q.Multiply(ephPriv.D).Normalize();
+
+                KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(pubKey.PublicKeyPacket, S));
+
+                IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm);
+                w.Init(true, new ParametersWithRandom(key, random));
+
+                byte[] paddedSessionData = PgpPad.PadSessionData(sessionInfo);
+
+                byte[] C = w.Wrap(paddedSessionData, 0, paddedSessionData.Length);
+                byte[] VB = new MPInteger(new BigInteger(1, ephPub.Q.GetEncoded(false))).GetEncoded();
 
-				c.Init(true, new ParametersWithRandom(akp, random));
+                byte[] rv = new byte[VB.Length + 1 + C.Length];
 
-				byte[] encKey = c.DoFinal(si);
+                Array.Copy(VB, 0, rv, 0, VB.Length);
+                rv[VB.Length] = (byte)C.Length;
+                Array.Copy(C, 0, rv, VB.Length + 1, C.Length);
 
-				switch (pubKey.Algorithm)
+                return rv;
+            }
+
+            private byte[][] ProcessSessionInfo(byte[] encryptedSessionInfo)
+            {
+                byte[][] data;
+
+                switch (pubKey.Algorithm)
                 {
-                    case PublicKeyAlgorithmTag.RsaEncrypt:
-                    case PublicKeyAlgorithmTag.RsaGeneral:
-						data = new BigInteger[]{ new BigInteger(1, encKey) };
-                        break;
-                    case PublicKeyAlgorithmTag.ElGamalEncrypt:
-                    case PublicKeyAlgorithmTag.ElGamalGeneral:
-						int halfLength = encKey.Length / 2;
-						data = new BigInteger[]
-						{
-							new BigInteger(1, encKey, 0, halfLength),
-							new BigInteger(1, encKey, halfLength, halfLength)
-						};
-                        break;
-                    default:
-                        throw new PgpException("unknown asymmetric algorithm: " + encAlgorithm);
+                case PublicKeyAlgorithmTag.RsaEncrypt:
+                case PublicKeyAlgorithmTag.RsaGeneral:
+                    data = new byte[][] { ConvertToEncodedMpi(encryptedSessionInfo) };
+                    break;
+                case PublicKeyAlgorithmTag.ElGamalEncrypt:
+                case PublicKeyAlgorithmTag.ElGamalGeneral:
+                    int halfLength = encryptedSessionInfo.Length / 2;
+                    byte[] b1 = new byte[halfLength];
+                    byte[] b2 = new byte[halfLength];
+
+                    Array.Copy(encryptedSessionInfo, 0, b1, 0, halfLength);
+                    Array.Copy(encryptedSessionInfo, halfLength, b2, 0, halfLength);
+
+                    data = new byte[][] {
+                        ConvertToEncodedMpi(b1),
+                        ConvertToEncodedMpi(b2),
+                    };
+                    break;
+                case PublicKeyAlgorithmTag.ECDH:
+                    data = new byte[][]{ encryptedSessionInfo };
+                    break;
+                default:
+                    throw new PgpException("unknown asymmetric algorithm: " + pubKey.Algorithm);
                 }
+
+                return data;
             }
 
-			public override void Encode(BcpgOutputStream pOut)
+            private byte[] ConvertToEncodedMpi(byte[] encryptedSessionInfo)
+            {
+                try
+                {
+                    return new MPInteger(new BigInteger(1, encryptedSessionInfo)).GetEncoded();
+                }
+                catch (IOException e)
+                {
+                    throw new PgpException("Invalid MPI encoding: " + e.Message, e);
+                }
+            }
+
+            public override void Encode(BcpgOutputStream pOut)
             {
-                PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket(
-                    pubKey.KeyId, pubKey.Algorithm, data);
+                PublicKeyEncSessionPacket pk = new PublicKeyEncSessionPacket(pubKey.KeyId, pubKey.Algorithm, data);
 
-				pOut.WritePacket(pk);
+                pOut.WritePacket(pk);
             }
         }
 
diff --git a/crypto/src/openpgp/PgpKeyPair.cs b/crypto/src/openpgp/PgpKeyPair.cs
index 6efb03a42..9cf78fa6f 100644
--- a/crypto/src/openpgp/PgpKeyPair.cs
+++ b/crypto/src/openpgp/PgpKeyPair.cs
@@ -34,7 +34,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             DateTime				time)
         {
             this.pub = new PgpPublicKey(algorithm, pubKey, time);
-			this.priv = new PgpPrivateKey(privKey, pub.KeyId);
+			this.priv = new PgpPrivateKey(pub.KeyId, pub.PublicKeyPacket, privKey);
         }
 
 		/// <summary>Create a key pair from a PgpPrivateKey and a PgpPublicKey.</summary>
diff --git a/crypto/src/openpgp/PgpPad.cs b/crypto/src/openpgp/PgpPad.cs
new file mode 100644
index 000000000..48f7f2f44
--- /dev/null
+++ b/crypto/src/openpgp/PgpPad.cs
@@ -0,0 +1,45 @@
+using System;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+    /// <remarks>Padding functions.</remarks>
+    public sealed class PgpPad
+    {
+        private PgpPad()
+        {
+        }
+
+        public static byte[] PadSessionData(byte[] sessionInfo)
+        {
+            byte[] result = new byte[40];
+
+            Array.Copy(sessionInfo, 0, result, 0, sessionInfo.Length);
+
+            byte padValue = (byte)(result.Length - sessionInfo.Length);
+
+            for (int i = sessionInfo.Length; i != result.Length; i++)
+            {
+                result[i] = padValue;
+            }
+
+            return result;
+        }
+
+        public static byte[] UnpadSessionData(byte[] encoded)
+        {
+            byte padValue = encoded[encoded.Length - 1];
+
+            for (int i = encoded.Length - padValue; i != encoded.Length; i++)
+            {
+                if (encoded[i] != padValue)
+                    throw new PgpException("bad padding found in session data");
+            }
+
+            byte[] taggedKey = new byte[encoded.Length - padValue];
+
+            Array.Copy(encoded, 0, taggedKey, 0, taggedKey.Length);
+
+            return taggedKey;
+        }
+    }
+}
diff --git a/crypto/src/openpgp/PgpPrivateKey.cs b/crypto/src/openpgp/PgpPrivateKey.cs
index 154c87cd7..61487a5b2 100644
--- a/crypto/src/openpgp/PgpPrivateKey.cs
+++ b/crypto/src/openpgp/PgpPrivateKey.cs
@@ -7,33 +7,42 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 	/// <remarks>General class to contain a private key for use with other OpenPGP objects.</remarks>
     public class PgpPrivateKey
     {
-        private readonly long keyId;
+        private readonly long keyID;
+        private readonly PublicKeyPacket publicKeyPacket;
         private readonly AsymmetricKeyParameter privateKey;
 
-		/// <summary>
-		/// Create a PgpPrivateKey from a regular private key and the ID of its
-		/// associated public key.
+        /// <summary>
+		/// Create a PgpPrivateKey from a keyID, the associated public data packet, and a regular private key.
 		/// </summary>
-		/// <param name="privateKey">Private key to use.</param>
-		/// <param name="keyId">ID of the corresponding public key.</param>
-		public PgpPrivateKey(
-            AsymmetricKeyParameter	privateKey,
-            long					keyId)
+		/// <param name="keyID">ID of the corresponding public key.</param>
+        /// <param name="publicKeyPacket">the public key data packet to be associated with this private key.</param>
+        /// <param name="privateKey">the private key data packet to be associated with this private key.</param>
+        public PgpPrivateKey(
+            long                    keyID,
+            PublicKeyPacket         publicKeyPacket,
+            AsymmetricKeyParameter	privateKey)
         {
 			if (!privateKey.IsPrivate)
 				throw new ArgumentException("Expected a private key", "privateKey");
 
-			this.privateKey = privateKey;
-            this.keyId = keyId;
+            this.keyID = keyID;
+            this.publicKeyPacket = publicKeyPacket;
+            this.privateKey = privateKey;
         }
 
-		/// <summary>The keyId associated with the contained private key.</summary>
+        /// <summary>The keyId associated with the contained private key.</summary>
         public long KeyId
         {
-			get { return keyId; }
+			get { return keyID; }
         }
 
-		/// <summary>The contained private key.</summary>
+        /// <summary>The public key packet associated with this private key, if available.</summary>
+        public PublicKeyPacket PublicKeyPacket
+        {
+            get { return publicKeyPacket; }
+        }
+
+        /// <summary>The contained private key.</summary>
         public AsymmetricKeyParameter Key
         {
 			get { return privateKey; }
diff --git a/crypto/src/openpgp/PgpPublicKey.cs b/crypto/src/openpgp/PgpPublicKey.cs
index 5bde2c8fe..904e29913 100644
--- a/crypto/src/openpgp/PgpPublicKey.cs
+++ b/crypto/src/openpgp/PgpPublicKey.cs
@@ -2,10 +2,14 @@ using System;
 using System.Collections;
 using System.IO;
 
+using Org.BouncyCastle.Asn1.Sec;
 using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.IO;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
@@ -15,6 +19,54 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
     /// <remarks>General class to handle a PGP public key object.</remarks>
     public class PgpPublicKey
     {
+        public static byte[] CalculateFingerprint(PublicKeyPacket publicPk)
+        {
+            IBcpgKey key = publicPk.Key;
+            IDigest digest;
+
+            if (publicPk.Version <= 3)
+            {
+                RsaPublicBcpgKey rK = (RsaPublicBcpgKey)key;
+
+                try
+                {
+                    digest = DigestUtilities.GetDigest("MD5");
+                    UpdateDigest(digest, rK.Modulus);
+                    UpdateDigest(digest, rK.PublicExponent);
+                }
+                catch (Exception e)
+                {
+                    throw new PgpException("can't encode key components: " + e.Message, e);
+                }
+            }
+            else
+            {
+                try
+                {
+                    byte[] kBytes = publicPk.GetEncodedContents();
+
+                    digest = DigestUtilities.GetDigest("SHA1");
+
+                    digest.Update(0x99);
+                    digest.Update((byte)(kBytes.Length >> 8));
+                    digest.Update((byte)kBytes.Length);
+                    digest.BlockUpdate(kBytes, 0, kBytes.Length);
+                }
+                catch (Exception e)
+                {
+                    throw new PgpException("can't encode key components: " + e.Message, e);
+                }
+            }
+
+            return DigestUtilities.DoFinal(digest);
+        }
+
+        private static void UpdateDigest(IDigest d, BigInteger b)
+        {
+            byte[] bytes = b.ToByteArrayUnsigned();
+            d.BlockUpdate(bytes, 0, bytes.Length);
+        }
+
         private static readonly int[] MasterKeyCertificationTypes = new int[]
         {
             PgpSignature.PositiveCertification,
@@ -39,51 +91,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         {
             IBcpgKey key = publicPk.Key;
 
+            this.fingerprint = CalculateFingerprint(publicPk);
+
             if (publicPk.Version <= 3)
             {
                 RsaPublicBcpgKey rK = (RsaPublicBcpgKey) key;
 
                 this.keyId = rK.Modulus.LongValue;
-
-                try
-                {
-                    IDigest digest = DigestUtilities.GetDigest("MD5");
-
-                    byte[] bytes = rK.Modulus.ToByteArrayUnsigned();
-                    digest.BlockUpdate(bytes, 0, bytes.Length);
-
-                    bytes = rK.PublicExponent.ToByteArrayUnsigned();
-                    digest.BlockUpdate(bytes, 0, bytes.Length);
-
-                    this.fingerprint = DigestUtilities.DoFinal(digest);
-                }
-                //catch (NoSuchAlgorithmException)
-                catch (Exception e)
-                {
-                    throw new IOException("can't find MD5", e);
-                }
-
                 this.keyStrength = rK.Modulus.BitLength;
             }
             else
             {
-                byte[] kBytes = publicPk.GetEncodedContents();
-
-                try
-                {
-                    IDigest digest = DigestUtilities.GetDigest("SHA1");
-
-                    digest.Update(0x99);
-                    digest.Update((byte)(kBytes.Length >> 8));
-                    digest.Update((byte)kBytes.Length);
-                    digest.BlockUpdate(kBytes, 0, kBytes.Length);
-                    this.fingerprint = DigestUtilities.DoFinal(digest);
-                }
-                catch (Exception e)
-                {
-                    throw new IOException("can't find SHA1", e);
-                }
-
                 this.keyId = (long)(((ulong)fingerprint[fingerprint.Length - 8] << 56)
                     | ((ulong)fingerprint[fingerprint.Length - 7] << 48)
                     | ((ulong)fingerprint[fingerprint.Length - 6] << 40)
@@ -107,7 +125,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 }
                 else if (key is ECPublicBcpgKey)
                 {
-                    this.keyStrength = ECNamedCurveTable.GetByOid(((ECPublicBcpgKey)key).CurveOid).Curve.FieldSize;
+                    this.keyStrength = ECKeyPairGenerator.FindECCurveByOid(((ECPublicBcpgKey)key).CurveOid).Curve.FieldSize;
                 }
             }
         }
@@ -146,6 +164,23 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
                 bcpgKey = new DsaPublicBcpgKey(dP.P, dP.Q, dP.G, dK.Y);
             }
+            else if (pubKey is ECPublicKeyParameters)
+            {
+                ECPublicKeyParameters ecK = (ECPublicKeyParameters)pubKey;
+
+                if (algorithm == PublicKeyAlgorithmTag.ECDH)
+                {
+                    bcpgKey = new ECDHPublicBcpgKey(ecK.PublicKeyParamSet, ecK.Q, HashAlgorithmTag.Sha256, SymmetricKeyAlgorithmTag.Aes128);
+                }
+                else if (algorithm == PublicKeyAlgorithmTag.ECDsa)
+                {
+                    bcpgKey = new ECDsaPublicBcpgKey(ecK.PublicKeyParamSet, ecK.Q);
+                }
+                else
+                {
+                    throw new PgpException("unknown EC algorithm");
+                }
+            }
             else if (pubKey is ElGamalPublicKeyParameters)
             {
                 ElGamalPublicKeyParameters eK = (ElGamalPublicKeyParameters) pubKey;
@@ -172,6 +207,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
         }
 
+        public PgpPublicKey(PublicKeyPacket publicPk)
+            : this(publicPk, Platform.CreateArrayList(), Platform.CreateArrayList())
+        {
+        }
+
         /// <summary>Constructor for a sub-key.</summary>
         internal PgpPublicKey(
             PublicKeyPacket	publicPk,
@@ -426,14 +466,18 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                     case PublicKeyAlgorithmTag.RsaEncrypt:
                     case PublicKeyAlgorithmTag.RsaGeneral:
                     case PublicKeyAlgorithmTag.RsaSign:
-                        RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey) publicPk.Key;
+                        RsaPublicBcpgKey rsaK = (RsaPublicBcpgKey)publicPk.Key;
                         return new RsaKeyParameters(false, rsaK.Modulus, rsaK.PublicExponent);
                     case PublicKeyAlgorithmTag.Dsa:
-                        DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey) publicPk.Key;
+                        DsaPublicBcpgKey dsaK = (DsaPublicBcpgKey)publicPk.Key;
                         return new DsaPublicKeyParameters(dsaK.Y, new DsaParameters(dsaK.P, dsaK.Q, dsaK.G));
+                    case PublicKeyAlgorithmTag.ECDsa:
+                        return GetECKey("ECDSA");
+                    case PublicKeyAlgorithmTag.ECDH:
+                        return GetECKey("ECDH");
                     case PublicKeyAlgorithmTag.ElGamalEncrypt:
                     case PublicKeyAlgorithmTag.ElGamalGeneral:
-                        ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey) publicPk.Key;
+                        ElGamalPublicBcpgKey elK = (ElGamalPublicBcpgKey)publicPk.Key;
                         return new ElGamalPublicKeyParameters(elK.Y, new ElGamalParameters(elK.P, elK.G));
                     default:
                         throw new PgpException("unknown public key algorithm encountered");
@@ -449,6 +493,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
         }
 
+        private ECPublicKeyParameters GetECKey(string algorithm)
+        {
+            ECPublicBcpgKey ecK = (ECPublicBcpgKey)publicPk.Key;
+            X9ECParameters x9 = ECKeyPairGenerator.FindECCurveByOid(ecK.CurveOid);
+            ECPoint q = x9.Curve.DecodePoint(BigIntegers.AsUnsignedByteArray(ecK.EncodedPoint));
+            return new ECPublicKeyParameters(algorithm, q, ecK.CurveOid);
+        }
+
         /// <summary>Allows enumeration of any user IDs associated with the key.</summary>
         /// <returns>An <c>IEnumerable</c> of <c>string</c> objects.</returns>
         public IEnumerable GetUserIds()
diff --git a/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs b/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs
index b6504cbcd..c2a351182 100644
--- a/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs
+++ b/crypto/src/openpgp/PgpPublicKeyEncryptedData.cs
@@ -1,10 +1,13 @@
 using System;
 using System.IO;
 
+using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.IO;
+using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
+using Org.BouncyCastle.Math.EC;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities.IO;
 
@@ -77,22 +80,29 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 		public SymmetricKeyAlgorithmTag GetSymmetricAlgorithm(
 			PgpPrivateKey privKey)
 		{
-			byte[] plain = fetchSymmetricKeyData(privKey);
+			byte[] sessionData = RecoverSessionData(privKey);
 
-			return (SymmetricKeyAlgorithmTag) plain[0];
+            return (SymmetricKeyAlgorithmTag)sessionData[0];
 		}
 
-		/// <summary>Return the decrypted data stream for the packet.</summary>
+        /// <summary>Return the decrypted data stream for the packet.</summary>
         public Stream GetDataStream(
             PgpPrivateKey privKey)
         {
-			byte[] plain = fetchSymmetricKeyData(privKey);
+			byte[] sessionData = RecoverSessionData(privKey);
 
-			IBufferedCipher c2;
-			string cipherName = PgpUtilities.GetSymmetricCipherName((SymmetricKeyAlgorithmTag) plain[0]);
+            if (!ConfirmCheckSum(sessionData))
+                throw new PgpKeyValidationException("key checksum failed");
+
+            SymmetricKeyAlgorithmTag symmAlg = (SymmetricKeyAlgorithmTag)sessionData[0];
+            if (symmAlg == SymmetricKeyAlgorithmTag.Null)
+                return encData.GetInputStream();
+
+            IBufferedCipher cipher;
+			string cipherName = PgpUtilities.GetSymmetricCipherName(symmAlg);
 			string cName = cipherName;
 
-			try
+            try
             {
                 if (encData is SymmetricEncIntegrityPacket)
                 {
@@ -103,7 +113,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 					cName += "/OpenPGPCFB/NoPadding";
                 }
 
-				c2 = CipherUtilities.GetCipher(cName);
+                cipher = CipherUtilities.GetCipher(cName);
 			}
             catch (PgpException e)
             {
@@ -114,19 +124,16 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                 throw new PgpException("exception creating cipher", e);
             }
 
-			if (c2 == null)
-				return encData.GetInputStream();
-
-			try
+            try
             {
 				KeyParameter key = ParameterUtilities.CreateKeyParameter(
-					cipherName, plain, 1, plain.Length - 3);
+					cipherName, sessionData, 1, sessionData.Length - 3);
 
-				byte[] iv = new byte[c2.GetBlockSize()];
+                byte[] iv = new byte[cipher.GetBlockSize()];
 
-				c2.Init(false, new ParametersWithIV(key, iv));
+                cipher.Init(false, new ParametersWithIV(key, iv));
 
-                encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), c2, null));
+                encStream = BcpgInputStream.Wrap(new CipherStream(encData.GetInputStream(), cipher, null));
 
 				if (encData is SymmetricEncIntegrityPacket)
                 {
@@ -178,75 +185,88 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
 		}
 
-		private byte[] fetchSymmetricKeyData(
-			PgpPrivateKey privKey)
+        private byte[] RecoverSessionData(PgpPrivateKey privKey)
 		{
-			IBufferedCipher c1 = GetKeyCipher(keyData.Algorithm);
+            byte[][] secKeyData = keyData.GetEncSessionKey();
+
+            if (keyData.Algorithm == PublicKeyAlgorithmTag.ECDH)
+            {
+                ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)privKey.PublicKeyPacket.Key;
+                X9ECParameters x9Params = ECKeyPairGenerator.FindECCurveByOid(ecKey.CurveOid);
+
+                byte[] enc = secKeyData[0];
+
+                int pLen = ((((enc[0] & 0xff) << 8) + (enc[1] & 0xff)) + 7) / 8;
+                byte[] pEnc = new byte[pLen];
+
+                Array.Copy(enc, 2, pEnc, 0, pLen);
+
+                byte[] keyEnc = new byte[enc[pLen + 2]];
+
+                Array.Copy(enc, 2 + pLen + 1, keyEnc, 0, keyEnc.Length);
+
+                ECPoint publicPoint = x9Params.Curve.DecodePoint(pEnc);
+
+                ECPrivateKeyParameters privKeyParams = (ECPrivateKeyParameters)privKey.Key;
+                ECPoint S = publicPoint.Multiply(privKeyParams.D).Normalize();
+
+                KeyParameter key = new KeyParameter(Rfc6637Utilities.CreateKey(privKey.PublicKeyPacket, S));
+
+                IWrapper w = PgpUtilities.CreateWrapper(ecKey.SymmetricKeyAlgorithm);
+                w.Init(false, key);
 
-			try
+                return PgpPad.UnpadSessionData(w.Unwrap(keyEnc, 0, keyEnc.Length));
+            }
+
+            IBufferedCipher cipher = GetKeyCipher(keyData.Algorithm);
+
+            try
 			{
-				c1.Init(false, privKey.Key);
+                cipher.Init(false, privKey.Key);
 			}
 			catch (InvalidKeyException e)
 			{
 				throw new PgpException("error setting asymmetric cipher", e);
 			}
 
-			BigInteger[] keyD = keyData.GetEncSessionKey();
-
-			if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt
+            if (keyData.Algorithm == PublicKeyAlgorithmTag.RsaEncrypt
 				|| keyData.Algorithm == PublicKeyAlgorithmTag.RsaGeneral)
 			{
-				c1.ProcessBytes(keyD[0].ToByteArrayUnsigned());
+                byte[] bi = secKeyData[0];
+
+                cipher.ProcessBytes(bi, 2, bi.Length - 2);
 			}
 			else
 			{
 				ElGamalPrivateKeyParameters k = (ElGamalPrivateKeyParameters)privKey.Key;
 				int size = (k.Parameters.P.BitLength + 7) / 8;
 
-				byte[] bi = keyD[0].ToByteArray();
-
-				int diff = bi.Length - size;
-				if (diff >= 0)
-				{
-					c1.ProcessBytes(bi, diff, size);
-				}
-				else
-				{
-					byte[] zeros = new byte[-diff];
-					c1.ProcessBytes(zeros);
-					c1.ProcessBytes(bi);
-				}
-
-				bi = keyD[1].ToByteArray();
-
-				diff = bi.Length - size;
-				if (diff >= 0)
-				{
-					c1.ProcessBytes(bi, diff, size);
-				}
-				else
-				{
-					byte[] zeros = new byte[-diff];
-					c1.ProcessBytes(zeros);
-					c1.ProcessBytes(bi);
-				}
+                ProcessEncodedMpi(cipher, size, secKeyData[0]);
+                ProcessEncodedMpi(cipher, size, secKeyData[1]);
 			}
 
-			byte[] plain;
-			try
+            try
 			{
-				plain = c1.DoFinal();
+                return cipher.DoFinal();
 			}
 			catch (Exception e)
 			{
 				throw new PgpException("exception decrypting secret key", e);
 			}
-
-			if (!ConfirmCheckSum(plain))
-				throw new PgpKeyValidationException("key checksum failed");
-
-			return plain;
 		}
+
+        private static void ProcessEncodedMpi(IBufferedCipher cipher, int size, byte[] mpiEnc)
+        {
+            if (mpiEnc.Length - 2 > size)  // leading Zero? Shouldn't happen but...
+            {
+                cipher.ProcessBytes(mpiEnc, 3, mpiEnc.Length - 3);
+            }
+            else
+            {
+                byte[] tmp = new byte[size];
+                Array.Copy(mpiEnc, 2, tmp, tmp.Length - (mpiEnc.Length - 2), mpiEnc.Length - 2);
+                cipher.ProcessBytes(tmp, 0, tmp.Length);
+            }
+        }
 	}
 }
diff --git a/crypto/src/openpgp/PgpSecretKey.cs b/crypto/src/openpgp/PgpSecretKey.cs
index 872316dd7..980f9222b 100644
--- a/crypto/src/openpgp/PgpSecretKey.cs
+++ b/crypto/src/openpgp/PgpSecretKey.cs
@@ -2,8 +2,11 @@ using System;
 using System.Collections;
 using System.IO;
 
+using Org.BouncyCastle.Asn1.X9;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Generators;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 
@@ -59,6 +62,11 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                     DsaPrivateKeyParameters dsK = (DsaPrivateKeyParameters) privKey.Key;
                     secKey = new DsaSecretBcpgKey(dsK.X);
                     break;
+                case PublicKeyAlgorithmTag.ECDH:
+                case PublicKeyAlgorithmTag.ECDsa:
+                    ECPrivateKeyParameters ecK = (ECPrivateKeyParameters)privKey.Key;
+                    secKey = new ECSecretBcpgKey(ecK.D);
+                    break;
                 case PublicKeyAlgorithmTag.ElGamalEncrypt:
                 case PublicKeyAlgorithmTag.ElGamalGeneral:
                     ElGamalPrivateKeyParameters esK = (ElGamalPrivateKeyParameters) privKey.Key;
@@ -309,24 +317,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
         private byte[] ExtractKeyData(
             char[] passPhrase)
         {
-            SymmetricKeyAlgorithmTag alg = secret.EncAlgorithm;
+            SymmetricKeyAlgorithmTag encAlgorithm = secret.EncAlgorithm;
             byte[] encData = secret.GetSecretKeyData();
 
-            if (alg == SymmetricKeyAlgorithmTag.Null)
+            if (encAlgorithm == SymmetricKeyAlgorithmTag.Null)
                 // TODO Check checksum here?
                 return encData;
 
-            IBufferedCipher c = null;
-            try
-            {
-                string cName = PgpUtilities.GetSymmetricCipherName(alg);
-                c = CipherUtilities.GetCipher(cName + "/CFB/NoPadding");
-            }
-            catch (Exception e)
-            {
-                throw new PgpException("Exception creating cipher", e);
-            }
-
             // TODO Factor this block out as 'decryptData'
             try
             {
@@ -336,9 +333,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
                 if (secret.PublicKeyPacket.Version >= 4)
                 {
-                    c.Init(false, new ParametersWithIV(key, iv));
-
-                    data = c.DoFinal(encData);
+                    data = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iv, encData, 0, encData.Length);
 
                     bool useSha1 = secret.S2kUsage == SecretKeyPacket.UsageSha1;
                     byte[] check = Checksum(useSha1, data, (useSha1) ? data.Length - 20 : data.Length - 2);
@@ -364,15 +359,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
                     for (int i = 0; i != 4; i++)
                     {
-                        c.Init(false, new ParametersWithIV(key, iv));
-
                         int encLen = (((encData[pos] << 8) | (encData[pos + 1] & 0xff)) + 7) / 8;
 
                         data[pos] = encData[pos];
                         data[pos + 1] = encData[pos + 1];
                         pos += 2;
 
-                        c.DoFinal(encData, pos, encLen, data, pos);
+                        byte[] tmp = RecoverKeyData(encAlgorithm, "/CFB/NoPadding", key, iv, encData, pos, encLen);
+                        Array.Copy(tmp, 0, data, pos, encLen);
                         pos += encLen;
 
                         if (i != 3)
@@ -416,6 +410,25 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
         }
 
+        private static byte[] RecoverKeyData(SymmetricKeyAlgorithmTag encAlgorithm, string modeAndPadding,
+            KeyParameter key, byte[] iv, byte[] keyData, int keyOff, int keyLen)
+        {
+            IBufferedCipher c;
+            try
+            {
+                string cName = PgpUtilities.GetSymmetricCipherName(encAlgorithm);
+                c = CipherUtilities.GetCipher(cName + modeAndPadding);
+            }
+            catch (Exception e)
+            {
+                throw new PgpException("Exception creating cipher", e);
+            }
+
+            c.Init(false, new ParametersWithIV(key, iv));
+
+            return c.DoFinal(keyData, keyOff, keyLen);
+        }
+
         /// <summary>Extract a <c>PgpPrivateKey</c> from this secret key's encrypted contents.</summary>
         public PgpPrivateKey ExtractPrivateKey(
             char[] passPhrase)
@@ -453,6 +466,12 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                     DsaParameters dsaParams = new DsaParameters(dsaPub.P, dsaPub.Q, dsaPub.G);
                     privateKey = new DsaPrivateKeyParameters(dsaPriv.X, dsaParams);
                     break;
+                case PublicKeyAlgorithmTag.ECDH:
+                    privateKey = GetECKey("ECDH", bcpgIn);
+                    break;
+                case PublicKeyAlgorithmTag.ECDsa:
+                    privateKey = GetECKey("ECDSA", bcpgIn);
+                    break;
                 case PublicKeyAlgorithmTag.ElGamalEncrypt:
                 case PublicKeyAlgorithmTag.ElGamalGeneral:
                     ElGamalPublicBcpgKey elPub = (ElGamalPublicBcpgKey)pubPk.Key;
@@ -464,7 +483,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
                     throw new PgpException("unknown public key algorithm encountered");
                 }
 
-                return new PgpPrivateKey(privateKey, KeyId);
+                return new PgpPrivateKey(KeyId, pubPk, privateKey);
             }
             catch (PgpException e)
             {
@@ -476,6 +495,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
         }
 
+        private ECPrivateKeyParameters GetECKey(string algorithm, BcpgInputStream bcpgIn)
+        {
+            ECPublicBcpgKey ecdsaPub = (ECPublicBcpgKey)secret.PublicKeyPacket.Key;
+            ECSecretBcpgKey ecdsaPriv = new ECSecretBcpgKey(bcpgIn);
+            return new ECPrivateKeyParameters(algorithm, ecdsaPriv.X, ecdsaPub.CurveOid);
+        }
+
         private static byte[] Checksum(
             bool	useSha1,
             byte[]	bytes,
@@ -698,5 +724,174 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
             return c.DoFinal(rawKeyData);
         }
+
+        /**
+         * Parse a secret key from one of the GPG S expression keys associating it with the passed in public key.
+         *
+         * @return a secret key object.
+         */
+        public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase, PgpPublicKey pubKey)
+        {
+            SXprUtilities.SkipOpenParenthesis(inputStream);
+
+            string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+            if (type.Equals("protected-private-key"))
+            {
+                SXprUtilities.SkipOpenParenthesis(inputStream);
+
+                string curveName;
+
+                string keyType = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+                if (keyType.Equals("ecc"))
+                {
+                    SXprUtilities.SkipOpenParenthesis(inputStream);
+
+                    string curveID = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+                    curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+
+                    SXprUtilities.SkipCloseParenthesis(inputStream);
+                }
+                else
+                {
+                    throw new PgpException("no curve details found");
+                }
+
+                byte[] qVal;
+
+                SXprUtilities.SkipOpenParenthesis(inputStream);
+
+                type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+                if (type.Equals("q"))
+                {
+                    qVal = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+                }
+                else
+                {
+                    throw new PgpException("no q value found");
+                }
+
+                SXprUtilities.SkipCloseParenthesis(inputStream);
+
+                byte[] dValue = GetDValue(inputStream, passPhrase, curveName);
+                // TODO: check SHA-1 hash.
+
+                return new PgpSecretKey(new SecretKeyPacket(pubKey.PublicKeyPacket, SymmetricKeyAlgorithmTag.Null, null, null,
+                    new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), pubKey);
+            }
+
+            throw new PgpException("unknown key type found");
+        }
+
+        /**
+        * Parse a secret key from one of the GPG S expression keys.
+        *
+        * @return a secret key object.
+        */
+        public static PgpSecretKey ParseSecretKeyFromSExpr(Stream inputStream, char[] passPhrase)
+        {
+            SXprUtilities.SkipOpenParenthesis(inputStream);
+
+            string type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+            if (type.Equals("protected-private-key"))
+            {
+                SXprUtilities.SkipOpenParenthesis(inputStream);
+
+                string curveName;
+
+                string keyType = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+                if (keyType.Equals("ecc"))
+                {
+                    SXprUtilities.SkipOpenParenthesis(inputStream);
+
+                    string curveID = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+                    curveName = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+
+                    if (curveName.StartsWith("NIST "))
+                    {
+                        curveName = curveName.Substring("NIST ".Length);
+                    }
+
+                    SXprUtilities.SkipCloseParenthesis(inputStream);
+                }
+                else
+                {
+                    throw new PgpException("no curve details found");
+                }
+
+                byte[] qVal;
+
+                SXprUtilities.SkipOpenParenthesis(inputStream);
+
+                type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+                if (type.Equals("q"))
+                {
+                    qVal = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+                }
+                else
+                {
+                    throw new PgpException("no q value found");
+                }
+
+                PublicKeyPacket pubPacket = new PublicKeyPacket(PublicKeyAlgorithmTag.ECDsa, DateTime.UtcNow,
+                    new ECDsaPublicBcpgKey(ECNamedCurveTable.GetOid(curveName), new BigInteger(1, qVal)));
+
+                SXprUtilities.SkipCloseParenthesis(inputStream);
+
+                byte[] dValue = GetDValue(inputStream, passPhrase, curveName);
+                // TODO: check SHA-1 hash.
+
+                return new PgpSecretKey(new SecretKeyPacket(pubPacket, SymmetricKeyAlgorithmTag.Null, null, null,
+                    new ECSecretBcpgKey(new BigInteger(1, dValue)).GetEncoded()), new PgpPublicKey(pubPacket));
+            }
+
+            throw new PgpException("unknown key type found");
+        }
+
+        private static byte[] GetDValue(Stream inputStream, char[] passPhrase, string curveName)
+        {
+            string type;
+            SXprUtilities.SkipOpenParenthesis(inputStream);
+
+            string protection;
+            S2k s2k;
+            byte[] iv;
+            byte[] secKeyData;
+
+            type = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+            if (type.Equals("protected"))
+            {
+                protection = SXprUtilities.ReadString(inputStream, inputStream.ReadByte());
+
+                SXprUtilities.SkipOpenParenthesis(inputStream);
+
+                s2k = SXprUtilities.ParseS2k(inputStream);
+
+                iv = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+
+                SXprUtilities.SkipCloseParenthesis(inputStream);
+
+                secKeyData = SXprUtilities.ReadBytes(inputStream, inputStream.ReadByte());
+            }
+            else
+            {
+                throw new PgpException("protected block not found");
+            }
+
+            // TODO: recognise other algorithms
+            KeyParameter key = PgpUtilities.MakeKeyFromPassPhrase(SymmetricKeyAlgorithmTag.Aes128, s2k, passPhrase);
+
+            byte[] data = RecoverKeyData(SymmetricKeyAlgorithmTag.Aes128, "/CBC/NoPadding", key, iv, secKeyData, 0, secKeyData.Length);
+
+            //
+            // parse the secret key S-expr
+            //
+            Stream keyIn = new MemoryStream(data, false);
+
+            SXprUtilities.SkipOpenParenthesis(keyIn);
+            SXprUtilities.SkipOpenParenthesis(keyIn);
+            SXprUtilities.SkipOpenParenthesis(keyIn);
+            String name = SXprUtilities.ReadString(keyIn, keyIn.ReadByte());
+            return SXprUtilities.ReadBytes(keyIn, keyIn.ReadByte());
+        }
     }
 }
diff --git a/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs b/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
index 4adf64012..d2177d09c 100644
--- a/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
+++ b/crypto/src/openpgp/PgpSignatureSubpacketGenerator.cs
@@ -25,7 +25,14 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             list.Add(new Exportable(isCritical, isExportable));
         }
 
-		/// <summary>
+        public void SetFeature(
+            bool    isCritical,
+            byte    feature)
+        {
+            list.Add(new Features(isCritical, feature));
+        }
+
+        /// <summary>
 		/// Add a TrustSignature packet to the signature. The values for depth and trust are largely
 		/// installation dependent but there are some guidelines in RFC 4880 - 5.2.3.13.
 		/// </summary>
@@ -117,7 +124,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			list.Add(new SignerUserId(isCritical, userId));
         }
 
-		public void SetEmbeddedSignature(
+        public void SetSignerUserId(
+            bool    isCritical,
+            byte[]  rawUserId)
+        {
+            if (rawUserId == null)
+                throw new ArgumentNullException("rawUserId");
+
+            list.Add(new SignerUserId(isCritical, false, rawUserId));
+        }
+
+        public void SetEmbeddedSignature(
 			bool			isCritical,
 			PgpSignature	pgpSignature)
 		{
@@ -136,7 +153,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 
 			Array.Copy(sig, sig.Length - data.Length, data, 0, data.Length);
 
-			list.Add(new EmbeddedSignature(isCritical, data));
+			list.Add(new EmbeddedSignature(isCritical, false, data));
 		}
 
 		public void SetPrimaryUserId(
diff --git a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
index 68fe4b594..156243f4e 100644
--- a/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
+++ b/crypto/src/openpgp/PgpSignatureSubpacketVector.cs
@@ -209,7 +209,17 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 			return list;
         }
 
-		[Obsolete("Use 'Count' property instead")]
+        public Features GetFeatures()
+        {
+            SignatureSubpacket p = this.GetSubpacket(SignatureSubpacketTag.Features);
+
+            if (p == null)
+                return null;
+
+            return new Features(p.IsCritical(), p.IsLongLength(), p.GetData());
+        }
+
+        [Obsolete("Use 'Count' property instead")]
 		public int Size
 		{
 			get { return packets.Length; }
diff --git a/crypto/src/openpgp/PgpUtilities.cs b/crypto/src/openpgp/PgpUtilities.cs
index cd53cc029..89c85a5f7 100644
--- a/crypto/src/openpgp/PgpUtilities.cs
+++ b/crypto/src/openpgp/PgpUtilities.cs
@@ -86,7 +86,13 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 				case PublicKeyAlgorithmTag.Dsa:
 					encAlg = "DSA";
 					break;
-				case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
+                case PublicKeyAlgorithmTag.ECDH:
+                    encAlg = "ECDH";
+                    break;
+                case PublicKeyAlgorithmTag.ECDsa:
+                    encAlg = "ECDSA";
+                    break;
+                case PublicKeyAlgorithmTag.ElGamalEncrypt: // in some malformed cases.
 				case PublicKeyAlgorithmTag.ElGamalGeneral:
 					encAlg = "ElGamal";
 					break;
@@ -135,7 +141,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             }
         }
 
-	public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
+        public static int GetKeySize(SymmetricKeyAlgorithmTag algorithm)
         {
             int keySize;
             switch (algorithm)
@@ -193,7 +199,7 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
             char[]						passPhrase)
         {
 			int keySize = GetKeySize(algorithm);
-			byte[] pBytes = Strings.ToByteArray(new string(passPhrase));
+			byte[] pBytes = Encoding.UTF8.GetBytes(passPhrase);
 			byte[] keyBytes = new byte[(keySize + 7) / 8];
 
 			int generatedBytes = 0;
@@ -433,5 +439,22 @@ namespace Org.BouncyCastle.Bcpg.OpenPgp
 				return new ArmoredInputStream(inputStream, hasHeaders);
             }
         }
+
+        internal static IWrapper CreateWrapper(SymmetricKeyAlgorithmTag encAlgorithm)
+        {
+            switch (encAlgorithm)
+            {
+            case SymmetricKeyAlgorithmTag.Aes128:
+            case SymmetricKeyAlgorithmTag.Aes192:
+            case SymmetricKeyAlgorithmTag.Aes256:
+                return WrapperUtilities.GetWrapper("AESWRAP");
+            case SymmetricKeyAlgorithmTag.Camellia128:
+            case SymmetricKeyAlgorithmTag.Camellia192:
+            case SymmetricKeyAlgorithmTag.Camellia256:
+                return WrapperUtilities.GetWrapper("CAMELLIAWRAP");
+            default:
+                throw new PgpException("unknown wrap algorithm: " + encAlgorithm);
+            }
+        }
     }
 }
diff --git a/crypto/src/openpgp/Rfc6637Utilities.cs b/crypto/src/openpgp/Rfc6637Utilities.cs
new file mode 100644
index 000000000..5d992ec51
--- /dev/null
+++ b/crypto/src/openpgp/Rfc6637Utilities.cs
@@ -0,0 +1,138 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Asn1;
+using Org.BouncyCastle.Asn1.Nist;
+using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Math.EC;
+using Org.BouncyCastle.Security;
+using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Utilities.Encoders;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+    public sealed class Rfc6637Utilities
+    {
+        private Rfc6637Utilities()
+        {
+        }
+
+        // "Anonymous Sender    ", which is the octet sequence
+        private static readonly byte[] ANONYMOUS_SENDER = Hex.Decode("416E6F6E796D6F75732053656E64657220202020");
+
+        public static string GetAgreementAlgorithm(PublicKeyPacket pubKeyData)
+        {
+            ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key;
+
+            switch (ecKey.HashAlgorithm)
+            {
+            case HashAlgorithmTag.Sha256:
+                return "ECCDHwithSHA256CKDF";
+            case HashAlgorithmTag.Sha384:
+                return "ECCDHwithSHA384CKDF";
+            case HashAlgorithmTag.Sha512:
+                return "ECCDHwithSHA512CKDF";
+            default:
+                throw new ArgumentException("Unknown hash algorithm specified: " + ecKey.HashAlgorithm);
+            }
+        }
+
+        public static DerObjectIdentifier GetKeyEncryptionOID(SymmetricKeyAlgorithmTag algID)
+        {
+            switch (algID)
+            {
+            case SymmetricKeyAlgorithmTag.Aes128:
+                return NistObjectIdentifiers.IdAes128Wrap;
+            case SymmetricKeyAlgorithmTag.Aes192:
+                return NistObjectIdentifiers.IdAes192Wrap;
+            case SymmetricKeyAlgorithmTag.Aes256:
+                return NistObjectIdentifiers.IdAes256Wrap;
+            default:
+                throw new PgpException("unknown symmetric algorithm ID: " + algID);
+            }
+        }
+
+        public static int GetKeyLength(SymmetricKeyAlgorithmTag algID)
+        {
+            switch (algID)
+            {
+            case SymmetricKeyAlgorithmTag.Aes128:
+                return 16;
+            case SymmetricKeyAlgorithmTag.Aes192:
+                return 24;
+            case SymmetricKeyAlgorithmTag.Aes256:
+                return 32;
+            default:
+                throw new PgpException("unknown symmetric algorithm ID: " + algID);
+            }
+        }
+
+        public static byte[] CreateKey(PublicKeyPacket pubKeyData, ECPoint s)
+        {
+            byte[] userKeyingMaterial = CreateUserKeyingMaterial(pubKeyData);
+
+            ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key;
+
+            return Kdf(ecKey.HashAlgorithm, s, GetKeyLength(ecKey.SymmetricKeyAlgorithm), userKeyingMaterial);
+        }
+
+        // RFC 6637 - Section 8
+        // curve_OID_len = (byte)len(curve_OID);
+        // Param = curve_OID_len || curve_OID || public_key_alg_ID || 03
+        // || 01 || KDF_hash_ID || KEK_alg_ID for AESKeyWrap || "Anonymous
+        // Sender    " || recipient_fingerprint;
+        // Z_len = the key size for the KEK_alg_ID used with AESKeyWrap
+        // Compute Z = KDF( S, Z_len, Param );
+        public static byte[] CreateUserKeyingMaterial(PublicKeyPacket pubKeyData)
+        {
+            MemoryStream pOut = new MemoryStream();
+            ECDHPublicBcpgKey ecKey = (ECDHPublicBcpgKey)pubKeyData.Key;
+            byte[] encOid = ecKey.CurveOid.GetEncoded();
+
+            pOut.Write(encOid, 1, encOid.Length - 1);
+            pOut.WriteByte((byte)pubKeyData.Algorithm);
+            pOut.WriteByte(0x03);
+            pOut.WriteByte(0x01);
+            pOut.WriteByte((byte)ecKey.HashAlgorithm);
+            pOut.WriteByte((byte)ecKey.SymmetricKeyAlgorithm);
+            pOut.Write(ANONYMOUS_SENDER, 0, ANONYMOUS_SENDER.Length);
+
+            byte[] fingerprint = PgpPublicKey.CalculateFingerprint(pubKeyData);
+            pOut.Write(fingerprint, 0, fingerprint.Length);
+
+            return pOut.ToArray();
+        }
+
+        // RFC 6637 - Section 7
+        //   Implements KDF( X, oBits, Param );
+        //   Input: point X = (x,y)
+        //   oBits - the desired size of output
+        //   hBits - the size of output of hash function Hash
+        //   Param - octets representing the parameters
+        //   Assumes that oBits <= hBits
+        //   Convert the point X to the octet string, see section 6:
+        //   ZB' = 04 || x || y
+        //   and extract the x portion from ZB'
+        //         ZB = x;
+        //         MB = Hash ( 00 || 00 || 00 || 01 || ZB || Param );
+        //   return oBits leftmost bits of MB.
+        private static byte[] Kdf(HashAlgorithmTag digestAlg, ECPoint s, int keyLen, byte[] parameters)
+        {
+            byte[] ZB = s.XCoord.GetEncoded();
+
+            string digestName = PgpUtilities.GetDigestName(digestAlg);
+			IDigest digest = DigestUtilities.GetDigest(digestName);
+
+            digest.Update(0x00);
+            digest.Update(0x00);
+            digest.Update(0x00);
+            digest.Update(0x01);
+            digest.BlockUpdate(ZB, 0, ZB.Length);
+            digest.BlockUpdate(parameters, 0, parameters.Length);
+
+            byte[] hash = DigestUtilities.DoFinal(digest);
+
+            return Arrays.CopyOfRange(hash, 0, keyLen);
+        }
+    }
+}
diff --git a/crypto/src/openpgp/SXprUtilities.cs b/crypto/src/openpgp/SXprUtilities.cs
new file mode 100644
index 000000000..68ff373a8
--- /dev/null
+++ b/crypto/src/openpgp/SXprUtilities.cs
@@ -0,0 +1,102 @@
+using System;
+using System.IO;
+
+using Org.BouncyCastle.Utilities.IO;
+
+namespace Org.BouncyCastle.Bcpg.OpenPgp
+{
+    /**
+     * Utility functions for looking a S-expression keys. This class will move when it finds a better home!
+     * <p>
+     * Format documented here:
+     * http://git.gnupg.org/cgi-bin/gitweb.cgi?p=gnupg.git;a=blob;f=agent/keyformat.txt;h=42c4b1f06faf1bbe71ffadc2fee0fad6bec91a97;hb=refs/heads/master
+     * </p>
+     */
+    public sealed class SXprUtilities
+    {
+        private SXprUtilities()
+        {
+        }
+
+        private static int ReadLength(Stream input, int ch)
+        {
+            int len = ch - '0';
+
+            while ((ch = input.ReadByte()) >= 0 && ch != ':')
+            {
+                len = len * 10 + ch - '0';
+            }
+
+            return len;
+        }
+
+        internal static string ReadString(Stream input, int ch)
+        {
+            int len = ReadLength(input, ch);
+
+            char[] chars = new char[len];
+
+            for (int i = 0; i != chars.Length; i++)
+            {
+                chars[i] = (char)input.ReadByte();
+            }
+
+            return new string(chars);
+        }
+
+        internal static byte[] ReadBytes(Stream input, int ch)
+        {
+            int len = ReadLength(input, ch);
+
+            byte[] data = new byte[len];
+
+            Streams.ReadFully(input, data);
+
+            return data;
+        }
+
+        internal static S2k ParseS2k(Stream input)
+        {
+            SkipOpenParenthesis(input);
+
+            string alg = ReadString(input, input.ReadByte());
+            byte[] iv = ReadBytes(input, input.ReadByte());
+            long iterationCount = Int64.Parse(ReadString(input, input.ReadByte()));
+
+            SkipCloseParenthesis(input);
+
+            // we have to return the actual iteration count provided.
+            return new MyS2k(HashAlgorithmTag.Sha1, iv, iterationCount);
+        }
+
+        internal static void SkipOpenParenthesis(Stream input)
+        {
+            int ch = input.ReadByte();
+            if (ch != '(')
+                throw new IOException("unknown character encountered");
+        }
+
+        internal static void SkipCloseParenthesis(Stream input)
+        {
+            int ch = input.ReadByte();
+            if (ch != ')')
+                throw new IOException("unknown character encountered");
+        }
+
+        private class MyS2k : S2k
+        {
+            private readonly long mIterationCount64;
+
+            internal MyS2k(HashAlgorithmTag algorithm, byte[] iv, long iterationCount64)
+                : base(algorithm, iv, (int)iterationCount64)
+            {
+                this.mIterationCount64 = iterationCount64;
+            }
+
+            public override long IterationCount
+            {
+                get { return mIterationCount64; }
+            }
+        }
+    }
+}
diff --git a/crypto/src/openpgp/WrappedGeneratorStream.cs b/crypto/src/openpgp/WrappedGeneratorStream.cs
index e57797427..60a1fbb0b 100644
--- a/crypto/src/openpgp/WrappedGeneratorStream.cs
+++ b/crypto/src/openpgp/WrappedGeneratorStream.cs
@@ -1,6 +1,6 @@
 using System.IO;
 
-using Org.BouncyCastle.Asn1.Utilities;
+using Org.BouncyCastle.Utilities.IO;
 
 namespace Org.BouncyCastle.Bcpg.OpenPgp
 {
diff --git a/crypto/src/openssl/PEMReader.cs b/crypto/src/openssl/PEMReader.cs
index 8c19fe601..ec5d1b414 100644
--- a/crypto/src/openssl/PEMReader.cs
+++ b/crypto/src/openssl/PEMReader.cs
@@ -109,6 +109,7 @@ namespace Org.BouncyCastle.OpenSsl
                 case "X509 CERTIFICATE":
                     return ReadCertificate(obj);
                 case "PKCS7":
+                case "CMS":
                     return ReadPkcs7(obj);
                 case "X509 CRL":
                     return ReadCrl(obj);
diff --git a/crypto/src/pkcs/Pkcs10CertificationRequest.cs b/crypto/src/pkcs/Pkcs10CertificationRequest.cs
index 9f24eb18a..e32510aaa 100644
--- a/crypto/src/pkcs/Pkcs10CertificationRequest.cs
+++ b/crypto/src/pkcs/Pkcs10CertificationRequest.cs
@@ -15,6 +15,7 @@ using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Collections;
 using Org.BouncyCastle.X509;
+using Org.BouncyCastle.Crypto.Operators;
 
 namespace Org.BouncyCastle.Pkcs
 {
@@ -198,17 +199,18 @@ namespace Org.BouncyCastle.Pkcs
 			Stream input)
 			: base((Asn1Sequence) Asn1Object.FromStream(input))
 		{
-		}
-
-		/// <summary>
-		/// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
-		/// </summary>
-		///<param name="signatureAlgorithm">Name of Sig Alg.</param>
-		/// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
-		/// <param name="publicKey">Public Key to be included in cert reqest.</param>
-		/// <param name="attributes">ASN1Set of Attributes.</param>
-		/// <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param>
-		public Pkcs10CertificationRequest(
+        }
+
+        /// <summary>
+        /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+        /// </summary>
+        ///<param name="signatureAlgorithm">Name of Sig Alg.</param>
+        /// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
+        /// <param name="publicKey">Public Key to be included in cert reqest.</param>
+        /// <param name="attributes">ASN1Set of Attributes.</param>
+        /// <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param>
+        [Obsolete("Use constructor with an ISignatureCalculator")]
+        public Pkcs10CertificationRequest(
 			string					signatureAlgorithm,
 			X509Name				subject,
 			AsymmetricKeyParameter	publicKey,
@@ -226,79 +228,84 @@ namespace Org.BouncyCastle.Pkcs
 			if (!signingKey.IsPrivate)
 				throw new ArgumentException("key for signing must be private", "signingKey");
 
-//			DerObjectIdentifier sigOid = SignerUtilities.GetObjectIdentifier(signatureAlgorithm);
-			string algorithmName = Platform.ToUpperInvariant(signatureAlgorithm);
-			DerObjectIdentifier sigOid = (DerObjectIdentifier) algorithms[algorithmName];
-
-			if (sigOid == null)
-			{
-				try
-				{
-					sigOid = new DerObjectIdentifier(algorithmName);
-				}
-				catch (Exception e)
-				{
-					throw new ArgumentException("Unknown signature type requested", e);
-				}
-			}
-
-			if (noParams.Contains(sigOid))
-			{
-				this.sigAlgId = new AlgorithmIdentifier(sigOid);
-			}
-			else if (exParams.Contains(algorithmName))
-			{
-				this.sigAlgId = new AlgorithmIdentifier(sigOid, (Asn1Encodable) exParams[algorithmName]);
-			}
-			else
-			{
-				this.sigAlgId = new AlgorithmIdentifier(sigOid, DerNull.Instance);
-			}
-
-			SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
-
-			this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes);
-
-			ISigner sig = SignerUtilities.GetSigner(signatureAlgorithm);
-
-			sig.Init(true, signingKey);
-
-			try
-			{
-				// Encode.
-				byte[] b = reqInfo.GetDerEncoded();
-				sig.BlockUpdate(b, 0, b.Length);
-			}
-			catch (Exception e)
-			{
-				throw new ArgumentException("exception encoding TBS cert request", e);
-			}
-
-			// Generate Signature.
-			sigBits = new DerBitString(sig.GenerateSignature());
+            init(new Asn1SignatureCalculator(signatureAlgorithm, signingKey), subject, publicKey, attributes, signingKey);
 		}
 
-//        internal Pkcs10CertificationRequest(
-//        	Asn1InputStream seqStream)
-//        {
-//			Asn1Sequence seq = (Asn1Sequence) seqStream.ReadObject();
-//            try
-//            {
-//                this.reqInfo = CertificationRequestInfo.GetInstance(seq[0]);
-//                this.sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]);
-//                this.sigBits = (DerBitString) seq[2];
-//            }
-//            catch (Exception ex)
-//            {
-//                throw new ArgumentException("Create From Asn1Sequence: " + ex.Message);
-//            }
-//        }
-
-		/// <summary>
-		/// Get the public key.
-		/// </summary>
-		/// <returns>The public key.</returns>
-		public AsymmetricKeyParameter GetPublicKey()
+        /// <summary>
+        /// Instantiate a Pkcs10CertificationRequest object with the necessary credentials.
+        /// </summary>
+        ///<param name="signatureCalculator">The signature calculator to sign the PKCS#10 request with.</param>
+        /// <param name="subject">X509Name of subject eg OU="My unit." O="My Organisatioin" C="au" </param>
+        /// <param name="publicKey">Public Key to be included in cert reqest.</param>
+        /// <param name="attributes">ASN1Set of Attributes.</param>
+        /// <param name="signingKey">Matching Private key for nominated (above) public key to be used to sign the request.</param>
+        public Pkcs10CertificationRequest(
+            ISignatureCalculator signatureCalculator,
+            X509Name subject,
+            AsymmetricKeyParameter publicKey,
+            Asn1Set attributes,
+            AsymmetricKeyParameter signingKey)
+        {
+            if (signatureCalculator == null)
+                throw new ArgumentNullException("signatureCalculator");
+            if (subject == null)
+                throw new ArgumentNullException("subject");
+            if (publicKey == null)
+                throw new ArgumentNullException("publicKey");
+            if (publicKey.IsPrivate)
+                throw new ArgumentException("expected public key", "publicKey");
+            if (!signingKey.IsPrivate)
+                throw new ArgumentException("key for signing must be private", "signingKey");
+
+            init(signatureCalculator, subject, publicKey, attributes, signingKey);
+        }
+
+        private void init(
+            ISignatureCalculator signatureCalculator, 
+            X509Name subject,
+            AsymmetricKeyParameter publicKey,
+            Asn1Set attributes,
+            AsymmetricKeyParameter signingKey)
+        {
+            this.sigAlgId = (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails;
+
+            SubjectPublicKeyInfo pubInfo = SubjectPublicKeyInfoFactory.CreateSubjectPublicKeyInfo(publicKey);
+
+            this.reqInfo = new CertificationRequestInfo(subject, pubInfo, attributes);
+
+            IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
+
+            byte[] reqInfoData = reqInfo.GetDerEncoded();
+
+            streamCalculator.Stream.Write(reqInfoData, 0, reqInfoData.Length);
+
+            streamCalculator.Stream.Dispose();
+
+            // Generate Signature.
+            sigBits = new DerBitString(((IBlockResult)streamCalculator.GetResult()).DoFinal());
+        }
+
+        //        internal Pkcs10CertificationRequest(
+        //        	Asn1InputStream seqStream)
+        //        {
+        //			Asn1Sequence seq = (Asn1Sequence) seqStream.ReadObject();
+        //            try
+        //            {
+        //                this.reqInfo = CertificationRequestInfo.GetInstance(seq[0]);
+        //                this.sigAlgId = AlgorithmIdentifier.GetInstance(seq[1]);
+        //                this.sigBits = (DerBitString) seq[2];
+        //            }
+        //            catch (Exception ex)
+        //            {
+        //                throw new ArgumentException("Create From Asn1Sequence: " + ex.Message);
+        //            }
+        //        }
+
+        /// <summary>
+        /// Get the public key.
+        /// </summary>
+        /// <returns>The public key.</returns>
+        public AsymmetricKeyParameter GetPublicKey()
 		{
 			return PublicKeyFactory.CreateKey(reqInfo.SubjectPublicKeyInfo);
 		}
@@ -315,55 +322,47 @@ namespace Org.BouncyCastle.Pkcs
 		public bool Verify(
 			AsymmetricKeyParameter publicKey)
 		{
-			ISigner sig;
-
-			try
-			{
-				sig = SignerUtilities.GetSigner(GetSignatureName(sigAlgId));
-			}
-			catch (Exception e)
-			{
-				// try an alternate
-				string alt = (string) oids[sigAlgId.ObjectID];
-
-				if (alt != null)
-				{
-					sig = SignerUtilities.GetSigner(alt);
-				}
-				else
-				{
-					throw e;
-				}
-			}
-
-			SetSignatureParameters(sig, sigAlgId.Parameters);
-
-			sig.Init(false, publicKey);
-
-			try
-			{
-				byte[] b = reqInfo.GetDerEncoded();
-				sig.BlockUpdate(b, 0, b.Length);
-			}
-			catch (Exception e)
-			{
-				throw new SignatureException("exception encoding TBS cert request", e);
-			}
-
-			return sig.VerifySignature(sigBits.GetBytes());
+            return Verify(new Asn1SignatureVerifierProvider(publicKey));
 		}
 
-//        /// <summary>
-//        /// Get the Der Encoded Pkcs10 Certification Request.
-//        /// </summary>
-//        /// <returns>A byte array.</returns>
-//        public byte[] GetEncoded()
-//        {
-//        	return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded();
-//        }
-
-		// TODO Figure out how to set parameters on an ISigner
-		private void SetSignatureParameters(
+        public bool Verify(
+            ISignatureVerifierProvider verifierProvider)
+        {
+            return Verify(verifierProvider.CreateSignatureVerifier(sigAlgId));
+        }
+
+        public bool Verify(
+            ISignatureVerifier verifier)
+        {
+            try
+            {
+                byte[] b = reqInfo.GetDerEncoded();
+
+                IStreamCalculator streamCalculator = verifier.CreateCalculator();
+
+                streamCalculator.Stream.Write(b, 0, b.Length);
+
+                streamCalculator.Stream.Dispose();
+
+                return ((IVerifier)streamCalculator.GetResult()).IsVerified(sigBits.GetBytes());
+            }
+            catch (Exception e)
+            {
+                throw new SignatureException("exception encoding TBS cert request", e);
+            }
+        }
+
+        //        /// <summary>
+        //        /// Get the Der Encoded Pkcs10 Certification Request.
+        //        /// </summary>
+        //        /// <returns>A byte array.</returns>
+        //        public byte[] GetEncoded()
+        //        {
+        //        	return new CertificationRequest(reqInfo, sigAlgId, sigBits).GetDerEncoded();
+        //        }
+
+        // TODO Figure out how to set parameters on an ISigner
+        private void SetSignatureParameters(
 			ISigner			signature,
 			Asn1Encodable	asn1Params)
 		{
diff --git a/crypto/src/security/AgreementUtilities.cs b/crypto/src/security/AgreementUtilities.cs
index 4c61ac354..12d427c8c 100644
--- a/crypto/src/security/AgreementUtilities.cs
+++ b/crypto/src/security/AgreementUtilities.cs
@@ -22,14 +22,14 @@ namespace Org.BouncyCastle.Security
 		private static readonly IDictionary algorithms = Platform.CreateHashtable();
         //private static readonly IDictionary oids = Platform.CreateHashtable();
 
-		static AgreementUtilities()
+        static AgreementUtilities()
 		{
-			//algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = ?;
+            algorithms[X9ObjectIdentifiers.DHSinglePassCofactorDHSha1KdfScheme.Id] = "ECCDHWITHSHA1KDF";
 			algorithms[X9ObjectIdentifiers.DHSinglePassStdDHSha1KdfScheme.Id] = "ECDHWITHSHA1KDF";
 			algorithms[X9ObjectIdentifiers.MqvSinglePassSha1KdfScheme.Id] = "ECMQVWITHSHA1KDF";
 		}
 
-		public static IBasicAgreement GetBasicAgreement(
+        public static IBasicAgreement GetBasicAgreement(
 			DerObjectIdentifier oid)
 		{
 			return GetBasicAgreement(oid.Id);
@@ -52,8 +52,8 @@ namespace Org.BouncyCastle.Security
 			if (mechanism == "ECDH")
 				return new ECDHBasicAgreement();
 
-			if (mechanism == "ECDHC")
-				return new ECDHCBasicAgreement();
+            if (mechanism == "ECDHC" || mechanism == "ECCDH")
+                    return new ECDHCBasicAgreement();
 
 			if (mechanism == "ECMQV")
 				return new ECMqvBasicAgreement();
diff --git a/crypto/src/security/DigestUtilities.cs b/crypto/src/security/DigestUtilities.cs
index ec3f63940..7ddf6c8e4 100644
--- a/crypto/src/security/DigestUtilities.cs
+++ b/crypto/src/security/DigestUtilities.cs
@@ -21,11 +21,13 @@ namespace Org.BouncyCastle.Security
     {
         private enum DigestAlgorithm {
             GOST3411,
+            KECCAK_224, KECCAK_256, KECCAK_288, KECCAK_384, KECCAK_512,
             MD2, MD4, MD5,
             RIPEMD128, RIPEMD160, RIPEMD256, RIPEMD320,
             SHA_1, SHA_224, SHA_256, SHA_384, SHA_512,
             SHA_512_224, SHA_512_256,
             SHA3_224, SHA3_256, SHA3_384, SHA3_512,
+            SHAKE128, SHAKE256,
             TIGER,
             WHIRLPOOL,
         };
@@ -72,7 +74,12 @@ namespace Org.BouncyCastle.Security
 
             algorithms[CryptoProObjectIdentifiers.GostR3411.Id] = "GOST3411";
 
-
+            algorithms[NistObjectIdentifiers.IdSha3_224.Id] = "SHA3-224";
+            algorithms[NistObjectIdentifiers.IdSha3_256.Id] = "SHA3-256";
+            algorithms[NistObjectIdentifiers.IdSha3_384.Id] = "SHA3-384";
+            algorithms[NistObjectIdentifiers.IdSha3_512.Id] = "SHA3-512";
+            algorithms[NistObjectIdentifiers.IdShake128.Id] = "SHAKE128";
+            algorithms[NistObjectIdentifiers.IdShake256.Id] = "SHAKE256";
 
             oids["MD2"] = PkcsObjectIdentifiers.MD2;
             oids["MD4"] = PkcsObjectIdentifiers.MD4;
@@ -84,6 +91,12 @@ namespace Org.BouncyCastle.Security
             oids["SHA-512"] = NistObjectIdentifiers.IdSha512;
             oids["SHA-512/224"] = NistObjectIdentifiers.IdSha512_224;
             oids["SHA-512/256"] = NistObjectIdentifiers.IdSha512_256;
+            oids["SHA3-224"] = NistObjectIdentifiers.IdSha3_224;
+            oids["SHA3-256"] = NistObjectIdentifiers.IdSha3_256;
+            oids["SHA3-384"] = NistObjectIdentifiers.IdSha3_384;
+            oids["SHA3-512"] = NistObjectIdentifiers.IdSha3_512;
+            oids["SHAKE128"] = NistObjectIdentifiers.IdShake128;
+            oids["SHAKE256"] = NistObjectIdentifiers.IdShake256;
             oids["RIPEMD128"] = TeleTrusTObjectIdentifiers.RipeMD128;
             oids["RIPEMD160"] = TeleTrusTObjectIdentifiers.RipeMD160;
             oids["RIPEMD256"] = TeleTrusTObjectIdentifiers.RipeMD256;
@@ -141,7 +154,12 @@ namespace Org.BouncyCastle.Security
                 switch (digestAlgorithm)
                 {
                     case DigestAlgorithm.GOST3411:      return new Gost3411Digest();
-                    case DigestAlgorithm.MD2:		    return new MD2Digest();
+                    case DigestAlgorithm.KECCAK_224:    return new KeccakDigest(224);
+                    case DigestAlgorithm.KECCAK_256:    return new KeccakDigest(256);
+                    case DigestAlgorithm.KECCAK_288:    return new KeccakDigest(288);
+                    case DigestAlgorithm.KECCAK_384:    return new KeccakDigest(384);
+                    case DigestAlgorithm.KECCAK_512:    return new KeccakDigest(512);
+                    case DigestAlgorithm.MD2:           return new MD2Digest();
                     case DigestAlgorithm.MD4:		    return new MD4Digest();
                     case DigestAlgorithm.MD5:		    return new MD5Digest();
                     case DigestAlgorithm.RIPEMD128:	    return new RipeMD128Digest();
@@ -159,6 +177,8 @@ namespace Org.BouncyCastle.Security
                     case DigestAlgorithm.SHA3_256:      return new Sha3Digest(256);
                     case DigestAlgorithm.SHA3_384:      return new Sha3Digest(384);
                     case DigestAlgorithm.SHA3_512:      return new Sha3Digest(512);
+                    case DigestAlgorithm.SHAKE128:      return new ShakeDigest(128);
+                    case DigestAlgorithm.SHAKE256:      return new ShakeDigest(256);
                     case DigestAlgorithm.TIGER:         return new TigerDigest();
                     case DigestAlgorithm.WHIRLPOOL:     return new WhirlpoolDigest();
                 }
diff --git a/crypto/src/security/SecureRandom.cs b/crypto/src/security/SecureRandom.cs
index dc91069a1..4745c0bae 100644
--- a/crypto/src/security/SecureRandom.cs
+++ b/crypto/src/security/SecureRandom.cs
@@ -13,12 +13,16 @@ namespace Org.BouncyCastle.Security
     {
         private static long counter = Times.NanoTime();
 
+#if NETCF_1_0 || PCL
+        private static object counterLock = new object();
         private static long NextCounterValue()
         {
-            return Interlocked.Increment(ref counter);
+            lock (counterLock)
+            {
+                return ++counter;
+            }
         }
 
-#if NETCF_1_0 || PCL
         private static readonly SecureRandom[] master = { null };
         private static SecureRandom Master
         {
@@ -43,6 +47,11 @@ namespace Org.BouncyCastle.Security
             }
         }
 #else
+        private static long NextCounterValue()
+        {
+            return Interlocked.Increment(ref counter);
+        }
+
         private static readonly SecureRandom master = new SecureRandom(new CryptoApiRandomGenerator());
         private static SecureRandom Master
         {
diff --git a/crypto/src/util/io/FilterStream.cs b/crypto/src/util/io/FilterStream.cs
new file mode 100644
index 000000000..1aa1f9889
--- /dev/null
+++ b/crypto/src/util/io/FilterStream.cs
@@ -0,0 +1,70 @@
+using System.IO;
+
+namespace Org.BouncyCastle.Utilities.IO
+{
+    public class FilterStream : Stream
+    {
+        public FilterStream(Stream s)
+        {
+            this.s = s;
+        }
+        public override bool CanRead
+        {
+            get { return s.CanRead; }
+        }
+        public override bool CanSeek
+        {
+            get { return s.CanSeek; }
+        }
+        public override bool CanWrite
+        {
+            get { return s.CanWrite; }
+        }
+        public override long Length
+        {
+            get { return s.Length; }
+        }
+        public override long Position
+        {
+            get { return s.Position; }
+            set { s.Position = value; }
+        }
+        protected override void Dispose(bool disposing)
+        {
+            if (disposing)
+            {
+                s.Dispose();
+            }
+            base.Dispose(disposing);
+        }
+        public override void Flush()
+        {
+            s.Flush();
+        }
+        public override long Seek(long offset, SeekOrigin origin)
+        {
+            return s.Seek(offset, origin);
+        }
+        public override void SetLength(long value)
+        {
+            s.SetLength(value);
+        }
+        public override int Read(byte[] buffer, int offset, int count)
+        {
+            return s.Read(buffer, offset, count);
+        }
+        public override int ReadByte()
+        {
+            return s.ReadByte();
+        }
+        public override void Write(byte[] buffer, int offset, int count)
+        {
+            s.Write(buffer, offset, count);
+        }
+        public override void WriteByte(byte value)
+        {
+            s.WriteByte(value);
+        }
+        protected readonly Stream s;
+    }
+}
diff --git a/crypto/src/x509/X509Certificate.cs b/crypto/src/x509/X509Certificate.cs
index f156f3147..415130044 100644
--- a/crypto/src/x509/X509Certificate.cs
+++ b/crypto/src/x509/X509Certificate.cs
@@ -14,6 +14,7 @@ using Org.BouncyCastle.Security.Certificates;
 using Org.BouncyCastle.Utilities;
 using Org.BouncyCastle.Utilities.Encoders;
 using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.Crypto.Operators;
 
 namespace Org.BouncyCastle.X509
 {
@@ -546,30 +547,38 @@ namespace Org.BouncyCastle.X509
 		public virtual void Verify(
 			AsymmetricKeyParameter key)
 		{
-			string sigName = X509SignatureUtilities.GetSignatureName(c.SignatureAlgorithm);
-			ISigner signature = SignerUtilities.GetSigner(sigName);
-
-			CheckSignature(key, signature);
+			CheckSignature(new Asn1SignatureVerifier(c.SignatureAlgorithm, key));
 		}
 
-		protected virtual void CheckSignature(
-			AsymmetricKeyParameter	publicKey,
-			ISigner					signature)
+        /// <summary>
+        /// Verify the certificate's signature using a verifier created using the passed in verifier provider.
+        /// </summary>
+        /// <param name="verifierProvider">An appropriate provider for verifying the certificate's signature.</param>
+        /// <returns>True if the signature is valid.</returns>
+        /// <exception cref="Exception">If verifier provider is not appropriate or the certificate algorithm is invalid.</exception>
+        public virtual void Verify(
+            ISignatureVerifierProvider verifierProvider)
+        {
+            CheckSignature(verifierProvider.CreateSignatureVerifier (c.SignatureAlgorithm));
+        }
+
+        protected virtual void CheckSignature(
+			ISignatureVerifier verifier)
 		{
 			if (!IsAlgIDEqual(c.SignatureAlgorithm, c.TbsCertificate.Signature))
 				throw new CertificateException("signature algorithm in TBS cert not same as outer cert");
 
 			Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
 
-			X509SignatureUtilities.SetSignatureParameters(signature, parameters);
-
-			signature.Init(false, publicKey);
+            IStreamCalculator streamCalculator = verifier.CreateCalculator();
 
 			byte[] b = this.GetTbsCertificate();
-			signature.BlockUpdate(b, 0, b.Length);
 
-			byte[] sig = this.GetSignature();
-			if (!signature.VerifySignature(sig))
+			streamCalculator.Stream.Write(b, 0, b.Length);
+
+            streamCalculator.Stream.Dispose();
+
+            if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature()))
 			{
 				throw new InvalidKeyException("Public key presented not for certificate signature");
 			}
diff --git a/crypto/src/x509/X509Crl.cs b/crypto/src/x509/X509Crl.cs
index 7d0e7aa72..c7740781e 100644
--- a/crypto/src/x509/X509Crl.cs
+++ b/crypto/src/x509/X509Crl.cs
@@ -14,6 +14,7 @@ using Org.BouncyCastle.Utilities.Collections;
 using Org.BouncyCastle.Utilities.Date;
 using Org.BouncyCastle.Utilities.Encoders;
 using Org.BouncyCastle.X509.Extension;
+using Org.BouncyCastle.Crypto.Operators;
 
 namespace Org.BouncyCastle.X509
 {
@@ -83,24 +84,46 @@ namespace Org.BouncyCastle.X509
 		public virtual void Verify(
 			AsymmetricKeyParameter publicKey)
 		{
-			if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
-			{
-				throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
-			}
+            Verify(new Asn1SignatureVerifierProvider(publicKey));
+		}
 
-			ISigner sig = SignerUtilities.GetSigner(SigAlgName);
-			sig.Init(false, publicKey);
+        /// <summary>
+        /// Verify the CRL's signature using a verifier created using the passed in verifier provider.
+        /// </summary>
+        /// <param name="verifierProvider">An appropriate provider for verifying the CRL's signature.</param>
+        /// <returns>True if the signature is valid.</returns>
+        /// <exception cref="Exception">If verifier provider is not appropriate or the CRL algorithm is invalid.</exception>
+        public virtual void Verify(
+            ISignatureVerifierProvider verifierProvider)
+        {
+            CheckSignature(verifierProvider.CreateSignatureVerifier(c.SignatureAlgorithm));
+        }
 
-			byte[] encoded = this.GetTbsCertList();
-			sig.BlockUpdate(encoded, 0, encoded.Length);
+        protected virtual void CheckSignature(
+            ISignatureVerifier verifier)
+        {
+            if (!c.SignatureAlgorithm.Equals(c.TbsCertList.Signature))
+            {
+                throw new CrlException("Signature algorithm on CertificateList does not match TbsCertList.");
+            }
 
-			if (!sig.VerifySignature(this.GetSignature()))
-			{
-				throw new SignatureException("CRL does not verify with supplied public key.");
-			}
-		}
+            Asn1Encodable parameters = c.SignatureAlgorithm.Parameters;
+
+            IStreamCalculator streamCalculator = verifier.CreateCalculator();
+
+            byte[] b = this.GetTbsCertList();
+
+            streamCalculator.Stream.Write(b, 0, b.Length);
+
+            streamCalculator.Stream.Dispose();
+
+            if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature()))
+            {
+                throw new InvalidKeyException("CRL does not verify with supplied public key.");
+            }
+        }
 
-		public virtual int Version
+        public virtual int Version
 		{
 			get { return c.Version; }
 		}
diff --git a/crypto/src/x509/X509V1CertificateGenerator.cs b/crypto/src/x509/X509V1CertificateGenerator.cs
index 02b58a198..354b91b8d 100644
--- a/crypto/src/x509/X509V1CertificateGenerator.cs
+++ b/crypto/src/x509/X509V1CertificateGenerator.cs
@@ -1,10 +1,12 @@
 using System;
+using System.IO;
 using System.Collections;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
 using Org.BouncyCastle.Crypto.Parameters;
+using Org.BouncyCastle.Crypto.Operators;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Security.Certificates;
@@ -119,6 +121,7 @@ namespace Org.BouncyCastle.X509
 		/// This can be either a name or an OID, names are treated as case insensitive.
 		/// </summary>
 		/// <param name="signatureAlgorithm">string representation of the algorithm name</param>
+		[Obsolete("Not needed if Generate used with an ISignatureCalculator")]
 		public void SetSignatureAlgorithm(
 			string signatureAlgorithm)
 		{
@@ -143,6 +146,7 @@ namespace Org.BouncyCastle.X509
 		/// </summary>
 		/// <param name="privateKey">The private key of the issuer used to sign this certificate.</param>
 		/// <returns>An X509Certificate.</returns>
+		[Obsolete("Use Generate with an ISignatureCalculator")]
 		public X509Certificate Generate(
 			AsymmetricKeyParameter privateKey)
 		{
@@ -155,43 +159,43 @@ namespace Org.BouncyCastle.X509
         /// <param name="privateKey">The private key of the issuer used to sign this certificate.</param>
         /// <param name="random">The Secure Random you want to use.</param>
         /// <returns>An X509Certificate.</returns>
+		[Obsolete("Use Generate with an ISignatureCalculator")]
 		public X509Certificate Generate(
 			AsymmetricKeyParameter	privateKey,
 			SecureRandom			random)
 		{
+			return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random));
+		}
+
+		/// <summary>
+		/// Generate a new X509Certificate using the passed in SignatureCalculator.
+		/// </summary>
+		/// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param>
+		/// <returns>An X509Certificate.</returns>
+		public X509Certificate Generate(ISignatureCalculator signatureCalculator)
+		{
+			tbsGen.SetSignature ((AlgorithmIdentifier)signatureCalculator.AlgorithmDetails);
+
 			TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
-			byte[] signature;
 
-			try
-			{
-				signature = X509Utilities.GetSignatureForObject(
-					sigOID, signatureAlgorithm, privateKey, random, tbsCert);
-			}
-			catch (Exception e)
-			{
-				// TODO
-//				throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
-				throw new CertificateEncodingException("exception encoding TBS cert", e);
-			}
+            IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
 
-			try
-			{
-				return GenerateJcaObject(tbsCert, signature);
-			}
-			catch (CertificateParsingException e)
-			{
-				// TODO
-				// throw new ExtCertificateEncodingException("exception producing certificate object", e);
-				throw new CertificateEncodingException("exception producing certificate object", e);
-			}
+            byte[] encoded = tbsCert.GetDerEncoded();
+
+            streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+            streamCalculator.Stream.Dispose();
+
+            return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal());
 		}
 
 		private X509Certificate GenerateJcaObject(
 			TbsCertificateStructure	tbsCert,
+			AlgorithmIdentifier     sigAlg,
 			byte[]					signature)
 		{
 			return new X509Certificate(
-				new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+				new X509CertificateStructure(tbsCert, sigAlg, new DerBitString(signature)));
 		}
 
 		/// <summary>
diff --git a/crypto/src/x509/X509V2AttributeCertificate.cs b/crypto/src/x509/X509V2AttributeCertificate.cs
index 117ac4cc2..56a7fc7a7 100644
--- a/crypto/src/x509/X509V2AttributeCertificate.cs
+++ b/crypto/src/x509/X509V2AttributeCertificate.cs
@@ -9,6 +9,7 @@ using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Security.Certificates;
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Crypto.Operators;
 
 namespace Org.BouncyCastle.X509
 {
@@ -151,29 +152,48 @@ namespace Org.BouncyCastle.X509
 			return cert.SignatureValue.GetBytes();
 		}
 
-		public virtual void Verify(
-			AsymmetricKeyParameter publicKey)
-		{
-			if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature))
+        public virtual void Verify(
+            AsymmetricKeyParameter key)
+        {
+            CheckSignature(new Asn1SignatureVerifier(cert.SignatureAlgorithm, key));
+        }
+
+        /// <summary>
+        /// Verify the certificate's signature using a verifier created using the passed in verifier provider.
+        /// </summary>
+        /// <param name="verifierProvider">An appropriate provider for verifying the certificate's signature.</param>
+        /// <returns>True if the signature is valid.</returns>
+        /// <exception cref="Exception">If verifier provider is not appropriate or the certificate algorithm is invalid.</exception>
+        public virtual void Verify(
+            ISignatureVerifierProvider verifierProvider)
+        {
+            CheckSignature(verifierProvider.CreateSignatureVerifier(cert.SignatureAlgorithm));
+        }
+
+        protected virtual void CheckSignature(
+            ISignatureVerifier verifier)
+        {
+            if (!cert.SignatureAlgorithm.Equals(cert.ACInfo.Signature))
 			{
 				throw new CertificateException("Signature algorithm in certificate info not same as outer certificate");
 			}
 
-			ISigner signature = SignerUtilities.GetSigner(cert.SignatureAlgorithm.ObjectID.Id);
-
-			signature.Init(false, publicKey);
+            IStreamCalculator streamCalculator = verifier.CreateCalculator();
 
 			try
 			{
-				byte[] b = cert.ACInfo.GetEncoded();
-				signature.BlockUpdate(b, 0, b.Length);
-			}
+                byte[] b = this.cert.ACInfo.GetEncoded();
+
+                streamCalculator.Stream.Write(b, 0, b.Length);
+
+                streamCalculator.Stream.Dispose();
+            }
 			catch (IOException e)
 			{
 				throw new SignatureException("Exception encoding certificate info object", e);
 			}
 
-			if (!signature.VerifySignature(this.GetSignature()))
+			if (!((IVerifier)streamCalculator.GetResult()).IsVerified(this.GetSignature()))
 			{
 				throw new InvalidKeyException("Public key presented not for certificate signature");
 			}
diff --git a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
index a683d5e20..507d00de8 100644
--- a/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
+++ b/crypto/src/x509/X509V2AttributeCertificateGenerator.cs
@@ -8,6 +8,8 @@ using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Security.Certificates;
 using Org.BouncyCastle.Utilities;
+using Org.BouncyCastle.Crypto.Operators;
+using System.IO;
 
 namespace Org.BouncyCastle.X509
 {
@@ -66,12 +68,13 @@ namespace Org.BouncyCastle.X509
 			acInfoGen.SetEndDate(new DerGeneralizedTime(date));
 		}
 
-		/// <summary>
-		/// Set the signature algorithm. This can be either a name or an OID, names
-		/// are treated as case insensitive.
-		/// </summary>
-		/// <param name="signatureAlgorithm">The algorithm name.</param>
-		public void SetSignatureAlgorithm(
+        /// <summary>
+        /// Set the signature algorithm. This can be either a name or an OID, names
+        /// are treated as case insensitive.
+        /// </summary>
+        /// <param name="signatureAlgorithm">The algorithm name.</param>
+        [Obsolete("Not needed if Generate used with an ISignatureCalculator")]
+        public void SetSignatureAlgorithm(
 			string signatureAlgorithm)
 		{
 			this.signatureAlgorithm = signatureAlgorithm;
@@ -127,37 +130,57 @@ namespace Org.BouncyCastle.X509
 			extGenerator.AddExtension(new DerObjectIdentifier(oid), critical, extensionValue);
 		}
 
-		/// <summary>
-		/// Generate an X509 certificate, based on the current issuer and subject.
-		/// </summary>
-		public IX509AttributeCertificate Generate(
-			AsymmetricKeyParameter publicKey)
+        /// <summary>
+        /// Generate an X509 certificate, based on the current issuer and subject.
+        /// </summary>
+        [Obsolete("Use Generate with an ISignatureCalculator")]
+        public IX509AttributeCertificate Generate(
+			AsymmetricKeyParameter privateKey)
 		{
-			return Generate(publicKey, null);
+			return Generate(privateKey, null);
 		}
 
-		/// <summary>
-		/// Generate an X509 certificate, based on the current issuer and subject,
-		/// using the supplied source of randomness, if required.
-		/// </summary>
-		public IX509AttributeCertificate Generate(
-			AsymmetricKeyParameter	publicKey,
+        /// <summary>
+        /// Generate an X509 certificate, based on the current issuer and subject,
+        /// using the supplied source of randomness, if required.
+        /// </summary>
+        [Obsolete("Use Generate with an ISignatureCalculator")]
+        public IX509AttributeCertificate Generate(
+			AsymmetricKeyParameter	privateKey,
 			SecureRandom			random)
-		{
-			if (!extGenerator.IsEmpty)
+        {
+            return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random));
+        }
+
+        /// <summary>
+        /// Generate a new X.509 Attribute Certificate using the passed in SignatureCalculator.
+        /// </summary>
+        /// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param>
+        /// <returns>An IX509AttributeCertificate.</returns>
+        public IX509AttributeCertificate Generate(ISignatureCalculator signatureCalculator)
+        {
+            if (!extGenerator.IsEmpty)
 			{
 				acInfoGen.SetExtensions(extGenerator.Generate());
 			}
 
 			AttributeCertificateInfo acInfo = acInfoGen.GenerateAttributeCertificateInfo();
 
-			Asn1EncodableVector v = new Asn1EncodableVector();
+            byte[] encoded = acInfo.GetDerEncoded();
+
+            IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
+
+            streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+            streamCalculator.Stream.Dispose();
+
+            Asn1EncodableVector v = new Asn1EncodableVector();
 
-			v.Add(acInfo, sigAlgId);
+			v.Add(acInfo, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails);
 
 			try
 			{
-				v.Add(new DerBitString(X509Utilities.GetSignatureForObject(sigOID, signatureAlgorithm, publicKey, random, acInfo)));
+				v.Add(new DerBitString(((IBlockResult)streamCalculator.GetResult()).DoFinal()));
 
 				return new X509V2AttributeCertificate(AttributeCertificate.GetInstance(new DerSequence(v)));
 			}
diff --git a/crypto/src/x509/X509V2CRLGenerator.cs b/crypto/src/x509/X509V2CRLGenerator.cs
index a2293b333..1f22e88b3 100644
--- a/crypto/src/x509/X509V2CRLGenerator.cs
+++ b/crypto/src/x509/X509V2CRLGenerator.cs
@@ -10,6 +10,7 @@ using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
 using Org.BouncyCastle.Security.Certificates;
 using Org.BouncyCastle.Utilities.Collections;
+using Org.BouncyCastle.Crypto.Operators;
 
 namespace Org.BouncyCastle.X509
 {
@@ -129,13 +130,12 @@ namespace Org.BouncyCastle.X509
 			}
 		}
 
-		/**
-		* Set the signature algorithm. This can be either a name or an oid, names
-		* are treated as case insensitive.
-		*
-		* @param signatureAlgorithm string representation of the algorithm name.
-		*/
-		public void SetSignatureAlgorithm(
+        /// <summary>
+        /// Set the signature algorithm that will be used to sign this CRL.
+        /// </summary>
+        /// <param name="signatureAlgorithm"/>
+        [Obsolete("Not needed if Generate used with an ISignatureCalculator")]
+        public void SetSignatureAlgorithm(
 			string signatureAlgorithm)
 		{
 			this.signatureAlgorithm = signatureAlgorithm;
@@ -198,40 +198,55 @@ namespace Org.BouncyCastle.X509
 			extGenerator.AddExtension(oid, critical, new DerOctetString(extensionValue));
 		}
 
-		/// <summary>Generate an X509 CRL, based on the current issuer and subject.</summary>
-		/// <param name="privateKey">The key used for signing.</param>
-		public X509Crl Generate(
-			AsymmetricKeyParameter privateKey)
-		{
-			return Generate(privateKey, null);
-		}
+        /// <summary>
+        /// Generate an X.509 CRL, based on the current issuer and subject.
+        /// </summary>
+        /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
+        /// <returns>An X509Crl.</returns>
+        [Obsolete("Use Generate with an ISignatureCalculator")]
+        public X509Crl Generate(
+            AsymmetricKeyParameter privateKey)
+        {
+            return Generate(privateKey, null);
+        }
 
-		/// <summary>Generate an X509 CRL, based on the current issuer and subject.</summary>
-		/// <param name="privateKey">The key used for signing.</param>
-		/// <param name="random">A user-defined source of randomness.</param>
-		public X509Crl Generate(
-			AsymmetricKeyParameter	privateKey,
-			SecureRandom			random)
-		{
-			TbsCertificateList tbsCrl = GenerateCertList();
-			byte[] signature;
+        /// <summary>
+        /// Generate an X.509 CRL, based on the current issuer and subject using the specified secure random.
+        /// </summary>
+        /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
+        /// <param name="random">Your Secure Random instance.</param>
+        /// <returns>An X509Crl.</returns>
+        [Obsolete("Use Generate with an ISignatureCalculator")]
+        public X509Crl Generate(
+            AsymmetricKeyParameter privateKey,
+            SecureRandom random)
+        {
+            return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random));
+        }
 
-			try
-			{
-				signature = X509Utilities.GetSignatureForObject(
-					sigOID, signatureAlgorithm, privateKey, random, tbsCrl);
-			}
-			catch (IOException e)
-			{
-				// TODO
-//				throw new ExtCrlException("cannot generate CRL encoding", e);
-				throw new CrlException("cannot generate CRL encoding", e);
-			}
+        /// <summary>
+        /// Generate a new X509Crl using the passed in SignatureCalculator.
+        /// </summary>
+        /// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param>
+        /// <returns>An X509Crl.</returns>
+        public X509Crl Generate(ISignatureCalculator signatureCalculator)
+        {
+            tbsGen.SetSignature((AlgorithmIdentifier)signatureCalculator.AlgorithmDetails);
 
-			return GenerateJcaObject(tbsCrl, signature);
-		}
+            TbsCertificateList tbsCertList = GenerateCertList();
+
+            IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
+
+            byte[] encoded = tbsCertList.GetDerEncoded();
+
+            streamCalculator.Stream.Write(encoded, 0, encoded.Length);
+
+            streamCalculator.Stream.Dispose();
+
+            return GenerateJcaObject(tbsCertList, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal());
+        }
 
-		private TbsCertificateList GenerateCertList()
+        private TbsCertificateList GenerateCertList()
 		{
 			if (!extGenerator.IsEmpty)
 			{
@@ -243,11 +258,12 @@ namespace Org.BouncyCastle.X509
 
 		private X509Crl GenerateJcaObject(
 			TbsCertificateList	tbsCrl,
+            AlgorithmIdentifier algId,
 			byte[]				signature)
 		{
 			return new X509Crl(
 				CertificateList.GetInstance(
-					new DerSequence(tbsCrl, sigAlgId, new DerBitString(signature))));
+					new DerSequence(tbsCrl, algId, new DerBitString(signature))));
 		}
 
 		/// <summary>
diff --git a/crypto/src/x509/X509V3CertificateGenerator.cs b/crypto/src/x509/X509V3CertificateGenerator.cs
index bb0dd9cbc..5af5dca3b 100644
--- a/crypto/src/x509/X509V3CertificateGenerator.cs
+++ b/crypto/src/x509/X509V3CertificateGenerator.cs
@@ -1,9 +1,11 @@
 using System;
 using System.Collections;
+using System.IO;
 
 using Org.BouncyCastle.Asn1;
 using Org.BouncyCastle.Asn1.X509;
 using Org.BouncyCastle.Crypto;
+using Org.BouncyCastle.Crypto.Operators;
 using Org.BouncyCastle.Crypto.Parameters;
 using Org.BouncyCastle.Math;
 using Org.BouncyCastle.Security;
@@ -110,6 +112,7 @@ namespace Org.BouncyCastle.X509
         /// Set the signature algorithm that will be used to sign this certificate.
         /// </summary>
         /// <param name="signatureAlgorithm"/>
+		[Obsolete("Not needed if Generate used with an ISignatureCalculator")]
         public void SetSignatureAlgorithm(
 			string signatureAlgorithm)
         {
@@ -274,7 +277,8 @@ namespace Org.BouncyCastle.X509
         /// </summary>
         /// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
         /// <returns>An X509Certificate.</returns>
-        public X509Certificate Generate(
+		[Obsolete("Use Generate with an ISignatureCalculator")]
+		public X509Certificate Generate(
 			AsymmetricKeyParameter privateKey)
         {
             return Generate(privateKey, null);
@@ -286,53 +290,48 @@ namespace Org.BouncyCastle.X509
 		/// <param name="privateKey">The private key of the issuer that is signing this certificate.</param>
 		/// <param name="random">You Secure Random instance.</param>
 		/// <returns>An X509Certificate.</returns>
+		[Obsolete("Use Generate with an ISignatureCalculator")]
 		public X509Certificate Generate(
 			AsymmetricKeyParameter	privateKey,
 			SecureRandom			random)
 		{
-			TbsCertificateStructure tbsCert = GenerateTbsCert();
-			byte[] signature;
-
-			try
-			{
-				signature = X509Utilities.GetSignatureForObject(
-					sigOid, signatureAlgorithm, privateKey, random, tbsCert);
-			}
-			catch (Exception e)
-			{
-				// TODO
-//				throw new ExtCertificateEncodingException("exception encoding TBS cert", e);
-				throw new CertificateEncodingException("exception encoding TBS cert", e);
-			}
-
-			try
-			{
-				return GenerateJcaObject(tbsCert, signature);
-			}
-			catch (CertificateParsingException e)
-			{
-				// TODO
-				// throw new ExtCertificateEncodingException("exception producing certificate object", e);
-				throw new CertificateEncodingException("exception producing certificate object", e);
-			}
+			return Generate(new Asn1SignatureCalculator(signatureAlgorithm, privateKey, random));
 		}
 
-		private TbsCertificateStructure GenerateTbsCert()
+		/// <summary>
+		/// Generate a new X509Certificate using the passed in SignatureCalculator.
+		/// </summary>
+		/// <param name="signatureCalculator">A signature calculator with the necessary algorithm details.</param>
+		/// <returns>An X509Certificate.</returns>
+		public X509Certificate Generate(ISignatureCalculator signatureCalculator)
 		{
-			if (!extGenerator.IsEmpty)
-			{
-				tbsGen.SetExtensions(extGenerator.Generate());
-			}
+			tbsGen.SetSignature ((AlgorithmIdentifier)signatureCalculator.AlgorithmDetails);
+
+            if (!extGenerator.IsEmpty)
+            {
+                tbsGen.SetExtensions(extGenerator.Generate());
+            }
+
+            TbsCertificateStructure tbsCert = tbsGen.GenerateTbsCertificate();
+
+			IStreamCalculator streamCalculator = signatureCalculator.CreateCalculator();
+
+			byte[] encoded = tbsCert.GetDerEncoded();
+
+			streamCalculator.Stream.Write (encoded, 0, encoded.Length);
+
+            streamCalculator.Stream.Dispose ();
 
-			return tbsGen.GenerateTbsCertificate();
+			return GenerateJcaObject(tbsCert, (AlgorithmIdentifier)signatureCalculator.AlgorithmDetails, ((IBlockResult)streamCalculator.GetResult()).DoFinal());
 		}
 
 		private X509Certificate GenerateJcaObject(
 			TbsCertificateStructure	tbsCert,
+			AlgorithmIdentifier     sigAlg,
 			byte[]					signature)
 		{
 			return new X509Certificate(
-				new X509CertificateStructure(tbsCert, sigAlgId, new DerBitString(signature)));
+				new X509CertificateStructure(tbsCert, sigAlg, new DerBitString(signature)));
 		}
 
 		/// <summary>